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