1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/codec/SkCodec.h" 9cb93a386Sopenharmony_ci#include "include/core/SkMath.h" 10cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 11cb93a386Sopenharmony_ci#include "src/codec/SkCodecPriv.h" 12cb93a386Sopenharmony_ci#include "src/codec/SkSampledCodec.h" 13cb93a386Sopenharmony_ci#include "src/codec/SkSampler.h" 14cb93a386Sopenharmony_ci#include "src/core/SkMathPriv.h" 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_ciSkSampledCodec::SkSampledCodec(SkCodec* codec) 17cb93a386Sopenharmony_ci : INHERITED(codec) 18cb93a386Sopenharmony_ci{} 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_ciSkISize SkSampledCodec::accountForNativeScaling(int* sampleSizePtr, int* nativeSampleSize) const { 21cb93a386Sopenharmony_ci SkISize preSampledSize = this->codec()->dimensions(); 22cb93a386Sopenharmony_ci int sampleSize = *sampleSizePtr; 23cb93a386Sopenharmony_ci SkASSERT(sampleSize > 1); 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ci if (nativeSampleSize) { 26cb93a386Sopenharmony_ci *nativeSampleSize = 1; 27cb93a386Sopenharmony_ci } 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ci // Only JPEG supports native downsampling. 30cb93a386Sopenharmony_ci if (this->codec()->getEncodedFormat() == SkEncodedImageFormat::kJPEG) { 31cb93a386Sopenharmony_ci // See if libjpeg supports this scale directly 32cb93a386Sopenharmony_ci switch (sampleSize) { 33cb93a386Sopenharmony_ci case 2: 34cb93a386Sopenharmony_ci case 4: 35cb93a386Sopenharmony_ci case 8: 36cb93a386Sopenharmony_ci // This class does not need to do any sampling. 37cb93a386Sopenharmony_ci *sampleSizePtr = 1; 38cb93a386Sopenharmony_ci return this->codec()->getScaledDimensions(get_scale_from_sample_size(sampleSize)); 39cb93a386Sopenharmony_ci default: 40cb93a386Sopenharmony_ci break; 41cb93a386Sopenharmony_ci } 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci // Check if sampleSize is a multiple of something libjpeg can support. 44cb93a386Sopenharmony_ci int remainder; 45cb93a386Sopenharmony_ci const int sampleSizes[] = { 8, 4, 2 }; 46cb93a386Sopenharmony_ci for (int supportedSampleSize : sampleSizes) { 47cb93a386Sopenharmony_ci int actualSampleSize; 48cb93a386Sopenharmony_ci SkTDivMod(sampleSize, supportedSampleSize, &actualSampleSize, &remainder); 49cb93a386Sopenharmony_ci if (0 == remainder) { 50cb93a386Sopenharmony_ci float scale = get_scale_from_sample_size(supportedSampleSize); 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci // this->codec() will scale to this size. 53cb93a386Sopenharmony_ci preSampledSize = this->codec()->getScaledDimensions(scale); 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_ci // And then this class will sample it. 56cb93a386Sopenharmony_ci *sampleSizePtr = actualSampleSize; 57cb93a386Sopenharmony_ci if (nativeSampleSize) { 58cb93a386Sopenharmony_ci *nativeSampleSize = supportedSampleSize; 59cb93a386Sopenharmony_ci } 60cb93a386Sopenharmony_ci break; 61cb93a386Sopenharmony_ci } 62cb93a386Sopenharmony_ci } 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci return preSampledSize; 66cb93a386Sopenharmony_ci} 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ciSkISize SkSampledCodec::onGetSampledDimensions(int sampleSize) const { 69cb93a386Sopenharmony_ci const SkISize size = this->accountForNativeScaling(&sampleSize); 70cb93a386Sopenharmony_ci return SkISize::Make(get_scaled_dimension(size.width(), sampleSize), 71cb93a386Sopenharmony_ci get_scaled_dimension(size.height(), sampleSize)); 72cb93a386Sopenharmony_ci} 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ciSkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void* pixels, 75cb93a386Sopenharmony_ci size_t rowBytes, const AndroidOptions& options) { 76cb93a386Sopenharmony_ci const SkIRect* subset = options.fSubset; 77cb93a386Sopenharmony_ci if (!subset || subset->size() == this->codec()->dimensions()) { 78cb93a386Sopenharmony_ci if (this->codec()->dimensionsSupported(info.dimensions())) { 79cb93a386Sopenharmony_ci return this->codec()->getPixels(info, pixels, rowBytes, &options); 80cb93a386Sopenharmony_ci } 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_ci // If the native codec does not support the requested scale, scale by sampling. 83cb93a386Sopenharmony_ci return this->sampledDecode(info, pixels, rowBytes, options); 84cb93a386Sopenharmony_ci } 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ci // We are performing a subset decode. 87cb93a386Sopenharmony_ci int sampleSize = options.fSampleSize; 88cb93a386Sopenharmony_ci SkISize scaledSize = this->getSampledDimensions(sampleSize); 89cb93a386Sopenharmony_ci if (!this->codec()->dimensionsSupported(scaledSize)) { 90cb93a386Sopenharmony_ci // If the native codec does not support the requested scale, scale by sampling. 91cb93a386Sopenharmony_ci return this->sampledDecode(info, pixels, rowBytes, options); 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci // Calculate the scaled subset bounds. 95cb93a386Sopenharmony_ci int scaledSubsetX = subset->x() / sampleSize; 96cb93a386Sopenharmony_ci int scaledSubsetY = subset->y() / sampleSize; 97cb93a386Sopenharmony_ci int scaledSubsetWidth = info.width(); 98cb93a386Sopenharmony_ci int scaledSubsetHeight = info.height(); 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_ci const SkImageInfo scaledInfo = info.makeDimensions(scaledSize); 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci // Copy so we can use a different fSubset. 103cb93a386Sopenharmony_ci AndroidOptions subsetOptions = options; 104cb93a386Sopenharmony_ci { 105cb93a386Sopenharmony_ci // Although startScanlineDecode expects the bottom and top to match the 106cb93a386Sopenharmony_ci // SkImageInfo, startIncrementalDecode uses them to determine which rows to 107cb93a386Sopenharmony_ci // decode. 108cb93a386Sopenharmony_ci SkIRect incrementalSubset = SkIRect::MakeXYWH(scaledSubsetX, scaledSubsetY, 109cb93a386Sopenharmony_ci scaledSubsetWidth, scaledSubsetHeight); 110cb93a386Sopenharmony_ci subsetOptions.fSubset = &incrementalSubset; 111cb93a386Sopenharmony_ci const SkCodec::Result startResult = this->codec()->startIncrementalDecode( 112cb93a386Sopenharmony_ci scaledInfo, pixels, rowBytes, &subsetOptions); 113cb93a386Sopenharmony_ci if (SkCodec::kSuccess == startResult) { 114cb93a386Sopenharmony_ci int rowsDecoded = 0; 115cb93a386Sopenharmony_ci const SkCodec::Result incResult = this->codec()->incrementalDecode(&rowsDecoded); 116cb93a386Sopenharmony_ci if (incResult == SkCodec::kSuccess) { 117cb93a386Sopenharmony_ci return SkCodec::kSuccess; 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci SkASSERT(incResult == SkCodec::kIncompleteInput || incResult == SkCodec::kErrorInInput); 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci // FIXME: Can zero initialized be read from SkCodec::fOptions? 122cb93a386Sopenharmony_ci this->codec()->fillIncompleteImage(scaledInfo, pixels, rowBytes, 123cb93a386Sopenharmony_ci options.fZeroInitialized, scaledSubsetHeight, rowsDecoded); 124cb93a386Sopenharmony_ci return incResult; 125cb93a386Sopenharmony_ci } else if (startResult != SkCodec::kUnimplemented) { 126cb93a386Sopenharmony_ci return startResult; 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci // Otherwise fall down to use the old scanline decoder. 129cb93a386Sopenharmony_ci // subsetOptions.fSubset will be reset below, so it will not continue to 130cb93a386Sopenharmony_ci // point to the object that is no longer on the stack. 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci // Start the scanline decode. 134cb93a386Sopenharmony_ci SkIRect scanlineSubset = SkIRect::MakeXYWH(scaledSubsetX, 0, scaledSubsetWidth, 135cb93a386Sopenharmony_ci scaledSize.height()); 136cb93a386Sopenharmony_ci subsetOptions.fSubset = &scanlineSubset; 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_ci SkCodec::Result result = this->codec()->startScanlineDecode(scaledInfo, 139cb93a386Sopenharmony_ci &subsetOptions); 140cb93a386Sopenharmony_ci if (SkCodec::kSuccess != result) { 141cb93a386Sopenharmony_ci return result; 142cb93a386Sopenharmony_ci } 143cb93a386Sopenharmony_ci 144cb93a386Sopenharmony_ci // At this point, we are only concerned with subsetting. Either no scale was 145cb93a386Sopenharmony_ci // requested, or the this->codec() is handling the scale. 146cb93a386Sopenharmony_ci // Note that subsetting is only supported for kTopDown, so this code will not be 147cb93a386Sopenharmony_ci // reached for other orders. 148cb93a386Sopenharmony_ci SkASSERT(this->codec()->getScanlineOrder() == SkCodec::kTopDown_SkScanlineOrder); 149cb93a386Sopenharmony_ci if (!this->codec()->skipScanlines(scaledSubsetY)) { 150cb93a386Sopenharmony_ci this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, 151cb93a386Sopenharmony_ci scaledSubsetHeight, 0); 152cb93a386Sopenharmony_ci return SkCodec::kIncompleteInput; 153cb93a386Sopenharmony_ci } 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci int decodedLines = this->codec()->getScanlines(pixels, scaledSubsetHeight, rowBytes); 156cb93a386Sopenharmony_ci if (decodedLines != scaledSubsetHeight) { 157cb93a386Sopenharmony_ci return SkCodec::kIncompleteInput; 158cb93a386Sopenharmony_ci } 159cb93a386Sopenharmony_ci return SkCodec::kSuccess; 160cb93a386Sopenharmony_ci} 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_ci 163cb93a386Sopenharmony_ciSkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pixels, 164cb93a386Sopenharmony_ci size_t rowBytes, const AndroidOptions& options) { 165cb93a386Sopenharmony_ci // We should only call this function when sampling. 166cb93a386Sopenharmony_ci SkASSERT(options.fSampleSize > 1); 167cb93a386Sopenharmony_ci 168cb93a386Sopenharmony_ci // FIXME: This was already called by onGetAndroidPixels. Can we reduce that? 169cb93a386Sopenharmony_ci int sampleSize = options.fSampleSize; 170cb93a386Sopenharmony_ci int nativeSampleSize; 171cb93a386Sopenharmony_ci SkISize nativeSize = this->accountForNativeScaling(&sampleSize, &nativeSampleSize); 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci // Check if there is a subset. 174cb93a386Sopenharmony_ci SkIRect subset; 175cb93a386Sopenharmony_ci int subsetY = 0; 176cb93a386Sopenharmony_ci int subsetWidth = nativeSize.width(); 177cb93a386Sopenharmony_ci int subsetHeight = nativeSize.height(); 178cb93a386Sopenharmony_ci if (options.fSubset) { 179cb93a386Sopenharmony_ci // We will need to know about subsetting in the y-dimension in order to use the 180cb93a386Sopenharmony_ci // scanline decoder. 181cb93a386Sopenharmony_ci // Update the subset to account for scaling done by this->codec(). 182cb93a386Sopenharmony_ci const SkIRect* subsetPtr = options.fSubset; 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_ci // Do the divide ourselves, instead of calling get_scaled_dimension. If 185cb93a386Sopenharmony_ci // X and Y are 0, they should remain 0, rather than being upgraded to 1 186cb93a386Sopenharmony_ci // due to being smaller than the sampleSize. 187cb93a386Sopenharmony_ci const int subsetX = subsetPtr->x() / nativeSampleSize; 188cb93a386Sopenharmony_ci subsetY = subsetPtr->y() / nativeSampleSize; 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci subsetWidth = get_scaled_dimension(subsetPtr->width(), nativeSampleSize); 191cb93a386Sopenharmony_ci subsetHeight = get_scaled_dimension(subsetPtr->height(), nativeSampleSize); 192cb93a386Sopenharmony_ci 193cb93a386Sopenharmony_ci // The scanline decoder only needs to be aware of subsetting in the x-dimension. 194cb93a386Sopenharmony_ci subset.setXYWH(subsetX, 0, subsetWidth, nativeSize.height()); 195cb93a386Sopenharmony_ci } 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_ci // Since we guarantee that output dimensions are always at least one (even if the sampleSize 198cb93a386Sopenharmony_ci // is greater than a given dimension), the input sampleSize is not always the sampleSize that 199cb93a386Sopenharmony_ci // we use in practice. 200cb93a386Sopenharmony_ci const int sampleX = subsetWidth / info.width(); 201cb93a386Sopenharmony_ci const int sampleY = subsetHeight / info.height(); 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci const int samplingOffsetY = get_start_coord(sampleY); 204cb93a386Sopenharmony_ci const int startY = samplingOffsetY + subsetY; 205cb93a386Sopenharmony_ci const int dstHeight = info.height(); 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_ci const SkImageInfo nativeInfo = info.makeDimensions(nativeSize); 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci { 210cb93a386Sopenharmony_ci // Although startScanlineDecode expects the bottom and top to match the 211cb93a386Sopenharmony_ci // SkImageInfo, startIncrementalDecode uses them to determine which rows to 212cb93a386Sopenharmony_ci // decode. 213cb93a386Sopenharmony_ci AndroidOptions incrementalOptions = options; 214cb93a386Sopenharmony_ci SkIRect incrementalSubset; 215cb93a386Sopenharmony_ci if (options.fSubset) { 216cb93a386Sopenharmony_ci incrementalSubset.fTop = subsetY; 217cb93a386Sopenharmony_ci incrementalSubset.fBottom = subsetY + subsetHeight; 218cb93a386Sopenharmony_ci incrementalSubset.fLeft = subset.fLeft; 219cb93a386Sopenharmony_ci incrementalSubset.fRight = subset.fRight; 220cb93a386Sopenharmony_ci incrementalOptions.fSubset = &incrementalSubset; 221cb93a386Sopenharmony_ci } 222cb93a386Sopenharmony_ci const SkCodec::Result startResult = this->codec()->startIncrementalDecode(nativeInfo, 223cb93a386Sopenharmony_ci pixels, rowBytes, &incrementalOptions); 224cb93a386Sopenharmony_ci if (SkCodec::kSuccess == startResult) { 225cb93a386Sopenharmony_ci SkSampler* sampler = this->codec()->getSampler(true); 226cb93a386Sopenharmony_ci if (!sampler) { 227cb93a386Sopenharmony_ci return SkCodec::kUnimplemented; 228cb93a386Sopenharmony_ci } 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_ci if (sampler->setSampleX(sampleX) != info.width()) { 231cb93a386Sopenharmony_ci return SkCodec::kInvalidScale; 232cb93a386Sopenharmony_ci } 233cb93a386Sopenharmony_ci if (get_scaled_dimension(subsetHeight, sampleY) != info.height()) { 234cb93a386Sopenharmony_ci return SkCodec::kInvalidScale; 235cb93a386Sopenharmony_ci } 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_ci sampler->setSampleY(sampleY); 238cb93a386Sopenharmony_ci 239cb93a386Sopenharmony_ci int rowsDecoded = 0; 240cb93a386Sopenharmony_ci const SkCodec::Result incResult = this->codec()->incrementalDecode(&rowsDecoded); 241cb93a386Sopenharmony_ci if (incResult == SkCodec::kSuccess) { 242cb93a386Sopenharmony_ci return SkCodec::kSuccess; 243cb93a386Sopenharmony_ci } 244cb93a386Sopenharmony_ci SkASSERT(incResult == SkCodec::kIncompleteInput || incResult == SkCodec::kErrorInInput); 245cb93a386Sopenharmony_ci 246cb93a386Sopenharmony_ci SkASSERT(rowsDecoded <= info.height()); 247cb93a386Sopenharmony_ci this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, 248cb93a386Sopenharmony_ci info.height(), rowsDecoded); 249cb93a386Sopenharmony_ci return incResult; 250cb93a386Sopenharmony_ci } else if (startResult == SkCodec::kIncompleteInput 251cb93a386Sopenharmony_ci || startResult == SkCodec::kErrorInInput) { 252cb93a386Sopenharmony_ci return SkCodec::kInvalidInput; 253cb93a386Sopenharmony_ci } else if (startResult != SkCodec::kUnimplemented) { 254cb93a386Sopenharmony_ci return startResult; 255cb93a386Sopenharmony_ci } // kUnimplemented means use the old method. 256cb93a386Sopenharmony_ci } 257cb93a386Sopenharmony_ci 258cb93a386Sopenharmony_ci // Start the scanline decode. 259cb93a386Sopenharmony_ci AndroidOptions sampledOptions = options; 260cb93a386Sopenharmony_ci if (options.fSubset) { 261cb93a386Sopenharmony_ci sampledOptions.fSubset = ⊂ 262cb93a386Sopenharmony_ci } 263cb93a386Sopenharmony_ci SkCodec::Result result = this->codec()->startScanlineDecode(nativeInfo, 264cb93a386Sopenharmony_ci &sampledOptions); 265cb93a386Sopenharmony_ci if (SkCodec::kIncompleteInput == result || SkCodec::kErrorInInput == result) { 266cb93a386Sopenharmony_ci return SkCodec::kInvalidInput; 267cb93a386Sopenharmony_ci } else if (SkCodec::kSuccess != result) { 268cb93a386Sopenharmony_ci return result; 269cb93a386Sopenharmony_ci } 270cb93a386Sopenharmony_ci 271cb93a386Sopenharmony_ci SkSampler* sampler = this->codec()->getSampler(true); 272cb93a386Sopenharmony_ci if (!sampler) { 273cb93a386Sopenharmony_ci return SkCodec::kInternalError; 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci 276cb93a386Sopenharmony_ci if (sampler->setSampleX(sampleX) != info.width()) { 277cb93a386Sopenharmony_ci return SkCodec::kInvalidScale; 278cb93a386Sopenharmony_ci } 279cb93a386Sopenharmony_ci if (get_scaled_dimension(subsetHeight, sampleY) != info.height()) { 280cb93a386Sopenharmony_ci return SkCodec::kInvalidScale; 281cb93a386Sopenharmony_ci } 282cb93a386Sopenharmony_ci 283cb93a386Sopenharmony_ci switch(this->codec()->getScanlineOrder()) { 284cb93a386Sopenharmony_ci case SkCodec::kTopDown_SkScanlineOrder: { 285cb93a386Sopenharmony_ci if (!this->codec()->skipScanlines(startY)) { 286cb93a386Sopenharmony_ci this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, 287cb93a386Sopenharmony_ci dstHeight, 0); 288cb93a386Sopenharmony_ci return SkCodec::kIncompleteInput; 289cb93a386Sopenharmony_ci } 290cb93a386Sopenharmony_ci void* pixelPtr = pixels; 291cb93a386Sopenharmony_ci for (int y = 0; y < dstHeight; y++) { 292cb93a386Sopenharmony_ci if (1 != this->codec()->getScanlines(pixelPtr, 1, rowBytes)) { 293cb93a386Sopenharmony_ci this->codec()->fillIncompleteImage(info, pixels, rowBytes, 294cb93a386Sopenharmony_ci options.fZeroInitialized, dstHeight, y + 1); 295cb93a386Sopenharmony_ci return SkCodec::kIncompleteInput; 296cb93a386Sopenharmony_ci } 297cb93a386Sopenharmony_ci if (y < dstHeight - 1) { 298cb93a386Sopenharmony_ci if (!this->codec()->skipScanlines(sampleY - 1)) { 299cb93a386Sopenharmony_ci this->codec()->fillIncompleteImage(info, pixels, rowBytes, 300cb93a386Sopenharmony_ci options.fZeroInitialized, dstHeight, y + 1); 301cb93a386Sopenharmony_ci return SkCodec::kIncompleteInput; 302cb93a386Sopenharmony_ci } 303cb93a386Sopenharmony_ci } 304cb93a386Sopenharmony_ci pixelPtr = SkTAddOffset<void>(pixelPtr, rowBytes); 305cb93a386Sopenharmony_ci } 306cb93a386Sopenharmony_ci return SkCodec::kSuccess; 307cb93a386Sopenharmony_ci } 308cb93a386Sopenharmony_ci case SkCodec::kBottomUp_SkScanlineOrder: { 309cb93a386Sopenharmony_ci // Note that these modes do not support subsetting. 310cb93a386Sopenharmony_ci SkASSERT(0 == subsetY && nativeSize.height() == subsetHeight); 311cb93a386Sopenharmony_ci int y; 312cb93a386Sopenharmony_ci for (y = 0; y < nativeSize.height(); y++) { 313cb93a386Sopenharmony_ci int srcY = this->codec()->nextScanline(); 314cb93a386Sopenharmony_ci if (is_coord_necessary(srcY, sampleY, dstHeight)) { 315cb93a386Sopenharmony_ci void* pixelPtr = SkTAddOffset<void>(pixels, 316cb93a386Sopenharmony_ci rowBytes * get_dst_coord(srcY, sampleY)); 317cb93a386Sopenharmony_ci if (1 != this->codec()->getScanlines(pixelPtr, 1, rowBytes)) { 318cb93a386Sopenharmony_ci break; 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci } else { 321cb93a386Sopenharmony_ci if (!this->codec()->skipScanlines(1)) { 322cb93a386Sopenharmony_ci break; 323cb93a386Sopenharmony_ci } 324cb93a386Sopenharmony_ci } 325cb93a386Sopenharmony_ci } 326cb93a386Sopenharmony_ci 327cb93a386Sopenharmony_ci if (nativeSize.height() == y) { 328cb93a386Sopenharmony_ci return SkCodec::kSuccess; 329cb93a386Sopenharmony_ci } 330cb93a386Sopenharmony_ci 331cb93a386Sopenharmony_ci // We handle filling uninitialized memory here instead of using this->codec(). 332cb93a386Sopenharmony_ci // this->codec() does not know that we are sampling. 333cb93a386Sopenharmony_ci const SkImageInfo fillInfo = info.makeWH(info.width(), 1); 334cb93a386Sopenharmony_ci for (; y < nativeSize.height(); y++) { 335cb93a386Sopenharmony_ci int srcY = this->codec()->outputScanline(y); 336cb93a386Sopenharmony_ci if (!is_coord_necessary(srcY, sampleY, dstHeight)) { 337cb93a386Sopenharmony_ci continue; 338cb93a386Sopenharmony_ci } 339cb93a386Sopenharmony_ci 340cb93a386Sopenharmony_ci void* rowPtr = SkTAddOffset<void>(pixels, rowBytes * get_dst_coord(srcY, sampleY)); 341cb93a386Sopenharmony_ci SkSampler::Fill(fillInfo, rowPtr, rowBytes, options.fZeroInitialized); 342cb93a386Sopenharmony_ci } 343cb93a386Sopenharmony_ci return SkCodec::kIncompleteInput; 344cb93a386Sopenharmony_ci } 345cb93a386Sopenharmony_ci default: 346cb93a386Sopenharmony_ci SkASSERT(false); 347cb93a386Sopenharmony_ci return SkCodec::kUnimplemented; 348cb93a386Sopenharmony_ci } 349cb93a386Sopenharmony_ci} 350