Index: src/images/SkDecodingImageGenerator.cpp |
diff --git a/src/images/SkDecodingImageGenerator.cpp b/src/images/SkDecodingImageGenerator.cpp |
index 05651c78c29e2f67af1b568846f2bfd24fb9727e..2b804441417938042168d4ddce2b65232faceb30 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); |
+} |
+ |