blob: bd4a7393d9fc9a3a029ca6ee5d053ef2938571cf [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
scroggo@google.com4d213ab2013-08-28 13:08:54 +0000110 if (!fStream->rewind()) {
111 SkDEBUGF(("Failed to rewind SkImageRef stream!"));
112 return false;
113 }
reed@android.coma14ea0e2009-03-17 17:59:53 +0000114
115 SkImageDecoder* codec;
116 if (fFactory) {
117 codec = fFactory->newDecoder(fStream);
118 } else {
119 codec = SkImageDecoder::Factory(fStream);
120 }
121
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122 if (codec) {
123 SkAutoTDelete<SkImageDecoder> ad(codec);
124
125 codec->setSampleSize(fSampleSize);
reed@android.combb9aea92009-09-24 17:21:05 +0000126 codec->setDitherImage(fDoDither);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 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) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146 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
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156size_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
djsollen@google.com528a5562013-02-01 15:57:13 +0000170SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
171 : INHERITED(buffer, mutex), fErrorInDecoding(false) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000172 fConfig = (SkBitmap::Config)buffer.readUInt();
173 fSampleSize = buffer.readInt();
reed@android.comc6ddc112009-11-10 15:54:55 +0000174 fDoDither = buffer.readBool();
175
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000176 size_t length = buffer.getArrayCount();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 fStream = SkNEW_ARGS(SkMemoryStream, (length));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000178 buffer.readByteArray((void*)fStream->getMemoryBase());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179
180 fPrev = fNext = NULL;
reed@android.com797d51a2009-03-20 12:08:57 +0000181 fFactory = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182}
183
djsollen@google.com54924242012-03-29 15:18:04 +0000184void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185 this->INHERITED::flatten(buffer);
186
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000187 buffer.writeUInt(fConfig);
188 buffer.writeInt(fSampleSize);
reed@android.comc6ddc112009-11-10 15:54:55 +0000189 buffer.writeBool(fDoDither);
scroggo@google.com4d213ab2013-08-28 13:08:54 +0000190 // 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 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201}