diff options
-rw-r--r-- | bench/subset/SubsetSingleBench.cpp | 53 | ||||
-rw-r--r-- | bench/subset/SubsetTranslateBench.cpp | 62 | ||||
-rw-r--r-- | bench/subset/SubsetZoomBench.cpp | 64 | ||||
-rw-r--r-- | dm/DMSrcSink.cpp | 28 | ||||
-rw-r--r-- | include/codec/SkCodec.h | 15 | ||||
-rw-r--r-- | src/codec/SkBmpCodec.cpp | 4 | ||||
-rw-r--r-- | src/codec/SkBmpMaskCodec.cpp | 8 | ||||
-rw-r--r-- | src/codec/SkBmpMaskCodec.h | 2 | ||||
-rw-r--r-- | src/codec/SkBmpRLECodec.cpp | 6 | ||||
-rw-r--r-- | src/codec/SkBmpStandardCodec.cpp | 6 | ||||
-rw-r--r-- | src/codec/SkCodec.cpp | 14 | ||||
-rw-r--r-- | src/codec/SkCodec_libgif.cpp | 18 | ||||
-rw-r--r-- | src/codec/SkCodec_libgif.h | 6 | ||||
-rw-r--r-- | src/codec/SkCodec_libpng.cpp | 15 | ||||
-rw-r--r-- | src/codec/SkCodec_libpng.h | 3 | ||||
-rw-r--r-- | src/codec/SkCodec_wbmp.cpp | 10 | ||||
-rw-r--r-- | src/codec/SkJpegCodec.cpp | 47 | ||||
-rw-r--r-- | src/codec/SkJpegCodec.h | 3 | ||||
-rw-r--r-- | src/codec/SkMaskSwizzler.cpp | 26 | ||||
-rw-r--r-- | src/codec/SkMaskSwizzler.h | 12 | ||||
-rw-r--r-- | src/codec/SkSwizzler.cpp | 35 | ||||
-rw-r--r-- | src/codec/SkSwizzler.h | 20 | ||||
-rw-r--r-- | src/codec/SkWebpCodec.cpp | 4 |
23 files changed, 194 insertions, 267 deletions
diff --git a/bench/subset/SubsetSingleBench.cpp b/bench/subset/SubsetSingleBench.cpp index b4e92e4e22..47a897fd83 100644 --- a/bench/subset/SubsetSingleBench.cpp +++ b/bench/subset/SubsetSingleBench.cpp @@ -65,56 +65,29 @@ void SubsetSingleBench::onDraw(int n, SkCanvas* canvas) { if (fUseCodec) { for (int count = 0; count < n; count++) { SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(fStream->duplicate())); + SkASSERT(SkCodec::kOutOfOrder_SkScanlineOrder != codec->getScanlineOrder()); const SkImageInfo info = codec->getInfo().makeColorType(fColorType); + // The scanline decoder will handle subsetting in the x-dimension. + SkIRect subset = SkIRect::MakeXYWH(fOffsetLeft, 0, fSubsetWidth, + codec->getInfo().height()); + SkCodec::Options options; + options.fSubset = ⊂ + SkDEBUGCODE(SkCodec::Result result =) - codec->startScanlineDecode(info, nullptr, colors, &colorCount); + codec->startScanlineDecode(info, &options, colors, &colorCount); SkASSERT(result == SkCodec::kSuccess); SkBitmap bitmap; SkImageInfo subsetInfo = info.makeWH(fSubsetWidth, fSubsetHeight); alloc_pixels(&bitmap, subsetInfo, colors, colorCount); - SkDEBUGCODE(int lines = ) codec->skipScanlines(fOffsetTop); - SkASSERT((uint32_t) lines == fOffsetTop); - - const uint32_t bpp = info.bytesPerPixel(); - - switch (codec->getScanlineOrder()) { - case SkCodec::kTopDown_SkScanlineOrder: { - SkAutoTDeleteArray<uint8_t> row(new uint8_t[info.minRowBytes()]); - for (uint32_t y = 0; y < fSubsetHeight; y++) { - SkDEBUGCODE(lines = ) codec->getScanlines(row.get(), 1, 0); - SkASSERT(lines == 1); - - memcpy(bitmap.getAddr(0, y), row.get() + fOffsetLeft * bpp, - fSubsetWidth * bpp); - } - break; - } - case SkCodec::kNone_SkScanlineOrder: { - // decode all scanlines that intersect the subset, and copy the subset - // into the output. - SkImageInfo stripeInfo = info.makeWH(info.width(), fSubsetHeight); - SkBitmap stripeBm; - alloc_pixels(&stripeBm, stripeInfo, colors, colorCount); - - SkDEBUGCODE(lines = ) codec->getScanlines(stripeBm.getPixels(), fSubsetHeight, - stripeBm.rowBytes()); - SkASSERT((uint32_t) lines == fSubsetHeight); - - for (uint32_t y = 0; y < fSubsetHeight; y++) { - memcpy(bitmap.getAddr(0, y), stripeBm.getAddr(fOffsetLeft, y), - fSubsetWidth * bpp); - } - break; - } - default: - // We currently are only testing kTopDown and kNone, which are the only - // two used by the subsets we care about. skbug.com/4428 - SkASSERT(false); + SkDEBUGCODE(bool success = ) codec->skipScanlines(fOffsetTop); + SkASSERT(success); - } + SkDEBUGCODE(uint32_t lines = ) codec->getScanlines(bitmap.getPixels(), fSubsetHeight, + bitmap.rowBytes()); + SkASSERT(lines == fSubsetHeight); } } else { for (int count = 0; count < n; count++) { diff --git a/bench/subset/SubsetTranslateBench.cpp b/bench/subset/SubsetTranslateBench.cpp index 27c628edde..d8da6db566 100644 --- a/bench/subset/SubsetTranslateBench.cpp +++ b/bench/subset/SubsetTranslateBench.cpp @@ -71,11 +71,8 @@ void SubsetTranslateBench::onDraw(int n, SkCanvas* canvas) { if (fUseCodec) { for (int count = 0; count < n; count++) { SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(fStream->duplicate())); + SkASSERT(SkCodec::kOutOfOrder_SkScanlineOrder != codec->getScanlineOrder()); const SkImageInfo info = codec->getInfo().makeColorType(fColorType); - SkAutoTDeleteArray<uint8_t> row(nullptr); - if (codec->getScanlineOrder() == SkCodec::kTopDown_SkScanlineOrder) { - row.reset(new uint8_t[info.minRowBytes()]); - } SkBitmap bitmap; // Note that we use the same bitmap for all of the subsets. @@ -83,17 +80,8 @@ void SubsetTranslateBench::onDraw(int n, SkCanvas* canvas) { SkImageInfo subsetInfo = info.makeWH(fSubsetWidth, fSubsetHeight); alloc_pixels(&bitmap, subsetInfo, colors, colorCount); - const uint32_t bpp = info.bytesPerPixel(); - for (int x = 0; x < info.width(); x += fSubsetWidth) { for (int y = 0; y < info.height(); y += fSubsetHeight) { - SkDEBUGCODE(SkCodec::Result result =) - codec->startScanlineDecode(info, nullptr, get_colors(&bitmap), &colorCount); - SkASSERT(SkCodec::kSuccess == result); - - SkDEBUGCODE(int lines =) codec->skipScanlines(y); - SkASSERT(y == lines); - const uint32_t currSubsetWidth = x + (int) fSubsetWidth > info.width() ? info.width() - x : fSubsetWidth; @@ -101,38 +89,22 @@ void SubsetTranslateBench::onDraw(int n, SkCanvas* canvas) { y + (int) fSubsetHeight > info.height() ? info.height() - y : fSubsetHeight; - switch (codec->getScanlineOrder()) { - case SkCodec::kTopDown_SkScanlineOrder: - for (uint32_t y = 0; y < currSubsetHeight; y++) { - SkDEBUGCODE(lines =) codec->getScanlines(row.get(), 1, 0); - SkASSERT(1 == lines); - - memcpy(bitmap.getAddr(0, y), row.get() + x * bpp, - currSubsetWidth * bpp); - } - break; - case SkCodec::kNone_SkScanlineOrder: { - // decode all scanlines that intersect the subset, and copy the subset - // into the output. - SkImageInfo stripeInfo = info.makeWH(info.width(), currSubsetHeight); - SkBitmap stripeBm; - alloc_pixels(&stripeBm, stripeInfo, colors, colorCount); - - SkDEBUGCODE(lines =) codec->getScanlines(stripeBm.getPixels(), - currSubsetHeight, stripeBm.rowBytes()); - SkASSERT(currSubsetHeight == (uint32_t) lines); - - for (uint32_t subsetY = 0; subsetY < currSubsetHeight; subsetY++) { - memcpy(bitmap.getAddr(0, subsetY), stripeBm.getAddr(x, subsetY), - currSubsetWidth * bpp); - } - break; - } - default: - // We currently are only testing kTopDown and kNone, which are the only - // two used by the subsets we care about. skbug.com/4428 - SkASSERT(false); - } + // The scanline decoder will handle subsetting in the x-dimension. + SkIRect subset = SkIRect::MakeXYWH(x, 0, currSubsetWidth, + codec->getInfo().height()); + SkCodec::Options options; + options.fSubset = ⊂ + + SkDEBUGCODE(SkCodec::Result result =) + codec->startScanlineDecode(info, &options, get_colors(&bitmap), &colorCount); + SkASSERT(SkCodec::kSuccess == result); + + SkDEBUGCODE(bool success =) codec->skipScanlines(y); + SkASSERT(success); + + SkDEBUGCODE(uint32_t lines =) codec->getScanlines(bitmap.getPixels(), + currSubsetHeight, bitmap.rowBytes()); + SkASSERT(currSubsetHeight == lines); } } } diff --git a/bench/subset/SubsetZoomBench.cpp b/bench/subset/SubsetZoomBench.cpp index 3edc17f1cb..f17a97c26b 100644 --- a/bench/subset/SubsetZoomBench.cpp +++ b/bench/subset/SubsetZoomBench.cpp @@ -61,69 +61,41 @@ void SubsetZoomBench::onDraw(int n, SkCanvas* canvas) { if (fUseCodec) { for (int count = 0; count < n; count++) { SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(fStream->duplicate())); + SkASSERT(SkCodec::kOutOfOrder_SkScanlineOrder != codec->getScanlineOrder()); const SkImageInfo info = codec->getInfo().makeColorType(fColorType); - SkAutoTDeleteArray<uint8_t> row(nullptr); - if (codec->getScanlineOrder() == SkCodec::kTopDown_SkScanlineOrder) { - row.reset(new uint8_t[info.minRowBytes()]); - } const int centerX = info.width() / 2; const int centerY = info.height() / 2; int w = fSubsetWidth; int h = fSubsetHeight; do { - SkDEBUGCODE(SkCodec::Result result = ) - codec->startScanlineDecode(info, nullptr, colors, &colorCount); - SkASSERT(SkCodec::kSuccess == result); - const int subsetStartX = SkTMax(0, centerX - w / 2); const int subsetStartY = SkTMax(0, centerY - h / 2); const int subsetWidth = SkTMin(w, info.width() - subsetStartX); const int subsetHeight = SkTMin(h, info.height() - subsetStartY); + + // The scanline decoder will handle subsetting in the x-dimension. + SkIRect subset = SkIRect::MakeXYWH(subsetStartX, 0, subsetWidth, + codec->getInfo().height()); + SkCodec::Options options; + options.fSubset = ⊂ + + SkDEBUGCODE(SkCodec::Result result = ) + codec->startScanlineDecode(info, &options, colors, &colorCount); + SkASSERT(SkCodec::kSuccess == result); + // Note that if we subsetted and scaled in a single step, we could use the // same bitmap - as is often done in actual use cases. SkBitmap bitmap; SkImageInfo subsetInfo = info.makeWH(subsetWidth, subsetHeight); alloc_pixels(&bitmap, subsetInfo, colors, colorCount); - uint32_t bpp = info.bytesPerPixel(); - - SkDEBUGCODE(int lines = ) codec->skipScanlines(subsetStartY); - SkASSERT(subsetStartY == lines); - - switch (codec->getScanlineOrder()) { - case SkCodec::kTopDown_SkScanlineOrder: - for (int y = 0; y < subsetHeight; y++) { - SkDEBUGCODE(lines = ) codec->getScanlines(row.get(), 1, 0); - SkASSERT(1 == lines); - - memcpy(bitmap.getAddr(0, y), row.get() + subsetStartX * bpp, - subsetWidth * bpp); - } - break; - case SkCodec::kNone_SkScanlineOrder: { - // decode all scanlines that intersect the subset, and copy the subset - // into the output. - SkImageInfo stripeInfo = info.makeWH(info.width(), subsetHeight); - SkBitmap stripeBm; - alloc_pixels(&stripeBm, stripeInfo, colors, colorCount); - - SkDEBUGCODE(lines = ) codec->getScanlines(stripeBm.getPixels(), - subsetHeight, stripeBm.rowBytes()); - SkASSERT(subsetHeight == lines); - - for (int y = 0; y < subsetHeight; y++) { - memcpy(bitmap.getAddr(0, y), - stripeBm.getAddr(subsetStartX, y), - subsetWidth * bpp); - } - break; - } - default: - // We currently are only testing kTopDown and kNone, which are the only - // two used by the subsets we care about. skbug.com/4428 - SkASSERT(false); - } + SkDEBUGCODE(bool success = ) codec->skipScanlines(subsetStartY); + SkASSERT(success); + + SkDEBUGCODE(int lines = ) codec->getScanlines(bitmap.getPixels(), + subsetHeight, bitmap.rowBytes()); + SkASSERT(subsetHeight == lines); w <<= 1; h <<= 1; diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp index c7b389d36d..4137154e99 100644 --- a/dm/DMSrcSink.cpp +++ b/dm/DMSrcSink.cpp @@ -404,9 +404,6 @@ Error CodecSrc::draw(SkCanvas* canvas) const { return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str(), largestSubsetDecodeInfo.width(), largestSubsetDecodeInfo.height()); } - const size_t rowBytes = decodeInfo.minRowBytes(); - char* buffer = new char[largestSubsetDecodeInfo.height() * rowBytes]; - SkAutoTDeleteArray<char> lineDeleter(buffer); for (int col = 0; col < divisor; col++) { //currentSubsetWidth may be larger than subsetWidth for rightmost subsets const int currentSubsetWidth = (col + 1 == divisor) ? @@ -418,10 +415,13 @@ Error CodecSrc::draw(SkCanvas* canvas) const { subsetHeight + extraY : subsetHeight; const int y = row * subsetHeight; //create scanline decoder for each subset - if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr, - colorCountPtr) - // TODO (msarett): Support this mode for all scanline orderings. - || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOrder()) { + SkCodec::Options options; + SkIRect subset = SkIRect::MakeXYWH(x, 0, currentSubsetWidth, h); + options.fSubset = ⊂ + // TODO (msarett): Support this mode for all scanline orderings. + if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options, + colorPtr, colorCountPtr) || + SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOrder()) { if (x == 0 && y == 0) { //first try, image may not be compatible return Error::Nonfatal("Could not start top-down scanline decoder"); @@ -440,17 +440,9 @@ Error CodecSrc::draw(SkCanvas* canvas) const { SkBitmap subsetBm; SkIRect bounds = SkIRect::MakeWH(currentSubsetWidth, currentSubsetHeight); SkAssertResult(largestSubsetBm.extractSubset(&subsetBm, bounds)); - SkAutoLockPixels autlockSubsetBm(subsetBm, true); - codec->getScanlines(buffer, currentSubsetHeight, rowBytes); - - const size_t bpp = decodeInfo.bytesPerPixel(); - char* bufferRow = buffer; - for (int subsetY = 0; subsetY < currentSubsetHeight; ++subsetY) { - memcpy(subsetBm.getAddr(0, subsetY), bufferRow + x*bpp, - currentSubsetWidth*bpp); - bufferRow += rowBytes; - } - + SkAutoLockPixels autolock(subsetBm, true); + codec->getScanlines(subsetBm.getAddr(0, 0), currentSubsetHeight, + subsetBm.rowBytes()); subsetBm.notifyPixelsChanged(); canvas->drawBitmap(subsetBm, SkIntToScalar(x), SkIntToScalar(y)); } diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h index 1b9cb0f5d7..8b6e210167 100644 --- a/include/codec/SkCodec.h +++ b/include/codec/SkCodec.h @@ -168,11 +168,20 @@ public: ZeroInitialized fZeroInitialized; /** * If not NULL, represents a subset of the original image to decode. - * * Must be within the bounds returned by getInfo(). - * * If the EncodedFormat is kWEBP_SkEncodedFormat (the only one which * currently supports subsets), the top and left values must be even. + * + * In getPixels, we will attempt to decode the exact rectangular + * subset specified by fSubset. + * + * In a scanline decode, it does not make sense to specify a subset + * top or subset height, since the client already controls which rows + * to get and which rows to skip. During scanline decodes, we will + * require that the subset top be zero and the subset height be equal + * to the full height. We will, however, use the values of + * subset left and subset width to decode partial scanlines on calls + * to getScanlines(). */ SkIRect* fSubset; }; @@ -259,7 +268,7 @@ public: * @return Enum representing success or reason for failure. */ Result startScanlineDecode(const SkImageInfo& dstInfo, const SkCodec::Options* options, - SkPMColor ctable[], int* ctableCount); + SkPMColor ctable[], int* ctableCount); /** * Simplified version of startScanlineDecode() that asserts that info is NOT diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp index 1aa43f583c..0222c8ce9f 100644 --- a/src/codec/SkBmpCodec.cpp +++ b/src/codec/SkBmpCodec.cpp @@ -564,10 +564,6 @@ uint32_t SkBmpCodec::computeNumColors(uint32_t numColors) { SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { - if (options.fSubset) { - // Subsets are not supported. - return kUnimplemented; - } if (!conversion_possible(dstInfo, this->getInfo())) { SkCodecPrintf("Error: cannot convert input type to output type.\n"); return kInvalidConversion; diff --git a/src/codec/SkBmpMaskCodec.cpp b/src/codec/SkBmpMaskCodec.cpp index 336698d319..2bc47b5126 100644 --- a/src/codec/SkBmpMaskCodec.cpp +++ b/src/codec/SkBmpMaskCodec.cpp @@ -58,10 +58,10 @@ SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo, return kSuccess; } -bool SkBmpMaskCodec::initializeSwizzler(const SkImageInfo& dstInfo) { +bool SkBmpMaskCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) { // Create the swizzler - fMaskSwizzler.reset(SkMaskSwizzler::CreateMaskSwizzler( - dstInfo, this->getInfo(), fMasks, this->bitsPerPixel())); + fMaskSwizzler.reset(SkMaskSwizzler::CreateMaskSwizzler(dstInfo, this->getInfo(), fMasks, + this->bitsPerPixel(), options)); if (nullptr == fMaskSwizzler.get()) { return false; @@ -73,7 +73,7 @@ bool SkBmpMaskCodec::initializeSwizzler(const SkImageInfo& dstInfo) { SkCodec::Result SkBmpMaskCodec::prepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { // Initialize a the mask swizzler - if (!this->initializeSwizzler(dstInfo)) { + if (!this->initializeSwizzler(dstInfo, options)) { SkCodecPrintf("Error: cannot initialize swizzler.\n"); return SkCodec::kInvalidConversion; } diff --git a/src/codec/SkBmpMaskCodec.h b/src/codec/SkBmpMaskCodec.h index 1c1d1d8c11..4ec868db0e 100644 --- a/src/codec/SkBmpMaskCodec.h +++ b/src/codec/SkBmpMaskCodec.h @@ -44,7 +44,7 @@ protected: private: - bool initializeSwizzler(const SkImageInfo& dstInfo); + bool initializeSwizzler(const SkImageInfo& dstInfo, const Options& options); SkSampler* getSampler(bool createIfNecessary) override { SkASSERT(fMaskSwizzler); return fMaskSwizzler; diff --git a/src/codec/SkBmpRLECodec.cpp b/src/codec/SkBmpRLECodec.cpp index 37af47600b..e215095266 100644 --- a/src/codec/SkBmpRLECodec.cpp +++ b/src/codec/SkBmpRLECodec.cpp @@ -259,6 +259,12 @@ void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes, SkCodec::Result SkBmpRLECodec::prepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { + // FIXME: Support subsets for scanline decodes. + if (options.fSubset) { + // Subsets are not supported. + return kUnimplemented; + } + // Reset fSampleX. If it needs to be a value other than 1, it will get modified by // the sampler. fSampleX = 1; diff --git a/src/codec/SkBmpStandardCodec.cpp b/src/codec/SkBmpStandardCodec.cpp index 938fe8c788..9557609360 100644 --- a/src/codec/SkBmpStandardCodec.cpp +++ b/src/codec/SkBmpStandardCodec.cpp @@ -161,8 +161,7 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, return true; } -bool SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, - const Options& opts) { +bool SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts) { // Get swizzler configuration SkSwizzler::SrcConfig config; switch (this->bitsPerPixel()) { @@ -197,8 +196,7 @@ bool SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); // Create swizzler - fSwizzler.reset(SkSwizzler::CreateSwizzler(config, - colorPtr, dstInfo, opts.fZeroInitialized)); + fSwizzler.reset(SkSwizzler::CreateSwizzler(config, colorPtr, dstInfo, opts)); if (nullptr == fSwizzler.get()) { return false; diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp index 0047d599ac..56f6a8de9e 100644 --- a/src/codec/SkCodec.cpp +++ b/src/codec/SkCodec.cpp @@ -220,11 +220,15 @@ SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, if (nullptr == options) { options = &optsStorage; } else if (options->fSubset) { - SkIRect subset(*options->fSubset); - if (!this->onGetValidSubset(&subset) || subset != *options->fSubset) { - // FIXME: How to differentiate between not supporting subset at all - // and not supporting this particular subset? - return kUnimplemented; + SkIRect size = SkIRect::MakeSize(dstInfo.dimensions()); + if (!size.contains(*options->fSubset)) { + return kInvalidInput; + } + + // We only support subsetting in the x-dimension for scanline decoder. + // Subsetting in the y-dimension can be accomplished using skipScanlines(). + if (options->fSubset->top() != 0 || options->fSubset->height() != dstInfo.height()) { + return kInvalidInput; } } diff --git a/src/codec/SkCodec_libgif.cpp b/src/codec/SkCodec_libgif.cpp index 856f69ba3c..0187891558 100644 --- a/src/codec/SkCodec_libgif.cpp +++ b/src/codec/SkCodec_libgif.cpp @@ -435,10 +435,6 @@ void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColor* inputColorPtr, int* inputColorCount, const Options& opts) { // Check for valid input parameters - if (opts.fSubset) { - // Subsets are not supported. - return kUnimplemented; - } if (!conversion_possible(dstInfo, this->getInfo())) { return gif_error("Cannot convert input type to output type.\n", kInvalidConversion); @@ -449,11 +445,9 @@ SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColo return kSuccess; } -SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, - ZeroInitialized zeroInit) { +SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts) { const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); - fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, - colorPtr, dstInfo, zeroInit)); + fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, colorPtr, dstInfo, opts)); if (nullptr != fSwizzler.get()) { return kSuccess; } @@ -485,7 +479,7 @@ SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, // Initialize the swizzler if (fFrameIsSubset) { const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFrameRect.height()); - if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitialized)) { + if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts)) { return gif_error("Could not initialize swizzler.\n", kUnimplemented); } @@ -499,7 +493,7 @@ SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + dstBytesPerPixel * fFrameRect.left()); } else { - if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)) { + if (kSuccess != this->initializeSwizzler(dstInfo, opts)) { return gif_error("Could not initialize swizzler.\n", kUnimplemented); } } @@ -535,11 +529,11 @@ SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, // Initialize the swizzler if (fFrameIsSubset) { const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFrameRect.height()); - if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitialized)) { + if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts)) { return gif_error("Could not initialize swizzler.\n", kUnimplemented); } } else { - if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized)) { + if (kSuccess != this->initializeSwizzler(dstInfo, opts)) { return gif_error("Could not initialize swizzler.\n", kUnimplemented); } } diff --git a/src/codec/SkCodec_libgif.h b/src/codec/SkCodec_libgif.h index 10fdac97f9..2e0c5a4a1d 100644 --- a/src/codec/SkCodec_libgif.h +++ b/src/codec/SkCodec_libgif.h @@ -129,9 +129,11 @@ private: * @param dstInfo Output image information. Dimensions may have been * adjusted if the image frame size does not match the size * indicated in the header. - * @param zeroInit Indicates if destination memory is zero initialized. + * @param options Informs the swizzler if destination memory is zero initialized. + * Contains subset information. */ - Result initializeSwizzler(const SkImageInfo& dstInfo, ZeroInitialized zeroInit); + Result initializeSwizzler(const SkImageInfo& dstInfo, + const Options& options); SkSampler* getSampler(bool createIfNecessary) override { SkASSERT(fSwizzler); diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp index e828e24999..7d41623a88 100644 --- a/src/codec/SkCodec_libpng.cpp +++ b/src/codec/SkCodec_libpng.cpp @@ -435,8 +435,7 @@ SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, // Create the swizzler. SkPngCodec retains ownership of the color table. const SkPMColor* colors = get_color_ptr(fColorTable.get()); - fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo, - options.fZeroInitialized)); + fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo, options)); if (!fSwizzler) { // FIXME: CreateSwizzler could fail for another reason. return kUnimplemented; @@ -477,8 +476,7 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* } // Note that ctable and ctableCount may be modified if there is a color table - const Result result = this->initializeSwizzler(requestedInfo, options, - ctable, ctableCount); + const Result result = this->initializeSwizzler(requestedInfo, options, ctable, ctableCount); if (result != kSuccess) { return result; } @@ -699,15 +697,14 @@ public: } Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options, - SkPMColor ctable[], int* ctableCount) override - { + SkPMColor ctable[], int* ctableCount) override { if (!conversion_possible(dstInfo, this->getInfo())) { return kInvalidConversion; } - const SkCodec::Result result = this->initializeSwizzler(dstInfo, options, ctable, - ctableCount); - if (result != SkCodec::kSuccess) { + const Result result = this->initializeSwizzler(dstInfo, options, ctable, + ctableCount); + if (result != kSuccess) { return result; } diff --git a/src/codec/SkCodec_libpng.h b/src/codec/SkCodec_libpng.h index 6bdf58065b..f003cbd4e0 100644 --- a/src/codec/SkCodec_libpng.h +++ b/src/codec/SkCodec_libpng.h @@ -18,7 +18,6 @@ #endif #include "png.h" -class SkScanlineDecoder; class SkStream; class SkPngCodec : public SkCodec { @@ -27,7 +26,6 @@ public: // Assume IsPng was called and returned true. static SkCodec* NewFromStream(SkStream*); - static SkScanlineDecoder* NewSDFromStream(SkStream*); virtual ~SkPngCodec(); @@ -78,7 +76,6 @@ private: SkSwizzler::SrcConfig fSrcConfig; const int fNumberPasses; int fBitDepth; - AlphaState fAlphaState; bool decodePalette(bool premultiply, int* ctableCount); diff --git a/src/codec/SkCodec_wbmp.cpp b/src/codec/SkCodec_wbmp.cpp index 14b720988f..19ae4eaf0e 100644 --- a/src/codec/SkCodec_wbmp.cpp +++ b/src/codec/SkCodec_wbmp.cpp @@ -70,8 +70,8 @@ bool SkWbmpCodec::onRewind() { return read_header(this->stream(), nullptr); } -SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info, - const SkPMColor* ctable, const Options& opts) { +SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info, const SkPMColor* ctable, + const Options& opts) { // Create the swizzler based on the desired color type switch (info.colorType()) { case kIndex_8_SkColorType: @@ -82,8 +82,7 @@ SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info, default: return nullptr; } - return SkSwizzler::CreateSwizzler(SkSwizzler::kBit, ctable, info, - opts.fZeroInitialized); + return SkSwizzler::CreateSwizzler(SkSwizzler::kBit, ctable, info, opts); } bool SkWbmpCodec::readRow(uint8_t* row) { @@ -188,8 +187,7 @@ SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, } // Initialize the swizzler - fSwizzler.reset(this->initializeSwizzler(dstInfo, - get_color_ptr(fColorTable.get()), options)); + fSwizzler.reset(this->initializeSwizzler(dstInfo, get_color_ptr(fColorTable.get()), options)); if (nullptr == fSwizzler.get()) { return kInvalidConversion; } diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp index 196543b682..d0d11b1a08 100644 --- a/src/codec/SkJpegCodec.cpp +++ b/src/codec/SkJpegCodec.cpp @@ -177,19 +177,19 @@ SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const { // support these as well unsigned int num; unsigned int denom = 8; - if (desiredScale > 0.875f) { + if (desiredScale >= 0.9375) { num = 8; - } else if (desiredScale > 0.75f) { + } else if (desiredScale >= 0.8125) { num = 7; - } else if (desiredScale > 0.625f) { + } else if (desiredScale >= 0.6875f) { num = 6; - } else if (desiredScale > 0.5f) { + } else if (desiredScale >= 0.5625f) { num = 5; - } else if (desiredScale > 0.375f) { + } else if (desiredScale >= 0.4375f) { num = 4; - } else if (desiredScale > 0.25f) { + } else if (desiredScale >= 0.3125f) { num = 3; - } else if (desiredScale > 0.125f) { + } else if (desiredScale >= 0.1875f) { num = 2; } else { num = 1; @@ -380,15 +380,9 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, return kSuccess; } -SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) { - if (!createIfNecessary || fSwizzler) { - SkASSERT(!fSwizzler || (fSrcRow && static_cast<uint8_t*>(fStorage.get()) == fSrcRow)); - return fSwizzler; - } - - const SkImageInfo& info = this->dstInfo(); +void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) { SkSwizzler::SrcConfig srcConfig; - switch (info.colorType()) { + switch (dstInfo.colorType()) { case kGray_8_SkColorType: srcConfig = SkSwizzler::kGray; break; @@ -406,14 +400,18 @@ SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) { SkASSERT(false); } - fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, info, - this->options().fZeroInitialized)); - if (!fSwizzler) { - return nullptr; - } - + fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, options)); fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); fSrcRow = static_cast<uint8_t*>(fStorage.get()); +} + +SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) { + if (!createIfNecessary || fSwizzler) { + SkASSERT(!fSwizzler || (fSrcRow && static_cast<uint8_t*>(fStorage.get()) == fSrcRow)); + return fSwizzler; + } + + this->initializeSwizzler(this->dstInfo(), this->options()); return fSwizzler; } @@ -441,6 +439,11 @@ SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, return kInvalidInput; } + // We will need a swizzler if we are performing a subset decode + if (options.fSubset) { + this->initializeSwizzler(dstInfo, options); + } + return kSuccess; } @@ -452,7 +455,7 @@ int SkJpegCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { // Read rows one at a time JSAMPLE* dstRow; if (fSwizzler) { - // write data to storage row, then sample using swizzler + // write data to storage row, then sample using swizzler dstRow = fSrcRow; } else { // write data directly to dst diff --git a/src/codec/SkJpegCodec.h b/src/codec/SkJpegCodec.h index 67680d66e8..687cf4b4b8 100644 --- a/src/codec/SkJpegCodec.h +++ b/src/codec/SkJpegCodec.h @@ -103,9 +103,10 @@ private: bool setOutputColorSpace(const SkImageInfo& dst); // scanline decoding + void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options); SkSampler* getSampler(bool createIfNecessary) override; Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options, - SkPMColor ctable[], int* ctableCount) override; + SkPMColor ctable[], int* ctableCount) override; int onGetScanlines(void* dst, int count, size_t rowBytes) override; bool onSkipScanlines(int count) override; diff --git a/src/codec/SkMaskSwizzler.cpp b/src/codec/SkMaskSwizzler.cpp index 9772d87e38..72dca28057 100644 --- a/src/codec/SkMaskSwizzler.cpp +++ b/src/codec/SkMaskSwizzler.cpp @@ -250,9 +250,9 @@ static SkSwizzler::ResultAlpha swizzle_mask32_to_565( * Create a new mask swizzler * */ -SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler( - const SkImageInfo& dstInfo, const SkImageInfo& srcInfo, SkMasks* masks, - uint32_t bitsPerPixel) { +SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler(const SkImageInfo& dstInfo, + const SkImageInfo& srcInfo, SkMasks* masks, uint32_t bitsPerPixel, + const SkCodec::Options& options) { // Choose the appropriate row procedure RowProc proc = nullptr; @@ -352,7 +352,14 @@ SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler( return nullptr; } - return new SkMaskSwizzler(dstInfo.width(), masks, proc); + int srcOffset = 0; + int srcWidth = dstInfo.width(); + if (options.fSubset) { + srcOffset = options.fSubset->left(); + srcWidth = options.fSubset->width(); + } + + return new SkMaskSwizzler(masks, proc, srcOffset, srcWidth); } /* @@ -360,13 +367,14 @@ SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler( * Constructor for mask swizzler * */ -SkMaskSwizzler::SkMaskSwizzler(int width, SkMasks* masks, RowProc proc) +SkMaskSwizzler::SkMaskSwizzler(SkMasks* masks, RowProc proc, int srcOffset, int srcWidth) : fMasks(masks) , fRowProc(proc) - , fSrcWidth(width) - , fDstWidth(width) + , fSrcWidth(srcWidth) + , fDstWidth(srcWidth) , fSampleX(1) - , fX0(0) + , fSrcOffset(srcOffset) + , fX0(srcOffset) {} int SkMaskSwizzler::onSetSampleX(int sampleX) { @@ -374,7 +382,7 @@ int SkMaskSwizzler::onSetSampleX(int sampleX) { SkASSERT(sampleX > 0); // Surely there is an upper limit? Should there be // way to report failure? fSampleX = sampleX; - fX0 = get_start_coord(sampleX); + fX0 = get_start_coord(sampleX) + fSrcOffset; fDstWidth = get_scaled_dimension(fSrcWidth, sampleX); // check that fX0 is less than original width diff --git a/src/codec/SkMaskSwizzler.h b/src/codec/SkMaskSwizzler.h index 0513d838c7..9aea5d8d70 100644 --- a/src/codec/SkMaskSwizzler.h +++ b/src/codec/SkMaskSwizzler.h @@ -28,7 +28,8 @@ public: static SkMaskSwizzler* CreateMaskSwizzler(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo, SkMasks* masks, - uint32_t bitsPerPixel); + uint32_t bitsPerPixel, + const SkCodec::Options& options); /* * Swizzle a row @@ -49,14 +50,10 @@ private: /* * Row procedure used for swizzle */ - typedef SkSwizzler::ResultAlpha (*RowProc)( - void* dstRow, const uint8_t* srcRow, int width, + typedef SkSwizzler::ResultAlpha (*RowProc)(void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX); - /* - * Constructor for mask swizzler - */ - SkMaskSwizzler(int width, SkMasks* masks, RowProc proc); + SkMaskSwizzler(SkMasks* masks, RowProc proc, int srcWidth, int srcOffset); int onSetSampleX(int) override; @@ -67,6 +64,7 @@ private: const int fSrcWidth; // Width of the source - i.e. before any sampling. int fDstWidth; // Width of dst, which may differ with sampling. int fSampleX; + int fSrcOffset; int fX0; }; diff --git a/src/codec/SkSwizzler.cpp b/src/codec/SkSwizzler.cpp index 8d13e56bd2..95ed1d7b96 100644 --- a/src/codec/SkSwizzler.cpp +++ b/src/codec/SkSwizzler.cpp @@ -230,9 +230,6 @@ static SkSwizzler::ResultAlpha swizzle_index_to_index( // SkScaledBitmap sampler just guesses that it is opaque. This is dangerous // and probably wrong since gif and bmp (rarely) may have alpha. if (1 == deltaSrc) { - // A non-zero offset is only used when sampling, meaning that deltaSrc will be - // greater than 1. The below loop relies on the fact that src remains unchanged. - SkASSERT(0 == offset); memcpy(dst, src, dstWidth); for (int x = 0; x < dstWidth; x++) { UPDATE_RESULT_ALPHA(ctable[src[x]] >> SK_A32_SHIFT); @@ -514,8 +511,8 @@ static bool swizzle_rgba_to_n32_unpremul_skipZ(void* SK_RESTRICT dstRow, SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, const SkPMColor* ctable, - const SkImageInfo& dstInfo, - SkCodec::ZeroInitialized zeroInit) { + const SkImageInfo& dstInfo, + const SkCodec::Options& options) { if (dstInfo.colorType() == kUnknown_SkColorType || kUnknown == sc) { return nullptr; } @@ -524,7 +521,7 @@ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, return nullptr; } RowProc proc = nullptr; - + SkCodec::ZeroInitialized zeroInit = options.fZeroInitialized; switch (sc) { case kBit: switch (dstInfo.colorType()) { @@ -683,28 +680,35 @@ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, return nullptr; } - // Store deltaSrc in bytes if it is an even multiple, otherwise use bits - int deltaSrc = SkIsAlign8(BitsPerPixel(sc)) ? BytesPerPixel(sc) : BitsPerPixel(sc); + // Store bpp in bytes if it is an even multiple, otherwise use bits + int bpp = SkIsAlign8(BitsPerPixel(sc)) ? BytesPerPixel(sc) : BitsPerPixel(sc); + + int srcOffset = 0; + int srcWidth = dstInfo.width(); + if (options.fSubset) { + srcOffset = options.fSubset->left(); + srcWidth = options.fSubset->width(); + } - return new SkSwizzler(proc, ctable, deltaSrc, dstInfo.width()); + return new SkSwizzler(proc, ctable, srcOffset, srcWidth, bpp); } -SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable, - int deltaSrc, int srcWidth) +SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable, int srcOffset, int srcWidth, int bpp) : fRowProc(proc) , fColorTable(ctable) - , fDeltaSrc(deltaSrc) + , fSrcOffset(srcOffset) + , fX0(srcOffset) , fSrcWidth(srcWidth) , fDstWidth(srcWidth) + , fBPP(bpp) , fSampleX(1) - , fX0(0) {} int SkSwizzler::onSetSampleX(int sampleX) { SkASSERT(sampleX > 0); // Surely there is an upper limit? Should there be // way to report failure? fSampleX = sampleX; - fX0 = get_start_coord(sampleX); + fX0 = get_start_coord(sampleX) + fSrcOffset; fDstWidth = get_scaled_dimension(fSrcWidth, sampleX); // check that fX0 is less than original width @@ -714,6 +718,5 @@ int SkSwizzler::onSetSampleX(int sampleX) { SkSwizzler::ResultAlpha SkSwizzler::swizzle(void* dst, const uint8_t* SK_RESTRICT src) { SkASSERT(nullptr != dst && nullptr != src); - return fRowProc(dst, src, fDstWidth, fDeltaSrc, fSampleX * fDeltaSrc, - fX0 * fDeltaSrc, fColorTable); + return fRowProc(dst, src, fDstWidth, fBPP, fSampleX * fBPP, fX0 * fBPP, fColorTable); } diff --git a/src/codec/SkSwizzler.h b/src/codec/SkSwizzler.h index d7f6337553..058044e420 100644 --- a/src/codec/SkSwizzler.h +++ b/src/codec/SkSwizzler.h @@ -121,13 +121,14 @@ public: * @param ctable Unowned pointer to an array of up to 256 colors for an * index source. * @param dstInfo Describes the destination. - * @param ZeroInitialized Whether dst is zero-initialized. The + * @param options Indicates if dst is zero-initialized. The * implementation may choose to skip writing zeroes * if set to kYes_ZeroInitialized. + * Contains subset information. * @return A new SkSwizzler or nullptr on failure. */ static SkSwizzler* CreateSwizzler(SrcConfig, const SkPMColor* ctable, - const SkImageInfo& dstInfo, SkCodec::ZeroInitialized); + const SkImageInfo& dstInfo, const SkCodec::Options&); /** * Swizzle a line. Generally this will be called height times, once @@ -173,16 +174,19 @@ private: const RowProc fRowProc; const SkPMColor* fColorTable; // Unowned pointer - const int fDeltaSrc; // if bitsPerPixel % 8 == 0 - // deltaSrc is bytesPerPixel - // else - // deltaSrc is bitsPerPixel + const int fSrcOffset; // Offset of the src in pixels, allows for partial + // scanline decodes. + int fX0; // Start coordinate for the src, may be different than + // fSrcOffset if we are sampling. const int fSrcWidth; // Width of the source - i.e. before any sampling. int fDstWidth; // Width of dst, which may differ with sampling. - int fX0; // first X coord to sample int fSampleX; // step between X samples + const int fBPP; // if bitsPerPixel % 8 == 0 + // fBPP is bytesPerPixel + // else + // fBPP is bitsPerPixel - SkSwizzler(RowProc proc, const SkPMColor* ctable, int deltaSrc, int srcWidth); + SkSwizzler(RowProc proc, const SkPMColor* ctable, int srcOffset, int srcWidth, int bpp); int onSetSampleX(int) override; diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp index a0fab0a153..3c61b93762 100644 --- a/src/codec/SkWebpCodec.cpp +++ b/src/codec/SkWebpCodec.cpp @@ -144,8 +144,8 @@ bool SkWebpCodec::onGetValidSubset(SkIRect* desiredSubset) const { return false; } - SkIRect bounds = SkIRect::MakeSize(this->getInfo().dimensions()); - if (!desiredSubset->intersect(bounds)) { + SkIRect dimensions = SkIRect::MakeSize(this->getInfo().dimensions()); + if (!dimensions.contains(*desiredSubset)) { return false; } |