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