blob: 299166c31ccc4a50c3a6402535c45abcab5ef44f [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"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000010#include "SkFlattenableBuffers.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#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
19///////////////////////////////////////////////////////////////////////////////
20
21SkImageRef::SkImageRef(SkStream* stream, SkBitmap::Config config,
djsollen@google.com528a5562013-02-01 15:57:13 +000022 int sampleSize, SkBaseMutex* mutex)
23 : SkPixelRef(mutex), fErrorInDecoding(false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000024 SkASSERT(stream);
reed@android.com1337a7b2009-03-16 13:56:10 +000025 stream->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +000026 fStream = stream;
27 fConfig = config;
28 fSampleSize = sampleSize;
reed@android.combb9aea92009-09-24 17:21:05 +000029 fDoDither = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +000030 fPrev = fNext = NULL;
reed@android.coma14ea0e2009-03-17 17:59:53 +000031 fFactory = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000032
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() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000040
41#ifdef DUMP_IMAGEREF_LIFECYCLE
42 SkDebugf("delete ImageRef %p [%d] data=%d\n",
43 this, fConfig, (int)fStream->getLength());
44#endif
45
reed@android.com1337a7b2009-03-16 13:56:10 +000046 fStream->unref();
reed@google.com82065d62011-02-07 15:30:46 +000047 SkSafeUnref(fFactory);
reed@android.com8a1c16f2008-12-17 15:59:43 +000048}
49
50bool SkImageRef::getInfo(SkBitmap* bitmap) {
djsollen@google.com528a5562013-02-01 15:57:13 +000051 SkAutoMutexAcquire ac(this->mutex());
reed@google.com82065d62011-02-07 15:30:46 +000052
reed@android.com8a1c16f2008-12-17 15:59:43 +000053 if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) {
54 return false;
55 }
reed@google.com82065d62011-02-07 15:30:46 +000056
reed@android.com8a1c16f2008-12-17 15:59:43 +000057 SkASSERT(SkBitmap::kNo_Config != fBitmap.config());
58 if (bitmap) {
59 bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height());
60 }
61 return true;
62}
63
djsollen@google.com57f49692011-02-23 20:46:31 +000064bool 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
reed@android.coma14ea0e2009-03-17 17:59:53 +000074SkImageDecoderFactory* SkImageRef::setDecoderFactory(
75 SkImageDecoderFactory* fact) {
76 SkRefCnt_SafeAssign(fFactory, fact);
77 return fact;
78}
79
reed@android.com8a1c16f2008-12-17 15:59:43 +000080///////////////////////////////////////////////////////////////////////////////
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) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000089
90 if (fErrorInDecoding) {
91 return false;
92 }
reed@google.com82065d62011-02-07 15:30:46 +000093
reed@android.com8a1c16f2008-12-17 15:59:43 +000094 /* 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 }
reed@google.com82065d62011-02-07 15:30:46 +0000101
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102 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 fStream->rewind();
reed@android.coma14ea0e2009-03-17 17:59:53 +0000111
112 SkImageDecoder* codec;
113 if (fFactory) {
114 codec = fFactory->newDecoder(fStream);
115 } else {
116 codec = SkImageDecoder::Factory(fStream);
117 }
118
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119 if (codec) {
120 SkAutoTDelete<SkImageDecoder> ad(codec);
121
122 codec->setSampleSize(fSampleSize);
reed@android.combb9aea92009-09-24 17:21:05 +0000123 codec->setDitherImage(fDoDither);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124 if (this->onDecode(codec, fStream, &fBitmap, fConfig, mode)) {
125 return true;
126 }
127 }
128
129#ifdef DUMP_IMAGEREF_LIFECYCLE
130 if (NULL == codec) {
131 SkDebugf("--- ImageRef: <%s> failed to find codec\n", this->getURI());
132 } else {
133 SkDebugf("--- ImageRef: <%s> failed in codec for %d mode\n",
134 this->getURI(), mode);
135 }
136#endif
137 fErrorInDecoding = true;
138 fBitmap.reset();
139 return false;
140}
141
142void* SkImageRef::onLockPixels(SkColorTable** ct) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 if (NULL == fBitmap.getPixels()) {
144 (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode);
145 }
146
147 if (ct) {
148 *ct = fBitmap.getColorTable();
149 }
150 return fBitmap.getPixels();
151}
152
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153size_t SkImageRef::ramUsed() const {
154 size_t size = 0;
155
156 if (fBitmap.getPixels()) {
157 size = fBitmap.getSize();
158 if (fBitmap.getColorTable()) {
159 size += fBitmap.getColorTable()->count() * sizeof(SkPMColor);
160 }
161 }
162 return size;
163}
164
165///////////////////////////////////////////////////////////////////////////////
166
djsollen@google.com528a5562013-02-01 15:57:13 +0000167SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
168 : INHERITED(buffer, mutex), fErrorInDecoding(false) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000169 fConfig = (SkBitmap::Config)buffer.readUInt();
170 fSampleSize = buffer.readInt();
reed@android.comc6ddc112009-11-10 15:54:55 +0000171 fDoDither = buffer.readBool();
172
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000173 size_t length = buffer.getArrayCount();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174 fStream = SkNEW_ARGS(SkMemoryStream, (length));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000175 buffer.readByteArray((void*)fStream->getMemoryBase());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176
177 fPrev = fNext = NULL;
reed@android.com797d51a2009-03-20 12:08:57 +0000178 fFactory = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179}
180
djsollen@google.com54924242012-03-29 15:18:04 +0000181void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 this->INHERITED::flatten(buffer);
183
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000184 buffer.writeUInt(fConfig);
185 buffer.writeInt(fSampleSize);
reed@android.comc6ddc112009-11-10 15:54:55 +0000186 buffer.writeBool(fDoDither);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 fStream->rewind();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000188 buffer.writeStream(fStream, fStream->getLength());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189}