diff options
Diffstat (limited to 'chromium/third_party/skia/src/images/SkDecodingImageGenerator.cpp')
-rw-r--r-- | chromium/third_party/skia/src/images/SkDecodingImageGenerator.cpp | 311 |
1 files changed, 192 insertions, 119 deletions
diff --git a/chromium/third_party/skia/src/images/SkDecodingImageGenerator.cpp b/chromium/third_party/skia/src/images/SkDecodingImageGenerator.cpp index a833c636ff9..88cdef9a321 100644 --- a/chromium/third_party/skia/src/images/SkDecodingImageGenerator.cpp +++ b/chromium/third_party/skia/src/images/SkDecodingImageGenerator.cpp @@ -5,81 +5,133 @@ * 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 { +bool equal_modulo_alpha(const SkImageInfo& a, const SkImageInfo& b) { + return a.width() == b.width() && a.height() == b.height() && + a.colorType() == b.colorType(); +} + +class DecodingImageGenerator : public SkImageGenerator { +public: + virtual ~DecodingImageGenerator(); + + SkData* fData; + SkStreamRewindable* fStream; + const SkImageInfo fInfo; + const int fSampleSize; + const bool fDitherImage; + + DecodingImageGenerator(SkData* data, + SkStreamRewindable* stream, + const SkImageInfo& info, + int sampleSize, + bool ditherImage); + +protected: + virtual SkData* onRefEncodedData() SK_OVERRIDE; + virtual bool onGetInfo(SkImageInfo* info) SK_OVERRIDE { + *info = fInfo; + return true; + } + virtual bool onGetPixels(const SkImageInfo& info, + void* pixels, size_t rowBytes, + SkPMColor ctable[], int* ctableCount) SK_OVERRIDE; + +private: + typedef SkImageGenerator INHERITED; +}; + /** * Special allocator used by getPixels(). Uses preallocated memory - * provided. + * provided if possible, else fall-back on the default allocator */ class TargetAllocator : public SkBitmap::Allocator { public: - TargetAllocator(void* target, size_t rowBytes, const SkImageInfo& info) - : fTarget(target) + TargetAllocator(const SkImageInfo& info, + void* target, + size_t rowBytes) + : fInfo(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; + bool isReady() { return (fTarget != NULL); } + + virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) { + if (NULL == fTarget || !equal_modulo_alpha(fInfo, bm->info())) { + // Call default allocator. + return bm->allocPixels(NULL, ct); } - bm->setConfig(bm->config(), bm->width(), bm->height(), - fRowBytes, bm->alphaType()); - bm->setPixels(fTarget, ct); + + // TODO(halcanary): verify that all callers of this function + // will respect new RowBytes. Will be moot once rowbytes belongs + // to PixelRef. + bm->installPixels(fInfo, fTarget, fRowBytes, ct, NULL, NULL); + + fTarget = NULL; // never alloc same pixels twice! return true; } private: - void* fTarget; - size_t fRowBytes; - SkImageInfo fInfo; + const 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 fInfo and fRowBytes + const size_t fRowBytes; // rowbytes for the destination bitmap + typedef SkBitmap::Allocator INHERITED; }; -} // namespace -//////////////////////////////////////////////////////////////////////////////// -SkDecodingImageGenerator::SkDecodingImageGenerator(SkData* data) - : fData(data) - , fHasInfo(false) - , fDoCopyTo(false) { - SkASSERT(fData != NULL); - fStream = SkNEW_ARGS(SkMemoryStream, (fData)); - SkASSERT(fStream != NULL); - SkASSERT(fStream->unique()); - fData->ref(); +// 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 + +//////////////////////////////////////////////////////////////////////////////// -SkDecodingImageGenerator::SkDecodingImageGenerator(SkStreamRewindable* stream) - : fData(NULL) +DecodingImageGenerator::DecodingImageGenerator( + SkData* data, + SkStreamRewindable* stream, + const SkImageInfo& info, + int sampleSize, + bool ditherImage) + : fData(data) , fStream(stream) - , fHasInfo(false) - , fDoCopyTo(false) { - SkASSERT(fStream != NULL); - SkASSERT(fStream->unique()); + , fInfo(info) + , fSampleSize(sampleSize) + , fDitherImage(ditherImage) +{ + SkASSERT(stream != NULL); + SkSafeRef(fData); // may be NULL. } -SkDecodingImageGenerator::~SkDecodingImageGenerator() { +DecodingImageGenerator::~DecodingImageGenerator() { 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() { +SkData* DecodingImageGenerator::onRefEncodedData() { // This functionality is used in `gm --serialize` + // Does not encode options. if (fData != NULL) { return SkSafeRef(fData); } @@ -98,111 +150,132 @@ 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; +bool DecodingImageGenerator::onGetPixels(const SkImageInfo& info, + void* pixels, size_t rowBytes, + SkPMColor ctableEntries[], int* ctableCount) { + if (fInfo != info) { + // 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; } + SkAssertResult(fStream->rewind()); SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream)); if (NULL == decoder.get()) { return false; } + decoder->setDitherImage(fDitherImage); + decoder->setSampleSize(fSampleSize); + decoder->setRequireUnpremultipliedColors( + info.fAlphaType == kUnpremul_SkAlphaType); + SkBitmap bitmap; - if (!decoder->decode(fStream, &bitmap, - SkImageDecoder::kDecodeBounds_Mode)) { - return false; - } - if (bitmap.config() == SkBitmap::kNo_Config) { + TargetAllocator allocator(fInfo, pixels, rowBytes); + decoder->setAllocator(&allocator); + bool success = decoder->decode(fStream, &bitmap, info.colorType(), + SkImageDecoder::kDecodePixels_Mode); + decoder->setAllocator(NULL); + if (!success) { 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)"); + if (allocator.isReady()) { // Did not use pixels! + SkBitmap bm; + SkASSERT(bitmap.canCopyTo(info.colorType())); + bool copySuccess = bitmap.copyTo(&bm, info.colorType(), &allocator); + if (!copySuccess || allocator.isReady()) { + SkDEBUGFAIL("bitmap.copyTo(requestedConfig) failed."); + // Earlier we checked canCopyto(); we expect consistency. return false; } - fDoCopyTo = true; - fInfo.fWidth = bitmap.width(); - fInfo.fHeight = bitmap.height(); - fInfo.fColorType = kPMColor_SkColorType; - fInfo.fAlphaType = bitmap.alphaType(); + SkASSERT(check_alpha(info.alphaType(), bm.alphaType())); + } else { + SkASSERT(check_alpha(info.alphaType(), bitmap.alphaType())); } - if (info != NULL) { - *info = fInfo; + + if (kIndex_8_SkColorType == info.colorType()) { + if (kIndex_8_SkColorType != bitmap.colorType()) { + return false; // they asked for Index8, but we didn't receive that from decoder + } + SkColorTable* ctable = bitmap.getColorTable(); + if (NULL == ctable) { + return false; + } + const int count = ctable->count(); + memcpy(ctableEntries, ctable->lockColors(), count * sizeof(SkPMColor)); + ctable->unlockColors(); + *ctableCount = count; } - 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)); +// 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* CreateDecodingImageGenerator( + SkData* data, + SkStreamRewindable* stream, + const SkDecodingImageGenerator::Options& opts) { + SkASSERT(stream); + SkAutoTUnref<SkStreamRewindable> autoStream(stream); // always unref this. + SkAssertResult(autoStream->rewind()); + SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(autoStream)); 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; + return NULL; } SkBitmap bitmap; - if (!bitmap.setConfig(info, rowBytes)) { - return false; + decoder->setSampleSize(opts.fSampleSize); + decoder->setRequireUnpremultipliedColors(opts.fRequireUnpremul); + if (!decoder->decode(stream, &bitmap, SkImageDecoder::kDecodeBounds_Mode)) { + return NULL; } - - TargetAllocator allocator(pixels, rowBytes, info); - if (!fDoCopyTo) { - decoder->setAllocator(&allocator); + if (kUnknown_SkColorType == bitmap.colorType()) { + return NULL; } - bool success = decoder->decode(fStream, &bitmap, - SkImageDecoder::kDecodePixels_Mode); - decoder->setAllocator(NULL); - if (!success) { - return false; + + SkImageInfo info = bitmap.info(); + + if (opts.fUseRequestedColorType && (opts.fRequestedColorType != info.colorType())) { + if (!bitmap.canCopyTo(opts.fRequestedColorType)) { + SkASSERT(bitmap.colorType() != opts.fRequestedColorType); + return NULL; // Can not translate to needed config. + } + info.fColorType = opts.fRequestedColorType; } - if (fDoCopyTo) { - SkBitmap bm8888; - bitmap.copyTo(&bm8888, SkBitmap::kARGB_8888_Config, &allocator); + + if (opts.fRequireUnpremul && info.fAlphaType != kOpaque_SkAlphaType) { + info.fAlphaType = kUnpremul_SkAlphaType; } - return true; + return SkNEW_ARGS(DecodingImageGenerator, + (data, autoStream.detach(), info, + opts.fSampleSize, opts.fDitherImage)); } -bool SkDecodingImageGenerator::Install(SkData* data, SkBitmap* dst, - SkDiscardableMemory::Factory* factory) { + +} // namespace + +//////////////////////////////////////////////////////////////////////////////// + +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 CreateDecodingImageGenerator(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; } - SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (stream))); - return SkInstallDiscardablePixelRef(gen, dst, factory); + return CreateDecodingImageGenerator(NULL, stream, opts); } |