aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar halcanary@google.com <halcanary@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-12-09 13:45:02 +0000
committerGravatar halcanary@google.com <halcanary@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-12-09 13:45:02 +0000
commit29d96935ae34dfcd6e403f9beefa7436e226836e (patch)
treed3a019094f19e47d9fd4b74da43a01f781b8375e /src
parent61867875ef8083ca39a76acc8ffeedd2623d4b35 (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.cpp187
-rw-r--r--src/images/SkDecodingImageGenerator.h65
-rw-r--r--src/images/SkImageDecoder.cpp147
-rw-r--r--src/ports/SkImageDecoder_empty.cpp5
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;
}