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