aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/images/SkDecodingImageGenerator.cpp
diff options
context:
space:
mode:
authorGravatar halcanary@google.com <halcanary@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-01-02 13:15:13 +0000
committerGravatar halcanary@google.com <halcanary@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-01-02 13:15:13 +0000
commit3d50ea1b87132833d7eab38964f40315ba553205 (patch)
tree3776e19965640462d197f926532c872ecb658cdc /src/images/SkDecodingImageGenerator.cpp
parentf8affa2e5cf9d4e0c8b020ba322f03355050794e (diff)
Add Options to SkDecodingImageGenerator, simplify API.
Motivation: We want to remove redundant classes from Skia. To that end we want to remove SkImageRef and its subclasses and replace their uses with SkDiscardablePixelRef + SkDecodingImageGenerator. Since Android uses SkImageRef, we need to make sure that SkDecodingImageGenerator allows all of the settings that Android exposes in BitmapFactory.Options. To that end, we have created an Options struct for the SkDecodingImageGenerator which lets the client of the generator set sample size, dithering, and bitmap config. We have made the SkDecodingImageGenerator constructor private and replaced the SkDecodingImageGenerator::Install functions with a SkDecodingImageGenerator::Create functions (one for SkData and one for SkStream) which now take a SkDecodingImageGenerator::Options struct. Also added a ImageDecoderOptions test which loops through a list of sets of options and tries them on a set of 5 small encoded images. Also updated several users of SkDecodingImageGenerator::Install to follow new call signature - gm/factory.cpp, LazyDecodeBitmap.cpp, and PictureTest.cpp, CachedDecodingPixelRefTest.cpp. We also added a new ImprovedBitmapFactory Test which simulates the exact function that Android will need to modify to use this, installPixelRef() in BitmapFactory. R=reed@google.com, scroggo@google.com Committed: https://code.google.com/p/skia/source/detail?r=12744 Review URL: https://codereview.chromium.org/93703004 git-svn-id: http://skia.googlecode.com/svn/trunk@12855 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/images/SkDecodingImageGenerator.cpp')
-rw-r--r--src/images/SkDecodingImageGenerator.cpp307
1 files changed, 193 insertions, 114 deletions
diff --git a/src/images/SkDecodingImageGenerator.cpp b/src/images/SkDecodingImageGenerator.cpp
index a833c636ff..153d1e220b 100644
--- a/src/images/SkDecodingImageGenerator.cpp
+++ b/src/images/SkDecodingImageGenerator.cpp
@@ -5,13 +5,14 @@
* found in the LICENSE file.
*/
-#include "SkDecodingImageGenerator.h"
#include "SkData.h"
+#include "SkDecodingImageGenerator.h"
#include "SkImageDecoder.h"
+#include "SkImageInfo.h"
#include "SkImageGenerator.h"
#include "SkImagePriv.h"
#include "SkStream.h"
-
+#include "SkUtils.h"
namespace {
/**
@@ -20,50 +21,89 @@ namespace {
*/
class TargetAllocator : public SkBitmap::Allocator {
public:
- TargetAllocator(void* target, size_t rowBytes, const SkImageInfo& info)
+ TargetAllocator(void* target,
+ size_t rowBytes,
+ int width,
+ int height,
+ SkBitmap::Config config)
: fTarget(target)
, fRowBytes(rowBytes)
- , fInfo(info) { }
+ , fWidth(width)
+ , fHeight(height)
+ , fConfig(config) { }
- virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE {
- if ((SkImageInfoToBitmapConfig(fInfo) != bm->config())
- || (bm->width() != fInfo.fWidth)
- || (bm->height() != fInfo.fHeight)) {
- return false;
+ bool isReady() { return (fTarget != NULL); }
+
+ virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) {
+ if ((NULL == fTarget)
+ || (fConfig != bm->config())
+ || (fWidth != bm->width())
+ || (fHeight != bm->height())
+ || (ct != NULL)) {
+ // Call default allocator.
+ return bm->allocPixels(NULL, ct);
}
- bm->setConfig(bm->config(), bm->width(), bm->height(),
- fRowBytes, bm->alphaType());
- bm->setPixels(fTarget, ct);
+ // make sure fRowBytes is correct.
+ bm->setConfig(fConfig, fWidth, fHeight, fRowBytes, bm->alphaType());
+ // TODO(halcanary): verify that all callers of this function
+ // will respect new RowBytes. Will be moot once rowbytes belongs
+ // to PixelRef.
+ bm->setPixels(fTarget, NULL);
+ fTarget = NULL; // never alloc same pixels twice!
return true;
}
private:
- void* fTarget;
- size_t fRowBytes;
- SkImageInfo fInfo;
+ void* fTarget; // Block of memory to be supplied as pixel memory
+ // in allocPixelRef. Must be large enough to hold
+ // a bitmap described by fWidth, fHeight, and
+ // fRowBytes.
+ size_t fRowBytes; // rowbytes for the destination bitmap
+ int fWidth; // Along with fHeight and fConfig, the information
+ int fHeight; // about the bitmap whose pixels this allocator is
+ // expected to allocate. If they do not match the
+ // bitmap passed to allocPixelRef, it is assumed
+ // that the bitmap will be copied to a bitmap with
+ // the correct info using this allocator, so the
+ // default allocator will be used instead of
+ // fTarget.
+ SkBitmap::Config fConfig;
typedef SkBitmap::Allocator INHERITED;
};
+
+// TODO(halcanary): Give this macro a better name and move it into SkTypes.h
+#ifdef SK_DEBUG
+ #define SkCheckResult(expr, value) SkASSERT((value) == (expr))
+#else
+ #define SkCheckResult(expr, value) (void)(expr)
+#endif
+
+#ifdef SK_DEBUG
+inline bool check_alpha(SkAlphaType reported, SkAlphaType actual) {
+ return ((reported == actual)
+ || ((reported == kPremul_SkAlphaType)
+ && (actual == kOpaque_SkAlphaType)));
+}
+#endif // SK_DEBUG
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
-SkDecodingImageGenerator::SkDecodingImageGenerator(SkData* data)
+SkDecodingImageGenerator::SkDecodingImageGenerator(
+ SkData* data,
+ SkStreamRewindable* stream,
+ const SkImageInfo& info,
+ int sampleSize,
+ bool ditherImage,
+ SkBitmap::Config requestedConfig)
: fData(data)
- , fHasInfo(false)
- , fDoCopyTo(false) {
- SkASSERT(fData != NULL);
- fStream = SkNEW_ARGS(SkMemoryStream, (fData));
- SkASSERT(fStream != NULL);
- SkASSERT(fStream->unique());
- fData->ref();
-}
-
-SkDecodingImageGenerator::SkDecodingImageGenerator(SkStreamRewindable* stream)
- : fData(NULL)
, fStream(stream)
- , fHasInfo(false)
- , fDoCopyTo(false) {
- SkASSERT(fStream != NULL);
- SkASSERT(fStream->unique());
+ , fInfo(info)
+ , fSampleSize(sampleSize)
+ , fDitherImage(ditherImage)
+ , fRequestedConfig(requestedConfig) {
+ SkASSERT(stream != NULL);
+ SkSafeRef(fData); // may be NULL.
}
SkDecodingImageGenerator::~SkDecodingImageGenerator() {
@@ -71,15 +111,16 @@ SkDecodingImageGenerator::~SkDecodingImageGenerator() {
fStream->unref();
}
-// TODO(halcanary): Give this macro a better name and move it into SkTypes.h
-#ifdef SK_DEBUG
- #define SkCheckResult(expr, value) SkASSERT((value) == (expr))
-#else
- #define SkCheckResult(expr, value) (void)(expr)
-#endif
+bool SkDecodingImageGenerator::getInfo(SkImageInfo* info) {
+ if (info != NULL) {
+ *info = fInfo;
+ }
+ return true;
+}
SkData* SkDecodingImageGenerator::refEncodedData() {
// This functionality is used in `gm --serialize`
+ // Does not encode options.
if (fData != NULL) {
return SkSafeRef(fData);
}
@@ -98,111 +139,149 @@ SkData* SkDecodingImageGenerator::refEncodedData() {
return SkSafeRef(fData);
}
-bool SkDecodingImageGenerator::getInfo(SkImageInfo* info) {
- // info can be NULL. If so, will update fInfo, fDoCopyTo, and fHasInfo.
- if (fHasInfo) {
- if (info != NULL) {
- *info = fInfo;
- }
- return true;
- }
- SkAssertResult(fStream->rewind());
- SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
- if (NULL == decoder.get()) {
- return false;
- }
- SkBitmap bitmap;
- if (!decoder->decode(fStream, &bitmap,
- SkImageDecoder::kDecodeBounds_Mode)) {
- return false;
- }
- if (bitmap.config() == SkBitmap::kNo_Config) {
- return false;
- }
- if (!bitmap.asImageInfo(&fInfo)) {
- // We can't use bitmap.config() as is.
- if (!bitmap.canCopyTo(SkBitmap::kARGB_8888_Config)) {
- SkDEBUGFAIL("!bitmap->canCopyTo(SkBitmap::kARGB_8888_Config)");
- return false;
- }
- fDoCopyTo = true;
- fInfo.fWidth = bitmap.width();
- fInfo.fHeight = bitmap.height();
- fInfo.fColorType = kPMColor_SkColorType;
- fInfo.fAlphaType = bitmap.alphaType();
- }
- if (info != NULL) {
- *info = fInfo;
- }
- fHasInfo = true;
- return true;
-}
-
bool SkDecodingImageGenerator::getPixels(const SkImageInfo& info,
void* pixels,
size_t rowBytes) {
if (NULL == pixels) {
return false;
}
- if (!this->getInfo(NULL)) {
- return false;
- }
- if (SkImageInfoToBitmapConfig(info) == SkBitmap::kNo_Config) {
- return false; // Unsupported SkColorType.
- }
- SkAssertResult(fStream->rewind());
- SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
- if (NULL == decoder.get()) {
- return false;
- }
if (fInfo != info) {
- // The caller has specified a different info. For now, this
- // is an error. In the future, we will check to see if we can
- // convert.
+ // The caller has specified a different info. This is an
+ // error for this kind of SkImageGenerator. Use the Options
+ // to change the settings.
return false;
}
- int bpp = SkBitmap::ComputeBytesPerPixel(SkImageInfoToBitmapConfig(info));
+ int bpp = SkBitmap::ComputeBytesPerPixel(fRequestedConfig);
if (static_cast<size_t>(bpp * info.fWidth) > rowBytes) {
+ // The caller has specified a bad rowBytes.
return false;
}
- SkBitmap bitmap;
- if (!bitmap.setConfig(info, rowBytes)) {
+
+ SkAssertResult(fStream->rewind());
+ SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
+ if (NULL == decoder.get()) {
return false;
}
+ decoder->setDitherImage(fDitherImage);
+ decoder->setSampleSize(fSampleSize);
- TargetAllocator allocator(pixels, rowBytes, info);
- if (!fDoCopyTo) {
- decoder->setAllocator(&allocator);
- }
- bool success = decoder->decode(fStream, &bitmap,
+ SkBitmap bitmap;
+ TargetAllocator allocator(pixels, rowBytes, info.fWidth,
+ info.fHeight, fRequestedConfig);
+ decoder->setAllocator(&allocator);
+ bool success = decoder->decode(fStream, &bitmap, fRequestedConfig,
SkImageDecoder::kDecodePixels_Mode);
decoder->setAllocator(NULL);
if (!success) {
return false;
}
- if (fDoCopyTo) {
- SkBitmap bm8888;
- bitmap.copyTo(&bm8888, SkBitmap::kARGB_8888_Config, &allocator);
+ if (allocator.isReady()) { // Did not use pixels!
+ SkBitmap bm;
+ SkASSERT(bitmap.canCopyTo(fRequestedConfig));
+ if (!bitmap.copyTo(&bm, fRequestedConfig, &allocator)
+ || allocator.isReady()) {
+ SkDEBUGFAIL("bitmap.copyTo(requestedConfig) failed.");
+ // Earlier we checked canCopyto(); we expect consistency.
+ return false;
+ }
+ SkASSERT(check_alpha(fInfo.fAlphaType, bm.alphaType()));
+ } else {
+ SkASSERT(check_alpha(fInfo.fAlphaType, bitmap.alphaType()));
}
return true;
}
-bool SkDecodingImageGenerator::Install(SkData* data, SkBitmap* dst,
- SkDiscardableMemory::Factory* factory) {
+
+SkImageGenerator* SkDecodingImageGenerator::Create(
+ SkData* data,
+ const SkDecodingImageGenerator::Options& opts) {
SkASSERT(data != NULL);
- SkASSERT(dst != NULL);
- SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (data)));
- return SkInstallDiscardablePixelRef(gen, dst, factory);
+ if (NULL == data) {
+ return NULL;
+ }
+ SkStreamRewindable* stream = SkNEW_ARGS(SkMemoryStream, (data));
+ SkASSERT(stream != NULL);
+ SkASSERT(stream->unique());
+ return SkDecodingImageGenerator::Create(data, stream, opts);
}
-bool SkDecodingImageGenerator::Install(SkStreamRewindable* stream,
- SkBitmap* dst,
- SkDiscardableMemory::Factory* factory) {
+SkImageGenerator* SkDecodingImageGenerator::Create(
+ SkStreamRewindable* stream,
+ const SkDecodingImageGenerator::Options& opts) {
SkASSERT(stream != NULL);
- SkASSERT(dst != NULL);
+ SkASSERT(stream->unique());
if ((stream == NULL) || !stream->unique()) {
SkSafeUnref(stream);
- return false;
+ return NULL;
+ }
+ return SkDecodingImageGenerator::Create(NULL, stream, opts);
+}
+
+// A contructor-type function that returns NULL on failure. This
+// prevents the returned SkImageGenerator from ever being in a bad
+// state. Called by both Create() functions
+SkImageGenerator* SkDecodingImageGenerator::Create(
+ SkData* data,
+ SkStreamRewindable* stream,
+ const SkDecodingImageGenerator::Options& opts) {
+ SkASSERT(stream);
+ SkAutoTUnref<SkStreamRewindable> autoStream(stream); // always unref this.
+ if (opts.fUseRequestedColorType &&
+ (kIndex_8_SkColorType == opts.fRequestedColorType)) {
+ // We do not support indexed color with SkImageGenerators,
+ return NULL;
+ }
+ SkAssertResult(autoStream->rewind());
+ SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(autoStream));
+ if (NULL == decoder.get()) {
+ return NULL;
+ }
+ SkBitmap bitmap;
+ decoder->setSampleSize(opts.fSampleSize);
+ if (!decoder->decode(stream, &bitmap,
+ SkImageDecoder::kDecodeBounds_Mode)) {
+ return NULL;
+ }
+ if (bitmap.config() == SkBitmap::kNo_Config) {
+ return NULL;
+ }
+
+ SkImageInfo info;
+ SkBitmap::Config config;
+
+ if (!opts.fUseRequestedColorType) {
+ // Use default config.
+ if (SkBitmap::kIndex8_Config == bitmap.config()) {
+ // We don't support kIndex8 because we don't support
+ // colortables in this workflow.
+ config = SkBitmap::kARGB_8888_Config;
+ info.fWidth = bitmap.width();
+ info.fHeight = bitmap.height();
+ info.fColorType = kPMColor_SkColorType;
+ info.fAlphaType = bitmap.alphaType();
+ } else {
+ config = bitmap.config(); // Save for later!
+ if (!bitmap.asImageInfo(&info)) {
+ SkDEBUGFAIL("Getting SkImageInfo from bitmap failed.");
+ return NULL;
+ }
+ }
+ } else {
+ config = SkColorTypeToBitmapConfig(opts.fRequestedColorType);
+ if (!bitmap.canCopyTo(config)) {
+ SkASSERT(bitmap.config() != config);
+ return NULL; // Can not translate to needed config.
+ }
+ info.fWidth = bitmap.width();
+ info.fHeight = bitmap.height();
+ info.fColorType = opts.fRequestedColorType;
+ info.fAlphaType = bitmap.alphaType();
+
+ // Sanity check.
+ SkDEBUGCODE(SkColorType tmp;)
+ SkASSERT(SkBitmapConfigToColorType(config, &tmp));
+ SkASSERT(tmp == opts.fRequestedColorType);
}
- SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (stream)));
- return SkInstallDiscardablePixelRef(gen, dst, factory);
+ return SkNEW_ARGS(SkDecodingImageGenerator,
+ (data, autoStream.detach(), info,
+ opts.fSampleSize, opts.fDitherImage, config));
}