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 "SkFlattenable.h"
11#include "SkImageDecoder.h"
12#include "SkStream.h"
13#include "SkTemplates.h"
14#include "SkThread.h"
15
16//#define DUMP_IMAGEREF_LIFECYCLE
17
18// can't be static, as SkImageRef_Pool needs to see it
19SK_DECLARE_GLOBAL_MUTEX(gImageRefMutex);
20
21///////////////////////////////////////////////////////////////////////////////
22
23SkImageRef::SkImageRef(SkStream* stream, SkBitmap::Config config,
24                       int sampleSize)
25        : SkPixelRef(&gImageRefMutex), fErrorInDecoding(false) {
26    SkASSERT(stream);
27    stream->ref();
28    fStream = stream;
29    fConfig = config;
30    fSampleSize = sampleSize;
31    fDoDither = true;
32    fPrev = fNext = NULL;
33    fFactory = NULL;
34
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
49    fStream->unref();
50    SkSafeUnref(fFactory);
51}
52
53bool SkImageRef::getInfo(SkBitmap* bitmap) {
54    SkAutoMutexAcquire ac(gImageRefMutex);
55
56    if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) {
57        return false;
58    }
59
60    SkASSERT(SkBitmap::kNo_Config != fBitmap.config());
61    if (bitmap) {
62        bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height());
63    }
64    return true;
65}
66
67bool 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
77SkImageDecoderFactory* SkImageRef::setDecoderFactory(
78                                                SkImageDecoderFactory* fact) {
79    SkRefCnt_SafeAssign(fFactory, fact);
80    return fact;
81}
82
83///////////////////////////////////////////////////////////////////////////////
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    }
97
98    /*  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    }
105
106    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();
115
116    SkImageDecoder* codec;
117    if (fFactory) {
118        codec = fFactory->newDecoder(fStream);
119    } else {
120        codec = SkImageDecoder::Factory(fStream);
121    }
122
123    if (codec) {
124        SkAutoTDelete<SkImageDecoder> ad(codec);
125
126        codec->setSampleSize(fSampleSize);
127        codec->setDitherImage(fDoDither);
128        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();
182    fDoDither = buffer.readBool();
183
184    size_t length = buffer.readU32();
185    fStream = SkNEW_ARGS(SkMemoryStream, (length));
186    buffer.read((void*)fStream->getMemoryBase(), length);
187
188    fPrev = fNext = NULL;
189    fFactory = NULL;
190}
191
192void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const {
193    this->INHERITED::flatten(buffer);
194
195    buffer.write8(fConfig);
196    buffer.write8(fSampleSize);
197    buffer.writeBool(fDoDither);
198    size_t length = fStream->getLength();
199    buffer.write32(length);
200    fStream->rewind();
201    buffer.readFromStream(fStream, length);
202}
203
204