| Index: src/codec/SkJpegCodec.cpp
|
| diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp
|
| index a89f8f53194839da9481d4bb87ece262fa4bef3d..f4116e324f82ca4e584e9080362735469abde463 100644
|
| --- a/src/codec/SkJpegCodec.cpp
|
| +++ b/src/codec/SkJpegCodec.cpp
|
| @@ -191,7 +191,7 @@
|
|
|
| // libjpeg errors will be caught and reported here
|
| if (setjmp(decoderMgr->getJmpBuf())) {
|
| - return decoderMgr->returnFalse("ReadHeader");
|
| + return decoderMgr->returnFalse("setjmp");
|
| }
|
|
|
| // Initialize the decompress info and the source manager
|
| @@ -207,7 +207,7 @@
|
|
|
| // Read the jpeg header
|
| if (JPEG_HEADER_OK != jpeg_read_header(decoderMgr->dinfo(), true)) {
|
| - return decoderMgr->returnFalse("ReadHeader");
|
| + return decoderMgr->returnFalse("read_header");
|
| }
|
|
|
| if (codecOut) {
|
| @@ -263,8 +263,7 @@
|
| : INHERITED(width, height, info, stream, std::move(colorSpace), origin)
|
| , fDecoderMgr(decoderMgr)
|
| , fReadyState(decoderMgr->dinfo()->global_state)
|
| - , fSwizzleSrcRow(nullptr)
|
| - , fColorXformSrcRow(nullptr)
|
| + , fSrcRow(nullptr)
|
| , fSwizzlerSubset(SkIRect::MakeEmpty())
|
| , fICCData(std::move(iccData))
|
| {}
|
| @@ -337,16 +336,14 @@
|
| bool SkJpegCodec::onRewind() {
|
| JpegDecoderMgr* decoderMgr = nullptr;
|
| if (!ReadHeader(this->stream(), nullptr, &decoderMgr)) {
|
| - return fDecoderMgr->returnFalse("onRewind");
|
| + return fDecoderMgr->returnFalse("could not rewind");
|
| }
|
| SkASSERT(nullptr != decoderMgr);
|
| fDecoderMgr.reset(decoderMgr);
|
|
|
| fSwizzler.reset(nullptr);
|
| - fSwizzleSrcRow = nullptr;
|
| - fColorXformSrcRow = nullptr;
|
| + fSrcRow = nullptr;
|
| fStorage.reset();
|
| - fColorXform.reset(nullptr);
|
|
|
| return true;
|
| }
|
| @@ -356,23 +353,22 @@
|
| * image has been implemented
|
| * Sets the output color space
|
| */
|
| -bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo, bool needsColorXform) {
|
| - if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
|
| +bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dst) {
|
| + if (kUnknown_SkAlphaType == dst.alphaType()) {
|
| return false;
|
| }
|
|
|
| - if (kOpaque_SkAlphaType != dstInfo.alphaType()) {
|
| + if (kOpaque_SkAlphaType != dst.alphaType()) {
|
| SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
|
| "- it is being decoded as non-opaque, which will draw slower\n");
|
| }
|
|
|
| - // Check if we will decode to CMYK. libjpeg-turbo does not convert CMYK to RGBA, so
|
| - // we must do it ourselves.
|
| - J_COLOR_SPACE encodedColorType = fDecoderMgr->dinfo()->jpeg_color_space;
|
| - bool isCMYK = (JCS_CMYK == encodedColorType || JCS_YCCK == encodedColorType);
|
| + // Check if we will decode to CMYK because a conversion to RGBA is not supported
|
| + J_COLOR_SPACE colorSpace = fDecoderMgr->dinfo()->jpeg_color_space;
|
| + bool isCMYK = JCS_CMYK == colorSpace || JCS_YCCK == colorSpace;
|
|
|
| // Check for valid color types and set the output color space
|
| - switch (dstInfo.colorType()) {
|
| + switch (dst.colorType()) {
|
| case kRGBA_8888_SkColorType:
|
| if (isCMYK) {
|
| fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
|
| @@ -383,19 +379,11 @@
|
| case kBGRA_8888_SkColorType:
|
| if (isCMYK) {
|
| fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
|
| - } else if (needsColorXform) {
|
| - // Our color transformation code requires RGBA order inputs, but it'll swizzle
|
| - // to BGRA for us.
|
| - fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
|
| } else {
|
| fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA;
|
| }
|
| return true;
|
| case kRGB_565_SkColorType:
|
| - if (needsColorXform) {
|
| - return false;
|
| - }
|
| -
|
| if (isCMYK) {
|
| fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
|
| } else {
|
| @@ -408,19 +396,12 @@
|
| }
|
| return true;
|
| case kGray_8_SkColorType:
|
| - if (needsColorXform || JCS_GRAYSCALE != encodedColorType) {
|
| + if (isCMYK) {
|
| return false;
|
| - }
|
| -
|
| - fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
|
| - return true;
|
| - case kRGBA_F16_SkColorType:
|
| - SkASSERT(needsColorXform);
|
| -
|
| - if (isCMYK) {
|
| - fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
|
| } else {
|
| - fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
|
| + // We will enable decodes to gray even if the image is color because this is
|
| + // much faster than decoding to color and then converting
|
| + fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
|
| }
|
| return true;
|
| default:
|
| @@ -434,7 +415,7 @@
|
| */
|
| bool SkJpegCodec::onDimensionsSupported(const SkISize& size) {
|
| if (setjmp(fDecoderMgr->getJmpBuf())) {
|
| - return fDecoderMgr->returnFalse("onDimensionsSupported");
|
| + return fDecoderMgr->returnFalse("onDimensionsSupported/setjmp");
|
| }
|
|
|
| const unsigned int dstWidth = size.width();
|
| @@ -467,83 +448,6 @@
|
| fDecoderMgr->dinfo()->scale_num = num;
|
| fDecoderMgr->dinfo()->scale_denom = denom;
|
| return true;
|
| -}
|
| -
|
| -static bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
|
| - // FIXME (msarett):
|
| - // Do a better check for color space equality.
|
| - return (kRGBA_F16_SkColorType == dstInfo.colorType()) ||
|
| - (dstInfo.colorSpace() && (dstInfo.colorSpace() != srcInfo.colorSpace()));
|
| -}
|
| -
|
| -int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count) {
|
| - // Set the jump location for libjpeg-turbo errors
|
| - if (setjmp(fDecoderMgr->getJmpBuf())) {
|
| - return 0;
|
| - }
|
| -
|
| - // When fSwizzleSrcRow is non-null, it means that we need to swizzle. In this case,
|
| - // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer.
|
| - // We can never swizzle "in place" because the swizzler may perform sampling and/or
|
| - // subsetting.
|
| - // When fColorXformSrcRow is non-null, it means that we need to color xform and that
|
| - // we cannot color xform "in place" (many times we can, but not when the dst is F16).
|
| - // In this case, we will color xform from fColorXformSrc into the dst.
|
| - JSAMPLE* decodeDst = (JSAMPLE*) dst;
|
| - uint32_t* swizzleDst = (uint32_t*) dst;
|
| - size_t decodeDstRowBytes = rowBytes;
|
| - size_t swizzleDstRowBytes = rowBytes;
|
| - if (fSwizzleSrcRow && fColorXformSrcRow) {
|
| - decodeDst = (JSAMPLE*) fSwizzleSrcRow;
|
| - swizzleDst = fColorXformSrcRow;
|
| - decodeDstRowBytes = 0;
|
| - swizzleDstRowBytes = 0;
|
| - } else if (fColorXformSrcRow) {
|
| - decodeDst = (JSAMPLE*) fColorXformSrcRow;
|
| - swizzleDst = fColorXformSrcRow;
|
| - decodeDstRowBytes = 0;
|
| - swizzleDstRowBytes = 0;
|
| - } else if (fSwizzleSrcRow) {
|
| - decodeDst = (JSAMPLE*) fSwizzleSrcRow;
|
| - decodeDstRowBytes = 0;
|
| - }
|
| -
|
| - for (int y = 0; y < count; y++) {
|
| - uint32_t lines = jpeg_read_scanlines(fDecoderMgr->dinfo(), &decodeDst, 1);
|
| - sk_msan_mark_initialized(decodeDst, decodeDst + rowBytes, "skbug.com/4550");
|
| - if (0 == lines) {
|
| - return y;
|
| - }
|
| -
|
| - if (fSwizzler) {
|
| - fSwizzler->swizzle(swizzleDst, decodeDst);
|
| - }
|
| -
|
| - if (fColorXform) {
|
| - int width = dstInfo.width();
|
| - switch (dstInfo.colorType()) {
|
| - case kRGBA_8888_SkColorType:
|
| - fColorXform->applyToRGBA((uint32_t*) dst, swizzleDst, width);
|
| - break;
|
| - case kBGRA_8888_SkColorType:
|
| - fColorXform->applyToBGRA((uint32_t*) dst, swizzleDst, width);
|
| - break;
|
| - case kRGBA_F16_SkColorType:
|
| - fColorXform->applyToF16((uint64_t*) dst, swizzleDst, width);
|
| - break;
|
| - default:
|
| - SkASSERT(false);
|
| - break;
|
| - }
|
| -
|
| - dst = SkTAddOffset<void>(dst, rowBytes);
|
| - }
|
| -
|
| - decodeDst = SkTAddOffset<JSAMPLE>(decodeDst, decodeDstRowBytes);
|
| - swizzleDst = SkTAddOffset<uint32_t>(swizzleDst, swizzleDstRowBytes);
|
| - }
|
| -
|
| - return count;
|
| }
|
|
|
| /*
|
| @@ -567,15 +471,11 @@
|
| }
|
|
|
| // Check if we can decode to the requested destination and set the output color space
|
| - bool needsColorXform = needs_color_xform(dstInfo, this->getInfo());
|
| - if (!this->setOutputColorSpace(dstInfo, needsColorXform)) {
|
| - return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion);
|
| - }
|
| -
|
| - if (!this->initializeColorXform(dstInfo, needsColorXform)) {
|
| - return fDecoderMgr->returnFailure("initializeColorXform", kInvalidParameters);
|
| - }
|
| -
|
| + if (!this->setOutputColorSpace(dstInfo)) {
|
| + return fDecoderMgr->returnFailure("conversion_possible", kInvalidConversion);
|
| + }
|
| +
|
| + // Now, given valid output dimensions, we can start the decompress
|
| if (!jpeg_start_decompress(dinfo)) {
|
| return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
|
| }
|
| @@ -589,37 +489,39 @@
|
| this->initializeSwizzler(dstInfo, options);
|
| }
|
|
|
| - this->allocateStorage(dstInfo);
|
| -
|
| - int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height());
|
| - if (rows < dstInfo.height()) {
|
| - *rowsDecoded = rows;
|
| - return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput);
|
| + // Perform the decode a single row at a time
|
| + uint32_t dstHeight = dstInfo.height();
|
| +
|
| + JSAMPLE* dstRow;
|
| + if (fSwizzler) {
|
| + // write data to storage row, then sample using swizzler
|
| + dstRow = fSrcRow;
|
| + } else {
|
| + // write data directly to dst
|
| + dstRow = (JSAMPLE*) dst;
|
| + }
|
| +
|
| + for (uint32_t y = 0; y < dstHeight; y++) {
|
| + // Read rows of the image
|
| + uint32_t lines = jpeg_read_scanlines(dinfo, &dstRow, 1);
|
| + sk_msan_mark_initialized(dstRow, dstRow + dstRowBytes, "skbug.com/4550");
|
| +
|
| + // If we cannot read enough rows, assume the input is incomplete
|
| + if (lines != 1) {
|
| + *rowsDecoded = y;
|
| + return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput);
|
| + }
|
| +
|
| + if (fSwizzler) {
|
| + // use swizzler to sample row
|
| + fSwizzler->swizzle(dst, dstRow);
|
| + dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes);
|
| + } else {
|
| + dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
|
| + }
|
| }
|
|
|
| return kSuccess;
|
| -}
|
| -
|
| -void SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) {
|
| - size_t swizzleBytes = 0;
|
| - if (fSwizzler) {
|
| - swizzleBytes = get_row_bytes(fDecoderMgr->dinfo());
|
| - SkASSERT(!fColorXform || SkIsAlign4(swizzleBytes));
|
| - }
|
| -
|
| - size_t xformBytes = 0;
|
| - if (kRGBA_F16_SkColorType == dstInfo.colorType()) {
|
| - SkASSERT(fColorXform);
|
| - xformBytes = dstInfo.width() * sizeof(SkColorSpaceXform::RGBA32);
|
| - }
|
| -
|
| - size_t totalBytes = swizzleBytes + xformBytes;
|
| - if (totalBytes > 0) {
|
| - fStorage.reset(totalBytes);
|
| - fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr;
|
| - fColorXformSrcRow = (xformBytes > 0) ?
|
| - SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr;
|
| - }
|
| }
|
|
|
| void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) {
|
| @@ -636,9 +538,9 @@
|
| break;
|
| case JCS_CMYK:
|
| preSwizzled = false;
|
| - swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kInvertedCMYK_Color,
|
| - swizzlerInfo.alpha(),
|
| - swizzlerInfo.bitsPerComponent());
|
| + swizzlerInfo = SkEncodedInfo::Make(
|
| + SkEncodedInfo::kInvertedCMYK_Color, swizzlerInfo.alpha(),
|
| + swizzlerInfo.bitsPerComponent());
|
| break;
|
| default:
|
| break;
|
| @@ -656,28 +558,17 @@
|
| fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr, dstInfo, swizzlerOptions,
|
| nullptr, preSwizzled));
|
| SkASSERT(fSwizzler);
|
| -}
|
| -
|
| -bool SkJpegCodec::initializeColorXform(const SkImageInfo& dstInfo, bool needsColorXform) {
|
| - if (needsColorXform) {
|
| - fColorXform = SkColorSpaceXform::New(sk_ref_sp(this->getInfo().colorSpace()),
|
| - sk_ref_sp(dstInfo.colorSpace()));
|
| - if (!fColorXform && kRGBA_F16_SkColorType == dstInfo.colorType()) {
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - return true;
|
| + fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
|
| + fSrcRow = fStorage.get();
|
| }
|
|
|
| SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) {
|
| if (!createIfNecessary || fSwizzler) {
|
| - SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcRow));
|
| + SkASSERT(!fSwizzler || (fSrcRow && fStorage.get() == fSrcRow));
|
| return fSwizzler;
|
| }
|
|
|
| this->initializeSwizzler(this->dstInfo(), this->options());
|
| - this->allocateStorage(this->dstInfo());
|
| return fSwizzler;
|
| }
|
|
|
| @@ -690,15 +581,11 @@
|
| }
|
|
|
| // Check if we can decode to the requested destination and set the output color space
|
| - bool needsColorXform = needs_color_xform(dstInfo, this->getInfo());
|
| - if (!this->setOutputColorSpace(dstInfo, needsColorXform)) {
|
| + if (!this->setOutputColorSpace(dstInfo)) {
|
| return kInvalidConversion;
|
| }
|
|
|
| - if (!this->initializeColorXform(dstInfo, needsColorXform)) {
|
| - return fDecoderMgr->returnFailure("initializeColorXform", kInvalidParameters);
|
| - }
|
| -
|
| + // Now, given valid output dimensions, we can start the decompress
|
| if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
|
| SkCodecPrintf("start decompress failed\n");
|
| return kInvalidInput;
|
| @@ -759,37 +646,62 @@
|
| }
|
| #endif
|
|
|
| - this->allocateStorage(dstInfo);
|
| -
|
| return kSuccess;
|
| }
|
|
|
| int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
|
| - int rows = this->readRows(this->dstInfo(), dst, dstRowBytes, count);
|
| - if (rows < count) {
|
| - // This allows us to skip calling jpeg_finish_decompress().
|
| - fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
|
| - }
|
| -
|
| - return rows;
|
| + // Set the jump location for libjpeg errors
|
| + if (setjmp(fDecoderMgr->getJmpBuf())) {
|
| + return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
|
| + }
|
| + // Read rows one at a time
|
| + JSAMPLE* dstRow;
|
| + size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo());
|
| + if (fSwizzler) {
|
| + // write data to storage row, then sample using swizzler
|
| + dstRow = fSrcRow;
|
| + } else {
|
| + // write data directly to dst
|
| + SkASSERT(count == 1 || dstRowBytes >= srcRowBytes);
|
| + dstRow = (JSAMPLE*) dst;
|
| + }
|
| +
|
| + for (int y = 0; y < count; y++) {
|
| + // Read row of the image
|
| + uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow, 1);
|
| + sk_msan_mark_initialized(dstRow, dstRow + srcRowBytes, "skbug.com/4550");
|
| + if (rowsDecoded != 1) {
|
| + fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
|
| + return y;
|
| + }
|
| +
|
| + if (fSwizzler) {
|
| + // use swizzler to sample row
|
| + fSwizzler->swizzle(dst, dstRow);
|
| + dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes);
|
| + } else {
|
| + dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
|
| + }
|
| + }
|
| + return count;
|
| }
|
|
|
| bool SkJpegCodec::onSkipScanlines(int count) {
|
| // Set the jump location for libjpeg errors
|
| if (setjmp(fDecoderMgr->getJmpBuf())) {
|
| - return fDecoderMgr->returnFalse("onSkipScanlines");
|
| + return fDecoderMgr->returnFalse("setjmp");
|
| }
|
|
|
| #ifdef TURBO_HAS_SKIP
|
| return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count);
|
| #else
|
| - if (!fSwizzleSrcRow) {
|
| + if (!fSrcRow) {
|
| fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
|
| - fSwizzleSrcRow = fStorage.get();
|
| + fSrcRow = fStorage.get();
|
| }
|
|
|
| for (int y = 0; y < count; y++) {
|
| - if (1 != jpeg_read_scanlines(fDecoderMgr->dinfo(), &fSwizzleSrcRow, 1)) {
|
| + if (1 != jpeg_read_scanlines(fDecoderMgr->dinfo(), &fSrcRow, 1)) {
|
| return false;
|
| }
|
| }
|
|
|