blob: 7d2d41629a1033bf85a44c590f9b0bccb6d15086 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SkImageRef.h"
2#include "SkBitmap.h"
3#include "SkFlattenable.h"
4#include "SkImageDecoder.h"
5#include "SkStream.h"
6#include "SkTemplates.h"
7#include "SkThread.h"
8
reed@android.comc6ddc112009-11-10 15:54:55 +00009//#define DUMP_IMAGEREF_LIFECYCLE
10
reed@android.com8a1c16f2008-12-17 15:59:43 +000011// can't be static, as SkImageRef_Pool needs to see it
12SkMutex gImageRefMutex;
13
14///////////////////////////////////////////////////////////////////////////////
15
16SkImageRef::SkImageRef(SkStream* stream, SkBitmap::Config config,
17 int sampleSize)
18 : SkPixelRef(&gImageRefMutex), fErrorInDecoding(false) {
19 SkASSERT(stream);
reed@android.com1337a7b2009-03-16 13:56:10 +000020 stream->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +000021 fStream = stream;
22 fConfig = config;
23 fSampleSize = sampleSize;
reed@android.combb9aea92009-09-24 17:21:05 +000024 fDoDither = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +000025 fPrev = fNext = NULL;
reed@android.coma14ea0e2009-03-17 17:59:53 +000026 fFactory = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000027
28#ifdef DUMP_IMAGEREF_LIFECYCLE
29 SkDebugf("add ImageRef %p [%d] data=%d\n",
30 this, config, (int)stream->getLength());
31#endif
32}
33
34SkImageRef::~SkImageRef() {
35 SkASSERT(&gImageRefMutex == this->mutex());
36
37#ifdef DUMP_IMAGEREF_LIFECYCLE
38 SkDebugf("delete ImageRef %p [%d] data=%d\n",
39 this, fConfig, (int)fStream->getLength());
40#endif
41
reed@android.com1337a7b2009-03-16 13:56:10 +000042 fStream->unref();
reed@google.com82065d62011-02-07 15:30:46 +000043 SkSafeUnref(fFactory);
reed@android.com8a1c16f2008-12-17 15:59:43 +000044}
45
46bool SkImageRef::getInfo(SkBitmap* bitmap) {
47 SkAutoMutexAcquire ac(gImageRefMutex);
reed@google.com82065d62011-02-07 15:30:46 +000048
reed@android.com8a1c16f2008-12-17 15:59:43 +000049 if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) {
50 return false;
51 }
reed@google.com82065d62011-02-07 15:30:46 +000052
reed@android.com8a1c16f2008-12-17 15:59:43 +000053 SkASSERT(SkBitmap::kNo_Config != fBitmap.config());
54 if (bitmap) {
55 bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height());
56 }
57 return true;
58}
59
djsollen@google.com57f49692011-02-23 20:46:31 +000060bool SkImageRef::isOpaque(SkBitmap* bitmap) {
61 if (bitmap && bitmap->pixelRef() == this) {
62 bitmap->lockPixels();
63 bitmap->setIsOpaque(fBitmap.isOpaque());
64 bitmap->unlockPixels();
65 return true;
66 }
67 return false;
68}
69
reed@android.coma14ea0e2009-03-17 17:59:53 +000070SkImageDecoderFactory* SkImageRef::setDecoderFactory(
71 SkImageDecoderFactory* fact) {
72 SkRefCnt_SafeAssign(fFactory, fact);
73 return fact;
74}
75
reed@android.com8a1c16f2008-12-17 15:59:43 +000076///////////////////////////////////////////////////////////////////////////////
77
78bool SkImageRef::onDecode(SkImageDecoder* codec, SkStream* stream,
79 SkBitmap* bitmap, SkBitmap::Config config,
80 SkImageDecoder::Mode mode) {
81 return codec->decode(stream, bitmap, config, mode);
82}
83
84bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) {
85 SkASSERT(&gImageRefMutex == this->mutex());
86
87 if (fErrorInDecoding) {
88 return false;
89 }
reed@google.com82065d62011-02-07 15:30:46 +000090
reed@android.com8a1c16f2008-12-17 15:59:43 +000091 /* As soon as we really know our config, we record it, so that on
92 subsequent calls to the codec, we are sure we will always get the same
93 result.
94 */
95 if (SkBitmap::kNo_Config != fBitmap.config()) {
96 fConfig = fBitmap.config();
97 }
reed@google.com82065d62011-02-07 15:30:46 +000098
reed@android.com8a1c16f2008-12-17 15:59:43 +000099 if (NULL != fBitmap.getPixels() ||
100 (SkBitmap::kNo_Config != fBitmap.config() &&
101 SkImageDecoder::kDecodeBounds_Mode == mode)) {
102 return true;
103 }
104
105 SkASSERT(fBitmap.getPixels() == NULL);
106
107 fStream->rewind();
reed@android.coma14ea0e2009-03-17 17:59:53 +0000108
109 SkImageDecoder* codec;
110 if (fFactory) {
111 codec = fFactory->newDecoder(fStream);
112 } else {
113 codec = SkImageDecoder::Factory(fStream);
114 }
115
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116 if (codec) {
117 SkAutoTDelete<SkImageDecoder> ad(codec);
118
119 codec->setSampleSize(fSampleSize);
reed@android.combb9aea92009-09-24 17:21:05 +0000120 codec->setDitherImage(fDoDither);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121 if (this->onDecode(codec, fStream, &fBitmap, fConfig, mode)) {
122 return true;
123 }
124 }
125
126#ifdef DUMP_IMAGEREF_LIFECYCLE
127 if (NULL == codec) {
128 SkDebugf("--- ImageRef: <%s> failed to find codec\n", this->getURI());
129 } else {
130 SkDebugf("--- ImageRef: <%s> failed in codec for %d mode\n",
131 this->getURI(), mode);
132 }
133#endif
134 fErrorInDecoding = true;
135 fBitmap.reset();
136 return false;
137}
138
139void* SkImageRef::onLockPixels(SkColorTable** ct) {
140 SkASSERT(&gImageRefMutex == this->mutex());
141
142 if (NULL == fBitmap.getPixels()) {
143 (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode);
144 }
145
146 if (ct) {
147 *ct = fBitmap.getColorTable();
148 }
149 return fBitmap.getPixels();
150}
151
152void SkImageRef::onUnlockPixels() {
153 // we're already have the mutex locked
154 SkASSERT(&gImageRefMutex == this->mutex());
155}
156
157size_t SkImageRef::ramUsed() const {
158 size_t size = 0;
159
160 if (fBitmap.getPixels()) {
161 size = fBitmap.getSize();
162 if (fBitmap.getColorTable()) {
163 size += fBitmap.getColorTable()->count() * sizeof(SkPMColor);
164 }
165 }
166 return size;
167}
168
169///////////////////////////////////////////////////////////////////////////////
170
171SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer)
172 : INHERITED(buffer, &gImageRefMutex), fErrorInDecoding(false) {
173 fConfig = (SkBitmap::Config)buffer.readU8();
174 fSampleSize = buffer.readU8();
reed@android.comc6ddc112009-11-10 15:54:55 +0000175 fDoDither = buffer.readBool();
176
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 size_t length = buffer.readU32();
178 fStream = SkNEW_ARGS(SkMemoryStream, (length));
179 buffer.read((void*)fStream->getMemoryBase(), length);
180
181 fPrev = fNext = NULL;
reed@android.com797d51a2009-03-20 12:08:57 +0000182 fFactory = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183}
184
185void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const {
186 this->INHERITED::flatten(buffer);
187
188 buffer.write8(fConfig);
189 buffer.write8(fSampleSize);
reed@android.comc6ddc112009-11-10 15:54:55 +0000190 buffer.writeBool(fDoDither);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191 size_t length = fStream->getLength();
192 buffer.write32(length);
193 fStream->rewind();
194 buffer.readFromStream(fStream, length);
195}
196