• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "SkDecodingImageGenerator.h"
9 #include "SkData.h"
10 #include "SkImageDecoder.h"
11 #include "SkImageGenerator.h"
12 #include "SkImagePriv.h"
13 #include "SkStream.h"
14 
15 
16 namespace {
17 /**
18  *  Special allocator used by getPixels(). Uses preallocated memory
19  *  provided.
20  */
21 class TargetAllocator : public SkBitmap::Allocator {
22 public:
TargetAllocator(void * target,size_t rowBytes,const SkImageInfo & info)23     TargetAllocator(void* target, size_t rowBytes, const SkImageInfo& info)
24         : fTarget(target)
25         , fRowBytes(rowBytes)
26         , fInfo(info) { }
27 
allocPixelRef(SkBitmap * bm,SkColorTable * ct)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 
40 private:
41     void* fTarget;
42     size_t fRowBytes;
43     SkImageInfo fInfo;
44     typedef SkBitmap::Allocator INHERITED;
45 };
46 }  // namespace
47 ////////////////////////////////////////////////////////////////////////////////
48 
SkDecodingImageGenerator(SkData * data)49 SkDecodingImageGenerator::SkDecodingImageGenerator(SkData* data)
50     : 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 
SkDecodingImageGenerator(SkStreamRewindable * stream)60 SkDecodingImageGenerator::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 
~SkDecodingImageGenerator()69 SkDecodingImageGenerator::~SkDecodingImageGenerator() {
70     SkSafeUnref(fData);
71     fStream->unref();
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 
refEncodedData()81 SkData* SkDecodingImageGenerator::refEncodedData() {
82     // This functionality is used in `gm --serialize`
83     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);
99 }
100 
getInfo(SkImageInfo * info)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 
getPixels(const SkImageInfo & info,void * pixels,size_t rowBytes)141 bool SkDecodingImageGenerator::getPixels(const SkImageInfo& info,
142                                          void* pixels,
143                                          size_t rowBytes) {
144     if (NULL == pixels) {
145         return false;
146     }
147     if (!this->getInfo(NULL)) {
148         return false;
149     }
150     if (SkImageInfoToBitmapConfig(info) == SkBitmap::kNo_Config) {
151         return false;  // Unsupported SkColorType.
152     }
153     SkAssertResult(fStream->rewind());
154     SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
155     if (NULL == decoder.get()) {
156         return false;
157     }
158     if (fInfo != info) {
159         // The caller has specified a different info.  For now, this
160         // is an error.  In the future, we will check to see if we can
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;
169     if (!bitmap.setConfig(info, rowBytes)) {
170         return false;
171     }
172 
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);
179     decoder->setAllocator(NULL);
180     if (!success) {
181         return false;
182     }
183     if (fDoCopyTo) {
184         SkBitmap bm8888;
185         bitmap.copyTo(&bm8888, SkBitmap::kARGB_8888_Config, &allocator);
186     }
187     return true;
188 }
Install(SkData * data,SkBitmap * dst,SkDiscardableMemory::Factory * factory)189 bool SkDecodingImageGenerator::Install(SkData* data, SkBitmap* dst,
190                                        SkDiscardableMemory::Factory* factory) {
191     SkASSERT(data != NULL);
192     SkASSERT(dst != NULL);
193     SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (data)));
194     return SkInstallDiscardablePixelRef(gen, dst, factory);
195 }
196 
Install(SkStreamRewindable * stream,SkBitmap * dst,SkDiscardableMemory::Factory * factory)197 bool SkDecodingImageGenerator::Install(SkStreamRewindable* stream,
198                                        SkBitmap* dst,
199                                        SkDiscardableMemory::Factory* factory) {
200     SkASSERT(stream != NULL);
201     SkASSERT(dst != NULL);
202     if ((stream == NULL) || !stream->unique()) {
203         SkSafeUnref(stream);
204         return false;
205     }
206     SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (stream)));
207     return SkInstallDiscardablePixelRef(gen, dst, factory);
208 }
209