diff options
author | 2013-12-09 13:45:02 +0000 | |
---|---|---|
committer | 2013-12-09 13:45:02 +0000 | |
commit | 29d96935ae34dfcd6e403f9beefa7436e226836e (patch) | |
tree | d3a019094f19e47d9fd4b74da43a01f781b8375e /src | |
parent | 61867875ef8083ca39a76acc8ffeedd2623d4b35 (diff) |
SkDecodingImageGenerator now uses SkStreamRewindable
This makes sense since Android will be giving us a stream and the
decoders expect a stream. This also removes some glue code,
DecodeMemoryToTarget, that works better using a SkImageGenerator.
Motivation: This is a necessary step to move from SkImageRef to
SkDiscardablePixelRef.
SkImageDecoder::DecodeMemoryToTarget function removed.
BUG=
R=reed@google.com, scroggo@google.com
Review URL: https://codereview.chromium.org/101973005
git-svn-id: http://skia.googlecode.com/svn/trunk@12560 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r-- | src/images/SkDecodingImageGenerator.cpp | 187 | ||||
-rw-r--r-- | src/images/SkDecodingImageGenerator.h | 65 | ||||
-rw-r--r-- | src/images/SkImageDecoder.cpp | 147 | ||||
-rw-r--r-- | src/ports/SkImageDecoder_empty.cpp | 5 |
4 files changed, 236 insertions, 168 deletions
diff --git a/src/images/SkDecodingImageGenerator.cpp b/src/images/SkDecodingImageGenerator.cpp index 05651c78c2..2b80444141 100644 --- a/src/images/SkDecodingImageGenerator.cpp +++ b/src/images/SkDecodingImageGenerator.cpp @@ -9,39 +9,184 @@ #include "SkData.h" #include "SkDiscardablePixelRef.h" #include "SkImageDecoder.h" +#include "SkImagePriv.h" +#include "SkStream.h" + + +namespace { +/** + * Special allocator used by getPixels(). Uses preallocated memory + * provided. + */ +class TargetAllocator : public SkBitmap::Allocator { +public: + TargetAllocator(void* target, size_t rowBytes, const SkImageInfo& info) + : fTarget(target) + , fRowBytes(rowBytes) + , fInfo(info) { } + + virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE { + if ((SkImageInfoToBitmapConfig(fInfo) != bm->config()) + || (bm->width() != fInfo.fWidth) + || (bm->height() != fInfo.fHeight)) { + return false; + } + bm->setConfig(bm->config(), bm->width(), bm->height(), + fRowBytes, bm->alphaType()); + bm->setPixels(fTarget, ct); + return true; + } + +private: + void* fTarget; + size_t fRowBytes; + SkImageInfo fInfo; + typedef SkBitmap::Allocator INHERITED; +}; +} // namespace +//////////////////////////////////////////////////////////////////////////////// SkDecodingImageGenerator::SkDecodingImageGenerator(SkData* data) - : fData(data) { + : 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()); +} + SkDecodingImageGenerator::~SkDecodingImageGenerator() { - fData->unref(); + SkSafeUnref(fData); + 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 + SkData* SkDecodingImageGenerator::refEncodedData() { // This functionality is used in `gm --serialize` - fData->ref(); - return fData; + if (fData != NULL) { + return SkSafeRef(fData); + } + // TODO(halcanary): SkStreamRewindable needs a refData() function + // which returns a cheap copy of the underlying data. + if (!fStream->rewind()) { + return NULL; + } + size_t length = fStream->getLength(); + if (0 == length) { + return NULL; + } + void* buffer = sk_malloc_flags(length, 0); + SkCheckResult(fStream->read(buffer, length), length); + fData = SkData::NewFromMalloc(buffer, length); + return SkSafeRef(fData); } bool SkDecodingImageGenerator::getInfo(SkImageInfo* info) { - SkASSERT(info != NULL); - return SkImageDecoder::DecodeMemoryToTarget(fData->data(), - fData->size(), - info, NULL); + // 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 (!SkBitmapToImageInfo(bitmap, &fInfo)) { + // We can't use bitmap.config() as is. + // Must be kARGB_4444_Config. + if (!bitmap.canCopyTo(SkBitmap::kARGB_8888_Config)) { + // kARGB_4444_Config can copy to kARGB_8888. + 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) { - SkASSERT(pixels != NULL); - SkImageDecoder::Target target = {pixels, rowBytes}; - SkImageInfo tmpInfo = info; - return SkImageDecoder::DecodeMemoryToTarget(fData->data(), - fData->size(), - &tmpInfo, &target); + 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. + return false; + } + int bpp = SkBitmap::ComputeBytesPerPixel(SkImageInfoToBitmapConfig(info)); + if (static_cast<size_t>(bpp * info.fWidth) > rowBytes) { + return false; + } + SkBitmap bitmap; + if (!bitmap.setConfig(info, rowBytes)) { + return false; + } + + TargetAllocator allocator(pixels, rowBytes, info); + if (!fDoCopyTo) { + decoder->setAllocator(&allocator); + } + bool success = decoder->decode(fStream, &bitmap, + SkImageDecoder::kDecodePixels_Mode); + decoder->setAllocator(NULL); + if (!success) { + return false; + } + if (fDoCopyTo) { + SkBitmap bm8888; + bitmap.copyTo(&bm8888, SkBitmap::kARGB_8888_Config, &allocator); + } + return true; } bool SkDecodingImageGenerator::Install(SkData* data, SkBitmap* dst, SkDiscardableMemory::Factory* factory) { @@ -50,3 +195,17 @@ bool SkDecodingImageGenerator::Install(SkData* data, SkBitmap* dst, SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (data))); return SkDiscardablePixelRef::Install(gen, dst, factory); } + +bool SkDecodingImageGenerator::Install(SkStreamRewindable* stream, + SkBitmap* dst, + SkDiscardableMemory::Factory* factory) { + SkASSERT(stream != NULL); + SkASSERT(dst != NULL); + if ((stream == NULL) || !stream->unique()) { + SkSafeUnref(stream); + return false; + } + SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (stream))); + return SkDiscardablePixelRef::Install(gen, dst, factory); +} + diff --git a/src/images/SkDecodingImageGenerator.h b/src/images/SkDecodingImageGenerator.h index 49f1295bf3..dba234bcf1 100644 --- a/src/images/SkDecodingImageGenerator.h +++ b/src/images/SkDecodingImageGenerator.h @@ -10,8 +10,10 @@ #include "SkDiscardableMemory.h" #include "SkImageGenerator.h" +#include "SkImageInfo.h" class SkBitmap; +class SkStreamRewindable; /** * Calls into SkImageDecoder::DecodeMemoryToTarget to implement a @@ -23,7 +25,32 @@ public: * The constructor will take a reference to the SkData. The * destructor will unref() it. */ - SkDecodingImageGenerator(SkData* data); + explicit SkDecodingImageGenerator(SkData* data); + + /* + * The SkData version of this constructor is preferred. If the + * stream has an underlying SkData (such as a SkMemoryStream) + * pass that in. + * + * This object will unref the stream when done. Since streams + * have internal state (position), the caller should not pass a + * shared stream in. Pass either a new duplicated stream in or + * transfer ownership of the stream. In the latter case, be sure + * that there are no other consumers of the stream who will + * modify the stream's position. This constructor asserts + * stream->unique(). + * + * For example: + * SkStreamRewindable* stream; + * ... + * SkImageGenerator* gen + * = SkNEW_ARGS(SkDecodingImageGenerator, + * (stream->duplicate())); + * ... + * SkDELETE(gen); + */ + explicit SkDecodingImageGenerator(SkStreamRewindable* stream); + virtual ~SkDecodingImageGenerator(); virtual SkData* refEncodedData() SK_OVERRIDE; @@ -52,8 +79,42 @@ public: */ static bool Install(SkData* data, SkBitmap* destination, SkDiscardableMemory::Factory* factory = NULL); + /** + * Install the stream into the destination bitmap, using a new + * SkDiscardablePixelRef and a new SkDecodingImageGenerator. + * + * The SkData version of this function is preferred. If the + * stream has an underlying SkData (such as a SkMemoryStream) + * pass that in. + * + * @param stream The source of encoded data that will be passed + * to the decoder. The installed SkDecodingImageGenerator will + * unref the stream when done. If false is returned, this + * function will perform the unref. Since streams have internal + * state (position), the caller should not pass a shared stream + * in. Pass either a new duplicated stream in or transfer + * ownership of the stream. In the latter case, be sure that + * there are no other consumers of the stream who will modify the + * stream's position. This function will fail if + * (!stream->unique()). + * + * @param destination Upon success, this bitmap will be + * configured and have a pixelref installed. + * + * @param factory If not NULL, this object will be used as a + * source of discardable memory when decoding. If NULL, then + * SkDiscardableMemory::Create() will be called. + * + * @return true iff successful. + */ + static bool Install(SkStreamRewindable* stream, SkBitmap* destination, + SkDiscardableMemory::Factory* factory = NULL); private: - SkData* fData; + SkData* fData; + SkStreamRewindable* fStream; + SkImageInfo fInfo; + bool fHasInfo; + bool fDoCopyTo; }; #endif // SkDecodingImageGenerator_DEFINED diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp index ee7ad5e035..32cf087ed8 100644 --- a/src/images/SkImageDecoder.cpp +++ b/src/images/SkImageDecoder.cpp @@ -282,153 +282,6 @@ bool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm, return SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format); } -/** - * Special allocator used by DecodeMemoryToTarget. Uses preallocated memory - * provided if the bm is 8888. Otherwise, uses a heap allocator. The same - * allocator will be used again for a copy to 8888, when the preallocated - * memory will be used. - */ -class TargetAllocator : public SkBitmap::HeapAllocator { - -public: - TargetAllocator(void* target) - : fTarget(target) {} - - virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE { - // If the config is not 8888, allocate a pixelref using the heap. - // fTarget will be used to store the final pixels when copied to - // 8888. - if (bm->config() != SkBitmap::kARGB_8888_Config) { - return INHERITED::allocPixelRef(bm, ct); - } - // In kARGB_8888_Config, there is no colortable. - SkASSERT(NULL == ct); - bm->setPixels(fTarget); - return true; - } - -private: - void* fTarget; - typedef SkBitmap::HeapAllocator INHERITED; -}; - -/** - * Helper function for DecodeMemoryToTarget. DecodeMemoryToTarget wants - * 8888, so set the config to it. All parameters must not be null. - * @param decoder Decoder appropriate for this stream. - * @param stream Rewound stream to the encoded data. - * @param bitmap On success, will have its bounds set to the bounds of the - * encoded data, and its config set to 8888. - * @return True if the bounds were decoded and the bitmap is 8888 or can be - * copied to 8888. - */ -static bool decode_bounds_to_8888(SkImageDecoder* decoder, SkStream* stream, - SkBitmap* bitmap) { - SkASSERT(decoder != NULL); - SkASSERT(stream != NULL); - SkASSERT(bitmap != NULL); - - if (!decoder->decode(stream, bitmap, SkImageDecoder::kDecodeBounds_Mode)) { - return false; - } - - if (bitmap->config() == SkBitmap::kARGB_8888_Config) { - return true; - } - - if (!bitmap->canCopyTo(SkBitmap::kARGB_8888_Config)) { - return false; - } - - bitmap->setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(), bitmap->height()); - return true; -} - -/** - * Helper function for DecodeMemoryToTarget. Decodes the stream into bitmap, and if - * the bitmap is not 8888, then it is copied to 8888. Either way, the end result has - * its pixels stored in target. All parameters must not be null. - * @param decoder Decoder appropriate for this stream. - * @param stream Rewound stream to the encoded data. - * @param bitmap On success, will contain the decoded image, with its pixels stored - * at target. - * @param target Preallocated memory for storing pixels. - * @return bool Whether the decode (and copy, if necessary) succeeded. - */ -static bool decode_pixels_to_8888(SkImageDecoder* decoder, SkStream* stream, - SkBitmap* bitmap, void* target) { - SkASSERT(decoder != NULL); - SkASSERT(stream != NULL); - SkASSERT(bitmap != NULL); - SkASSERT(target != NULL); - - TargetAllocator allocator(target); - decoder->setAllocator(&allocator); - - bool success = decoder->decode(stream, bitmap, SkImageDecoder::kDecodePixels_Mode); - decoder->setAllocator(NULL); - - if (!success) { - return false; - } - - if (bitmap->config() == SkBitmap::kARGB_8888_Config) { - return true; - } - - SkBitmap bm8888; - if (!bitmap->copyTo(&bm8888, SkBitmap::kARGB_8888_Config, &allocator)) { - return false; - } - - bitmap->swap(bm8888); - return true; -} - -bool SkImageDecoder::DecodeMemoryToTarget(const void* buffer, size_t size, - SkImageInfo* info, - const SkImageDecoder::Target* target) { - // FIXME: Just to get this working, implement in terms of existing - // ImageDecoder calls. - SkBitmap bm; - SkMemoryStream stream(buffer, size); - SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream)); - if (NULL == decoder.get()) { - return false; - } - - if (!decode_bounds_to_8888(decoder.get(), &stream, &bm)) { - return false; - } - - SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config); - - // Now set info properly. - // Since Config is SkBitmap::kARGB_8888_Config, SkBitmapToImageInfo - // will always succeed. - if (info) { - SkAssertResult(SkBitmapToImageInfo(bm, info)); - } - - if (NULL == target) { - return true; - } - - if (target->fRowBytes != SkToU32(bm.rowBytes())) { - size_t minRB = SkBitmap::ComputeRowBytes(bm.config(), bm.width()); - if (target->fRowBytes < minRB) { - SkDEBUGFAIL("Desired row bytes is too small"); - return false; - } - bm.setConfig(bm.config(), bm.width(), bm.height(), target->fRowBytes); - } - - // SkMemoryStream.rewind() will always return true. - SkAssertResult(stream.rewind()); - return decode_pixels_to_8888(decoder.get(), &stream, &bm, target->fAddr); -} - - bool SkImageDecoder::DecodeStream(SkStreamRewindable* stream, SkBitmap* bm, SkBitmap::Config pref, Mode mode, Format* format) { diff --git a/src/ports/SkImageDecoder_empty.cpp b/src/ports/SkImageDecoder_empty.cpp index 67214970d4..ae0fc36325 100644 --- a/src/ports/SkImageDecoder_empty.cpp +++ b/src/ports/SkImageDecoder_empty.cpp @@ -83,11 +83,6 @@ SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator*) { void SkImageDecoder::setSampleSize(int) {} -bool SkImageDecoder::DecodeMemoryToTarget(const void*, size_t, SkImageInfo*, - const SkImageDecoder::Target*) { - return false; -} - SkBitmap::Config SkImageDecoder::GetDeviceConfig() { return SkBitmap::kNo_Config; } |