1/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkData.h"
9#include "SkDecodingImageGenerator.h"
10#include "SkImageDecoder.h"
11#include "SkImageInfo.h"
12#include "SkImageGenerator.h"
13#include "SkImagePriv.h"
14#include "SkStream.h"
15#include "SkUtils.h"
16
17namespace {
18bool equal_modulo_alpha(const SkImageInfo& a, const SkImageInfo& b) {
19    return a.width() == b.width() && a.height() == b.height() &&
20           a.colorType() == b.colorType();
21}
22
23class DecodingImageGenerator : public SkImageGenerator {
24public:
25    virtual ~DecodingImageGenerator();
26
27    SkData*                fData;
28    SkStreamRewindable*    fStream;
29    const SkImageInfo      fInfo;
30    const int              fSampleSize;
31    const bool             fDitherImage;
32
33    DecodingImageGenerator(SkData* data,
34                           SkStreamRewindable* stream,
35                           const SkImageInfo& info,
36                           int sampleSize,
37                           bool ditherImage);
38
39protected:
40    virtual SkData* onRefEncodedData() SK_OVERRIDE;
41    virtual bool onGetInfo(SkImageInfo* info) SK_OVERRIDE {
42        *info = fInfo;
43        return true;
44    }
45    virtual bool onGetPixels(const SkImageInfo& info,
46                             void* pixels, size_t rowBytes,
47                             SkPMColor ctable[], int* ctableCount) SK_OVERRIDE;
48
49private:
50    typedef SkImageGenerator INHERITED;
51};
52
53/**
54 *  Special allocator used by getPixels(). Uses preallocated memory
55 *  provided if possible, else fall-back on the default allocator
56 */
57class TargetAllocator : public SkBitmap::Allocator {
58public:
59    TargetAllocator(const SkImageInfo& info,
60                    void* target,
61                    size_t rowBytes)
62        : fInfo(info)
63        , fTarget(target)
64        , fRowBytes(rowBytes)
65    {}
66
67    bool isReady() { return (fTarget != NULL); }
68
69    virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) {
70        if (NULL == fTarget || !equal_modulo_alpha(fInfo, bm->info())) {
71            // Call default allocator.
72            return bm->tryAllocPixels(NULL, ct);
73        }
74
75        // TODO(halcanary): verify that all callers of this function
76        // will respect new RowBytes.  Will be moot once rowbytes belongs
77        // to PixelRef.
78        bm->installPixels(fInfo, fTarget, fRowBytes, ct, NULL, NULL);
79
80        fTarget = NULL;  // never alloc same pixels twice!
81        return true;
82    }
83
84private:
85    const SkImageInfo fInfo;
86    void* fTarget;  // Block of memory to be supplied as pixel memory
87                    // in allocPixelRef.  Must be large enough to hold
88                    // a bitmap described by fInfo and fRowBytes
89    const size_t fRowBytes;  // rowbytes for the destination bitmap
90
91    typedef SkBitmap::Allocator INHERITED;
92};
93
94// TODO(halcanary): Give this macro a better name and move it into SkTypes.h
95#ifdef SK_DEBUG
96    #define SkCheckResult(expr, value)  SkASSERT((value) == (expr))
97#else
98    #define SkCheckResult(expr, value)  (void)(expr)
99#endif
100
101#ifdef SK_DEBUG
102inline bool check_alpha(SkAlphaType reported, SkAlphaType actual) {
103    return ((reported == actual)
104            || ((reported == kPremul_SkAlphaType)
105                && (actual == kOpaque_SkAlphaType)));
106}
107#endif  // SK_DEBUG
108
109////////////////////////////////////////////////////////////////////////////////
110
111DecodingImageGenerator::DecodingImageGenerator(
112        SkData* data,
113        SkStreamRewindable* stream,
114        const SkImageInfo& info,
115        int sampleSize,
116        bool ditherImage)
117    : fData(data)
118    , fStream(stream)
119    , fInfo(info)
120    , fSampleSize(sampleSize)
121    , fDitherImage(ditherImage)
122{
123    SkASSERT(stream != NULL);
124    SkSafeRef(fData);  // may be NULL.
125}
126
127DecodingImageGenerator::~DecodingImageGenerator() {
128    SkSafeUnref(fData);
129    fStream->unref();
130}
131
132SkData* DecodingImageGenerator::onRefEncodedData() {
133    // This functionality is used in `gm --serialize`
134    // Does not encode options.
135    if (NULL == fData) {
136        // TODO(halcanary): SkStreamRewindable needs a refData() function
137        // which returns a cheap copy of the underlying data.
138        if (!fStream->rewind()) {
139            return NULL;
140        }
141        size_t length = fStream->getLength();
142        if (length) {
143            fData = SkData::NewFromStream(fStream, length);
144        }
145    }
146    return SkSafeRef(fData);
147}
148
149bool DecodingImageGenerator::onGetPixels(const SkImageInfo& info,
150                                         void* pixels, size_t rowBytes,
151                                         SkPMColor ctableEntries[], int* ctableCount) {
152    if (fInfo != info) {
153        // The caller has specified a different info.  This is an
154        // error for this kind of SkImageGenerator.  Use the Options
155        // to change the settings.
156        return false;
157    }
158
159    SkAssertResult(fStream->rewind());
160    SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
161    if (NULL == decoder.get()) {
162        return false;
163    }
164    decoder->setDitherImage(fDitherImage);
165    decoder->setSampleSize(fSampleSize);
166    decoder->setRequireUnpremultipliedColors(info.alphaType() == kUnpremul_SkAlphaType);
167
168    SkBitmap bitmap;
169    TargetAllocator allocator(fInfo, pixels, rowBytes);
170    decoder->setAllocator(&allocator);
171    bool success = decoder->decode(fStream, &bitmap, info.colorType(),
172                                   SkImageDecoder::kDecodePixels_Mode);
173    decoder->setAllocator(NULL);
174    if (!success) {
175        return false;
176    }
177    if (allocator.isReady()) {  // Did not use pixels!
178        SkBitmap bm;
179        SkASSERT(bitmap.canCopyTo(info.colorType()));
180        bool copySuccess = bitmap.copyTo(&bm, info.colorType(), &allocator);
181        if (!copySuccess || allocator.isReady()) {
182            SkDEBUGFAIL("bitmap.copyTo(requestedConfig) failed.");
183            // Earlier we checked canCopyto(); we expect consistency.
184            return false;
185        }
186        SkASSERT(check_alpha(info.alphaType(), bm.alphaType()));
187    } else {
188        SkASSERT(check_alpha(info.alphaType(), bitmap.alphaType()));
189    }
190
191    if (kIndex_8_SkColorType == info.colorType()) {
192        if (kIndex_8_SkColorType != bitmap.colorType()) {
193            return false;   // they asked for Index8, but we didn't receive that from decoder
194        }
195        SkColorTable* ctable = bitmap.getColorTable();
196        if (NULL == ctable) {
197            return false;
198        }
199        const int count = ctable->count();
200        memcpy(ctableEntries, ctable->lockColors(), count * sizeof(SkPMColor));
201        ctable->unlockColors();
202        *ctableCount = count;
203    }
204    return true;
205}
206
207// A contructor-type function that returns NULL on failure.  This
208// prevents the returned SkImageGenerator from ever being in a bad
209// state.  Called by both Create() functions
210SkImageGenerator* CreateDecodingImageGenerator(
211        SkData* data,
212        SkStreamRewindable* stream,
213        const SkDecodingImageGenerator::Options& opts) {
214    SkASSERT(stream);
215    SkAutoTUnref<SkStreamRewindable> autoStream(stream);  // always unref this.
216    SkAssertResult(autoStream->rewind());
217    SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(autoStream));
218    if (NULL == decoder.get()) {
219        return NULL;
220    }
221    SkBitmap bitmap;
222    decoder->setSampleSize(opts.fSampleSize);
223    decoder->setRequireUnpremultipliedColors(opts.fRequireUnpremul);
224    if (!decoder->decode(stream, &bitmap, SkImageDecoder::kDecodeBounds_Mode)) {
225        return NULL;
226    }
227    if (kUnknown_SkColorType == bitmap.colorType()) {
228        return NULL;
229    }
230
231    SkImageInfo info = bitmap.info();
232
233    if (opts.fUseRequestedColorType && (opts.fRequestedColorType != info.colorType())) {
234        if (!bitmap.canCopyTo(opts.fRequestedColorType)) {
235            SkASSERT(bitmap.colorType() != opts.fRequestedColorType);
236            return NULL;  // Can not translate to needed config.
237        }
238        info = info.makeColorType(opts.fRequestedColorType);
239    }
240
241    if (opts.fRequireUnpremul && info.alphaType() != kOpaque_SkAlphaType) {
242        info = info.makeAlphaType(kUnpremul_SkAlphaType);
243    }
244
245    SkAlphaType newAlphaType = info.alphaType();
246    if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAlphaType)) {
247        return NULL;
248    }
249
250    return SkNEW_ARGS(DecodingImageGenerator,
251                      (data, autoStream.detach(), info.makeAlphaType(newAlphaType),
252                       opts.fSampleSize, opts.fDitherImage));
253}
254
255}  // namespace
256
257////////////////////////////////////////////////////////////////////////////////
258
259SkImageGenerator* SkDecodingImageGenerator::Create(
260        SkData* data,
261        const SkDecodingImageGenerator::Options& opts) {
262    SkASSERT(data != NULL);
263    if (NULL == data) {
264        return NULL;
265    }
266    SkStreamRewindable* stream = SkNEW_ARGS(SkMemoryStream, (data));
267    SkASSERT(stream != NULL);
268    SkASSERT(stream->unique());
269    return CreateDecodingImageGenerator(data, stream, opts);
270}
271
272SkImageGenerator* SkDecodingImageGenerator::Create(
273        SkStreamRewindable* stream,
274        const SkDecodingImageGenerator::Options& opts) {
275    SkASSERT(stream != NULL);
276    SkASSERT(stream->unique());
277    if ((stream == NULL) || !stream->unique()) {
278        SkSafeUnref(stream);
279        return NULL;
280    }
281    return CreateDecodingImageGenerator(NULL, stream, opts);
282}
283