blob: ead835f7ab9c9c4c16f6a5e810026855973554f6 [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
scroggo@google.comb5571b32013-09-25 21:34:24 +000021SkImageRef::SkImageRef(SkStreamRewindable* 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();
reed@google.com383a6972013-10-21 14:00:07 +000067 // what about colortables??????
68 bitmap->setAlphaType(fBitmap.alphaType());
djsollen@google.com57f49692011-02-23 20:46:31 +000069 bitmap->unlockPixels();
70 return true;
71 }
72 return false;
73}
74
reed@android.coma14ea0e2009-03-17 17:59:53 +000075SkImageDecoderFactory* SkImageRef::setDecoderFactory(
76 SkImageDecoderFactory* fact) {
77 SkRefCnt_SafeAssign(fFactory, fact);
78 return fact;
79}
80
reed@android.com8a1c16f2008-12-17 15:59:43 +000081///////////////////////////////////////////////////////////////////////////////
82
scroggo@google.comb5571b32013-09-25 21:34:24 +000083bool SkImageRef::onDecode(SkImageDecoder* codec, SkStreamRewindable* stream,
reed@android.com8a1c16f2008-12-17 15:59:43 +000084 SkBitmap* bitmap, SkBitmap::Config config,
85 SkImageDecoder::Mode mode) {
86 return codec->decode(stream, bitmap, config, mode);
87}
88
89bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000090
91 if (fErrorInDecoding) {
92 return false;
93 }
reed@google.com82065d62011-02-07 15:30:46 +000094
reed@android.com8a1c16f2008-12-17 15:59:43 +000095 /* As soon as we really know our config, we record it, so that on
96 subsequent calls to the codec, we are sure we will always get the same
97 result.
98 */
99 if (SkBitmap::kNo_Config != fBitmap.config()) {
100 fConfig = fBitmap.config();
101 }
reed@google.com82065d62011-02-07 15:30:46 +0000102
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103 if (NULL != fBitmap.getPixels() ||
104 (SkBitmap::kNo_Config != fBitmap.config() &&
105 SkImageDecoder::kDecodeBounds_Mode == mode)) {
106 return true;
107 }
108
109 SkASSERT(fBitmap.getPixels() == NULL);
110
scroggo@google.com4d213ab2013-08-28 13:08:54 +0000111 if (!fStream->rewind()) {
112 SkDEBUGF(("Failed to rewind SkImageRef stream!"));
113 return false;
114 }
reed@android.coma14ea0e2009-03-17 17:59:53 +0000115
116 SkImageDecoder* codec;
117 if (fFactory) {
118 codec = fFactory->newDecoder(fStream);
119 } else {
120 codec = SkImageDecoder::Factory(fStream);
121 }
122
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123 if (codec) {
124 SkAutoTDelete<SkImageDecoder> ad(codec);
125
126 codec->setSampleSize(fSampleSize);
reed@android.combb9aea92009-09-24 17:21:05 +0000127 codec->setDitherImage(fDoDither);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 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) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147 if (NULL == fBitmap.getPixels()) {
148 (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode);
149 }
150
151 if (ct) {
152 *ct = fBitmap.getColorTable();
153 }
154 return fBitmap.getPixels();
155}
156
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157size_t SkImageRef::ramUsed() const {
158 size_t size = 0;
159
160 if (fBitmap.getPixels()) {
161 size = fBitmap.getSize();
162 if (fBitmap.getColorTable()) {
163 size += fBitmap.getColorTable()->count() * sizeof(SkPMColor);
164 }
165 }
166 return size;
167}
168
169///////////////////////////////////////////////////////////////////////////////
170
djsollen@google.com528a5562013-02-01 15:57:13 +0000171SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
172 : INHERITED(buffer, mutex), fErrorInDecoding(false) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000173 fConfig = (SkBitmap::Config)buffer.readUInt();
174 fSampleSize = buffer.readInt();
reed@android.comc6ddc112009-11-10 15:54:55 +0000175 fDoDither = buffer.readBool();
176
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000177 size_t length = buffer.getArrayCount();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 fStream = SkNEW_ARGS(SkMemoryStream, (length));
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000179 buffer.readByteArray((void*)fStream->getMemoryBase());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180
181 fPrev = fNext = NULL;
reed@android.com797d51a2009-03-20 12:08:57 +0000182 fFactory = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183}
184
djsollen@google.com54924242012-03-29 15:18:04 +0000185void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186 this->INHERITED::flatten(buffer);
187
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000188 buffer.writeUInt(fConfig);
189 buffer.writeInt(fSampleSize);
reed@android.comc6ddc112009-11-10 15:54:55 +0000190 buffer.writeBool(fDoDither);
scroggo@google.com4d213ab2013-08-28 13:08:54 +0000191 // FIXME: Consider moving this logic should go into writeStream itself.
192 // writeStream currently has no other callers, so this may be fine for
193 // now.
194 if (!fStream->rewind()) {
195 SkDEBUGF(("Failed to rewind SkImageRef stream!"));
196 buffer.write32(0);
197 } else {
198 // FIXME: Handle getLength properly here. Perhaps this class should
199 // take an SkStreamAsset.
200 buffer.writeStream(fStream, fStream->getLength());
201 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202}