aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar msarett <msarett@google.com>2015-10-27 12:50:25 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-10-27 12:50:25 -0700
commit35e5d1b4495478ca3bede66914ae07f50a447c4d (patch)
tree1db71991433b478c83d50b36211c4683649c5336
parentf7c0822911e736940a8690fb0553821561bf8ac7 (diff)
Refactor SkBitmapRegionDecoderInterface for Android
The result SkBitmap, the pixel allocator, and the alpha preference need to be communicated from the client to the region decoder. BUG=skia: Review URL: https://codereview.chromium.org/1418093006
-rw-r--r--bench/BitmapRegionDecoderBench.cpp6
-rw-r--r--bench/nanobench.cpp9
-rw-r--r--dm/DMSrcSink.cpp29
-rw-r--r--tools/SkBitmapRegionCanvas.cpp54
-rw-r--r--tools/SkBitmapRegionCanvas.h12
-rw-r--r--tools/SkBitmapRegionCodec.cpp36
-rw-r--r--tools/SkBitmapRegionCodec.h12
-rw-r--r--tools/SkBitmapRegionDecoderInterface.h36
-rw-r--r--tools/SkBitmapRegionSampler.cpp34
-rw-r--r--tools/SkBitmapRegionSampler.h12
10 files changed, 105 insertions, 135 deletions
diff --git a/bench/BitmapRegionDecoderBench.cpp b/bench/BitmapRegionDecoderBench.cpp
index 092693619b..70e3e760e0 100644
--- a/bench/BitmapRegionDecoderBench.cpp
+++ b/bench/BitmapRegionDecoderBench.cpp
@@ -61,10 +61,8 @@ void BitmapRegionDecoderBench::onDelayedSetup() {
}
void BitmapRegionDecoderBench::onDraw(int n, SkCanvas* canvas) {
- SkAutoTDelete<SkBitmap> bitmap;
for (int i = 0; i < n; i++) {
- bitmap.reset(fBRD->decodeRegion(fSubset.left(), fSubset.top(), fSubset.width(),
- fSubset.height(), fSampleSize, fColorType));
- SkASSERT(nullptr != bitmap.get());
+ SkBitmap bm;
+ SkAssertResult(fBRD->decodeRegion(&bm, nullptr, fSubset, fSampleSize, fColorType, false));
}
}
diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp
index 054fbb27b1..de4545f2fa 100644
--- a/bench/nanobench.cpp
+++ b/bench/nanobench.cpp
@@ -603,9 +603,12 @@ static bool valid_brd_bench(SkData* encoded, SkBitmapRegionDecoderInterface::Str
return false;
}
- SkAutoTDelete<SkBitmap> bitmap(brd->decodeRegion(0, 0, brd->width(), brd->height(), 1,
- colorType));
- if (nullptr == bitmap.get() || colorType != bitmap->colorType()) {
+ SkBitmap bitmap;
+ if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, brd->width(), brd->height()),
+ 1, colorType, false)) {
+ return false;
+ }
+ if (colorType != bitmap.colorType()) {
// This indicates that conversion to the requested color type is not supported for the
// particular image.
return false;
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index e0ec5e139c..b14c573679 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -125,12 +125,18 @@ Error BRDSrc::draw(SkCanvas* canvas) const {
}
switch (fMode) {
case kFullImage_Mode: {
- SkAutoTDelete<SkBitmap> bitmap(brd->decodeRegion(0, 0, width, height, fSampleSize,
- colorType));
- if (nullptr == bitmap.get() || colorType != bitmap->colorType()) {
+ SkBitmap bitmap;
+ if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, width, height),
+ fSampleSize, colorType, false)) {
+ // FIXME: Make this a fatal error. We need to disable webps for kCanvas_Strategy
+ // because we have not implemented kCanvas_Strategy for webp. We may also need to
+ // deal with color conversion errors for kOriginal_Strategy.
+ return Error::Nonfatal("Cannot decode region.\n");
+ }
+ if (colorType != bitmap.colorType()) {
return Error::Nonfatal("Cannot convert to color type.\n");
}
- canvas->drawBitmap(*bitmap, 0, 0);
+ canvas->drawBitmap(bitmap, 0, 0);
return "";
}
case kDivisor_Mode: {
@@ -178,13 +184,20 @@ Error BRDSrc::draw(SkCanvas* canvas) const {
const int decodeTop = top - unscaledBorder;
const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2;
const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2;
- SkAutoTDelete<SkBitmap> bitmap(brd->decodeRegion(decodeLeft,
- decodeTop, decodeWidth, decodeHeight, fSampleSize, colorType));
- if (nullptr == bitmap.get() || colorType != bitmap->colorType()) {
+ SkBitmap bitmap;
+ if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(decodeLeft,
+ decodeTop, decodeWidth, decodeHeight), fSampleSize, colorType, false)) {
+ // FIXME: Make this a fatal error. We need to disable webps for
+ // kCanvas_Strategy because we have not implemented kCanvas_Strategy for
+ // webp. We may also need to deal with color conversion errors for
+ // kOriginal_Strategy.
+ return Error::Nonfatal("Cannot not decode region.\n");
+ }
+ if (colorType != bitmap.colorType()) {
return Error::Nonfatal("Cannot convert to color type.\n");
}
- canvas->drawBitmapRect(*bitmap,
+ canvas->drawBitmapRect(bitmap,
SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder,
(SkScalar) (subsetWidth / fSampleSize),
(SkScalar) (subsetHeight / fSampleSize)),
diff --git a/tools/SkBitmapRegionCanvas.cpp b/tools/SkBitmapRegionCanvas.cpp
index f9c9573c44..9129245b11 100644
--- a/tools/SkBitmapRegionCanvas.cpp
+++ b/tools/SkBitmapRegionCanvas.cpp
@@ -15,23 +15,27 @@ SkBitmapRegionCanvas::SkBitmapRegionCanvas(SkCodec* decoder)
, fDecoder(decoder)
{}
-/*
- * Three differences from the Android version:
- * Returns a Skia bitmap instead of an Android bitmap.
- * Android version attempts to reuse a recycled bitmap.
- * Removed the options object and used parameters for color type and
- * sample size.
- */
-SkBitmap* SkBitmapRegionCanvas::decodeRegion(int inputX, int inputY,
- int inputWidth, int inputHeight,
- int sampleSize,
- SkColorType dstColorType) {
+bool SkBitmapRegionCanvas::decodeRegion(SkBitmap* bitmap, SkBitmap::Allocator* allocator,
+ const SkIRect& desiredSubset, int sampleSize, SkColorType dstColorType,
+ bool requireUnpremul) {
// Reject color types not supported by this method
if (kIndex_8_SkColorType == dstColorType || kGray_8_SkColorType == dstColorType) {
SkCodecPrintf("Error: Color type not supported.\n");
- return nullptr;
+ return false;
+ }
+
+ // Reject requests for unpremultiplied alpha
+ if (requireUnpremul) {
+ SkCodecPrintf("Error: Alpha type not supported.\n");
+ return false;
+ }
+ SkAlphaType dstAlphaType = fDecoder->getInfo().alphaType();
+ if (kUnpremul_SkAlphaType == dstAlphaType) {
+ dstAlphaType = kPremul_SkAlphaType;
}
+ // FIXME: Can we add checks and support kIndex8 or unpremultiplied alpha in special cases?
+
// Fix the input sampleSize if necessary.
if (sampleSize < 1) {
sampleSize = 1;
@@ -48,17 +52,13 @@ SkBitmap* SkBitmapRegionCanvas::decodeRegion(int inputX, int inputY,
// If outY is non-zero, subsetY must be zero.
int outX;
int outY;
- SkIRect subset = SkIRect::MakeXYWH(inputX, inputY, inputWidth, inputHeight);
+ SkIRect subset = desiredSubset;
SubsetType type = adjust_subset_rect(fDecoder->getInfo().dimensions(), &subset, &outX, &outY);
if (SubsetType::kOutside_SubsetType == type) {
- return nullptr;
+ return false;
}
// Create the image info for the decode
- SkAlphaType dstAlphaType = fDecoder->getInfo().alphaType();
- if (kUnpremul_SkAlphaType == dstAlphaType) {
- dstAlphaType = kPremul_SkAlphaType;
- }
SkImageInfo decodeInfo = SkImageInfo::Make(this->width(), this->height(),
dstColorType, dstAlphaType);
@@ -66,7 +66,7 @@ SkBitmap* SkBitmapRegionCanvas::decodeRegion(int inputX, int inputY,
SkCodec::Result r = fDecoder->startScanlineDecode(decodeInfo);
if (SkCodec::kSuccess != r) {
SkCodecPrintf("Error: Could not start scanline decoder.\n");
- return nullptr;
+ return false;
}
// Allocate a bitmap for the unscaled decode
@@ -74,28 +74,28 @@ SkBitmap* SkBitmapRegionCanvas::decodeRegion(int inputX, int inputY,
SkImageInfo tmpInfo = decodeInfo.makeWH(this->width(), subset.height());
if (!tmp.tryAllocPixels(tmpInfo)) {
SkCodecPrintf("Error: Could not allocate pixels.\n");
- return nullptr;
+ return false;
}
// Skip the unneeded rows
if (!fDecoder->skipScanlines(subset.y())) {
SkCodecPrintf("Error: Failed to skip scanlines.\n");
- return nullptr;
+ return false;
}
// Decode the necessary rows
fDecoder->getScanlines(tmp.getAddr(0, 0), subset.height(), tmp.rowBytes());
// Calculate the size of the output
- const int outWidth = get_scaled_dimension(inputWidth, sampleSize);
- const int outHeight = get_scaled_dimension(inputHeight, sampleSize);
+ const int outWidth = get_scaled_dimension(desiredSubset.width(), sampleSize);
+ const int outHeight = get_scaled_dimension(desiredSubset.height(), sampleSize);
// Initialize the destination bitmap
- SkAutoTDelete<SkBitmap> bitmap(new SkBitmap());
SkImageInfo dstInfo = decodeInfo.makeWH(outWidth, outHeight);
- if (!bitmap->tryAllocPixels(dstInfo)) {
+ bitmap->setInfo(dstInfo, dstInfo.minRowBytes());
+ if (!bitmap->tryAllocPixels(allocator, nullptr)) {
SkCodecPrintf("Error: Could not allocate pixels.\n");
- return nullptr;
+ return false;
}
// Zero the bitmap if the region is not completely within the image.
@@ -123,7 +123,7 @@ SkBitmap* SkBitmapRegionCanvas::decodeRegion(int inputX, int inputY,
// TODO (msarett): Test multiple filter qualities. kNone is the default.
canvas.drawBitmapRect(tmp, src, dst, &paint);
- return bitmap.detach();
+ return true;
}
bool SkBitmapRegionCanvas::conversionSupported(SkColorType colorType) {
diff --git a/tools/SkBitmapRegionCanvas.h b/tools/SkBitmapRegionCanvas.h
index f82e9fa77a..217082ac33 100644
--- a/tools/SkBitmapRegionCanvas.h
+++ b/tools/SkBitmapRegionCanvas.h
@@ -24,15 +24,9 @@ public:
*/
SkBitmapRegionCanvas(SkCodec* decoder);
- /*
- * Three differences from the Android version:
- * Returns a Skia bitmap instead of an Android bitmap.
- * Android version attempts to reuse a recycled bitmap.
- * Removed the options object and used parameters for color type and
- * sample size.
- */
- SkBitmap* decodeRegion(int start_x, int start_y, int width, int height,
- int sampleSize, SkColorType prefColorType) override;
+ bool decodeRegion(SkBitmap* bitmap, SkBitmap::Allocator* allocator,
+ const SkIRect& desiredSubset, int sampleSize,
+ SkColorType colorType, bool requireUnpremul) override;
bool conversionSupported(SkColorType colorType) override;
diff --git a/tools/SkBitmapRegionCodec.cpp b/tools/SkBitmapRegionCodec.cpp
index 3f2cd24b78..cac99452e0 100644
--- a/tools/SkBitmapRegionCodec.cpp
+++ b/tools/SkBitmapRegionCodec.cpp
@@ -15,15 +15,9 @@ SkBitmapRegionCodec::SkBitmapRegionCodec(SkAndroidCodec* codec)
, fCodec(codec)
{}
-/*
- * Three differences from the Android version:
- * Returns a skia bitmap instead of an Android bitmap.
- * Android version attempts to reuse a recycled bitmap.
- * Removed the options object and used parameters for color type and sample size.
- */
-// FIXME: Should this function should take in SkIRect?
-SkBitmap* SkBitmapRegionCodec::decodeRegion(int inputX, int inputY, int inputWidth, int inputHeight,
- int sampleSize, SkColorType dstColorType) {
+bool SkBitmapRegionCodec::decodeRegion(SkBitmap* bitmap, SkBitmap::Allocator* allocator,
+ const SkIRect& desiredSubset, int sampleSize, SkColorType dstColorType,
+ bool requireUnpremul) {
// Fix the input sampleSize if necessary.
if (sampleSize < 1) {
@@ -41,23 +35,23 @@ SkBitmap* SkBitmapRegionCodec::decodeRegion(int inputX, int inputY, int inputWid
// If outY is non-zero, subsetY must be zero.
int outX;
int outY;
- SkIRect subset = SkIRect::MakeXYWH(inputX, inputY, inputWidth, inputHeight);
+ SkIRect subset = desiredSubset;
SubsetType type = adjust_subset_rect(fCodec->getInfo().dimensions(), &subset, &outX, &outY);
if (SubsetType::kOutside_SubsetType == type) {
- return nullptr;
+ return false;
}
// Ask the codec for a scaled subset
if (!fCodec->getSupportedSubset(&subset)) {
SkCodecPrintf("Error: Could not get subset.\n");
- return nullptr;
+ return false;
}
SkISize scaledSize = fCodec->getSampledSubsetDimensions(sampleSize, subset);
// Create the image info for the decode
SkAlphaType dstAlphaType = fCodec->getInfo().alphaType();
- if (kUnpremul_SkAlphaType == dstAlphaType) {
- dstAlphaType = kPremul_SkAlphaType;
+ if (kOpaque_SkAlphaType != dstAlphaType) {
+ dstAlphaType = requireUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
}
SkImageInfo decodeInfo = SkImageInfo::Make(scaledSize.width(), scaledSize.height(),
dstColorType, dstAlphaType);
@@ -83,7 +77,6 @@ SkBitmap* SkBitmapRegionCodec::decodeRegion(int inputX, int inputY, int inputWid
}
// Initialize the destination bitmap
- SkAutoTDelete<SkBitmap> bitmap(new SkBitmap());
int scaledOutX = 0;
int scaledOutY = 0;
int scaledOutWidth = scaledSize.width();
@@ -92,17 +85,18 @@ SkBitmap* SkBitmapRegionCodec::decodeRegion(int inputX, int inputY, int inputWid
scaledOutX = outX / sampleSize;
scaledOutY = outY / sampleSize;
// We need to be safe here because getSupportedSubset() may have modified the subset.
- const int extraX = SkTMax(0, inputWidth - outX - subset.width());
- const int extraY = SkTMax(0, inputHeight - outY - subset.height());
+ const int extraX = SkTMax(0, desiredSubset.width() - outX - subset.width());
+ const int extraY = SkTMax(0, desiredSubset.height() - outY - subset.height());
const int scaledExtraX = extraX / sampleSize;
const int scaledExtraY = extraY / sampleSize;
scaledOutWidth += scaledOutX + scaledExtraX;
scaledOutHeight += scaledOutY + scaledExtraY;
}
SkImageInfo outInfo = decodeInfo.makeWH(scaledOutWidth, scaledOutHeight);
- if (!bitmap->tryAllocPixels(outInfo, nullptr, colorTable.get())) {
+ bitmap->setInfo(outInfo, outInfo.minRowBytes());
+ if (!bitmap->tryAllocPixels(allocator, colorTable.get())) {
SkCodecPrintf("Error: Could not allocate pixels.\n");
- return nullptr;
+ return false;
}
// Zero the bitmap if the region is not completely within the image.
@@ -129,10 +123,10 @@ SkBitmap* SkBitmapRegionCodec::decodeRegion(int inputX, int inputY, int inputWid
SkCodec::Result result = fCodec->getAndroidPixels(decodeInfo, dst, rowBytes, &options);
if (SkCodec::kSuccess != result && SkCodec::kIncompleteInput != result) {
SkCodecPrintf("Error: Could not get pixels.\n");
- return nullptr;
+ return false;
}
- return bitmap.detach();
+ return true;
}
bool SkBitmapRegionCodec::conversionSupported(SkColorType colorType) {
diff --git a/tools/SkBitmapRegionCodec.h b/tools/SkBitmapRegionCodec.h
index 14d024ea45..4dd69ab0fa 100644
--- a/tools/SkBitmapRegionCodec.h
+++ b/tools/SkBitmapRegionCodec.h
@@ -20,15 +20,9 @@ public:
*/
SkBitmapRegionCodec(SkAndroidCodec* codec);
- /*
- * Three differences from the Android version:
- * Returns a Skia bitmap instead of an Android bitmap.
- * Android version attempts to reuse a recycled bitmap.
- * Removed the options object and used parameters for color type and
- * sample size.
- */
- SkBitmap* decodeRegion(int start_x, int start_y, int width, int height,
- int sampleSize, SkColorType prefColorType) override;
+ bool decodeRegion(SkBitmap* bitmap, SkBitmap::Allocator* allocator,
+ const SkIRect& desiredSubset, int sampleSize,
+ SkColorType colorType, bool requireUnpremul) override;
bool conversionSupported(SkColorType colorType) override;
diff --git a/tools/SkBitmapRegionDecoderInterface.h b/tools/SkBitmapRegionDecoderInterface.h
index e1f79bccb6..a6a3111457 100644
--- a/tools/SkBitmapRegionDecoderInterface.h
+++ b/tools/SkBitmapRegionDecoderInterface.h
@@ -35,26 +35,24 @@ public:
/*
* Decode a scaled region of the encoded image stream
*
- * @param start_x X-coordinate of upper-left corner of region.
- * This coordinate is unscaled, relative to the original dimensions.
- * @param start_y Y-coordinate of upper-left corner of region.
- * This coordinate is unscaled, relative to the original dimensions.
- * @param width Width of the region to decode.
- * This distance is unscaled, relative to the original dimensions.
- * @param height Height of the region to decode.
- * This distance is unscaled, relative to the original dimensions.
- * @param sampleSize An integer downscaling factor for the decode.
- * @param colorType Preferred output colorType.
- * New implementations should return NULL if they do not support
- * decoding to this color type.
- * The old kOriginal_Strategy will decode to a default color type
- * if this color type is unsupported.
- * @return Pointer to a bitmap of the decoded region on success, NULL on
- * failure.
+ * @param bitmap Container for decoded pixels. It is assumed that the pixels
+ * are initially unallocated and will be allocated by this function.
+ * @param allocator Allocator for the pixels. If this is NULL, the default
+ * allocator (HeapAllocator) will be used.
+ * @param desiredSubset Subset of the original image to decode.
+ * @param sampleSize An integer downscaling factor for the decode.
+ * @param colorType Preferred output colorType.
+ * New implementations should return NULL if they do not support
+ * decoding to this color type.
+ * The old kOriginal_Strategy will decode to a default color type
+ * if this color type is unsupported.
+ * @param requireUnpremul If the image is not opaque, we will use this to determine the
+ * alpha type to use.
+ *
*/
- virtual SkBitmap* decodeRegion(int start_x, int start_y, int width,
- int height, int sampleSize,
- SkColorType colorType) = 0;
+ virtual bool decodeRegion(SkBitmap* bitmap, SkBitmap::Allocator* allocator,
+ const SkIRect& desiredSubset, int sampleSize,
+ SkColorType colorType, bool requireUnpremul) = 0;
/*
* @param Requested destination color type
* @return true if we support the requested color type and false otherwise
diff --git a/tools/SkBitmapRegionSampler.cpp b/tools/SkBitmapRegionSampler.cpp
index 514af10859..0714c26fbf 100644
--- a/tools/SkBitmapRegionSampler.cpp
+++ b/tools/SkBitmapRegionSampler.cpp
@@ -14,38 +14,20 @@ SkBitmapRegionSampler::SkBitmapRegionSampler(SkImageDecoder* decoder, int width,
, fDecoder(decoder)
{}
-/*
- * Three differences from the Android version:
- * Returns a Skia bitmap instead of an Android bitmap.
- * Android version attempts to reuse a recycled bitmap.
- * Removed the options object and used parameters for color type and
- * sample size.
- */
-SkBitmap* SkBitmapRegionSampler::decodeRegion(int start_x, int start_y,
- int width, int height,
- int sampleSize,
- SkColorType prefColorType) {
- // Match Android's default settings
+bool SkBitmapRegionSampler::decodeRegion(SkBitmap* bitmap, SkBitmap::Allocator* allocator,
+ const SkIRect& desiredSubset, int sampleSize, SkColorType colorType, bool requireUnpremul) {
fDecoder->setDitherImage(true);
fDecoder->setPreferQualityOverSpeed(false);
fDecoder->setRequireUnpremultipliedColors(false);
fDecoder->setSampleSize(sampleSize);
+ fDecoder->setAllocator(allocator);
// kAlpha8 is the legacy representation of kGray8 used by SkImageDecoder
- if (kGray_8_SkColorType == prefColorType) {
- prefColorType = kAlpha_8_SkColorType;
+ if (kGray_8_SkColorType == colorType) {
+ colorType = kAlpha_8_SkColorType;
}
- SkIRect region;
- region.fLeft = start_x;
- region.fTop = start_y;
- region.fRight = start_x + width;
- region.fBottom = start_y + height;
-
- SkAutoTDelete<SkBitmap> bitmap(new SkBitmap());
- if (!fDecoder->decodeSubset(bitmap.get(), region, prefColorType)) {
- SkCodecPrintf("Error: decodeRegion failed.\n");
- return nullptr;
- }
- return bitmap.detach();
+ bool result = fDecoder->decodeSubset(bitmap, desiredSubset, colorType);
+ fDecoder->setAllocator(nullptr);
+ return result;
}
diff --git a/tools/SkBitmapRegionSampler.h b/tools/SkBitmapRegionSampler.h
index 8ed95e2524..be2d23961e 100644
--- a/tools/SkBitmapRegionSampler.h
+++ b/tools/SkBitmapRegionSampler.h
@@ -22,15 +22,9 @@ public:
*/
SkBitmapRegionSampler(SkImageDecoder* decoder, int width, int height);
- /*
- * Three differences from the Android version:
- * Returns a Skia bitmap instead of an Android bitmap.
- * Android version attempts to reuse a recycled bitmap.
- * Removed the options object and used parameters for color type and
- * sample size.
- */
- SkBitmap* decodeRegion(int start_x, int start_y, int width, int height,
- int sampleSize, SkColorType prefColorType) override;
+ bool decodeRegion(SkBitmap* bitmap, SkBitmap::Allocator* allocator,
+ const SkIRect& desiredSubset, int sampleSize,
+ SkColorType colorType, bool requireUnpremul) override;
bool conversionSupported(SkColorType colorType) override {
// SkBitmapRegionSampler does not allow the client to check if the conversion