Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / 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 /**
19  *  Special allocator used by getPixels(). Uses preallocated memory
20  *  provided.
21  */
22 class TargetAllocator : public SkBitmap::Allocator {
23 public:
24     TargetAllocator(void* target,
25                     size_t rowBytes,
26                     int width,
27                     int height,
28                     SkBitmap::Config config)
29         : fTarget(target)
30         , fRowBytes(rowBytes)
31         , fWidth(width)
32         , fHeight(height)
33         , fConfig(config) { }
34
35     bool isReady() { return (fTarget != NULL); }
36
37     virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) {
38         if ((NULL == fTarget)
39             || (fConfig != bm->config())
40             || (fWidth != bm->width())
41             || (fHeight != bm->height())
42             || (ct != NULL)) {
43             // Call default allocator.
44             return bm->allocPixels(NULL, ct);
45         }
46         // make sure fRowBytes is correct.
47         bm->setConfig(fConfig, fWidth, fHeight, fRowBytes, bm->alphaType());
48         // TODO(halcanary): verify that all callers of this function
49         // will respect new RowBytes.  Will be moot once rowbytes belongs
50         // to PixelRef.
51         bm->setPixels(fTarget, NULL);
52         fTarget = NULL;  // never alloc same pixels twice!
53         return true;
54     }
55
56 private:
57     void* fTarget;  // Block of memory to be supplied as pixel memory
58                     // in allocPixelRef.  Must be large enough to hold
59                     // a bitmap described by fWidth, fHeight, and
60                     // fRowBytes.
61     size_t fRowBytes;  // rowbytes for the destination bitmap
62     int fWidth;   // Along with fHeight and fConfig, the information
63     int fHeight;  // about the bitmap whose pixels this allocator is
64                   // expected to allocate. If they do not match the
65                   // bitmap passed to allocPixelRef, it is assumed
66                   // that the bitmap will be copied to a bitmap with
67                   // the correct info using this allocator, so the
68                   // default allocator will be used instead of
69                   // fTarget.
70     SkBitmap::Config fConfig;
71     typedef SkBitmap::Allocator INHERITED;
72 };
73
74 // TODO(halcanary): Give this macro a better name and move it into SkTypes.h
75 #ifdef SK_DEBUG
76     #define SkCheckResult(expr, value)  SkASSERT((value) == (expr))
77 #else
78     #define SkCheckResult(expr, value)  (void)(expr)
79 #endif
80
81 #ifdef SK_DEBUG
82 inline bool check_alpha(SkAlphaType reported, SkAlphaType actual) {
83     return ((reported == actual)
84             || ((reported == kPremul_SkAlphaType)
85                 && (actual == kOpaque_SkAlphaType)));
86 }
87 #endif  // SK_DEBUG
88
89 }  // namespace
90 ////////////////////////////////////////////////////////////////////////////////
91
92 SkDecodingImageGenerator::SkDecodingImageGenerator(
93         SkData* data,
94         SkStreamRewindable* stream,
95         const SkImageInfo& info,
96         int sampleSize,
97         bool ditherImage,
98         SkBitmap::Config requestedConfig)
99     : fData(data)
100     , fStream(stream)
101     , fInfo(info)
102     , fSampleSize(sampleSize)
103     , fDitherImage(ditherImage)
104     , fRequestedConfig(requestedConfig) {
105     SkASSERT(stream != NULL);
106     SkSafeRef(fData);  // may be NULL.
107 }
108
109 SkDecodingImageGenerator::~SkDecodingImageGenerator() {
110     SkSafeUnref(fData);
111     fStream->unref();
112 }
113
114 bool SkDecodingImageGenerator::getInfo(SkImageInfo* info) {
115     if (info != NULL) {
116         *info = fInfo;
117     }
118     return true;
119 }
120
121 SkData* SkDecodingImageGenerator::refEncodedData() {
122     // This functionality is used in `gm --serialize`
123     // Does not encode options.
124     if (fData != NULL) {
125         return SkSafeRef(fData);
126     }
127     // TODO(halcanary): SkStreamRewindable needs a refData() function
128     // which returns a cheap copy of the underlying data.
129     if (!fStream->rewind()) {
130         return NULL;
131     }
132     size_t length = fStream->getLength();
133     if (0 == length) {
134         return NULL;
135     }
136     void* buffer = sk_malloc_flags(length, 0);
137     SkCheckResult(fStream->read(buffer, length), length);
138     fData = SkData::NewFromMalloc(buffer, length);
139     return SkSafeRef(fData);
140 }
141
142 bool SkDecodingImageGenerator::getPixels(const SkImageInfo& info,
143                                          void* pixels,
144                                          size_t rowBytes) {
145     if (NULL == pixels) {
146         return false;
147     }
148     if (fInfo != info) {
149         // The caller has specified a different info.  This is an
150         // error for this kind of SkImageGenerator.  Use the Options
151         // to change the settings.
152         return false;
153     }
154     int bpp = SkBitmap::ComputeBytesPerPixel(fRequestedConfig);
155     if (static_cast<size_t>(bpp * info.fWidth) > rowBytes) {
156         // The caller has specified a bad rowBytes.
157         return false;
158     }
159
160     SkAssertResult(fStream->rewind());
161     SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
162     if (NULL == decoder.get()) {
163         return false;
164     }
165     decoder->setDitherImage(fDitherImage);
166     decoder->setSampleSize(fSampleSize);
167
168     SkBitmap bitmap;
169     TargetAllocator allocator(pixels, rowBytes, info.fWidth,
170                               info.fHeight, fRequestedConfig);
171     decoder->setAllocator(&allocator);
172     bool success = decoder->decode(fStream, &bitmap, fRequestedConfig,
173                                    SkImageDecoder::kDecodePixels_Mode);
174     decoder->setAllocator(NULL);
175     if (!success) {
176         return false;
177     }
178     if (allocator.isReady()) {  // Did not use pixels!
179         SkBitmap bm;
180         SkASSERT(bitmap.canCopyTo(fRequestedConfig));
181         if (!bitmap.copyTo(&bm, fRequestedConfig, &allocator)
182             || allocator.isReady()) {
183             SkDEBUGFAIL("bitmap.copyTo(requestedConfig) failed.");
184             // Earlier we checked canCopyto(); we expect consistency.
185             return false;
186         }
187         SkASSERT(check_alpha(fInfo.fAlphaType, bm.alphaType()));
188     } else {
189         SkASSERT(check_alpha(fInfo.fAlphaType, bitmap.alphaType()));
190     }
191     return true;
192 }
193
194 SkImageGenerator* SkDecodingImageGenerator::Create(
195         SkData* data,
196         const SkDecodingImageGenerator::Options& opts) {
197     SkASSERT(data != NULL);
198     if (NULL == data) {
199         return NULL;
200     }
201     SkStreamRewindable* stream = SkNEW_ARGS(SkMemoryStream, (data));
202     SkASSERT(stream != NULL);
203     SkASSERT(stream->unique());
204     return SkDecodingImageGenerator::Create(data, stream, opts);
205 }
206
207 SkImageGenerator* SkDecodingImageGenerator::Create(
208         SkStreamRewindable* stream,
209         const SkDecodingImageGenerator::Options& opts) {
210     SkASSERT(stream != NULL);
211     SkASSERT(stream->unique());
212     if ((stream == NULL) || !stream->unique()) {
213         SkSafeUnref(stream);
214         return NULL;
215     }
216     return SkDecodingImageGenerator::Create(NULL, stream, opts);
217 }
218
219 // A contructor-type function that returns NULL on failure.  This
220 // prevents the returned SkImageGenerator from ever being in a bad
221 // state.  Called by both Create() functions
222 SkImageGenerator* SkDecodingImageGenerator::Create(
223         SkData* data,
224         SkStreamRewindable* stream,
225         const SkDecodingImageGenerator::Options& opts) {
226     SkASSERT(stream);
227     SkAutoTUnref<SkStreamRewindable> autoStream(stream);  // always unref this.
228     if (opts.fUseRequestedColorType &&
229         (kIndex_8_SkColorType == opts.fRequestedColorType)) {
230         // We do not support indexed color with SkImageGenerators,
231         return NULL;
232     }
233     SkAssertResult(autoStream->rewind());
234     SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(autoStream));
235     if (NULL == decoder.get()) {
236         return NULL;
237     }
238     SkBitmap bitmap;
239     decoder->setSampleSize(opts.fSampleSize);
240     if (!decoder->decode(stream, &bitmap,
241                          SkImageDecoder::kDecodeBounds_Mode)) {
242         return NULL;
243     }
244     if (bitmap.config() == SkBitmap::kNo_Config) {
245         return NULL;
246     }
247
248     SkImageInfo info;
249     SkBitmap::Config config;
250
251     if (!opts.fUseRequestedColorType) {
252         // Use default config.
253         if (SkBitmap::kIndex8_Config == bitmap.config()) {
254             // We don't support kIndex8 because we don't support
255             // colortables in this workflow.
256             config = SkBitmap::kARGB_8888_Config;
257             info.fWidth = bitmap.width();
258             info.fHeight = bitmap.height();
259             info.fColorType = kPMColor_SkColorType;
260             info.fAlphaType = bitmap.alphaType();
261         } else {
262             config = bitmap.config();  // Save for later!
263             if (!bitmap.asImageInfo(&info)) {
264                 SkDEBUGFAIL("Getting SkImageInfo from bitmap failed.");
265                 return NULL;
266             }
267         }
268     } else {
269         config = SkColorTypeToBitmapConfig(opts.fRequestedColorType);
270         if (!bitmap.canCopyTo(config)) {
271             SkASSERT(bitmap.config() != config);
272             return NULL;  // Can not translate to needed config.
273         }
274         info.fWidth = bitmap.width();
275         info.fHeight = bitmap.height();
276         info.fColorType = opts.fRequestedColorType;
277         info.fAlphaType = bitmap.alphaType();
278     }
279     return SkNEW_ARGS(SkDecodingImageGenerator,
280                       (data, autoStream.detach(), info,
281                        opts.fSampleSize, opts.fDitherImage, config));
282 }