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(const SkImageInfo& info, SkStreamRewindable* stream,
22                       int sampleSize, SkBaseMutex* mutex)
23        : SkPixelRef(info, mutex), fErrorInDecoding(false) {
24    SkASSERT(stream);
25    stream->ref();
26    fStream = stream;
27    fSampleSize = sampleSize;
28    fDoDither = true;
29    fPrev = fNext = NULL;
30    fFactory = NULL;
31
32#ifdef DUMP_IMAGEREF_LIFECYCLE
33    SkDebugf("add ImageRef %p [%d] data=%d\n",
34              this, this->info().fColorType, (int)stream->getLength());
35#endif
36}
37
38SkImageRef::~SkImageRef() {
39
40#ifdef DUMP_IMAGEREF_LIFECYCLE
41    SkDebugf("delete ImageRef %p [%d] data=%d\n",
42              this, fConfig, (int)fStream->getLength());
43#endif
44
45    fStream->unref();
46    SkSafeUnref(fFactory);
47}
48
49bool SkImageRef::getInfo(SkBitmap* bitmap) {
50    SkAutoMutexAcquire ac(this->mutex());
51
52    if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) {
53        return false;
54    }
55
56    SkASSERT(SkBitmap::kNo_Config != fBitmap.config());
57    if (bitmap) {
58        bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height());
59    }
60    return true;
61}
62
63bool SkImageRef::isOpaque(SkBitmap* bitmap) {
64    if (bitmap && bitmap->pixelRef() == this) {
65        bitmap->lockPixels();
66        // what about colortables??????
67        bitmap->setAlphaType(fBitmap.alphaType());
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, SkStreamRewindable* 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    if (NULL != fBitmap.getPixels() ||
95            (SkBitmap::kNo_Config != fBitmap.config() &&
96             SkImageDecoder::kDecodeBounds_Mode == mode)) {
97        return true;
98    }
99
100    SkASSERT(fBitmap.getPixels() == NULL);
101
102    if (!fStream->rewind()) {
103        SkDEBUGF(("Failed to rewind SkImageRef stream!"));
104        return false;
105    }
106
107    SkImageDecoder* codec;
108    if (fFactory) {
109        codec = fFactory->newDecoder(fStream);
110    } else {
111        codec = SkImageDecoder::Factory(fStream);
112    }
113
114    if (codec) {
115        SkAutoTDelete<SkImageDecoder> ad(codec);
116
117        codec->setSampleSize(fSampleSize);
118        codec->setDitherImage(fDoDither);
119        if (this->onDecode(codec, fStream, &fBitmap, fBitmap.config(), mode)) {
120            return true;
121        }
122    }
123
124#ifdef DUMP_IMAGEREF_LIFECYCLE
125    if (NULL == codec) {
126        SkDebugf("--- ImageRef: <%s> failed to find codec\n", this->getURI());
127    } else {
128        SkDebugf("--- ImageRef: <%s> failed in codec for %d mode\n",
129                 this->getURI(), mode);
130    }
131#endif
132    fErrorInDecoding = true;
133    fBitmap.reset();
134    return false;
135}
136
137void* SkImageRef::onLockPixels(SkColorTable** ct) {
138    if (NULL == fBitmap.getPixels()) {
139        (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode);
140    }
141
142    if (ct) {
143        *ct = fBitmap.getColorTable();
144    }
145    return fBitmap.getPixels();
146}
147
148size_t SkImageRef::ramUsed() const {
149    size_t size = 0;
150
151    if (fBitmap.getPixels()) {
152        size = fBitmap.getSize();
153        if (fBitmap.getColorTable()) {
154            size += fBitmap.getColorTable()->count() * sizeof(SkPMColor);
155        }
156    }
157    return size;
158}
159
160///////////////////////////////////////////////////////////////////////////////
161
162SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
163        : INHERITED(buffer, mutex), fErrorInDecoding(false) {
164    fSampleSize = buffer.readInt();
165    fDoDither = buffer.readBool();
166
167    size_t length = buffer.getArrayCount();
168    fStream = SkNEW_ARGS(SkMemoryStream, (length));
169    buffer.readByteArray((void*)fStream->getMemoryBase(), length);
170
171    fPrev = fNext = NULL;
172    fFactory = NULL;
173}
174
175void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const {
176    this->INHERITED::flatten(buffer);
177
178    buffer.writeInt(fSampleSize);
179    buffer.writeBool(fDoDither);
180    // FIXME: Consider moving this logic should go into writeStream itself.
181    // writeStream currently has no other callers, so this may be fine for
182    // now.
183    if (!fStream->rewind()) {
184        SkDEBUGF(("Failed to rewind SkImageRef stream!"));
185        buffer.write32(0);
186    } else {
187        // FIXME: Handle getLength properly here. Perhaps this class should
188        // take an SkStreamAsset.
189        buffer.writeStream(fStream, fStream->getLength());
190    }
191}
192