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