Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: src/images/SkDecodingImageGenerator.cpp

Issue 93703004: Change SkDecodingImageGenerator API (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: rebased Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/images/SkDecodingImageGenerator.h ('k') | src/lazy/SkCachingPixelRef.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkData.h"
8 #include "SkDecodingImageGenerator.h" 9 #include "SkDecodingImageGenerator.h"
9 #include "SkData.h"
10 #include "SkImageDecoder.h" 10 #include "SkImageDecoder.h"
11 #include "SkImageInfo.h"
11 #include "SkImageGenerator.h" 12 #include "SkImageGenerator.h"
12 #include "SkImagePriv.h" 13 #include "SkImagePriv.h"
13 #include "SkStream.h" 14 #include "SkStream.h"
14 15 #include "SkUtils.h"
15 16
16 namespace { 17 namespace {
17 /** 18 /**
18 * Special allocator used by getPixels(). Uses preallocated memory 19 * Special allocator used by getPixels(). Uses preallocated memory
19 * provided. 20 * provided.
20 */ 21 */
21 class TargetAllocator : public SkBitmap::Allocator { 22 class TargetAllocator : public SkBitmap::Allocator {
22 public: 23 public:
23 TargetAllocator(void* target, size_t rowBytes, const SkImageInfo& info) 24 TargetAllocator(void* target,
25 size_t rowBytes,
26 int width,
27 int height,
28 SkBitmap::Config config)
24 : fTarget(target) 29 : fTarget(target)
25 , fRowBytes(rowBytes) 30 , fRowBytes(rowBytes)
26 , fInfo(info) { } 31 , fWidth(width)
32 , fHeight(height)
33 , fConfig(config) { }
27 34
28 virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE { 35 bool isReady() { return (fTarget != NULL); }
29 if ((SkImageInfoToBitmapConfig(fInfo) != bm->config()) 36
30 || (bm->width() != fInfo.fWidth) 37 virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) {
31 || (bm->height() != fInfo.fHeight)) { 38 if ((NULL == fTarget)
32 return false; 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);
33 } 45 }
34 bm->setConfig(bm->config(), bm->width(), bm->height(), 46 // make sure fRowBytes is correct.
35 fRowBytes, bm->alphaType()); 47 bm->setConfig(fConfig, fWidth, fHeight, fRowBytes, bm->alphaType());
36 bm->setPixels(fTarget, ct); 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!
37 return true; 53 return true;
38 } 54 }
39 55
40 private: 56 private:
41 void* fTarget; 57 void* fTarget; // Block of memory to be supplied as pixel memory
42 size_t fRowBytes; 58 // in allocPixelRef. Must be large enough to hold
43 SkImageInfo fInfo; 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;
44 typedef SkBitmap::Allocator INHERITED; 71 typedef SkBitmap::Allocator INHERITED;
45 }; 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
46 } // namespace 89 } // namespace
47 //////////////////////////////////////////////////////////////////////////////// 90 ////////////////////////////////////////////////////////////////////////////////
48 91
49 SkDecodingImageGenerator::SkDecodingImageGenerator(SkData* data) 92 SkDecodingImageGenerator::SkDecodingImageGenerator(
93 SkData* data,
94 SkStreamRewindable* stream,
95 const SkImageInfo& info,
96 int sampleSize,
97 bool ditherImage,
98 SkBitmap::Config requestedConfig)
50 : fData(data) 99 : fData(data)
51 , fHasInfo(false)
52 , fDoCopyTo(false) {
53 SkASSERT(fData != NULL);
54 fStream = SkNEW_ARGS(SkMemoryStream, (fData));
55 SkASSERT(fStream != NULL);
56 SkASSERT(fStream->unique());
57 fData->ref();
58 }
59
60 SkDecodingImageGenerator::SkDecodingImageGenerator(SkStreamRewindable* stream)
61 : fData(NULL)
62 , fStream(stream) 100 , fStream(stream)
63 , fHasInfo(false) 101 , fInfo(info)
64 , fDoCopyTo(false) { 102 , fSampleSize(sampleSize)
65 SkASSERT(fStream != NULL); 103 , fDitherImage(ditherImage)
66 SkASSERT(fStream->unique()); 104 , fRequestedConfig(requestedConfig) {
105 SkASSERT(stream != NULL);
106 SkSafeRef(fData); // may be NULL.
67 } 107 }
68 108
69 SkDecodingImageGenerator::~SkDecodingImageGenerator() { 109 SkDecodingImageGenerator::~SkDecodingImageGenerator() {
70 SkSafeUnref(fData); 110 SkSafeUnref(fData);
71 fStream->unref(); 111 fStream->unref();
72 } 112 }
73 113
74 // TODO(halcanary): Give this macro a better name and move it into SkTypes.h 114 bool SkDecodingImageGenerator::getInfo(SkImageInfo* info) {
75 #ifdef SK_DEBUG 115 if (info != NULL) {
76 #define SkCheckResult(expr, value) SkASSERT((value) == (expr)) 116 *info = fInfo;
77 #else 117 }
78 #define SkCheckResult(expr, value) (void)(expr) 118 return true;
79 #endif 119 }
80 120
81 SkData* SkDecodingImageGenerator::refEncodedData() { 121 SkData* SkDecodingImageGenerator::refEncodedData() {
82 // This functionality is used in `gm --serialize` 122 // This functionality is used in `gm --serialize`
123 // Does not encode options.
83 if (fData != NULL) { 124 if (fData != NULL) {
84 return SkSafeRef(fData); 125 return SkSafeRef(fData);
85 } 126 }
86 // TODO(halcanary): SkStreamRewindable needs a refData() function 127 // TODO(halcanary): SkStreamRewindable needs a refData() function
87 // which returns a cheap copy of the underlying data. 128 // which returns a cheap copy of the underlying data.
88 if (!fStream->rewind()) { 129 if (!fStream->rewind()) {
89 return NULL; 130 return NULL;
90 } 131 }
91 size_t length = fStream->getLength(); 132 size_t length = fStream->getLength();
92 if (0 == length) { 133 if (0 == length) {
93 return NULL; 134 return NULL;
94 } 135 }
95 void* buffer = sk_malloc_flags(length, 0); 136 void* buffer = sk_malloc_flags(length, 0);
96 SkCheckResult(fStream->read(buffer, length), length); 137 SkCheckResult(fStream->read(buffer, length), length);
97 fData = SkData::NewFromMalloc(buffer, length); 138 fData = SkData::NewFromMalloc(buffer, length);
98 return SkSafeRef(fData); 139 return SkSafeRef(fData);
99 } 140 }
100 141
101 bool SkDecodingImageGenerator::getInfo(SkImageInfo* info) {
102 // info can be NULL. If so, will update fInfo, fDoCopyTo, and fHasInfo.
103 if (fHasInfo) {
104 if (info != NULL) {
105 *info = fInfo;
106 }
107 return true;
108 }
109 SkAssertResult(fStream->rewind());
110 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
111 if (NULL == decoder.get()) {
112 return false;
113 }
114 SkBitmap bitmap;
115 if (!decoder->decode(fStream, &bitmap,
116 SkImageDecoder::kDecodeBounds_Mode)) {
117 return false;
118 }
119 if (bitmap.config() == SkBitmap::kNo_Config) {
120 return false;
121 }
122 if (!bitmap.asImageInfo(&fInfo)) {
123 // We can't use bitmap.config() as is.
124 if (!bitmap.canCopyTo(SkBitmap::kARGB_8888_Config)) {
125 SkDEBUGFAIL("!bitmap->canCopyTo(SkBitmap::kARGB_8888_Config)");
126 return false;
127 }
128 fDoCopyTo = true;
129 fInfo.fWidth = bitmap.width();
130 fInfo.fHeight = bitmap.height();
131 fInfo.fColorType = kPMColor_SkColorType;
132 fInfo.fAlphaType = bitmap.alphaType();
133 }
134 if (info != NULL) {
135 *info = fInfo;
136 }
137 fHasInfo = true;
138 return true;
139 }
140
141 bool SkDecodingImageGenerator::getPixels(const SkImageInfo& info, 142 bool SkDecodingImageGenerator::getPixels(const SkImageInfo& info,
142 void* pixels, 143 void* pixels,
143 size_t rowBytes) { 144 size_t rowBytes) {
144 if (NULL == pixels) { 145 if (NULL == pixels) {
145 return false; 146 return false;
146 } 147 }
147 if (!this->getInfo(NULL)) { 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.
148 return false; 152 return false;
149 } 153 }
150 if (SkImageInfoToBitmapConfig(info) == SkBitmap::kNo_Config) { 154 int bpp = SkBitmap::ComputeBytesPerPixel(fRequestedConfig);
151 return false; // Unsupported SkColorType. 155 if (static_cast<size_t>(bpp * info.fWidth) > rowBytes) {
156 // The caller has specified a bad rowBytes.
157 return false;
152 } 158 }
159
153 SkAssertResult(fStream->rewind()); 160 SkAssertResult(fStream->rewind());
154 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream)); 161 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
155 if (NULL == decoder.get()) { 162 if (NULL == decoder.get()) {
156 return false; 163 return false;
157 } 164 }
158 if (fInfo != info) { 165 decoder->setDitherImage(fDitherImage);
159 // The caller has specified a different info. For now, this 166 decoder->setSampleSize(fSampleSize);
160 // is an error. In the future, we will check to see if we can 167
161 // convert.
162 return false;
163 }
164 int bpp = SkBitmap::ComputeBytesPerPixel(SkImageInfoToBitmapConfig(info));
165 if (static_cast<size_t>(bpp * info.fWidth) > rowBytes) {
166 return false;
167 }
168 SkBitmap bitmap; 168 SkBitmap bitmap;
169 if (!bitmap.setConfig(info, rowBytes)) { 169 TargetAllocator allocator(pixels, rowBytes, info.fWidth,
170 return false; 170 info.fHeight, fRequestedConfig);
171 } 171 decoder->setAllocator(&allocator);
172 172 bool success = decoder->decode(fStream, &bitmap, fRequestedConfig,
173 TargetAllocator allocator(pixels, rowBytes, info);
174 if (!fDoCopyTo) {
175 decoder->setAllocator(&allocator);
176 }
177 bool success = decoder->decode(fStream, &bitmap,
178 SkImageDecoder::kDecodePixels_Mode); 173 SkImageDecoder::kDecodePixels_Mode);
179 decoder->setAllocator(NULL); 174 decoder->setAllocator(NULL);
180 if (!success) { 175 if (!success) {
181 return false; 176 return false;
182 } 177 }
183 if (fDoCopyTo) { 178 if (allocator.isReady()) { // Did not use pixels!
184 SkBitmap bm8888; 179 SkBitmap bm;
185 bitmap.copyTo(&bm8888, SkBitmap::kARGB_8888_Config, &allocator); 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()));
186 } 190 }
187 return true; 191 return true;
188 } 192 }
189 bool SkDecodingImageGenerator::Install(SkData* data, SkBitmap* dst, 193
190 SkDiscardableMemory::Factory* factory) { 194 SkImageGenerator* SkDecodingImageGenerator::Create(
195 SkData* data,
196 const SkDecodingImageGenerator::Options& opts) {
191 SkASSERT(data != NULL); 197 SkASSERT(data != NULL);
192 SkASSERT(dst != NULL); 198 if (NULL == data) {
193 SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (data))); 199 return NULL;
194 return SkInstallDiscardablePixelRef(gen, dst, factory); 200 }
201 SkStreamRewindable* stream = SkNEW_ARGS(SkMemoryStream, (data));
202 SkASSERT(stream != NULL);
203 SkASSERT(stream->unique());
204 return SkDecodingImageGenerator::Create(data, stream, opts);
195 } 205 }
196 206
197 bool SkDecodingImageGenerator::Install(SkStreamRewindable* stream, 207 SkImageGenerator* SkDecodingImageGenerator::Create(
198 SkBitmap* dst, 208 SkStreamRewindable* stream,
199 SkDiscardableMemory::Factory* factory) { 209 const SkDecodingImageGenerator::Options& opts) {
200 SkASSERT(stream != NULL); 210 SkASSERT(stream != NULL);
201 SkASSERT(dst != NULL); 211 SkASSERT(stream->unique());
202 if ((stream == NULL) || !stream->unique()) { 212 if ((stream == NULL) || !stream->unique()) {
203 SkSafeUnref(stream); 213 SkSafeUnref(stream);
204 return false; 214 return NULL;
205 } 215 }
206 SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (stream))); 216 return SkDecodingImageGenerator::Create(NULL, stream, opts);
207 return SkInstallDiscardablePixelRef(gen, dst, factory);
208 } 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 // Sanity check.
280 SkDEBUGCODE(SkColorType tmp;)
281 SkASSERT(SkBitmapConfigToColorType(config, &tmp));
282 SkASSERT(tmp == opts.fRequestedColorType);
283 }
284 return SkNEW_ARGS(SkDecodingImageGenerator,
285 (data, autoStream.detach(), info,
286 opts.fSampleSize, opts.fDitherImage, config));
287 }
OLDNEW
« no previous file with comments | « src/images/SkDecodingImageGenerator.h ('k') | src/lazy/SkCachingPixelRef.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698