blob: 2b804441417938042168d4ddce2b65232faceb30 [file] [log] [blame]
halcanary@google.comad04eb42013-11-21 15:32:08 +00001/*
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 "SkDecodingImageGenerator.h"
halcanary@google.comad04eb42013-11-21 15:32:08 +00009#include "SkData.h"
10#include "SkDiscardablePixelRef.h"
11#include "SkImageDecoder.h"
halcanary@google.com29d96932013-12-09 13:45:02 +000012#include "SkImagePriv.h"
13#include "SkStream.h"
14
15
16namespace {
17/**
18 * Special allocator used by getPixels(). Uses preallocated memory
19 * provided.
20 */
21class TargetAllocator : public SkBitmap::Allocator {
22public:
23 TargetAllocator(void* target, size_t rowBytes, const SkImageInfo& info)
24 : fTarget(target)
25 , fRowBytes(rowBytes)
26 , fInfo(info) { }
27
28 virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE {
29 if ((SkImageInfoToBitmapConfig(fInfo) != bm->config())
30 || (bm->width() != fInfo.fWidth)
31 || (bm->height() != fInfo.fHeight)) {
32 return false;
33 }
34 bm->setConfig(bm->config(), bm->width(), bm->height(),
35 fRowBytes, bm->alphaType());
36 bm->setPixels(fTarget, ct);
37 return true;
38 }
39
40private:
41 void* fTarget;
42 size_t fRowBytes;
43 SkImageInfo fInfo;
44 typedef SkBitmap::Allocator INHERITED;
45};
46} // namespace
47////////////////////////////////////////////////////////////////////////////////
halcanary@google.comad04eb42013-11-21 15:32:08 +000048
49SkDecodingImageGenerator::SkDecodingImageGenerator(SkData* data)
halcanary@google.com29d96932013-12-09 13:45:02 +000050 : fData(data)
51 , fHasInfo(false)
52 , fDoCopyTo(false) {
halcanary@google.comad04eb42013-11-21 15:32:08 +000053 SkASSERT(fData != NULL);
halcanary@google.com29d96932013-12-09 13:45:02 +000054 fStream = SkNEW_ARGS(SkMemoryStream, (fData));
55 SkASSERT(fStream != NULL);
56 SkASSERT(fStream->unique());
halcanary@google.comad04eb42013-11-21 15:32:08 +000057 fData->ref();
58}
59
halcanary@google.com29d96932013-12-09 13:45:02 +000060SkDecodingImageGenerator::SkDecodingImageGenerator(SkStreamRewindable* stream)
61 : fData(NULL)
62 , fStream(stream)
63 , fHasInfo(false)
64 , fDoCopyTo(false) {
65 SkASSERT(fStream != NULL);
66 SkASSERT(fStream->unique());
67}
68
halcanary@google.comad04eb42013-11-21 15:32:08 +000069SkDecodingImageGenerator::~SkDecodingImageGenerator() {
halcanary@google.com29d96932013-12-09 13:45:02 +000070 SkSafeUnref(fData);
71 fStream->unref();
halcanary@google.comad04eb42013-11-21 15:32:08 +000072}
73
halcanary@google.com29d96932013-12-09 13:45:02 +000074// 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
halcanary@google.comad04eb42013-11-21 15:32:08 +000081SkData* SkDecodingImageGenerator::refEncodedData() {
halcanary@google.com2c7c7ee2013-12-05 18:31:42 +000082 // This functionality is used in `gm --serialize`
halcanary@google.com29d96932013-12-09 13:45:02 +000083 if (fData != NULL) {
84 return SkSafeRef(fData);
85 }
86 // TODO(halcanary): SkStreamRewindable needs a refData() function
87 // which returns a cheap copy of the underlying data.
88 if (!fStream->rewind()) {
89 return NULL;
90 }
91 size_t length = fStream->getLength();
92 if (0 == length) {
93 return NULL;
94 }
95 void* buffer = sk_malloc_flags(length, 0);
96 SkCheckResult(fStream->read(buffer, length), length);
97 fData = SkData::NewFromMalloc(buffer, length);
98 return SkSafeRef(fData);
halcanary@google.comad04eb42013-11-21 15:32:08 +000099}
100
101bool SkDecodingImageGenerator::getInfo(SkImageInfo* info) {
halcanary@google.com29d96932013-12-09 13:45:02 +0000102 // 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 (!SkBitmapToImageInfo(bitmap, &fInfo)) {
123 // We can't use bitmap.config() as is.
124 // Must be kARGB_4444_Config.
125 if (!bitmap.canCopyTo(SkBitmap::kARGB_8888_Config)) {
126 // kARGB_4444_Config can copy to kARGB_8888.
127 SkDEBUGFAIL("!bitmap->canCopyTo(SkBitmap::kARGB_8888_Config)");
128 return false;
129 }
130 fDoCopyTo = true;
131 fInfo.fWidth = bitmap.width();
132 fInfo.fHeight = bitmap.height();
133 fInfo.fColorType = kPMColor_SkColorType;
134 fInfo.fAlphaType = bitmap.alphaType();
135 }
136 if (info != NULL) {
137 *info = fInfo;
138 }
139 fHasInfo = true;
140 return true;
halcanary@google.comad04eb42013-11-21 15:32:08 +0000141}
142
143bool SkDecodingImageGenerator::getPixels(const SkImageInfo& info,
144 void* pixels,
145 size_t rowBytes) {
halcanary@google.com29d96932013-12-09 13:45:02 +0000146 if (NULL == pixels) {
147 return false;
148 }
149 if (!this->getInfo(NULL)) {
150 return false;
151 }
152 if (SkImageInfoToBitmapConfig(info) == SkBitmap::kNo_Config) {
153 return false; // Unsupported SkColorType.
154 }
155 SkAssertResult(fStream->rewind());
156 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
157 if (NULL == decoder.get()) {
158 return false;
159 }
160 if (fInfo != info) {
161 // The caller has specified a different info. For now, this
162 // is an error. In the future, we will check to see if we can
163 // convert.
164 return false;
165 }
166 int bpp = SkBitmap::ComputeBytesPerPixel(SkImageInfoToBitmapConfig(info));
167 if (static_cast<size_t>(bpp * info.fWidth) > rowBytes) {
168 return false;
169 }
170 SkBitmap bitmap;
171 if (!bitmap.setConfig(info, rowBytes)) {
172 return false;
173 }
174
175 TargetAllocator allocator(pixels, rowBytes, info);
176 if (!fDoCopyTo) {
177 decoder->setAllocator(&allocator);
178 }
179 bool success = decoder->decode(fStream, &bitmap,
180 SkImageDecoder::kDecodePixels_Mode);
181 decoder->setAllocator(NULL);
182 if (!success) {
183 return false;
184 }
185 if (fDoCopyTo) {
186 SkBitmap bm8888;
187 bitmap.copyTo(&bm8888, SkBitmap::kARGB_8888_Config, &allocator);
188 }
189 return true;
halcanary@google.comad04eb42013-11-21 15:32:08 +0000190}
halcanary@google.com2c7c7ee2013-12-05 18:31:42 +0000191bool SkDecodingImageGenerator::Install(SkData* data, SkBitmap* dst,
192 SkDiscardableMemory::Factory* factory) {
halcanary@google.comad04eb42013-11-21 15:32:08 +0000193 SkASSERT(data != NULL);
194 SkASSERT(dst != NULL);
195 SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (data)));
halcanary@google.com2c7c7ee2013-12-05 18:31:42 +0000196 return SkDiscardablePixelRef::Install(gen, dst, factory);
halcanary@google.comad04eb42013-11-21 15:32:08 +0000197}
halcanary@google.com29d96932013-12-09 13:45:02 +0000198
199bool SkDecodingImageGenerator::Install(SkStreamRewindable* stream,
200 SkBitmap* dst,
201 SkDiscardableMemory::Factory* factory) {
202 SkASSERT(stream != NULL);
203 SkASSERT(dst != NULL);
204 if ((stream == NULL) || !stream->unique()) {
205 SkSafeUnref(stream);
206 return false;
207 }
208 SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (stream)));
209 return SkDiscardablePixelRef::Install(gen, dst, factory);
210}
211