| Index: src/codec/SkScaledCodec.cpp
|
| diff --git a/src/codec/SkScaledCodec.cpp b/src/codec/SkScaledCodec.cpp
|
| index 01e29ad86ac5ac353ff0dc7a5e64a5b3a95791a5..afd49cc097016285b25255c1f7658406bc7d9d75 100644
|
| --- a/src/codec/SkScaledCodec.cpp
|
| +++ b/src/codec/SkScaledCodec.cpp
|
| @@ -18,7 +18,7 @@ SkCodec* SkScaledCodec::NewFromStream(SkStream* stream) {
|
| }
|
| if (isWebp) {
|
| // Webp codec supports scaling and subsetting natively
|
| - return SkWebpCodec::NewFromStream(stream);
|
| + return SkWebpCodec::NewFromStream(stream);
|
| }
|
|
|
| SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream));
|
| @@ -44,20 +44,28 @@ SkScaledCodec::SkScaledCodec(SkCodec* codec)
|
|
|
| SkScaledCodec::~SkScaledCodec() {}
|
|
|
| -bool SkScaledCodec::onRewind() {
|
| - return fCodec->onRewind();
|
| +static bool is_in_subset(int coord, int offset, int length) {
|
| + if (coord < offset || coord >= offset + length) {
|
| + return false;
|
| + }
|
| + return true;
|
| }
|
|
|
| -static SkISize best_scaled_dimensions(const SkISize& origDims, const SkISize& nativeDims,
|
| - const SkISize& scaledCodecDims, float desiredScale) {
|
| - if (nativeDims == scaledCodecDims) {
|
| - // does not matter which to return if equal. Return here to skip below calculations
|
| - return nativeDims;
|
| +static int get_sample_size(float scale) {
|
| + return SkScalarRoundToInt(1.0f / scale);
|
| +}
|
| +
|
| +static bool use_native_scaling(const SkISize& origDims, const SkISize& nativeDims,
|
| + const SkISize& sampledDims, float desiredScale) {
|
| + if (nativeDims == sampledDims) {
|
| + // If both options are the same, choose native scaling.
|
| + return true;
|
| }
|
| +
|
| float idealWidth = origDims.width() * desiredScale;
|
| float idealHeight = origDims.height() * desiredScale;
|
|
|
| - // calculate difference between native dimensions and ideal dimensions
|
| + // Calculate difference between native scaling and ideal scaling.
|
| float nativeWDiff = SkTAbs(idealWidth - nativeDims.width());
|
| float nativeHDiff = SkTAbs(idealHeight - nativeDims.height());
|
| float nativeDiff = nativeWDiff + nativeHDiff;
|
| @@ -65,52 +73,78 @@ static SkISize best_scaled_dimensions(const SkISize& origDims, const SkISize& na
|
| // Native scaling is preferred to sampling. If we can scale natively to
|
| // within one of the ideal value, we should choose to scale natively.
|
| if (nativeWDiff < 1.0f && nativeHDiff < 1.0f) {
|
| - return nativeDims;
|
| + return true;
|
| }
|
|
|
| - // calculate difference between scaledCodec dimensions and ideal dimensions
|
| - float scaledCodecWDiff = SkTAbs(idealWidth - scaledCodecDims.width());
|
| - float scaledCodecHDiff = SkTAbs(idealHeight - scaledCodecDims.height());
|
| - float scaledCodecDiff = scaledCodecWDiff + scaledCodecHDiff;
|
| + // Calculate difference between native scaling and sampled scaling.
|
| + float sampledWDiff = SkTAbs(idealWidth - sampledDims.width());
|
| + float sampledHDiff = SkTAbs(idealHeight - sampledDims.height());
|
| + float sampledDiff = sampledWDiff + sampledHDiff;
|
|
|
| - // return dimensions closest to ideal dimensions.
|
| - // If the differences are equal, return nativeDims, as native scaling is more efficient.
|
| - return nativeDiff > scaledCodecDiff ? scaledCodecDims : nativeDims;
|
| + // Use native scaling if it is closer to the ideal scale.
|
| + return nativeDiff <= sampledDiff;
|
| }
|
|
|
| /*
|
| * Return a valid set of output dimensions for this decoder, given an input scale
|
| */
|
| SkISize SkScaledCodec::onGetScaledDimensions(float desiredScale) const {
|
| - SkISize nativeDimensions = fCodec->getScaledDimensions(desiredScale);
|
| - // support scaling down by integer numbers. Ex: 1/2, 1/3, 1/4 ...
|
| - SkISize scaledCodecDimensions;
|
| - if (desiredScale > 0.5f) {
|
| - // sampleSize = 1
|
| - scaledCodecDimensions = fCodec->getInfo().dimensions();
|
| + SkISize nativeDims = fCodec->getScaledDimensions(desiredScale);
|
| + int sampleSize = get_sample_size(desiredScale);
|
| + SkISize sampledDims = SkISize::Make(
|
| + get_scaled_dimension(this->getInfo().width(), sampleSize),
|
| + get_scaled_dimension(this->getInfo().height(), sampleSize));
|
| +
|
| + if (use_native_scaling(this->getInfo().dimensions(), nativeDims, sampledDims, desiredScale)) {
|
| + return nativeDims;
|
| }
|
| - // sampleSize determines the step size between samples
|
| - // Ex: sampleSize = 2, sample every second pixel in x and y directions
|
| - int sampleSize = int ((1.0f / desiredScale) + 0.5f);
|
|
|
| - int scaledWidth = get_scaled_dimension(this->getInfo().width(), sampleSize);
|
| - int scaledHeight = get_scaled_dimension(this->getInfo().height(), sampleSize);
|
| + return sampledDims;
|
| +}
|
|
|
| - // Return the calculated output dimensions for the given scale
|
| - scaledCodecDimensions = SkISize::Make(scaledWidth, scaledHeight);
|
| +bool SkScaledCodec::onGetScaledSubsetDimensions(float desiredScale, Options* options) const {
|
| +
|
| + SkISize nativeDims = fCodec->getScaledDimensions(desiredScale);
|
| + int sampleSize = get_sample_size(desiredScale);
|
| + SkISize sampledDims = SkISize::Make(
|
| + get_scaled_dimension(this->getInfo().width(), sampleSize),
|
| + get_scaled_dimension(this->getInfo().height(), sampleSize));
|
| +
|
| + if (use_native_scaling(this->getInfo().dimensions(), nativeDims, sampledDims, desiredScale)) {
|
| + // Set the scaled dimensions and calculate subset size using native scaling.
|
| + options->fScaledDimensions = nativeDims;
|
| + float widthScale = ((float) nativeDims.width()) / ((float) this->getInfo().width());
|
| + float heightScale = ((float) nativeDims.height()) / ((float) this->getInfo().height());
|
| + // Notice that we may round the size of the subset up to 1. This means that we must
|
| + // floor the left and top offsets to ensure that we do not suggest a subset that is
|
| + // off the edge of the image.
|
| + options->fScaledSubset = SkIRect::MakeXYWH(
|
| + int (((float) options->fSubset->left()) * widthScale),
|
| + int (((float) options->fSubset->top()) * heightScale),
|
| + SkTMax(1, SkScalarRoundToInt(((float) options->fSubset->width()) * widthScale)),
|
| + SkTMax(1, SkScalarRoundToInt(((float) options->fSubset->height()) * heightScale)));
|
| + return true;
|
| + }
|
|
|
| - return best_scaled_dimensions(this->getInfo().dimensions(), nativeDimensions,
|
| - scaledCodecDimensions, desiredScale);
|
| + // Set the scaled dimensions and calculate subset size using sampling.
|
| + options->fScaledDimensions = sampledDims;
|
| + options->fScaledSubset = SkIRect::MakeXYWH(
|
| + options->fSubset->left() / sampleSize,
|
| + options->fSubset->top() / sampleSize,
|
| + get_scaled_dimension(options->fSubset->width(), sampleSize),
|
| + get_scaled_dimension(options->fSubset->height(), sampleSize));
|
| + return true;
|
| }
|
|
|
| // check if scaling to dstInfo size from srcInfo size using sampleSize is possible
|
| -static bool scaling_supported(const SkISize& dstDim, const SkISize& srcDim,
|
| +static bool scaling_supported(const SkISize& dstSize, const SkISize& srcSize,
|
| int* sampleX, int* sampleY) {
|
| - SkScaledCodec::ComputeSampleSize(dstDim, srcDim, sampleX, sampleY);
|
| - const int dstWidth = dstDim.width();
|
| - const int dstHeight = dstDim.height();
|
| - const int srcWidth = srcDim.width();
|
| - const int srcHeight = srcDim.height();
|
| + SkScaledCodec::ComputeSampleSize(dstSize, srcSize, sampleX, sampleY);
|
| + const int dstWidth = dstSize.width();
|
| + const int dstHeight = dstSize.height();
|
| + const int srcWidth = srcSize.width();
|
| + const int srcHeight = srcSize.height();
|
| +
|
| // only support down sampling, not up sampling
|
| if (dstWidth > srcWidth || dstHeight > srcHeight) {
|
| return false;
|
| @@ -151,12 +185,12 @@ bool SkScaledCodec::onDimensionsSupported(const SkISize& dim) {
|
| }
|
|
|
| // calculates sampleSize in x and y direction
|
| -void SkScaledCodec::ComputeSampleSize(const SkISize& dstDim, const SkISize& srcDim,
|
| +void SkScaledCodec::ComputeSampleSize(const SkISize& dstSize, const SkISize& srcSize,
|
| int* sampleXPtr, int* sampleYPtr) {
|
| - int srcWidth = srcDim.width();
|
| - int dstWidth = dstDim.width();
|
| - int srcHeight = srcDim.height();
|
| - int dstHeight = dstDim.height();
|
| + int srcWidth = srcSize.width();
|
| + int dstWidth = dstSize.width();
|
| + int srcHeight = srcSize.height();
|
| + int dstHeight = dstSize.height();
|
|
|
| int sampleX = srcWidth / dstWidth;
|
| int sampleY = srcHeight / dstHeight;
|
| @@ -183,6 +217,7 @@ void SkScaledCodec::ComputeSampleSize(const SkISize& dstDim, const SkISize& srcD
|
| } else if (get_scaled_dimension(srcHeight, sampleX) == dstHeight) {
|
| sampleY = sampleX;
|
| }
|
| + // FIXME (msarett): Should this never be reached?
|
| }
|
| }
|
|
|
| @@ -194,66 +229,173 @@ void SkScaledCodec::ComputeSampleSize(const SkISize& dstDim, const SkISize& srcD
|
| }
|
| }
|
|
|
| -// TODO: Implement subsetting in onGetPixels which works when and when not sampling
|
| +SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& scaledSubsetInfo, void* dst,
|
| + size_t rowBytes, const Options& options, SkPMColor ctable[], int* ctableCount,
|
| + int* rowsDecoded) {
|
| +
|
| + // There are various values of Rect, Size, and Info used in this function. I think it is
|
| + // useful to go ahead and define what they mean.
|
| + // orig_: Refers to the original image size.
|
| + // scaledSubset_: Refers to the size of the final output. This can match the original
|
| + // dimensions, be a subset of the original dimensions, be a scaled version
|
| + // of the original dimensions, or be a scaled subset of the original dimensions.
|
| + // subset_: Refers to the size of the unscaled subset in terms of the original image
|
| + // dimensions. If this is not a subset decode, this will match the original
|
| + // image dimensions.
|
| + // scaled_: Refers to the scaled size of the original image, ignoring any subsetting.
|
| + // If we are not scaling, this will match the original dimensions.
|
| + SkISize origSize = this->getInfo().dimensions();
|
| + SkIRect subsetRect;
|
| + SkISize scaledSize;
|
| + SkIRect scaledSubsetRect;
|
| + if (nullptr == options.fSubset) {
|
| + // This is not a subset decode.
|
| + SkASSERT(options.fScaledDimensions.isZero());
|
| + SkASSERT(options.fScaledSubset.isEmpty());
|
| +
|
| + // Set the "subset" to the full image dimensions.
|
| + subsetRect = SkIRect::MakeSize(origSize);
|
| +
|
| + // This may be scaled or unscaled, depending on if scaledSize matches origSize.
|
| + scaledSize = scaledSubsetInfo.dimensions();
|
| + scaledSubsetRect = SkIRect::MakeSize(scaledSize);
|
| + } else {
|
| + // This is a subset decode.
|
| + if (!is_valid_subset(options.fSubset, origSize)) {
|
| + return kInvalidParameters;
|
| + }
|
|
|
| -SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
|
| - size_t rowBytes, const Options& options,
|
| - SkPMColor ctable[], int* ctableCount,
|
| - int* rowsDecoded) {
|
| + subsetRect = *(options.fSubset);
|
| + if (options.fScaledDimensions.isZero()) {
|
| + // This is an unscaled subset decode.
|
| + SkASSERT(options.fScaledSubset.isEmpty());
|
| + SkASSERT(scaledSubsetInfo.dimensions() == subsetRect.size());
|
| +
|
| + scaledSize = origSize;
|
| + scaledSubsetRect = subsetRect;
|
| + } else {
|
| + // This is a scaled subset decode.
|
| + SkASSERT(!options.fScaledSubset.isEmpty());
|
| + SkASSERT(scaledSubsetInfo.dimensions() == options.fScaledSubset.size());
|
| + if (!is_valid_subset(&options.fScaledSubset, options.fScaledDimensions)) {
|
| + return kInvalidParameters;
|
| + }
|
|
|
| - if (options.fSubset) {
|
| - // Subsets are not supported.
|
| - return kUnimplemented;
|
| + scaledSize = options.fScaledDimensions;
|
| + scaledSubsetRect = options.fScaledSubset;
|
| + }
|
| }
|
|
|
| - if (fCodec->dimensionsSupported(requestedInfo.dimensions())) {
|
| - // Make sure that the parent class does not fill on an incomplete decode, since
|
| - // fCodec will take care of filling the uninitialized lines.
|
| - *rowsDecoded = requestedInfo.height();
|
| - return fCodec->getPixels(requestedInfo, dst, rowBytes, &options, ctable, ctableCount);
|
| + // Reset the options for use by fCodec. We will handle scaling and subsetting
|
| + // from this level, the native codec does not need to know about it.
|
| + Options newOptions = options;
|
| + newOptions.fSubset = nullptr;
|
| + newOptions.fScaledDimensions = SkISize::Make(0, 0);
|
| + newOptions.fScaledSubset = SkIRect::MakeEmpty();
|
| +
|
| + // The native decoder needs the scaled size of the entire image to check if it can decode to
|
| + // the requested scale.
|
| + SkImageInfo scaledInfo = scaledSubsetInfo.makeWH(scaledSize.width(), scaledSize.height());
|
| + Result result = fCodec->startScanlineDecode(scaledInfo, &newOptions, ctable, ctableCount,
|
| + scaledSubsetRect.left(), scaledSubsetRect.width());
|
| + switch (result) {
|
| + case kSuccess:
|
| + return this->nativeDecode(scaledInfo, dst, rowBytes, scaledSubsetRect,
|
| + options.fZeroInitialized, rowsDecoded);
|
| + case kInvalidScale:
|
| + // We will attempt to scale by sampling below.
|
| + break;
|
| + default:
|
| + return result;
|
| }
|
|
|
| - // scaling requested
|
| + // Try to provide the scale using sampling.
|
| int sampleX;
|
| int sampleY;
|
| - if (!scaling_supported(requestedInfo.dimensions(), fCodec->getInfo().dimensions(),
|
| - &sampleX, &sampleY)) {
|
| - // onDimensionsSupported would have returned false, meaning we should never reach here.
|
| - SkASSERT(false);
|
| + if (!scaling_supported(scaledSubsetInfo.dimensions(), subsetRect.size(), &sampleX, &sampleY)) {
|
| return kInvalidScale;
|
| }
|
|
|
| - // set first sample pixel in y direction
|
| - const int Y0 = get_start_coord(sampleY);
|
| -
|
| - const int dstHeight = requestedInfo.height();
|
| - const int srcWidth = fCodec->getInfo().width();
|
| - const int srcHeight = fCodec->getInfo().height();
|
| -
|
| - const SkImageInfo info = requestedInfo.makeWH(srcWidth, srcHeight);
|
| -
|
| - Result result = fCodec->startScanlineDecode(info, &options, ctable, ctableCount);
|
| -
|
| + // Create the image info that will be passed to fCodec. We support scaling in the
|
| + // x-dimension, but we will perform scaling in the y-dimension here, so we pass the scaled
|
| + // width and the original height.
|
| + // FIXME: This is a bit confusing. I think there is a plan to move scaling completely out
|
| + // of the native codec.
|
| + SkImageInfo decodeInfo = scaledSubsetInfo.makeWH(scaledSize.width(), this->getInfo().height());
|
| +
|
| + // When starting the fCodec, we pass the left offset based on the original image
|
| + // dimensions, but need the scaled version of the subset width.
|
| + // FIXME: This is a bit confusing. I think there is a plan to move scaling completely out
|
| + // of the native codec.
|
| + result = fCodec->startScanlineDecode(decodeInfo, &newOptions, ctable, ctableCount,
|
| + subsetRect.left(), scaledSubsetInfo.width());
|
| if (kSuccess != result) {
|
| + SkASSERT(kInvalidScale != result);
|
| return result;
|
| }
|
|
|
| - SkSampler* sampler = fCodec->getSampler(true);
|
| - if (!sampler) {
|
| - return kUnimplemented;
|
| - }
|
| + return this->sampledDecode(scaledSubsetInfo, dst, rowBytes, subsetRect, scaledSubsetRect,
|
| + sampleX, sampleY, options.fZeroInitialized, rowsDecoded);
|
| +}
|
|
|
| - if (sampler->setSampleX(sampleX) != requestedInfo.width()) {
|
| - return kInvalidScale;
|
| +SkCodec::Result SkScaledCodec::nativeDecode(const SkImageInfo& scaledInfo, void* dst,
|
| + size_t rowBytes, const SkIRect& scaledSubsetRect, ZeroInitialized zeroInit,
|
| + int* rowsDecoded) {
|
| +
|
| + int scaledSubsetTop = scaledSubsetRect.top();
|
| + int scaledSubsetHeight = scaledSubsetRect.height();
|
| + switch (fCodec->getScanlineOrder()) {
|
| + case SkCodec::kTopDown_SkScanlineOrder:
|
| + case SkCodec::kBottomUp_SkScanlineOrder:
|
| + case SkCodec::kNone_SkScanlineOrder: {
|
| + if (!fCodec->skipScanlines(scaledSubsetTop)) {
|
| + *rowsDecoded = 0;
|
| + return kIncompleteInput;
|
| + }
|
| +
|
| + uint32_t decodedLines = fCodec->getScanlines(dst, scaledSubsetHeight,
|
| + rowBytes);
|
| + if (decodedLines != scaledSubsetHeight) {
|
| + *rowsDecoded = decodedLines;
|
| + return kIncompleteInput;
|
| + }
|
| + return kSuccess;
|
| + }
|
| + case SkCodec::kOutOfOrder_SkScanlineOrder: {
|
| + for (int y = 0; y < scaledInfo.height(); y++) {
|
| + int dstY = fCodec->nextScanline();
|
| + if (is_in_subset(dstY, scaledSubsetTop, scaledSubsetHeight)) {
|
| + void* dstPtr = SkTAddOffset<void>(dst, rowBytes * (dstY - scaledSubsetTop));
|
| + if (1 != fCodec->getScanlines(dstPtr, 1, rowBytes)) {
|
| + *rowsDecoded = y + 1;
|
| + return kIncompleteInput;
|
| + }
|
| + } else {
|
| + if (!fCodec->skipScanlines(1)) {
|
| + *rowsDecoded = y + 1;
|
| + return kIncompleteInput;
|
| + }
|
| + }
|
| + }
|
| + return kSuccess;
|
| + }
|
| }
|
| +}
|
| +
|
| +SkCodec::Result SkScaledCodec::sampledDecode(const SkImageInfo& scaledSubsetInfo, void* dst,
|
| + size_t rowBytes, const SkIRect& subsetRect, const SkIRect& scaledSubsetRect, int sampleX,
|
| + int sampleY, ZeroInitialized zeroInit, int* rowsDecoded) {
|
|
|
| + // Set first sample pixel in y direction.
|
| + int y0 = get_start_coord(sampleY);
|
| + int scaledSubsetHeight = scaledSubsetRect.height();
|
| switch(fCodec->getScanlineOrder()) {
|
| - case SkCodec::kTopDown_SkScanlineOrder: {
|
| - if (!fCodec->skipScanlines(Y0)) {
|
| + case SkCodec::kTopDown_SkScanlineOrder:
|
| + if (!fCodec->skipScanlines(y0 + subsetRect.top())) {
|
| *rowsDecoded = 0;
|
| return kIncompleteInput;
|
| }
|
| - for (int y = 0; y < dstHeight; y++) {
|
| + for (int y = 0; y < scaledSubsetHeight; y++) {
|
| if (1 != fCodec->getScanlines(dst, 1, rowBytes)) {
|
| // The failed call to getScanlines() will take care of
|
| // filling the failed row, so we indicate that we have
|
| @@ -261,7 +403,7 @@ SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi
|
| *rowsDecoded = y + 1;
|
| return kIncompleteInput;
|
| }
|
| - if (y < dstHeight - 1) {
|
| + if (y < scaledSubsetHeight - 1) {
|
| if (!fCodec->skipScanlines(sampleY - 1)) {
|
| *rowsDecoded = y + 1;
|
| return kIncompleteInput;
|
| @@ -270,14 +412,13 @@ SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi
|
| dst = SkTAddOffset<void>(dst, rowBytes);
|
| }
|
| return kSuccess;
|
| - }
|
| case SkCodec::kBottomUp_SkScanlineOrder:
|
| case SkCodec::kOutOfOrder_SkScanlineOrder: {
|
| Result result = kSuccess;
|
| int y;
|
| - for (y = 0; y < srcHeight; y++) {
|
| + for (y = 0; y < this->getInfo().height(); y++) {
|
| int srcY = fCodec->nextScanline();
|
| - if (is_coord_necessary(srcY, sampleY, dstHeight)) {
|
| + if (is_coord_necessary(srcY, sampleY, scaledSubsetHeight, subsetRect.top())) {
|
| void* dstPtr = SkTAddOffset<void>(dst, rowBytes * get_dst_coord(srcY, sampleY));
|
| if (1 != fCodec->getScanlines(dstPtr, 1, rowBytes)) {
|
| result = kIncompleteInput;
|
| @@ -294,38 +435,43 @@ SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi
|
| // We handle filling uninitialized memory here instead of in the parent class.
|
| // The parent class does not know that we are sampling.
|
| if (kIncompleteInput == result) {
|
| - const uint32_t fillValue = fCodec->getFillValue(requestedInfo.colorType(),
|
| - requestedInfo.alphaType());
|
| - for (; y < srcHeight; y++) {
|
| + const uint32_t fillValue = fCodec->getFillValue(scaledSubsetInfo.colorType(),
|
| + scaledSubsetInfo.alphaType());
|
| + for (; y < this->getInfo().height(); y++) {
|
| int srcY = fCodec->outputScanline(y);
|
| - if (is_coord_necessary(srcY, sampleY, dstHeight)) {
|
| + if (is_coord_necessary(srcY, sampleY, scaledSubsetHeight, subsetRect.top())) {
|
| void* dstRow = SkTAddOffset<void>(dst,
|
| rowBytes * get_dst_coord(srcY, sampleY));
|
| - SkSampler::Fill(dstRow, requestedInfo.colorType(), requestedInfo.width(),
|
| - 1, rowBytes, fillValue, options.fZeroInitialized);
|
| + SkSampler::Fill(dstRow, scaledSubsetInfo.colorType(),
|
| + scaledSubsetInfo.width(), 1, rowBytes, fillValue,
|
| + zeroInit);
|
| }
|
| }
|
| - *rowsDecoded = dstHeight;
|
| + *rowsDecoded = scaledSubsetInfo.height();
|
| }
|
| return result;
|
| }
|
| case SkCodec::kNone_SkScanlineOrder: {
|
| - SkAutoMalloc storage(srcHeight * rowBytes);
|
| + SkAutoMalloc storage(subsetRect.height() * rowBytes);
|
| uint8_t* storagePtr = static_cast<uint8_t*>(storage.get());
|
| - int scanlines = fCodec->getScanlines(storagePtr, srcHeight, rowBytes);
|
| - storagePtr += Y0 * rowBytes;
|
| - scanlines -= Y0;
|
| + if (!fCodec->skipScanlines(subsetRect.top())) {
|
| + *rowsDecoded = 0;
|
| + return kIncompleteInput;
|
| + }
|
| + int scanlines = fCodec->getScanlines(storagePtr, subsetRect.height(), rowBytes);
|
| + scanlines -= y0;
|
| + storagePtr += y0 * rowBytes;
|
| int y = 0;
|
| - while (y < dstHeight && scanlines > 0) {
|
| - memcpy(dst, storagePtr, rowBytes);
|
| + while (y < scaledSubsetHeight && scanlines > 0) {
|
| + memcpy(dst, storagePtr, scaledSubsetInfo.minRowBytes());
|
| storagePtr += sampleY * rowBytes;
|
| dst = SkTAddOffset<void>(dst, rowBytes);
|
| scanlines -= sampleY;
|
| y++;
|
| }
|
| - if (y < dstHeight) {
|
| + if (y < scaledSubsetHeight) {
|
| // fCodec has already handled filling uninitialized memory.
|
| - *rowsDecoded = dstHeight;
|
| + *rowsDecoded = scaledSubsetInfo.height();
|
| return kIncompleteInput;
|
| }
|
| return kSuccess;
|
| @@ -336,6 +482,10 @@ SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi
|
| }
|
| }
|
|
|
| +bool SkScaledCodec::onRewind() {
|
| + return fCodec->onRewind();
|
| +}
|
| +
|
| uint32_t SkScaledCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType) const {
|
| return fCodec->onGetFillValue(colorType, alphaType);
|
| }
|
|
|