blob: 0865c88595a1fa96a98ee95a5d4d1c7288be9261 [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
9// can't be static, as SkImageRef_Pool needs to see it
10SkMutex gImageRefMutex;
11
12///////////////////////////////////////////////////////////////////////////////
13
14SkImageRef::SkImageRef(SkStream* stream, SkBitmap::Config config,
15 int sampleSize)
16 : SkPixelRef(&gImageRefMutex), fErrorInDecoding(false) {
17 SkASSERT(stream);
reed@android.com1337a7b2009-03-16 13:56:10 +000018 stream->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +000019 fStream = stream;
20 fConfig = config;
21 fSampleSize = sampleSize;
22 fPrev = fNext = NULL;
reed@android.coma14ea0e2009-03-17 17:59:53 +000023 fFactory = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000024
25#ifdef DUMP_IMAGEREF_LIFECYCLE
26 SkDebugf("add ImageRef %p [%d] data=%d\n",
27 this, config, (int)stream->getLength());
28#endif
29}
30
31SkImageRef::~SkImageRef() {
32 SkASSERT(&gImageRefMutex == this->mutex());
33
34#ifdef DUMP_IMAGEREF_LIFECYCLE
35 SkDebugf("delete ImageRef %p [%d] data=%d\n",
36 this, fConfig, (int)fStream->getLength());
37#endif
38
reed@android.com1337a7b2009-03-16 13:56:10 +000039 fStream->unref();
reed@android.coma14ea0e2009-03-17 17:59:53 +000040 fFactory->safeUnref();
reed@android.com8a1c16f2008-12-17 15:59:43 +000041}
42
43bool SkImageRef::getInfo(SkBitmap* bitmap) {
44 SkAutoMutexAcquire ac(gImageRefMutex);
45
46 if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) {
47 return false;
48 }
49
50 SkASSERT(SkBitmap::kNo_Config != fBitmap.config());
51 if (bitmap) {
52 bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height());
53 }
54 return true;
55}
56
reed@android.coma14ea0e2009-03-17 17:59:53 +000057SkImageDecoderFactory* SkImageRef::setDecoderFactory(
58 SkImageDecoderFactory* fact) {
59 SkRefCnt_SafeAssign(fFactory, fact);
60 return fact;
61}
62
reed@android.com8a1c16f2008-12-17 15:59:43 +000063///////////////////////////////////////////////////////////////////////////////
64
65bool SkImageRef::onDecode(SkImageDecoder* codec, SkStream* stream,
66 SkBitmap* bitmap, SkBitmap::Config config,
67 SkImageDecoder::Mode mode) {
68 return codec->decode(stream, bitmap, config, mode);
69}
70
71bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) {
72 SkASSERT(&gImageRefMutex == this->mutex());
73
74 if (fErrorInDecoding) {
75 return false;
76 }
77
78 /* As soon as we really know our config, we record it, so that on
79 subsequent calls to the codec, we are sure we will always get the same
80 result.
81 */
82 if (SkBitmap::kNo_Config != fBitmap.config()) {
83 fConfig = fBitmap.config();
84 }
85
86 if (NULL != fBitmap.getPixels() ||
87 (SkBitmap::kNo_Config != fBitmap.config() &&
88 SkImageDecoder::kDecodeBounds_Mode == mode)) {
89 return true;
90 }
91
92 SkASSERT(fBitmap.getPixels() == NULL);
93
94 fStream->rewind();
reed@android.coma14ea0e2009-03-17 17:59:53 +000095
96 SkImageDecoder* codec;
97 if (fFactory) {
98 codec = fFactory->newDecoder(fStream);
99 } else {
100 codec = SkImageDecoder::Factory(fStream);
101 }
102
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103 if (codec) {
104 SkAutoTDelete<SkImageDecoder> ad(codec);
105
106 codec->setSampleSize(fSampleSize);
107 if (this->onDecode(codec, fStream, &fBitmap, fConfig, mode)) {
108 return true;
109 }
110 }
111
112#ifdef DUMP_IMAGEREF_LIFECYCLE
113 if (NULL == codec) {
114 SkDebugf("--- ImageRef: <%s> failed to find codec\n", this->getURI());
115 } else {
116 SkDebugf("--- ImageRef: <%s> failed in codec for %d mode\n",
117 this->getURI(), mode);
118 }
119#endif
120 fErrorInDecoding = true;
121 fBitmap.reset();
122 return false;
123}
124
125void* SkImageRef::onLockPixels(SkColorTable** ct) {
126 SkASSERT(&gImageRefMutex == this->mutex());
127
128 if (NULL == fBitmap.getPixels()) {
129 (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode);
130 }
131
132 if (ct) {
133 *ct = fBitmap.getColorTable();
134 }
135 return fBitmap.getPixels();
136}
137
138void SkImageRef::onUnlockPixels() {
139 // we're already have the mutex locked
140 SkASSERT(&gImageRefMutex == this->mutex());
141}
142
143size_t SkImageRef::ramUsed() const {
144 size_t size = 0;
145
146 if (fBitmap.getPixels()) {
147 size = fBitmap.getSize();
148 if (fBitmap.getColorTable()) {
149 size += fBitmap.getColorTable()->count() * sizeof(SkPMColor);
150 }
151 }
152 return size;
153}
154
155///////////////////////////////////////////////////////////////////////////////
156
157SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer)
158 : INHERITED(buffer, &gImageRefMutex), fErrorInDecoding(false) {
159 fConfig = (SkBitmap::Config)buffer.readU8();
160 fSampleSize = buffer.readU8();
161 size_t length = buffer.readU32();
162 fStream = SkNEW_ARGS(SkMemoryStream, (length));
163 buffer.read((void*)fStream->getMemoryBase(), length);
164
165 fPrev = fNext = NULL;
166}
167
168void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const {
169 this->INHERITED::flatten(buffer);
170
171 buffer.write8(fConfig);
172 buffer.write8(fSampleSize);
173 size_t length = fStream->getLength();
174 buffer.write32(length);
175 fStream->rewind();
176 buffer.readFromStream(fStream, length);
177}
178