• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 #include "SkImageRef.h"
9 #include "SkBitmap.h"
10 #include "SkFlattenableBuffers.h"
11 #include "SkImageDecoder.h"
12 #include "SkStream.h"
13 #include "SkTemplates.h"
14 #include "SkThread.h"
15 
16 //#define DUMP_IMAGEREF_LIFECYCLE
17 
18 
19 ///////////////////////////////////////////////////////////////////////////////
20 
SkImageRef(const SkImageInfo & info,SkStreamRewindable * stream,int sampleSize,SkBaseMutex * mutex)21 SkImageRef::SkImageRef(const SkImageInfo& info, SkStreamRewindable* stream,
22                        int sampleSize, SkBaseMutex* mutex)
23         : SkPixelRef(info, mutex), fErrorInDecoding(false) {
24     SkASSERT(stream);
25     stream->ref();
26     fStream = stream;
27     fSampleSize = sampleSize;
28     fDoDither = true;
29     fPrev = fNext = NULL;
30     fFactory = NULL;
31 
32     // This sets the colortype/alphatype to exactly match our info, so that this
33     // can get communicated down to the codec.
34     fBitmap.setConfig(info);
35 
36 #ifdef DUMP_IMAGEREF_LIFECYCLE
37     SkDebugf("add ImageRef %p [%d] data=%d\n",
38               this, this->info().fColorType, (int)stream->getLength());
39 #endif
40 }
41 
~SkImageRef()42 SkImageRef::~SkImageRef() {
43 
44 #ifdef DUMP_IMAGEREF_LIFECYCLE
45     SkDebugf("delete ImageRef %p [%d] data=%d\n",
46               this, fConfig, (int)fStream->getLength());
47 #endif
48 
49     fStream->unref();
50     SkSafeUnref(fFactory);
51 }
52 
getInfo(SkBitmap * bitmap)53 bool SkImageRef::getInfo(SkBitmap* bitmap) {
54     SkAutoMutexAcquire ac(this->mutex());
55 
56     if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) {
57         return false;
58     }
59 
60     SkASSERT(SkBitmap::kNo_Config != fBitmap.config());
61     if (bitmap) {
62         bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height());
63     }
64     return true;
65 }
66 
isOpaque(SkBitmap * bitmap)67 bool SkImageRef::isOpaque(SkBitmap* bitmap) {
68     if (bitmap && bitmap->pixelRef() == this) {
69         bitmap->lockPixels();
70         // what about colortables??????
71         bitmap->setAlphaType(fBitmap.alphaType());
72         bitmap->unlockPixels();
73         return true;
74     }
75     return false;
76 }
77 
setDecoderFactory(SkImageDecoderFactory * fact)78 SkImageDecoderFactory* SkImageRef::setDecoderFactory(
79                                                 SkImageDecoderFactory* fact) {
80     SkRefCnt_SafeAssign(fFactory, fact);
81     return fact;
82 }
83 
84 ///////////////////////////////////////////////////////////////////////////////
85 
onDecode(SkImageDecoder * codec,SkStreamRewindable * stream,SkBitmap * bitmap,SkBitmap::Config config,SkImageDecoder::Mode mode)86 bool SkImageRef::onDecode(SkImageDecoder* codec, SkStreamRewindable* stream,
87                           SkBitmap* bitmap, SkBitmap::Config config,
88                           SkImageDecoder::Mode mode) {
89     return codec->decode(stream, bitmap, config, mode);
90 }
91 
prepareBitmap(SkImageDecoder::Mode mode)92 bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) {
93 
94     if (fErrorInDecoding) {
95         return false;
96     }
97 
98     if (NULL != fBitmap.getPixels() ||
99             (SkBitmap::kNo_Config != fBitmap.config() &&
100              SkImageDecoder::kDecodeBounds_Mode == mode)) {
101         return true;
102     }
103 
104     SkASSERT(fBitmap.getPixels() == NULL);
105 
106     if (!fStream->rewind()) {
107         SkDEBUGF(("Failed to rewind SkImageRef stream!"));
108         return false;
109     }
110 
111     SkImageDecoder* codec;
112     if (fFactory) {
113         codec = fFactory->newDecoder(fStream);
114     } else {
115         codec = SkImageDecoder::Factory(fStream);
116     }
117 
118     if (codec) {
119         SkAutoTDelete<SkImageDecoder> ad(codec);
120 
121         codec->setSampleSize(fSampleSize);
122         codec->setDitherImage(fDoDither);
123         if (this->onDecode(codec, fStream, &fBitmap, fBitmap.config(), mode)) {
124             SkDEBUGCODE(SkImageInfo info;)
125             SkASSERT(!fBitmap.asImageInfo(&info) || this->info().fColorType == info.fColorType);
126             SkASSERT(this->info().fWidth == fBitmap.width());
127             SkASSERT(this->info().fHeight == fBitmap.height());
128             return true;
129         }
130     }
131 
132 #ifdef DUMP_IMAGEREF_LIFECYCLE
133     if (NULL == codec) {
134         SkDebugf("--- ImageRef: <%s> failed to find codec\n", this->getURI());
135     } else {
136         SkDebugf("--- ImageRef: <%s> failed in codec for %d mode\n",
137                  this->getURI(), mode);
138     }
139 #endif
140     fErrorInDecoding = true;
141     fBitmap.reset();
142     return false;
143 }
144 
onLockPixels(SkColorTable ** ct)145 void* SkImageRef::onLockPixels(SkColorTable** ct) {
146     if (NULL == fBitmap.getPixels()) {
147         (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode);
148     }
149 
150     if (ct) {
151         *ct = fBitmap.getColorTable();
152     }
153     return fBitmap.getPixels();
154 }
155 
ramUsed() const156 size_t SkImageRef::ramUsed() const {
157     size_t size = 0;
158 
159     if (fBitmap.getPixels()) {
160         size = fBitmap.getSize();
161         if (fBitmap.getColorTable()) {
162             size += fBitmap.getColorTable()->count() * sizeof(SkPMColor);
163         }
164     }
165     return size;
166 }
167 
168 ///////////////////////////////////////////////////////////////////////////////
169 
SkImageRef(SkFlattenableReadBuffer & buffer,SkBaseMutex * mutex)170 SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
171         : INHERITED(buffer, mutex), fErrorInDecoding(false) {
172     fSampleSize = buffer.readInt();
173     fDoDither = buffer.readBool();
174 
175     size_t length = buffer.getArrayCount();
176     fStream = SkNEW_ARGS(SkMemoryStream, (length));
177     buffer.readByteArray((void*)fStream->getMemoryBase(), length);
178 
179     fPrev = fNext = NULL;
180     fFactory = NULL;
181 
182     // This sets the colortype/alphatype to exactly match our info, so that this
183     // can get communicated down to the codec.
184     fBitmap.setConfig(this->info());
185 }
186 
flatten(SkFlattenableWriteBuffer & buffer) const187 void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const {
188     this->INHERITED::flatten(buffer);
189 
190     buffer.writeInt(fSampleSize);
191     buffer.writeBool(fDoDither);
192     // FIXME: Consider moving this logic should go into writeStream itself.
193     // writeStream currently has no other callers, so this may be fine for
194     // now.
195     if (!fStream->rewind()) {
196         SkDEBUGF(("Failed to rewind SkImageRef stream!"));
197         buffer.write32(0);
198     } else {
199         // FIXME: Handle getLength properly here. Perhaps this class should
200         // take an SkStreamAsset.
201         buffer.writeStream(fStream, fStream->getLength());
202     }
203 }
204