gfx/skia/trunk/src/images/SkDecodingImageGenerator.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/images/SkDecodingImageGenerator.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,256 @@
     1.4 +/*
     1.5 + * Copyright 2013 Google Inc.
     1.6 + *
     1.7 + * Use of this source code is governed by a BSD-style license that can be
     1.8 + * found in the LICENSE file.
     1.9 + */
    1.10 +
    1.11 +#include "SkData.h"
    1.12 +#include "SkDecodingImageGenerator.h"
    1.13 +#include "SkImageDecoder.h"
    1.14 +#include "SkImageInfo.h"
    1.15 +#include "SkImageGenerator.h"
    1.16 +#include "SkImagePriv.h"
    1.17 +#include "SkStream.h"
    1.18 +#include "SkUtils.h"
    1.19 +
    1.20 +static bool equal_modulo_alpha(const SkImageInfo& a, const SkImageInfo& b) {
    1.21 +    return a.width() == b.width() && a.height() == b.height() &&
    1.22 +           a.colorType() == b.colorType();
    1.23 +}
    1.24 +
    1.25 +namespace {
    1.26 +/**
    1.27 + *  Special allocator used by getPixels(). Uses preallocated memory
    1.28 + *  provided if possible, else fall-back on the default allocator
    1.29 + */
    1.30 +class TargetAllocator : public SkBitmap::Allocator {
    1.31 +public:
    1.32 +    TargetAllocator(const SkImageInfo& info,
    1.33 +                    void* target,
    1.34 +                    size_t rowBytes)
    1.35 +        : fInfo(info)
    1.36 +        , fTarget(target)
    1.37 +        , fRowBytes(rowBytes)
    1.38 +    {}
    1.39 +
    1.40 +    bool isReady() { return (fTarget != NULL); }
    1.41 +
    1.42 +    virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) {
    1.43 +        if (NULL == fTarget || !equal_modulo_alpha(fInfo, bm->info())) {
    1.44 +            // Call default allocator.
    1.45 +            return bm->allocPixels(NULL, ct);
    1.46 +        }
    1.47 +
    1.48 +        // TODO(halcanary): verify that all callers of this function
    1.49 +        // will respect new RowBytes.  Will be moot once rowbytes belongs
    1.50 +        // to PixelRef.
    1.51 +        bm->installPixels(fInfo, fTarget, fRowBytes, NULL, NULL);
    1.52 +
    1.53 +        fTarget = NULL;  // never alloc same pixels twice!
    1.54 +        return true;
    1.55 +    }
    1.56 +
    1.57 +private:
    1.58 +    const SkImageInfo fInfo;
    1.59 +    void* fTarget;  // Block of memory to be supplied as pixel memory
    1.60 +                    // in allocPixelRef.  Must be large enough to hold
    1.61 +                    // a bitmap described by fInfo and fRowBytes
    1.62 +    const size_t fRowBytes;  // rowbytes for the destination bitmap
    1.63 +
    1.64 +    typedef SkBitmap::Allocator INHERITED;
    1.65 +};
    1.66 +
    1.67 +// TODO(halcanary): Give this macro a better name and move it into SkTypes.h
    1.68 +#ifdef SK_DEBUG
    1.69 +    #define SkCheckResult(expr, value)  SkASSERT((value) == (expr))
    1.70 +#else
    1.71 +    #define SkCheckResult(expr, value)  (void)(expr)
    1.72 +#endif
    1.73 +
    1.74 +#ifdef SK_DEBUG
    1.75 +inline bool check_alpha(SkAlphaType reported, SkAlphaType actual) {
    1.76 +    return ((reported == actual)
    1.77 +            || ((reported == kPremul_SkAlphaType)
    1.78 +                && (actual == kOpaque_SkAlphaType)));
    1.79 +}
    1.80 +#endif  // SK_DEBUG
    1.81 +
    1.82 +}  // namespace
    1.83 +////////////////////////////////////////////////////////////////////////////////
    1.84 +
    1.85 +SkDecodingImageGenerator::SkDecodingImageGenerator(
    1.86 +        SkData* data,
    1.87 +        SkStreamRewindable* stream,
    1.88 +        const SkImageInfo& info,
    1.89 +        int sampleSize,
    1.90 +        bool ditherImage)
    1.91 +    : fData(data)
    1.92 +    , fStream(stream)
    1.93 +    , fInfo(info)
    1.94 +    , fSampleSize(sampleSize)
    1.95 +    , fDitherImage(ditherImage)
    1.96 +{
    1.97 +    SkASSERT(stream != NULL);
    1.98 +    SkSafeRef(fData);  // may be NULL.
    1.99 +}
   1.100 +
   1.101 +SkDecodingImageGenerator::~SkDecodingImageGenerator() {
   1.102 +    SkSafeUnref(fData);
   1.103 +    fStream->unref();
   1.104 +}
   1.105 +
   1.106 +bool SkDecodingImageGenerator::getInfo(SkImageInfo* info) {
   1.107 +    if (info != NULL) {
   1.108 +        *info = fInfo;
   1.109 +    }
   1.110 +    return true;
   1.111 +}
   1.112 +
   1.113 +SkData* SkDecodingImageGenerator::refEncodedData() {
   1.114 +    // This functionality is used in `gm --serialize`
   1.115 +    // Does not encode options.
   1.116 +    if (fData != NULL) {
   1.117 +        return SkSafeRef(fData);
   1.118 +    }
   1.119 +    // TODO(halcanary): SkStreamRewindable needs a refData() function
   1.120 +    // which returns a cheap copy of the underlying data.
   1.121 +    if (!fStream->rewind()) {
   1.122 +        return NULL;
   1.123 +    }
   1.124 +    size_t length = fStream->getLength();
   1.125 +    if (0 == length) {
   1.126 +        return NULL;
   1.127 +    }
   1.128 +    void* buffer = sk_malloc_flags(length, 0);
   1.129 +    SkCheckResult(fStream->read(buffer, length), length);
   1.130 +    fData = SkData::NewFromMalloc(buffer, length);
   1.131 +    return SkSafeRef(fData);
   1.132 +}
   1.133 +
   1.134 +bool SkDecodingImageGenerator::getPixels(const SkImageInfo& info,
   1.135 +                                         void* pixels,
   1.136 +                                         size_t rowBytes) {
   1.137 +    if (NULL == pixels) {
   1.138 +        return false;
   1.139 +    }
   1.140 +    if (fInfo != info) {
   1.141 +        // The caller has specified a different info.  This is an
   1.142 +        // error for this kind of SkImageGenerator.  Use the Options
   1.143 +        // to change the settings.
   1.144 +        return false;
   1.145 +    }
   1.146 +    if (info.minRowBytes() > rowBytes) {
   1.147 +        // The caller has specified a bad rowBytes.
   1.148 +        return false;
   1.149 +    }
   1.150 +
   1.151 +    SkAssertResult(fStream->rewind());
   1.152 +    SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
   1.153 +    if (NULL == decoder.get()) {
   1.154 +        return false;
   1.155 +    }
   1.156 +    decoder->setDitherImage(fDitherImage);
   1.157 +    decoder->setSampleSize(fSampleSize);
   1.158 +
   1.159 +    SkBitmap bitmap;
   1.160 +    TargetAllocator allocator(fInfo, pixels, rowBytes);
   1.161 +    decoder->setAllocator(&allocator);
   1.162 +    // TODO: need to be able to pass colortype directly to decoder
   1.163 +    SkBitmap::Config legacyConfig = SkColorTypeToBitmapConfig(info.colorType());
   1.164 +    bool success = decoder->decode(fStream, &bitmap, legacyConfig,
   1.165 +                                   SkImageDecoder::kDecodePixels_Mode);
   1.166 +    decoder->setAllocator(NULL);
   1.167 +    if (!success) {
   1.168 +        return false;
   1.169 +    }
   1.170 +    if (allocator.isReady()) {  // Did not use pixels!
   1.171 +        SkBitmap bm;
   1.172 +        SkASSERT(bitmap.canCopyTo(info.colorType()));
   1.173 +        bool copySuccess = bitmap.copyTo(&bm, info.colorType(), &allocator);
   1.174 +        if (!copySuccess || allocator.isReady()) {
   1.175 +            SkDEBUGFAIL("bitmap.copyTo(requestedConfig) failed.");
   1.176 +            // Earlier we checked canCopyto(); we expect consistency.
   1.177 +            return false;
   1.178 +        }
   1.179 +        SkASSERT(check_alpha(info.alphaType(), bm.alphaType()));
   1.180 +    } else {
   1.181 +        SkASSERT(check_alpha(info.alphaType(), bitmap.alphaType()));
   1.182 +    }
   1.183 +    return true;
   1.184 +}
   1.185 +
   1.186 +SkImageGenerator* SkDecodingImageGenerator::Create(
   1.187 +        SkData* data,
   1.188 +        const SkDecodingImageGenerator::Options& opts) {
   1.189 +    SkASSERT(data != NULL);
   1.190 +    if (NULL == data) {
   1.191 +        return NULL;
   1.192 +    }
   1.193 +    SkStreamRewindable* stream = SkNEW_ARGS(SkMemoryStream, (data));
   1.194 +    SkASSERT(stream != NULL);
   1.195 +    SkASSERT(stream->unique());
   1.196 +    return SkDecodingImageGenerator::Create(data, stream, opts);
   1.197 +}
   1.198 +
   1.199 +SkImageGenerator* SkDecodingImageGenerator::Create(
   1.200 +        SkStreamRewindable* stream,
   1.201 +        const SkDecodingImageGenerator::Options& opts) {
   1.202 +    SkASSERT(stream != NULL);
   1.203 +    SkASSERT(stream->unique());
   1.204 +    if ((stream == NULL) || !stream->unique()) {
   1.205 +        SkSafeUnref(stream);
   1.206 +        return NULL;
   1.207 +    }
   1.208 +    return SkDecodingImageGenerator::Create(NULL, stream, opts);
   1.209 +}
   1.210 +
   1.211 +// A contructor-type function that returns NULL on failure.  This
   1.212 +// prevents the returned SkImageGenerator from ever being in a bad
   1.213 +// state.  Called by both Create() functions
   1.214 +SkImageGenerator* SkDecodingImageGenerator::Create(
   1.215 +        SkData* data,
   1.216 +        SkStreamRewindable* stream,
   1.217 +        const SkDecodingImageGenerator::Options& opts) {
   1.218 +    SkASSERT(stream);
   1.219 +    SkAutoTUnref<SkStreamRewindable> autoStream(stream);  // always unref this.
   1.220 +    if (opts.fUseRequestedColorType &&
   1.221 +        (kIndex_8_SkColorType == opts.fRequestedColorType)) {
   1.222 +        // We do not support indexed color with SkImageGenerators,
   1.223 +        return NULL;
   1.224 +    }
   1.225 +    SkAssertResult(autoStream->rewind());
   1.226 +    SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(autoStream));
   1.227 +    if (NULL == decoder.get()) {
   1.228 +        return NULL;
   1.229 +    }
   1.230 +    SkBitmap bitmap;
   1.231 +    decoder->setSampleSize(opts.fSampleSize);
   1.232 +    if (!decoder->decode(stream, &bitmap,
   1.233 +                         SkImageDecoder::kDecodeBounds_Mode)) {
   1.234 +        return NULL;
   1.235 +    }
   1.236 +    if (bitmap.config() == SkBitmap::kNo_Config) {
   1.237 +        return NULL;
   1.238 +    }
   1.239 +
   1.240 +    SkImageInfo info = bitmap.info();
   1.241 +
   1.242 +    if (!opts.fUseRequestedColorType) {
   1.243 +        // Use default
   1.244 +        if (kIndex_8_SkColorType == bitmap.colorType()) {
   1.245 +            // We don't support kIndex8 because we don't support
   1.246 +            // colortables in this workflow.
   1.247 +            info.fColorType = kPMColor_SkColorType;
   1.248 +        }
   1.249 +    } else {
   1.250 +        if (!bitmap.canCopyTo(opts.fRequestedColorType)) {
   1.251 +            SkASSERT(bitmap.colorType() != opts.fRequestedColorType);
   1.252 +            return NULL;  // Can not translate to needed config.
   1.253 +        }
   1.254 +        info.fColorType = opts.fRequestedColorType;
   1.255 +    }
   1.256 +    return SkNEW_ARGS(SkDecodingImageGenerator,
   1.257 +                      (data, autoStream.detach(), info,
   1.258 +                       opts.fSampleSize, opts.fDitherImage));
   1.259 +}

mercurial