blob: 16c2820b92fcc236c9c1cde031a844bf8423610b [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
reed@android.coma14ea0e2009-03-17 17:59:53 +000060SkImageDecoderFactory* SkImageRef::setDecoderFactory(
61 SkImageDecoderFactory* fact) {
62 SkRefCnt_SafeAssign(fFactory, fact);
63 return fact;
64}
65
reed@android.com8a1c16f2008-12-17 15:59:43 +000066///////////////////////////////////////////////////////////////////////////////
67
68bool SkImageRef::onDecode(SkImageDecoder* codec, SkStream* stream,
69 SkBitmap* bitmap, SkBitmap::Config config,
70 SkImageDecoder::Mode mode) {
71 return codec->decode(stream, bitmap, config, mode);
72}
73
74bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) {
75 SkASSERT(&gImageRefMutex == this->mutex());
76
77 if (fErrorInDecoding) {
78 return false;
79 }
reed@google.com82065d62011-02-07 15:30:46 +000080
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 /* As soon as we really know our config, we record it, so that on
82 subsequent calls to the codec, we are sure we will always get the same
83 result.
84 */
85 if (SkBitmap::kNo_Config != fBitmap.config()) {
86 fConfig = fBitmap.config();
87 }
reed@google.com82065d62011-02-07 15:30:46 +000088
reed@android.com8a1c16f2008-12-17 15:59:43 +000089 if (NULL != fBitmap.getPixels() ||
90 (SkBitmap::kNo_Config != fBitmap.config() &&
91 SkImageDecoder::kDecodeBounds_Mode == mode)) {
92 return true;
93 }
94
95 SkASSERT(fBitmap.getPixels() == NULL);
96
97 fStream->rewind();
reed@android.coma14ea0e2009-03-17 17:59:53 +000098
99 SkImageDecoder* codec;
100 if (fFactory) {
101 codec = fFactory->newDecoder(fStream);
102 } else {
103 codec = SkImageDecoder::Factory(fStream);
104 }
105
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106 if (codec) {
107 SkAutoTDelete<SkImageDecoder> ad(codec);
108
109 codec->setSampleSize(fSampleSize);
reed@android.combb9aea92009-09-24 17:21:05 +0000110 codec->setDitherImage(fDoDither);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000111 if (this->onDecode(codec, fStream, &fBitmap, fConfig, mode)) {
112 return true;
113 }
114 }
115
116#ifdef DUMP_IMAGEREF_LIFECYCLE
117 if (NULL == codec) {
118 SkDebugf("--- ImageRef: <%s> failed to find codec\n", this->getURI());
119 } else {
120 SkDebugf("--- ImageRef: <%s> failed in codec for %d mode\n",
121 this->getURI(), mode);
122 }
123#endif
124 fErrorInDecoding = true;
125 fBitmap.reset();
126 return false;
127}
128
129void* SkImageRef::onLockPixels(SkColorTable** ct) {
130 SkASSERT(&gImageRefMutex == this->mutex());
131
132 if (NULL == fBitmap.getPixels()) {
133 (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode);
134 }
135
136 if (ct) {
137 *ct = fBitmap.getColorTable();
138 }
139 return fBitmap.getPixels();
140}
141
142void SkImageRef::onUnlockPixels() {
143 // we're already have the mutex locked
144 SkASSERT(&gImageRefMutex == this->mutex());
145}
146
147size_t SkImageRef::ramUsed() const {
148 size_t size = 0;
149
150 if (fBitmap.getPixels()) {
151 size = fBitmap.getSize();
152 if (fBitmap.getColorTable()) {
153 size += fBitmap.getColorTable()->count() * sizeof(SkPMColor);
154 }
155 }
156 return size;
157}
158
159///////////////////////////////////////////////////////////////////////////////
160
161SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer)
162 : INHERITED(buffer, &gImageRefMutex), fErrorInDecoding(false) {
163 fConfig = (SkBitmap::Config)buffer.readU8();
164 fSampleSize = buffer.readU8();
reed@android.comc6ddc112009-11-10 15:54:55 +0000165 fDoDither = buffer.readBool();
166
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167 size_t length = buffer.readU32();
168 fStream = SkNEW_ARGS(SkMemoryStream, (length));
169 buffer.read((void*)fStream->getMemoryBase(), length);
170
171 fPrev = fNext = NULL;
reed@android.com797d51a2009-03-20 12:08:57 +0000172 fFactory = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173}
174
175void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const {
176 this->INHERITED::flatten(buffer);
177
178 buffer.write8(fConfig);
179 buffer.write8(fSampleSize);
reed@android.comc6ddc112009-11-10 15:54:55 +0000180 buffer.writeBool(fDoDither);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181 size_t length = fStream->getLength();
182 buffer.write32(length);
183 fStream->rewind();
184 buffer.readFromStream(fStream, length);
185}
186