|
1 |
|
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 */ |
|
8 #include "SkImageRef.h" |
|
9 #include "SkBitmap.h" |
|
10 #include "SkReadBuffer.h" |
|
11 #include "SkWriteBuffer.h" |
|
12 #include "SkImageDecoder.h" |
|
13 #include "SkStream.h" |
|
14 #include "SkTemplates.h" |
|
15 #include "SkThread.h" |
|
16 |
|
17 //#define DUMP_IMAGEREF_LIFECYCLE |
|
18 |
|
19 /////////////////////////////////////////////////////////////////////////////// |
|
20 |
|
21 SkImageRef::SkImageRef(const SkImageInfo& info, SkStreamRewindable* stream, |
|
22 int sampleSize, SkBaseMutex* mutex) |
|
23 : INHERITED(info, mutex), fErrorInDecoding(false) |
|
24 { |
|
25 SkASSERT(stream); |
|
26 stream->ref(); |
|
27 fStream = stream; |
|
28 fSampleSize = sampleSize; |
|
29 fDoDither = true; |
|
30 fPrev = fNext = NULL; |
|
31 fFactory = NULL; |
|
32 |
|
33 // This sets the colortype/alphatype to exactly match our info, so that this |
|
34 // can get communicated down to the codec. |
|
35 fBitmap.setConfig(info); |
|
36 |
|
37 #ifdef DUMP_IMAGEREF_LIFECYCLE |
|
38 SkDebugf("add ImageRef %p [%d] data=%d\n", |
|
39 this, this->info().fColorType, (int)stream->getLength()); |
|
40 #endif |
|
41 } |
|
42 |
|
43 SkImageRef::~SkImageRef() { |
|
44 |
|
45 #ifdef DUMP_IMAGEREF_LIFECYCLE |
|
46 SkDebugf("delete ImageRef %p [%d] data=%d\n", |
|
47 this, this->info().fColorType, (int)fStream->getLength()); |
|
48 #endif |
|
49 |
|
50 fStream->unref(); |
|
51 SkSafeUnref(fFactory); |
|
52 } |
|
53 |
|
54 bool SkImageRef::getInfo(SkBitmap* bitmap) { |
|
55 SkAutoMutexAcquire ac(this->mutex()); |
|
56 |
|
57 if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) { |
|
58 return false; |
|
59 } |
|
60 |
|
61 SkASSERT(SkBitmap::kNo_Config != fBitmap.config()); |
|
62 if (bitmap) { |
|
63 bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height()); |
|
64 } |
|
65 return true; |
|
66 } |
|
67 |
|
68 bool SkImageRef::isOpaque(SkBitmap* bitmap) { |
|
69 if (bitmap && bitmap->pixelRef() == this) { |
|
70 bitmap->lockPixels(); |
|
71 // what about colortables?????? |
|
72 bitmap->setAlphaType(fBitmap.alphaType()); |
|
73 bitmap->unlockPixels(); |
|
74 return true; |
|
75 } |
|
76 return false; |
|
77 } |
|
78 |
|
79 SkImageDecoderFactory* SkImageRef::setDecoderFactory( |
|
80 SkImageDecoderFactory* fact) { |
|
81 SkRefCnt_SafeAssign(fFactory, fact); |
|
82 return fact; |
|
83 } |
|
84 |
|
85 /////////////////////////////////////////////////////////////////////////////// |
|
86 |
|
87 bool SkImageRef::onDecode(SkImageDecoder* codec, SkStreamRewindable* stream, |
|
88 SkBitmap* bitmap, SkBitmap::Config config, |
|
89 SkImageDecoder::Mode mode) { |
|
90 return codec->decode(stream, bitmap, config, mode); |
|
91 } |
|
92 |
|
93 bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) { |
|
94 |
|
95 if (fErrorInDecoding) { |
|
96 return false; |
|
97 } |
|
98 |
|
99 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 if (!fStream->rewind()) { |
|
108 SkDEBUGF(("Failed to rewind SkImageRef stream!")); |
|
109 return false; |
|
110 } |
|
111 |
|
112 SkImageDecoder* codec; |
|
113 if (fFactory) { |
|
114 codec = fFactory->newDecoder(fStream); |
|
115 } else { |
|
116 codec = SkImageDecoder::Factory(fStream); |
|
117 } |
|
118 |
|
119 if (codec) { |
|
120 SkAutoTDelete<SkImageDecoder> ad(codec); |
|
121 |
|
122 codec->setSampleSize(fSampleSize); |
|
123 codec->setDitherImage(fDoDither); |
|
124 codec->setRequireUnpremultipliedColors(this->info().fAlphaType == kUnpremul_SkAlphaType); |
|
125 if (this->onDecode(codec, fStream, &fBitmap, fBitmap.config(), mode)) { |
|
126 if (kOpaque_SkAlphaType == fBitmap.alphaType()) { |
|
127 this->changeAlphaType(kOpaque_SkAlphaType); |
|
128 } |
|
129 SkASSERT(this->info() == fBitmap.info()); |
|
130 return true; |
|
131 } |
|
132 } |
|
133 |
|
134 #ifdef DUMP_IMAGEREF_LIFECYCLE |
|
135 if (NULL == codec) { |
|
136 SkDebugf("--- ImageRef: <%s> failed to find codec\n", this->getURI()); |
|
137 } else { |
|
138 SkDebugf("--- ImageRef: <%s> failed in codec for %d mode\n", |
|
139 this->getURI(), mode); |
|
140 } |
|
141 #endif |
|
142 fErrorInDecoding = true; |
|
143 fBitmap.reset(); |
|
144 return false; |
|
145 } |
|
146 |
|
147 bool SkImageRef::onNewLockPixels(LockRec* rec) { |
|
148 if (NULL == fBitmap.getPixels()) { |
|
149 (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode); |
|
150 } |
|
151 |
|
152 if (NULL == fBitmap.getPixels()) { |
|
153 return false; |
|
154 } |
|
155 rec->fPixels = fBitmap.getPixels(); |
|
156 rec->fColorTable = NULL; |
|
157 rec->fRowBytes = fBitmap.rowBytes(); |
|
158 return true; |
|
159 } |
|
160 |
|
161 size_t SkImageRef::ramUsed() const { |
|
162 size_t size = 0; |
|
163 |
|
164 if (fBitmap.getPixels()) { |
|
165 size = fBitmap.getSize(); |
|
166 if (fBitmap.getColorTable()) { |
|
167 size += fBitmap.getColorTable()->count() * sizeof(SkPMColor); |
|
168 } |
|
169 } |
|
170 return size; |
|
171 } |
|
172 |
|
173 /////////////////////////////////////////////////////////////////////////////// |
|
174 |
|
175 SkImageRef::SkImageRef(SkReadBuffer& buffer, SkBaseMutex* mutex) |
|
176 : INHERITED(buffer, mutex), fErrorInDecoding(false) { |
|
177 fSampleSize = buffer.readInt(); |
|
178 fDoDither = buffer.readBool(); |
|
179 |
|
180 size_t length = buffer.getArrayCount(); |
|
181 if (buffer.validateAvailable(length)) { |
|
182 fStream = SkNEW_ARGS(SkMemoryStream, (length)); |
|
183 buffer.readByteArray((void*)fStream->getMemoryBase(), length); |
|
184 } else { |
|
185 fStream = NULL; |
|
186 } |
|
187 |
|
188 fPrev = fNext = NULL; |
|
189 fFactory = NULL; |
|
190 |
|
191 // This sets the colortype/alphatype to exactly match our info, so that this |
|
192 // can get communicated down to the codec. |
|
193 fBitmap.setConfig(this->info()); |
|
194 } |
|
195 |
|
196 void SkImageRef::flatten(SkWriteBuffer& buffer) const { |
|
197 this->INHERITED::flatten(buffer); |
|
198 |
|
199 buffer.writeInt(fSampleSize); |
|
200 buffer.writeBool(fDoDither); |
|
201 // FIXME: Consider moving this logic should go into writeStream itself. |
|
202 // writeStream currently has no other callers, so this may be fine for |
|
203 // now. |
|
204 if (!fStream->rewind()) { |
|
205 SkDEBUGF(("Failed to rewind SkImageRef stream!")); |
|
206 buffer.write32(0); |
|
207 } else { |
|
208 // FIXME: Handle getLength properly here. Perhaps this class should |
|
209 // take an SkStreamAsset. |
|
210 buffer.writeStream(fStream, fStream->getLength()); |
|
211 } |
|
212 } |