1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "sk_ohoscodec.h"
17 #include "src/codec/SkSampler.h"
18 #include "include/codec/SkCodec.h"
19 #include "include/core/SkPixmap.h"
20 #include "src/codec/SkCodecPriv.h"
21 #include "src/codec/SkSampledCodec.h"
22 #include "src/core/SkMathPriv.h"
23
is_valid_sample_size(int sampleSize)24 static bool is_valid_sample_size(int sampleSize)
25 {
26 return sampleSize > 0;
27 }
28
29 static constexpr int RGB_CHANNEL_COUNT = 3;
30 static constexpr int SAMPLE_SIZE_TWO = 2;
31 static constexpr int SAMPLE_SIZE_FOUR = 4;
32 static constexpr int SAMPLE_SIZE_EIGHT = 8;
33
load_gamut(SkPoint rgb[],int length,const skcms_Matrix3x3 & xyz)34 static void load_gamut(SkPoint rgb[], int length, const skcms_Matrix3x3& xyz)
35 {
36 // rx = rX / (rX + rY + rZ)
37 // ry = rY / (rX + rY + rZ)
38 // gx, gy, bx, and gy are calulcated similarly.
39 for (int rgbIdx = 0; rgbIdx < length; rgbIdx++) {
40 float sum = xyz.vals[rgbIdx][0] + xyz.vals[rgbIdx][1] + xyz.vals[rgbIdx][2];
41 rgb[rgbIdx].fX = xyz.vals[rgbIdx][0] / sum;
42 rgb[rgbIdx].fY = xyz.vals[rgbIdx][1] / sum;
43 }
44 }
45
calculate_area(SkPoint abc[],int length)46 static float calculate_area(SkPoint abc[], int length)
47 {
48 SkPoint a = abc[length - 3];
49 SkPoint b = abc[length - 2];
50 SkPoint c = abc[length - 1];
51 return 0.5f * SkTAbs(a.fX*b.fY + b.fX*c.fY - a.fX*c.fY - c.fX*b.fY - b.fX*a.fY);
52 }
53
54 static constexpr float SRGB_D50_GAMUT_AREA = 0.084f;
55
is_wide_gamut(const skcms_ICCProfile & profile)56 static bool is_wide_gamut(const skcms_ICCProfile& profile)
57 {
58 if (profile.has_toXYZD50) {
59 SkPoint rgb[3];
60 load_gamut(rgb, RGB_CHANNEL_COUNT, profile.toXYZD50);
61 return calculate_area(rgb, RGB_CHANNEL_COUNT) > SRGB_D50_GAMUT_AREA;
62 }
63
64 return false;
65 }
66
supports_any_down_scale(const SkCodec * codec)67 static bool supports_any_down_scale(const SkCodec* codec)
68 {
69 return codec->getEncodedFormat() == SkEncodedImageFormat::kWEBP;
70 }
71
smaller_than(const SkISize & a,const SkISize & b)72 static inline bool smaller_than(const SkISize& a, const SkISize& b)
73 {
74 return a.width() < b.width() || a.height() < b.height();
75 }
76
strictly_bigger_than(const SkISize & a,const SkISize & b)77 static inline bool strictly_bigger_than(const SkISize& a, const SkISize& b)
78 {
79 return a.width() > b.width() && a.height() > b.height();
80 }
81
SkOHOSCodec(SkCodec * codec)82 SkOHOSCodec::SkOHOSCodec(SkCodec* codec)
83 : fInfo(codec->getInfo()), fCodec(codec)
84 {}
85
~SkOHOSCodec()86 SkOHOSCodec::~SkOHOSCodec() {}
87
MakeFromStream(std::unique_ptr<SkStream> stream,SkPngChunkReader * chunkReader)88 std::unique_ptr<SkOHOSCodec> SkOHOSCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
89 SkPngChunkReader* chunkReader)
90 {
91 auto codec = SkCodec::MakeFromStream(std::move(stream), nullptr, chunkReader);
92 return MakeFromCodec(std::move(codec));
93 }
94
MakeFromCodec(std::unique_ptr<SkCodec> codec)95 std::unique_ptr<SkOHOSCodec> SkOHOSCodec::MakeFromCodec(std::unique_ptr<SkCodec> codec)
96 {
97 if (nullptr == codec) {
98 return nullptr;
99 }
100
101 switch ((SkEncodedImageFormat)codec->getEncodedFormat()) {
102 case SkEncodedImageFormat::kPNG:
103 case SkEncodedImageFormat::kICO:
104 case SkEncodedImageFormat::kJPEG:
105 #ifndef SK_HAS_WUFFS_LIBRARY
106 case SkEncodedImageFormat::kGIF:
107 #endif
108 case SkEncodedImageFormat::kBMP:
109 case SkEncodedImageFormat::kWBMP:
110 case SkEncodedImageFormat::kHEIF:
111 case SkEncodedImageFormat::kAVIF:
112 return std::make_unique<SkOHOSSampledCodec>(codec.release());
113 #ifdef SK_HAS_WUFFS_LIBRARY
114 case SkEncodedImageFormat::kGIF:
115 #endif
116 #ifdef SK_CODEC_DECODES_WEBP
117 case SkEncodedImageFormat::kWEBP:
118 #endif
119 #ifdef SK_CODEC_DECODES_RAW
120 case SkEncodedImageFormat::kDNG:
121 #endif
122 #if defined(SK_CODEC_DECODES_WEBP) || defined(SK_CODEC_DECODES_RAW) || defined(SK_HAS_WUFFS_LIBRARY)
123 return std::make_unique<SkOHOSCodecAdapter>(codec.release());
124 #endif
125
126 default:
127 return nullptr;
128 }
129 }
130
MakeFromData(sk_sp<SkData> data,SkPngChunkReader * chunkReader)131 std::unique_ptr<SkOHOSCodec> SkOHOSCodec::MakeFromData(sk_sp<SkData> data,
132 SkPngChunkReader* chunkReader)
133 {
134 if (!data) {
135 return nullptr;
136 }
137
138 return MakeFromStream(SkMemoryStream::Make(std::move(data)), chunkReader);
139 }
140
computeOutputColorType(SkColorType requestedColorType)141 SkColorType SkOHOSCodec::computeOutputColorType(SkColorType requestedColorType)
142 {
143 bool highPrecision = fCodec->callGetEncodedInfo().bitsPerComponent() > 8;
144 switch (requestedColorType) {
145 case kARGB_4444_SkColorType:
146 return kN32_SkColorType;
147 case kN32_SkColorType:
148 break;
149 case kAlpha_8_SkColorType:
150 // Fall through to kGray_8. Before kGray_8_SkColorType existed,
151 // we allowed clients to request kAlpha_8 when they wanted a
152 // grayscale decode.
153 case kGray_8_SkColorType:
154 if (kGray_8_SkColorType == this->getInfo().colorType()) {
155 return kGray_8_SkColorType;
156 }
157 break;
158 case kRGB_565_SkColorType:
159 if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
160 return kRGB_565_SkColorType;
161 }
162 break;
163 case kRGBA_F16_SkColorType:
164 return kRGBA_F16_SkColorType;
165 default:
166 break;
167 }
168
169 return highPrecision ? kRGBA_F16_SkColorType : kN32_SkColorType;
170 }
171
computeOutputAlphaType(bool requestedUnpremul)172 SkAlphaType SkOHOSCodec::computeOutputAlphaType(bool requestedUnpremul)
173 {
174 if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
175 return kOpaque_SkAlphaType;
176 }
177 return requestedUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
178 }
179
computeOutputColorSpace(SkColorType outputColorType,sk_sp<SkColorSpace> prefColorSpace)180 sk_sp<SkColorSpace> SkOHOSCodec::computeOutputColorSpace(SkColorType outputColorType,
181 sk_sp<SkColorSpace> prefColorSpace)
182 {
183 switch (outputColorType) {
184 case kRGBA_F16_SkColorType:
185 case kRGB_565_SkColorType:
186 case kRGBA_8888_SkColorType:
187 case kBGRA_8888_SkColorType: {
188 if (prefColorSpace) {
189 return prefColorSpace;
190 }
191
192 const skcms_ICCProfile* encodedProfile = fCodec->callGetEncodedInfo().profile();
193 if (encodedProfile) {
194 if (auto encodedSpace = SkColorSpace::Make(*encodedProfile)) {
195 return encodedSpace;
196 }
197
198 if (is_wide_gamut(*encodedProfile)) {
199 return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3);
200 }
201 }
202
203 return SkColorSpace::MakeSRGB();
204 }
205 default:
206 return nullptr;
207 }
208 }
209
computeSampleSize(SkISize * desiredSize) const210 int SkOHOSCodec::computeSampleSize(SkISize* desiredSize) const
211 {
212 SkASSERT(desiredSize);
213
214 const auto origDims = fCodec->dimensions();
215 if (!desiredSize || *desiredSize == origDims) {
216 return 1;
217 }
218
219 if (smaller_than(origDims, *desiredSize)) {
220 *desiredSize = origDims;
221 return 1;
222 }
223
224 if (desiredSize->width() < 1 || desiredSize->height() < 1) {
225 *desiredSize = SkISize::Make(std::max(1, desiredSize->width()),
226 std::max(1, desiredSize->height()));
227 }
228
229 if (supports_any_down_scale(fCodec.get())) {
230 return 1;
231 }
232
233 int sampleX = origDims.width() / desiredSize->width();
234 int sampleY = origDims.height() / desiredSize->height();
235 int sampleSize = std::min(sampleX, sampleY);
236 auto computedSize = this->getSampledDimensions(sampleSize);
237 if (computedSize == *desiredSize) {
238 return sampleSize;
239 }
240
241 if (computedSize == origDims || sampleSize == 1) {
242 *desiredSize = computedSize;
243 return 1;
244 }
245
246 if (strictly_bigger_than(computedSize, *desiredSize)) {
247 while (true) {
248 auto smaller = this->getSampledDimensions(sampleSize + 1);
249 if (smaller == *desiredSize) {
250 return sampleSize + 1;
251 }
252 if (smaller == computedSize || smaller_than(smaller, *desiredSize)) {
253 *desiredSize = computedSize;
254 return sampleSize;
255 }
256
257 sampleSize++;
258 computedSize = smaller;
259 }
260
261 SkASSERT(false);
262 }
263
264 if (!smaller_than(computedSize, *desiredSize)) {
265 *desiredSize = computedSize;
266 return sampleSize;
267 }
268
269 while (sampleSize > SAMPLE_SIZE_TWO) {
270 auto bigger = this->getSampledDimensions(sampleSize - 1);
271 if (bigger == *desiredSize || !smaller_than(bigger, *desiredSize)) {
272 *desiredSize = bigger;
273 return sampleSize - 1;
274 }
275 sampleSize--;
276 }
277
278 *desiredSize = origDims;
279 return 1;
280 }
281
getSampledDimensions(int sampleSize) const282 SkISize SkOHOSCodec::getSampledDimensions(int sampleSize) const
283 {
284 if (!is_valid_sample_size(sampleSize)) {
285 return {0, 0};
286 }
287
288 if (1 == sampleSize) {
289 return fCodec->dimensions();
290 }
291
292 return this->onGetSampledDimensions(sampleSize);
293 }
294
getSupportedSubset(SkIRect * desiredSubset) const295 bool SkOHOSCodec::getSupportedSubset(SkIRect* desiredSubset) const
296 {
297 if (!desiredSubset || !is_valid_subset(*desiredSubset, fCodec->dimensions())) {
298 return false;
299 }
300
301 return this->onGetSupportedSubset(desiredSubset);
302 }
303
getSampledSubsetDimensions(int sampleSize,const SkIRect & subset) const304 SkISize SkOHOSCodec::getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const
305 {
306 if (!is_valid_sample_size(sampleSize)) {
307 return {0, 0};
308 }
309
310 SkIRect copySubset = subset;
311 if (!this->getSupportedSubset(©Subset) || copySubset != subset) {
312 return {0, 0};
313 }
314
315 if (fCodec->dimensions() == subset.size()) {
316 return this->getSampledDimensions(sampleSize);
317 }
318
319 return {get_scaled_dimension(subset.width(), sampleSize),
320 get_scaled_dimension(subset.height(), sampleSize)};
321 }
322
getOHOSPixels(const SkImageInfo & requestInfo,void * requestPixels,size_t requestRowBytes,const OHOSOptions * options)323 SkCodec::Result SkOHOSCodec::getOHOSPixels(const SkImageInfo& requestInfo,
324 void* requestPixels, size_t requestRowBytes, const OHOSOptions* options)
325 {
326 if (!requestPixels) {
327 return SkCodec::kInvalidParameters;
328 }
329 if (requestRowBytes < requestInfo.minRowBytes()) {
330 return SkCodec::kInvalidParameters;
331 }
332
333 OHOSOptions defaultOptions;
334 if (!options) {
335 options = &defaultOptions;
336 } else {
337 if (options->fSubset) {
338 if (!is_valid_subset(*options->fSubset, fCodec->dimensions())) {
339 return SkCodec::kInvalidParameters;
340 }
341
342 if (SkIRect::MakeSize(fCodec->dimensions()) == *options->fSubset) {
343 defaultOptions = *options;
344 defaultOptions.fSubset = nullptr;
345 options = &defaultOptions;
346 }
347 }
348 }
349 auto getPixelsFn = [&](const SkImageInfo& info, void* pixels, size_t rowBytes,
350 const SkCodec::Options& opts, int requiredFrame
351 ) -> SkCodec::Result {
352 SkOHOSCodec::OHOSOptions prevFrameOptions(
353 reinterpret_cast<const SkOHOSCodec::OHOSOptions&>(opts));
354 prevFrameOptions.fFrameIndex = requiredFrame;
355 return this->getOHOSPixels(info, pixels, rowBytes, &prevFrameOptions);
356 };
357 auto result = fCodec->callHandleFrameIndex(requestInfo, requestPixels, requestRowBytes,
358 *options, getPixelsFn);
359 if (result != SkCodec::kSuccess) {
360 return result;
361 }
362
363 return this->onGetOHOSPixels(requestInfo, requestPixels, requestRowBytes, *options);
364 }
365
getOHOSPixels(const SkImageInfo & info,void * pixels,size_t rowBytes)366 SkCodec::Result SkOHOSCodec::getOHOSPixels(const SkImageInfo& info, void* pixels,
367 size_t rowBytes)
368 {
369 return this->getOHOSPixels(info, pixels, rowBytes, nullptr);
370 }
371
SkOHOSCodecAdapter(SkCodec * codec)372 SkOHOSCodecAdapter::SkOHOSCodecAdapter(SkCodec* codec)
373 : INHERITED(codec)
374 {}
375
onGetSampledDimensions(int sampleSize) const376 SkISize SkOHOSCodecAdapter::onGetSampledDimensions(int sampleSize) const
377 {
378 float scale = get_scale_from_sample_size(sampleSize);
379 return this->codec()->getScaledDimensions(scale);
380 }
381
onGetSupportedSubset(SkIRect * desiredSubset) const382 bool SkOHOSCodecAdapter::onGetSupportedSubset(SkIRect* desiredSubset) const
383 {
384 return this->codec()->getValidSubset(desiredSubset);
385 }
386
onGetOHOSPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const OHOSOptions & options)387 SkCodec::Result SkOHOSCodecAdapter::onGetOHOSPixels(const SkImageInfo& info, void* pixels,
388 size_t rowBytes, const OHOSOptions& options)
389 {
390 return this->codec()->getPixels(info, pixels, rowBytes, &options);
391 }
392
SkOHOSSampledCodec(SkCodec * codec)393 SkOHOSSampledCodec::SkOHOSSampledCodec(SkCodec* codec)
394 : INHERITED(codec)
395 {}
396
accountForNativeScaling(int * sampleSizePtr,int * nativeSampleSize) const397 SkISize SkOHOSSampledCodec::accountForNativeScaling(int* sampleSizePtr, int* nativeSampleSize) const
398 {
399 SkISize preSampledSize = this->codec()->dimensions();
400 int sampleSize = *sampleSizePtr;
401 SkASSERT(sampleSize > 1);
402
403 if (nativeSampleSize) {
404 *nativeSampleSize = 1;
405 }
406
407 if (this->codec()->getEncodedFormat() == SkEncodedImageFormat::kJPEG) {
408 switch (sampleSize) {
409 case SAMPLE_SIZE_TWO:
410 case SAMPLE_SIZE_FOUR:
411 case SAMPLE_SIZE_EIGHT:
412 *sampleSizePtr = 1;
413 return this->codec()->getScaledDimensions(get_scale_from_sample_size(sampleSize));
414 default:
415 break;
416 }
417
418 int ohosRemainder;
419 const int ohosSampleSizes[] = { 8, 4, 2 };
420 for (int supportedSampleSize : ohosSampleSizes) {
421 int ohosActualSampleSize;
422 SkTDivMod(sampleSize, supportedSampleSize, &ohosActualSampleSize, &ohosRemainder);
423 if (0 == ohosRemainder) {
424 float scale = get_scale_from_sample_size(supportedSampleSize);
425
426 preSampledSize = this->codec()->getScaledDimensions(scale);
427
428 *sampleSizePtr = ohosActualSampleSize;
429 if (nativeSampleSize) {
430 *nativeSampleSize = supportedSampleSize;
431 }
432 break;
433 }
434 }
435 }
436
437 return preSampledSize;
438 }
439
onGetSampledDimensions(int sampleSize) const440 SkISize SkOHOSSampledCodec::onGetSampledDimensions(int sampleSize) const
441 {
442 const SkISize size = this->accountForNativeScaling(&sampleSize);
443 return SkISize::Make(get_scaled_dimension(size.width(), sampleSize),
444 get_scaled_dimension(size.height(), sampleSize));
445 }
446
onGetOHOSPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const OHOSOptions & options)447 SkCodec::Result SkOHOSSampledCodec::onGetOHOSPixels(const SkImageInfo& info, void* pixels,
448 size_t rowBytes, const OHOSOptions& options)
449 {
450 const SkIRect* subset = options.fSubset;
451 if (!subset || subset->size() == this->codec()->dimensions()) {
452 if (this->codec()->callDimensionsSupported(info.dimensions())) {
453 return this->codec()->getPixels(info, pixels, rowBytes, &options);
454 }
455
456 return this->sampledDecode(info, pixels, rowBytes, options);
457 }
458
459 int sampleSize = options.fSampleSize;
460 SkISize scaledSize = this->getSampledDimensions(sampleSize);
461 if (!this->codec()->callDimensionsSupported(scaledSize)) {
462 return this->sampledDecode(info, pixels, rowBytes, options);
463 }
464
465 int scaledSubsetX = subset->x() / sampleSize;
466 int scaledSubsetY = subset->y() / sampleSize;
467 int scaledSubsetWidth = info.width();
468 int subsetScaledHeight = info.height();
469
470 const SkImageInfo scaledInfo = info.makeDimensions(scaledSize);
471
472 OHOSOptions subsetOptions = options;
473 {
474 SkIRect incrementalSubset = SkIRect::MakeXYWH(scaledSubsetX, scaledSubsetY,
475 scaledSubsetWidth, subsetScaledHeight);
476 subsetOptions.fSubset = &incrementalSubset;
477 const SkCodec::Result startIncrementalResult = this->codec()->startIncrementalDecode(
478 scaledInfo, pixels, rowBytes, &subsetOptions);
479 if (SkCodec::kSuccess == startIncrementalResult) {
480 int decodedRows = 0;
481 const SkCodec::Result incrementalResult = this->codec()->incrementalDecode(&decodedRows);
482 if (incrementalResult == SkCodec::kSuccess) {
483 return SkCodec::kSuccess;
484 }
485 SkASSERT(incrementalResult == SkCodec::kIncompleteInput || incrementalResult == SkCodec::kErrorInInput);
486
487 this->codec()->callFillIncompleteImage(scaledInfo, pixels, rowBytes,
488 options.fZeroInitialized, subsetScaledHeight, decodedRows);
489 return incrementalResult;
490 } else if (startIncrementalResult != SkCodec::kUnimplemented) {
491 return startIncrementalResult;
492 }
493 }
494
495 SkIRect scanlineSubset = SkIRect::MakeXYWH(scaledSubsetX, 0, scaledSubsetWidth,
496 scaledSize.height());
497 subsetOptions.fSubset = &scanlineSubset;
498
499 SkCodec::Result result = this->codec()->startScanlineDecode(scaledInfo,
500 &subsetOptions);
501 if (SkCodec::kSuccess != result) {
502 return result;
503 }
504
505 SkASSERT(this->codec()->getScanlineOrder() == SkCodec::kTopDown_SkScanlineOrder);
506 if (!this->codec()->skipScanlines(scaledSubsetY)) {
507 this->codec()->callFillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized,
508 subsetScaledHeight, 0);
509 return SkCodec::kIncompleteInput;
510 }
511
512 int decodedLines = this->codec()->getScanlines(pixels, subsetScaledHeight, rowBytes);
513 if (decodedLines != subsetScaledHeight) {
514 return SkCodec::kIncompleteInput;
515 }
516 return SkCodec::kSuccess;
517 }
518
sampledDecode(const SkImageInfo & info,void * pixels,size_t rowBytes,const OHOSOptions & options)519 SkCodec::Result SkOHOSSampledCodec::sampledDecode(const SkImageInfo& info, void* pixels,
520 size_t rowBytes, const OHOSOptions& options)
521 {
522 SkASSERT(options.fSampleSize > 1);
523
524 int sampleSize = options.fSampleSize;
525 int nativeSampleSize;
526 SkISize ohosNativeSize = this->accountForNativeScaling(&sampleSize, &nativeSampleSize);
527
528 SkIRect subset;
529 int ohosSubsetY = 0;
530 int ohosSubsetWidth = ohosNativeSize.width();
531 int ohosSubsetHeight = ohosNativeSize.height();
532 if (options.fSubset) {
533 const SkIRect* subsetPtr = options.fSubset;
534
535 const int subsetX = subsetPtr->x() / nativeSampleSize;
536 ohosSubsetY = subsetPtr->y() / nativeSampleSize;
537
538 ohosSubsetWidth = get_scaled_dimension(subsetPtr->width(), nativeSampleSize);
539 ohosSubsetHeight = get_scaled_dimension(subsetPtr->height(), nativeSampleSize);
540
541 subset.setXYWH(subsetX, 0, ohosSubsetWidth, ohosNativeSize.height());
542 }
543
544 const int ohosSampleX = ohosSubsetWidth / info.width();
545 const int ohosSampleY = ohosSubsetHeight / info.height();
546
547 const int ohosSamplingOffsetY = get_start_coord(ohosSampleY);
548 const int ohosStartY = ohosSamplingOffsetY + ohosSubsetY;
549 const int ohosDstHeight = info.height();
550
551 const SkImageInfo nativeInfo = info.makeDimensions(ohosNativeSize);
552
553 {
554 OHOSOptions incrementalOptions = options;
555 SkIRect incrementalSubset;
556 if (options.fSubset) {
557 incrementalSubset.fTop = ohosSubsetY;
558 incrementalSubset.fBottom = ohosSubsetY + ohosSubsetHeight;
559 incrementalSubset.fLeft = subset.fLeft;
560 incrementalSubset.fRight = subset.fRight;
561 incrementalOptions.fSubset = &incrementalSubset;
562 }
563 const SkCodec::Result startResult = this->codec()->startIncrementalDecode(nativeInfo,
564 pixels, rowBytes, &incrementalOptions);
565 if (SkCodec::kSuccess == startResult) {
566 SkSampler* ohosSampler = this->codec()->callGetSampler(true);
567 if (!ohosSampler) {
568 return SkCodec::kUnimplemented;
569 }
570
571 if (ohosSampler->setSampleX(ohosSampleX) != info.width()) {
572 return SkCodec::kInvalidScale;
573 }
574 if (get_scaled_dimension(ohosSubsetHeight, ohosSampleY) != info.height()) {
575 return SkCodec::kInvalidScale;
576 }
577
578 ohosSampler->setSampleY(ohosSampleY);
579
580 int rowsDecoded = 0;
581 const SkCodec::Result incrementalResult = this->codec()->incrementalDecode(&rowsDecoded);
582 if (incrementalResult == SkCodec::kSuccess) {
583 return SkCodec::kSuccess;
584 }
585 SkASSERT(incrementalResult == SkCodec::kIncompleteInput || incrementalResult == SkCodec::kErrorInInput);
586
587 SkASSERT(rowsDecoded <= info.height());
588 this->codec()->callFillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized,
589 info.height(), rowsDecoded);
590 return incrementalResult;
591 } else if (startResult == SkCodec::kIncompleteInput
592 || startResult == SkCodec::kErrorInInput) {
593 return SkCodec::kInvalidInput;
594 } else if (startResult != SkCodec::kUnimplemented) {
595 return startResult;
596 }
597 }
598
599 OHOSOptions ohosSampledOptions = options;
600 if (options.fSubset) {
601 ohosSampledOptions.fSubset = ⊂
602 }
603 SkCodec::Result startScanlineResult = this->codec()->startScanlineDecode(nativeInfo,
604 &ohosSampledOptions);
605 if (SkCodec::kIncompleteInput == startScanlineResult || SkCodec::kErrorInInput == startScanlineResult) {
606 return SkCodec::kInvalidInput;
607 } else if (SkCodec::kSuccess != startScanlineResult) {
608 return startScanlineResult;
609 }
610
611 SkSampler* ohosSampler = this->codec()->callGetSampler(true);
612 if (!ohosSampler) {
613 return SkCodec::kInternalError;
614 }
615
616 if (ohosSampler->setSampleX(ohosSampleX) != info.width()) {
617 return SkCodec::kInvalidScale;
618 }
619 if (get_scaled_dimension(ohosSubsetHeight, ohosSampleY) != info.height()) {
620 return SkCodec::kInvalidScale;
621 }
622
623 switch (this->codec()->getScanlineOrder()) {
624 case SkCodec::kTopDown_SkScanlineOrder: {
625 if (!this->codec()->skipScanlines(ohosStartY)) {
626 this->codec()->callFillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized,
627 ohosDstHeight, 0);
628 return SkCodec::kIncompleteInput;
629 }
630 void* pixelPtr = pixels;
631 for (int y = 0; y < ohosDstHeight; y++) {
632 if (1 != this->codec()->getScanlines(pixelPtr, 1, rowBytes)) {
633 this->codec()->callFillIncompleteImage(info, pixels, rowBytes,
634 options.fZeroInitialized, ohosDstHeight, y + 1);
635 return SkCodec::kIncompleteInput;
636 }
637 if (y < ohosDstHeight - 1) {
638 if (!this->codec()->skipScanlines(ohosSampleY - 1)) {
639 this->codec()->callFillIncompleteImage(info, pixels, rowBytes,
640 options.fZeroInitialized, ohosDstHeight, y + 1);
641 return SkCodec::kIncompleteInput;
642 }
643 }
644 pixelPtr = SkTAddOffset<void>(pixelPtr, rowBytes);
645 }
646 return SkCodec::kSuccess;
647 }
648 case SkCodec::kBottomUp_SkScanlineOrder: {
649 SkASSERT(0 == ohosSubsetY && ohosNativeSize.height() == ohosSubsetHeight);
650 int y;
651 for (y = 0; y < ohosNativeSize.height(); y++) {
652 int srcY = this->codec()->nextScanline();
653 if (is_coord_necessary(srcY, ohosSampleY, ohosDstHeight)) {
654 void* pixelPtr = SkTAddOffset<void>(pixels,
655 rowBytes * get_dst_coord(srcY, ohosSampleY));
656 if (1 != this->codec()->getScanlines(pixelPtr, 1, rowBytes)) {
657 break;
658 }
659 } else {
660 if (!this->codec()->skipScanlines(1)) {
661 break;
662 }
663 }
664 }
665
666 if (ohosNativeSize.height() == y) {
667 return SkCodec::kSuccess;
668 }
669
670 const SkImageInfo ohosFillInfo = info.makeWH(info.width(), 1);
671 for (; y < ohosNativeSize.height(); y++) {
672 int srcY = this->codec()->outputScanline(y);
673 if (!is_coord_necessary(srcY, ohosSampleY, ohosDstHeight)) {
674 continue;
675 }
676
677 void* rowPtr = SkTAddOffset<void>(pixels, rowBytes * get_dst_coord(srcY, ohosSampleY));
678 SkSampler::Fill(ohosFillInfo, rowPtr, rowBytes, options.fZeroInitialized);
679 }
680 return SkCodec::kIncompleteInput;
681 }
682 default:
683 SkASSERT(false);
684 return SkCodec::kUnimplemented;
685 }
686 }