blob: 1d6b270d6ced0630938ea70a6fdcffc56ee9a1ac [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkImageRef.h"
9#include "SkBitmap.h"
10#include "SkFlattenable.h"
11#include "SkImageDecoder.h"
12#include "SkStream.h"
13#include "SkTemplates.h"
14#include "SkThread.h"
15
reed@android.comc6ddc112009-11-10 15:54:55 +000016//#define DUMP_IMAGEREF_LIFECYCLE
17
reed@android.com8a1c16f2008-12-17 15:59:43 +000018// can't be static, as SkImageRef_Pool needs to see it
digit@google.com1771cbf2012-01-26 21:26:40 +000019SK_DECLARE_GLOBAL_MUTEX(gImageRefMutex);
reed@android.com8a1c16f2008-12-17 15:59:43 +000020
21///////////////////////////////////////////////////////////////////////////////
22
23SkImageRef::SkImageRef(SkStream* stream, SkBitmap::Config config,
24 int sampleSize)
25 : SkPixelRef(&gImageRefMutex), fErrorInDecoding(false) {
26 SkASSERT(stream);
reed@android.com1337a7b2009-03-16 13:56:10 +000027 stream->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +000028 fStream = stream;
29 fConfig = config;
30 fSampleSize = sampleSize;
reed@android.combb9aea92009-09-24 17:21:05 +000031 fDoDither = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +000032 fPrev = fNext = NULL;
reed@android.coma14ea0e2009-03-17 17:59:53 +000033 fFactory = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000034
35#ifdef DUMP_IMAGEREF_LIFECYCLE
36 SkDebugf("add ImageRef %p [%d] data=%d\n",
37 this, config, (int)stream->getLength());
38#endif
39}
40
41SkImageRef::~SkImageRef() {
42 SkASSERT(&gImageRefMutex == this->mutex());
43
44#ifdef DUMP_IMAGEREF_LIFECYCLE
45 SkDebugf("delete ImageRef %p [%d] data=%d\n",
46 this, fConfig, (int)fStream->getLength());
47#endif
48
reed@android.com1337a7b2009-03-16 13:56:10 +000049 fStream->unref();
reed@google.com82065d62011-02-07 15:30:46 +000050 SkSafeUnref(fFactory);
reed@android.com8a1c16f2008-12-17 15:59:43 +000051}
52
53bool SkImageRef::getInfo(SkBitmap* bitmap) {
54 SkAutoMutexAcquire ac(gImageRefMutex);
reed@google.com82065d62011-02-07 15:30:46 +000055
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) {
57 return false;
58 }
reed@google.com82065d62011-02-07 15:30:46 +000059
reed@android.com8a1c16f2008-12-17 15:59:43 +000060 SkASSERT(SkBitmap::kNo_Config != fBitmap.config());
61 if (bitmap) {
62 bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height());
63 }
64 return true;
65}
66
djsollen@google.com57f49692011-02-23 20:46:31 +000067bool SkImageRef::isOpaque(SkBitmap* bitmap) {
68 if (bitmap && bitmap->pixelRef() == this) {
69 bitmap->lockPixels();
70 bitmap->setIsOpaque(fBitmap.isOpaque());
71 bitmap->unlockPixels();
72 return true;
73 }
74 return false;
75}
76
reed@android.coma14ea0e2009-03-17 17:59:53 +000077SkImageDecoderFactory* SkImageRef::setDecoderFactory(
78 SkImageDecoderFactory* fact) {
79 SkRefCnt_SafeAssign(fFactory, fact);
80 return fact;
81}
82
reed@android.com8a1c16f2008-12-17 15:59:43 +000083///////////////////////////////////////////////////////////////////////////////
84
85bool SkImageRef::onDecode(SkImageDecoder* codec, SkStream* stream,
86 SkBitmap* bitmap, SkBitmap::Config config,
87 SkImageDecoder::Mode mode) {
88 return codec->decode(stream, bitmap, config, mode);
89}
90
91bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) {
92 SkASSERT(&gImageRefMutex == this->mutex());
93
94 if (fErrorInDecoding) {
95 return false;
96 }
reed@google.com82065d62011-02-07 15:30:46 +000097
reed@android.com8a1c16f2008-12-17 15:59:43 +000098 /* As soon as we really know our config, we record it, so that on
99 subsequent calls to the codec, we are sure we will always get the same
100 result.
101 */
102 if (SkBitmap::kNo_Config != fBitmap.config()) {
103 fConfig = fBitmap.config();
104 }
reed@google.com82065d62011-02-07 15:30:46 +0000105
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106 if (NULL != fBitmap.getPixels() ||
107 (SkBitmap::kNo_Config != fBitmap.config() &&
108 SkImageDecoder::kDecodeBounds_Mode == mode)) {
109 return true;
110 }
111
112 SkASSERT(fBitmap.getPixels() == NULL);
113
114 fStream->rewind();
reed@android.coma14ea0e2009-03-17 17:59:53 +0000115
116 SkImageDecoder* codec;
117 if (fFactory) {
118 codec = fFactory->newDecoder(fStream);
119 } else {
120 codec = SkImageDecoder::Factory(fStream);
121 }
122
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123 if (codec) {
124 SkAutoTDelete<SkImageDecoder> ad(codec);
125
126 codec->setSampleSize(fSampleSize);
reed@android.combb9aea92009-09-24 17:21:05 +0000127 codec->setDitherImage(fDoDither);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 if (this->onDecode(codec, fStream, &fBitmap, fConfig, mode)) {
129 return true;
130 }
131 }
132
133#ifdef DUMP_IMAGEREF_LIFECYCLE
134 if (NULL == codec) {
135 SkDebugf("--- ImageRef: <%s> failed to find codec\n", this->getURI());
136 } else {
137 SkDebugf("--- ImageRef: <%s> failed in codec for %d mode\n",
138 this->getURI(), mode);
139 }
140#endif
141 fErrorInDecoding = true;
142 fBitmap.reset();
143 return false;
144}
145
146void* SkImageRef::onLockPixels(SkColorTable** ct) {
147 SkASSERT(&gImageRefMutex == this->mutex());
148
149 if (NULL == fBitmap.getPixels()) {
150 (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode);
151 }
152
153 if (ct) {
154 *ct = fBitmap.getColorTable();
155 }
156 return fBitmap.getPixels();
157}
158
159void SkImageRef::onUnlockPixels() {
160 // we're already have the mutex locked
161 SkASSERT(&gImageRefMutex == this->mutex());
162}
163
164size_t SkImageRef::ramUsed() const {
165 size_t size = 0;
166
167 if (fBitmap.getPixels()) {
168 size = fBitmap.getSize();
169 if (fBitmap.getColorTable()) {
170 size += fBitmap.getColorTable()->count() * sizeof(SkPMColor);
171 }
172 }
173 return size;
174}
175
176///////////////////////////////////////////////////////////////////////////////
177
178SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer)
179 : INHERITED(buffer, &gImageRefMutex), fErrorInDecoding(false) {
180 fConfig = (SkBitmap::Config)buffer.readU8();
181 fSampleSize = buffer.readU8();
reed@android.comc6ddc112009-11-10 15:54:55 +0000182 fDoDither = buffer.readBool();
183
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184 size_t length = buffer.readU32();
185 fStream = SkNEW_ARGS(SkMemoryStream, (length));
186 buffer.read((void*)fStream->getMemoryBase(), length);
187
188 fPrev = fNext = NULL;
reed@android.com797d51a2009-03-20 12:08:57 +0000189 fFactory = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190}
191
192void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const {
193 this->INHERITED::flatten(buffer);
194
195 buffer.write8(fConfig);
196 buffer.write8(fSampleSize);
reed@android.comc6ddc112009-11-10 15:54:55 +0000197 buffer.writeBool(fDoDither);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198 size_t length = fStream->getLength();
199 buffer.write32(length);
200 fStream->rewind();
201 buffer.readFromStream(fStream, length);
202}
203