| Index: src/images/SkDecodingImageGenerator.cpp
|
| diff --git a/src/images/SkDecodingImageGenerator.cpp b/src/images/SkDecodingImageGenerator.cpp
|
| index a833c636ff9c8d30df1c1ade660743ea8b2a47d2..153d1e220bc6be643dea492e8c4d74192872268c 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));
|
| }
|
|
|