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 "SkFlattenableBuffers.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
19///////////////////////////////////////////////////////////////////////////////
20
21SkImageRef::SkImageRef(SkStream* stream, SkBitmap::Config config,
22                       int sampleSize, SkBaseMutex* mutex)
23        : SkPixelRef(mutex), fErrorInDecoding(false) {
24    SkASSERT(stream);
25    stream->ref();
26    fStream = stream;
27    fConfig = config;
28    fSampleSize = sampleSize;
29    fDoDither = true;
30    fPrev = fNext = NULL;
31    fFactory = NULL;
32
33#ifdef DUMP_IMAGEREF_LIFECYCLE
34    SkDebugf("add ImageRef %p [%d] data=%d\n",
35              this, config, (int)stream->getLength());
36#endif
37}
38
39SkImageRef::~SkImageRef() {
40
41#ifdef DUMP_IMAGEREF_LIFECYCLE
42    SkDebugf("delete ImageRef %p [%d] data=%d\n",
43              this, fConfig, (int)fStream->getLength());
44#endif
45
46    fStream->unref();
47    SkSafeUnref(fFactory);
48}
49
50bool SkImageRef::getInfo(SkBitmap* bitmap) {
51    SkAutoMutexAcquire ac(this->mutex());
52
53    if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) {
54        return false;
55    }
56
57    SkASSERT(SkBitmap::kNo_Config != fBitmap.config());
58    if (bitmap) {
59        bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height());
60    }
61    return true;
62}
63
64bool SkImageRef::isOpaque(SkBitmap* bitmap) {
65    if (bitmap && bitmap->pixelRef() == this) {
66        bitmap->lockPixels();
67        bitmap->setIsOpaque(fBitmap.isOpaque());
68        bitmap->unlockPixels();
69        return true;
70    }
71    return false;
72}
73
74SkImageDecoderFactory* SkImageRef::setDecoderFactory(
75                                                SkImageDecoderFactory* fact) {
76    SkRefCnt_SafeAssign(fFactory, fact);
77    return fact;
78}
79
80///////////////////////////////////////////////////////////////////////////////
81
82bool SkImageRef::onDecode(SkImageDecoder* codec, SkStream* stream,
83                          SkBitmap* bitmap, SkBitmap::Config config,
84                          SkImageDecoder::Mode mode) {
85    return codec->decode(stream, bitmap, config, mode);
86}
87
88bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) {
89
90    if (fErrorInDecoding) {
91        return false;
92    }
93
94    /*  As soon as we really know our config, we record it, so that on
95        subsequent calls to the codec, we are sure we will always get the same
96        result.
97    */
98    if (SkBitmap::kNo_Config != fBitmap.config()) {
99        fConfig = fBitmap.config();
100    }
101
102    if (NULL != fBitmap.getPixels() ||
103            (SkBitmap::kNo_Config != fBitmap.config() &&
104             SkImageDecoder::kDecodeBounds_Mode == mode)) {
105        return true;
106    }
107
108    SkASSERT(fBitmap.getPixels() == NULL);
109
110    if (!fStream->rewind()) {
111        SkDEBUGF(("Failed to rewind SkImageRef stream!"));
112        return false;
113    }
114
115    SkImageDecoder* codec;
116    if (fFactory) {
117        codec = fFactory->newDecoder(fStream);
118    } else {
119        codec = SkImageDecoder::Factory(fStream);
120    }
121
122    if (codec) {
123        SkAutoTDelete<SkImageDecoder> ad(codec);
124
125        codec->setSampleSize(fSampleSize);
126        codec->setDitherImage(fDoDither);
127        if (this->onDecode(codec, fStream, &fBitmap, fConfig, mode)) {
128            return true;
129        }
130    }
131
132#ifdef DUMP_IMAGEREF_LIFECYCLE
133    if (NULL == codec) {
134        SkDebugf("--- ImageRef: <%s> failed to find codec\n", this->getURI());
135    } else {
136        SkDebugf("--- ImageRef: <%s> failed in codec for %d mode\n",
137                 this->getURI(), mode);
138    }
139#endif
140    fErrorInDecoding = true;
141    fBitmap.reset();
142    return false;
143}
144
145void* SkImageRef::onLockPixels(SkColorTable** ct) {
146    if (NULL == fBitmap.getPixels()) {
147        (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode);
148    }
149
150    if (ct) {
151        *ct = fBitmap.getColorTable();
152    }
153    return fBitmap.getPixels();
154}
155
156size_t SkImageRef::ramUsed() const {
157    size_t size = 0;
158
159    if (fBitmap.getPixels()) {
160        size = fBitmap.getSize();
161        if (fBitmap.getColorTable()) {
162            size += fBitmap.getColorTable()->count() * sizeof(SkPMColor);
163        }
164    }
165    return size;
166}
167
168///////////////////////////////////////////////////////////////////////////////
169
170SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
171        : INHERITED(buffer, mutex), fErrorInDecoding(false) {
172    fConfig = (SkBitmap::Config)buffer.readUInt();
173    fSampleSize = buffer.readInt();
174    fDoDither = buffer.readBool();
175
176    size_t length = buffer.getArrayCount();
177    fStream = SkNEW_ARGS(SkMemoryStream, (length));
178    buffer.readByteArray((void*)fStream->getMemoryBase());
179
180    fPrev = fNext = NULL;
181    fFactory = NULL;
182}
183
184void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const {
185    this->INHERITED::flatten(buffer);
186
187    buffer.writeUInt(fConfig);
188    buffer.writeInt(fSampleSize);
189    buffer.writeBool(fDoDither);
190    // FIXME: Consider moving this logic should go into writeStream itself.
191    // writeStream currently has no other callers, so this may be fine for
192    // now.
193    if (!fStream->rewind()) {
194        SkDEBUGF(("Failed to rewind SkImageRef stream!"));
195        buffer.write32(0);
196    } else {
197        // FIXME: Handle getLength properly here. Perhaps this class should
198        // take an SkStreamAsset.
199        buffer.writeStream(fStream, fStream->getLength());
200    }
201}
202