Index: dm/DMSrcSink.cpp |
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp |
index 394b84fa7bd568a6a44a0235cff6bfb08a1201f7..24ae2d6087ebd4da20775ca7710072190a42d8e3 100644 |
--- a/dm/DMSrcSink.cpp |
+++ b/dm/DMSrcSink.cpp |
@@ -7,6 +7,7 @@ |
#include "DMSrcSink.h" |
#include "SamplePipeControllers.h" |
+#include "SkAndroidCodec.h" |
#include "SkCodec.h" |
#include "SkCodecTools.h" |
#include "SkCommonFlags.h" |
@@ -25,11 +26,9 @@ |
#include "SkRecorder.h" |
#include "SkRemote.h" |
#include "SkSVGCanvas.h" |
-#include "SkScaledCodec.h" |
#include "SkStream.h" |
#include "SkTLogic.h" |
#include "SkXMLWriter.h" |
-#include "SkScaledCodec.h" |
#include "SkSwizzler.h" |
DEFINE_bool(multiPage, false, "For document-type backends, render the source" |
@@ -244,46 +243,47 @@ bool CodecSrc::veto(SinkFlags flags) const { |
|| flags.approach != SinkFlags::kDirect; |
} |
+bool get_decode_info(SkImageInfo* decodeInfo, const SkImageInfo& defaultInfo, |
+ SkColorType canvasColorType, CodecSrc::DstColorType dstColorType) { |
+ switch (dstColorType) { |
+ case CodecSrc::kIndex8_Always_DstColorType: |
+ if (kRGB_565_SkColorType == canvasColorType) { |
+ return false; |
+ } |
+ *decodeInfo = defaultInfo.makeColorType(kIndex_8_SkColorType); |
+ break; |
+ case CodecSrc::kGrayscale_Always_DstColorType: |
+ if (kRGB_565_SkColorType == canvasColorType) { |
+ return false; |
+ } |
+ *decodeInfo = defaultInfo.makeColorType(kGray_8_SkColorType); |
+ break; |
+ default: |
+ *decodeInfo = defaultInfo.makeColorType(canvasColorType); |
+ break; |
+ } |
+ |
+ // FIXME: Currently we cannot draw unpremultiplied sources. |
+ if (decodeInfo->alphaType() == kUnpremul_SkAlphaType) { |
+ decodeInfo->makeAlphaType(kPremul_SkAlphaType); |
+ } |
+ return true; |
+} |
+ |
Error CodecSrc::draw(SkCanvas* canvas) const { |
SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); |
if (!encoded) { |
return SkStringPrintf("Couldn't read %s.", fPath.c_str()); |
} |
- SkAutoTDelete<SkCodec> codec(NULL); |
- if (kScaledCodec_Mode == fMode) { |
- codec.reset(SkScaledCodec::NewFromData(encoded)); |
- // TODO (msarett): This should fall through to a fatal error once we support scaled |
- // codecs for all image types. |
- if (nullptr == codec.get()) { |
- return Error::Nonfatal(SkStringPrintf("Couldn't create scaled codec for %s.", |
- fPath.c_str())); |
- } |
- } else { |
- codec.reset(SkCodec::NewFromData(encoded)); |
- } |
+ SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); |
if (nullptr == codec.get()) { |
return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); |
} |
- // Choose the color type to decode to |
- SkImageInfo decodeInfo = codec->getInfo(); |
- SkColorType canvasColorType = canvas->imageInfo().colorType(); |
- switch (fDstColorType) { |
- case kIndex8_Always_DstColorType: |
- decodeInfo = codec->getInfo().makeColorType(kIndex_8_SkColorType); |
- if (kRGB_565_SkColorType == canvasColorType) { |
- return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); |
- } |
- break; |
- case kGrayscale_Always_DstColorType: |
- decodeInfo = codec->getInfo().makeColorType(kGray_8_SkColorType); |
- if (kRGB_565_SkColorType == canvasColorType) { |
- return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); |
- } |
- break; |
- default: |
- decodeInfo = decodeInfo.makeColorType(canvasColorType); |
- break; |
+ SkImageInfo decodeInfo; |
+ if (!get_decode_info(&decodeInfo, codec->getInfo(), canvas->imageInfo().colorType(), |
+ fDstColorType)) { |
+ return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); |
} |
// Try to scale the image if it is desired |
@@ -311,11 +311,6 @@ Error CodecSrc::draw(SkCanvas* canvas) const { |
colorCountPtr = &maxColors; |
} |
- // FIXME: Currently we cannot draw unpremultiplied sources. |
- if (decodeInfo.alphaType() == kUnpremul_SkAlphaType) { |
- decodeInfo = decodeInfo.makeAlphaType(kPremul_SkAlphaType); |
- } |
- |
SkBitmap bitmap; |
if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) { |
return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str(), |
@@ -323,7 +318,6 @@ Error CodecSrc::draw(SkCanvas* canvas) const { |
} |
switch (fMode) { |
- case kScaledCodec_Mode: |
case kCodec_Mode: { |
switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), nullptr, |
colorPtr, colorCountPtr)) { |
@@ -585,14 +579,7 @@ Error CodecSrc::draw(SkCanvas* canvas) const { |
SkISize CodecSrc::size() const { |
SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); |
- SkAutoTDelete<SkCodec> codec(nullptr); |
- |
- if (kScaledCodec_Mode == fMode) { |
- codec.reset(SkScaledCodec::NewFromData(encoded)); |
- } else { |
- codec.reset(SkCodec::NewFromData(encoded)); |
- } |
- |
+ SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); |
if (nullptr == codec) { |
return SkISize::Make(0, 0); |
} |
@@ -608,6 +595,163 @@ Name CodecSrc::name() const { |
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ |
+AndroidCodecSrc::AndroidCodecSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType, |
+ int sampleSize) |
+ : fPath(path) |
+ , fMode(mode) |
+ , fDstColorType(dstColorType) |
+ , fSampleSize(sampleSize) |
+{} |
+ |
+bool AndroidCodecSrc::veto(SinkFlags flags) const { |
+ // No need to test decoding to non-raster or indirect backend. |
+ // TODO: Once we implement GPU paths (e.g. JPEG YUV), we should use a deferred decode to |
+ // let the GPU handle it. |
+ return flags.type != SinkFlags::kRaster |
+ || flags.approach != SinkFlags::kDirect; |
+} |
+ |
+Error AndroidCodecSrc::draw(SkCanvas* canvas) const { |
+ SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); |
+ if (!encoded) { |
+ return SkStringPrintf("Couldn't read %s.", fPath.c_str()); |
+ } |
+ SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded)); |
+ if (nullptr == codec.get()) { |
+ return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str()); |
+ } |
+ |
+ SkImageInfo decodeInfo; |
+ if (!get_decode_info(&decodeInfo, codec->getInfo(), canvas->imageInfo().colorType(), |
+ fDstColorType)) { |
+ return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); |
+ } |
+ |
+ // Scale the image if it is desired. |
+ SkISize size = codec->getSampledDimensions(fSampleSize); |
+ |
+ // Visually inspecting very small output images is not necessary. We will |
+ // cover these cases in unit testing. |
+ if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) { |
+ return Error::Nonfatal("Scaling very small images is uninteresting."); |
+ } |
+ decodeInfo = decodeInfo.makeWH(size.width(), size.height()); |
+ |
+ // Construct a color table for the decode if necessary |
+ SkAutoTUnref<SkColorTable> colorTable(nullptr); |
+ SkPMColor* colorPtr = nullptr; |
+ int* colorCountPtr = nullptr; |
+ int maxColors = 256; |
+ if (kIndex_8_SkColorType == decodeInfo.colorType()) { |
+ SkPMColor colors[256]; |
+ colorTable.reset(new SkColorTable(colors, maxColors)); |
+ colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); |
+ colorCountPtr = &maxColors; |
+ } |
+ |
+ SkBitmap bitmap; |
+ if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) { |
+ return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str(), |
+ decodeInfo.width(), decodeInfo.height()); |
+ } |
+ |
+ // Create options for the codec. |
+ SkAndroidCodec::AndroidOptions options; |
+ options.fColorPtr = colorPtr; |
+ options.fColorCount = colorCountPtr; |
+ options.fSampleSize = fSampleSize; |
+ |
+ switch (fMode) { |
+ case kFullImage_Mode: { |
+ switch (codec->getAndroidPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), |
+ &options)) { |
+ case SkCodec::kSuccess: |
+ case SkCodec::kIncompleteInput: |
+ break; |
+ case SkCodec::kInvalidConversion: |
+ return Error::Nonfatal("Cannot convert to requested color type.\n"); |
+ default: |
+ return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); |
+ } |
+ canvas->drawBitmap(bitmap, 0, 0); |
+ return ""; |
+ } |
+ case kDivisor_Mode: { |
+ const int width = codec->getInfo().width(); |
+ const int height = codec->getInfo().height(); |
+ const int divisor = 2; |
+ if (width < divisor || height < divisor) { |
+ return Error::Nonfatal("Divisor is larger than image dimension.\n"); |
+ } |
+ |
+ // Rounding the size of the subsets may leave some pixels uninitialized on the bottom |
+ // and right edges of the bitmap. |
+ bitmap.eraseColor(0); |
+ for (int x = 0; x < divisor; x++) { |
+ for (int y = 0; y < divisor; y++) { |
+ // Calculate the subset dimensions |
+ int subsetWidth = width / divisor; |
+ int subsetHeight = height / divisor; |
+ const int left = x * subsetWidth; |
+ const int top = y * subsetHeight; |
+ |
+ // Increase the size of the last subset in each row or column, when the |
+ // divisor does not divide evenly into the image dimensions |
+ subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0; |
+ subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0; |
+ SkIRect subset = SkIRect::MakeXYWH(left, top, subsetWidth, subsetHeight); |
+ if (!codec->getSupportedSubset(&subset)) { |
+ return "Could not get supported subset to decode.\n"; |
+ } |
+ options.fSubset = ⊂ |
+ void* pixels = bitmap.getAddr(subset.left() / fSampleSize, |
+ subset.top() / fSampleSize); |
+ SkISize scaledSubsetSize = codec->getSampledSubsetDimensions(fSampleSize, |
+ subset); |
+ SkImageInfo subsetDecodeInfo = decodeInfo.makeWH(scaledSubsetSize.width(), |
+ scaledSubsetSize.height()); |
+ |
+ switch (codec->getAndroidPixels(subsetDecodeInfo, pixels, bitmap.rowBytes(), |
+ &options)) { |
+ case SkCodec::kSuccess: |
+ case SkCodec::kIncompleteInput: |
+ break; |
+ case SkCodec::kInvalidConversion: |
+ return Error::Nonfatal("Cannot convert to requested color type.\n"); |
+ default: |
+ return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); |
+ } |
+ } |
+ } |
+ canvas->drawBitmap(bitmap, 0, 0); |
+ return ""; |
+ } |
+ default: |
+ SkASSERT(false); |
+ return "Error: Should not be reached.\n"; |
+ } |
+} |
+ |
+SkISize AndroidCodecSrc::size() const { |
+ SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); |
+ SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded)); |
+ if (nullptr == codec) { |
+ return SkISize::Make(0, 0); |
+ } |
+ return codec->getSampledDimensions(fSampleSize); |
+} |
+ |
+Name AndroidCodecSrc::name() const { |
+ // We will replicate the names used by CodecSrc so that images can |
+ // be compared in Gold. |
+ if (1 == fSampleSize) { |
+ return SkOSPath::Basename(fPath.c_str()); |
+ } |
+ return get_scaled_name(fPath, get_scale_from_sample_size(fSampleSize)); |
+} |
+ |
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ |
+ |
ImageSrc::ImageSrc(Path path, int divisor) : fPath(path), fDivisor(divisor) {} |
bool ImageSrc::veto(SinkFlags flags) const { |