blob: 2c1ec38116c60970dd90c465b147f4e80dc83d77 [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
reed@google.combf790232013-12-13 19:45:58 +000020SkImageRef::SkImageRef(const SkImageInfo& info, SkStreamRewindable* stream,
djsollen@google.com528a5562013-02-01 15:57:13 +000021 int sampleSize, SkBaseMutex* mutex)
reed@google.comd0419b12014-01-06 17:08:27 +000022 : INHERITED(info, mutex), fErrorInDecoding(false)
23{
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;
reed@android.com8a1c16f2008-12-17 15:59:43 +000027 fSampleSize = sampleSize;
reed@android.combb9aea92009-09-24 17:21:05 +000028 fDoDither = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +000029 fPrev = fNext = NULL;
reed@android.coma14ea0e2009-03-17 17:59:53 +000030 fFactory = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000031
32#ifdef DUMP_IMAGEREF_LIFECYCLE
33 SkDebugf("add ImageRef %p [%d] data=%d\n",
reed@google.combf790232013-12-13 19:45:58 +000034 this, this->info().fColorType, (int)stream->getLength());
reed@android.com8a1c16f2008-12-17 15:59:43 +000035#endif
36}
37
38SkImageRef::~SkImageRef() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000039
40#ifdef DUMP_IMAGEREF_LIFECYCLE
41 SkDebugf("delete ImageRef %p [%d] data=%d\n",
reed@google.comd0419b12014-01-06 17:08:27 +000042 this, this->info().fColorType, (int)fStream->getLength());
reed@android.com8a1c16f2008-12-17 15:59:43 +000043#endif
44
reed@android.com1337a7b2009-03-16 13:56:10 +000045 fStream->unref();
reed@google.com82065d62011-02-07 15:30:46 +000046 SkSafeUnref(fFactory);
reed@android.com8a1c16f2008-12-17 15:59:43 +000047}
48
49bool SkImageRef::getInfo(SkBitmap* bitmap) {
djsollen@google.com528a5562013-02-01 15:57:13 +000050 SkAutoMutexAcquire ac(this->mutex());
reed@google.com82065d62011-02-07 15:30:46 +000051
reed@android.com8a1c16f2008-12-17 15:59:43 +000052 if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) {
53 return false;
54 }
reed@google.com82065d62011-02-07 15:30:46 +000055
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 SkASSERT(SkBitmap::kNo_Config != fBitmap.config());
57 if (bitmap) {
58 bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height());
59 }
60 return true;
61}
62
djsollen@google.com57f49692011-02-23 20:46:31 +000063bool SkImageRef::isOpaque(SkBitmap* bitmap) {
64 if (bitmap && bitmap->pixelRef() == this) {
65 bitmap->lockPixels();
reed@google.com383a6972013-10-21 14:00:07 +000066 // what about colortables??????
67 bitmap->setAlphaType(fBitmap.alphaType());
djsollen@google.com57f49692011-02-23 20:46:31 +000068 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
scroggo@google.comb5571b32013-09-25 21:34:24 +000082bool SkImageRef::onDecode(SkImageDecoder* codec, SkStreamRewindable* stream,
reed@android.com8a1c16f2008-12-17 15:59:43 +000083 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 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
scroggo@google.com4d213ab2013-08-28 13:08:54 +0000102 if (!fStream->rewind()) {
103 SkDEBUGF(("Failed to rewind SkImageRef stream!"));
104 return false;
105 }
reed@android.coma14ea0e2009-03-17 17:59:53 +0000106
107 SkImageDecoder* codec;
108 if (fFactory) {
109 codec = fFactory->newDecoder(fStream);
110 } else {
111 codec = SkImageDecoder::Factory(fStream);
112 }
113
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 if (codec) {
115 SkAutoTDelete<SkImageDecoder> ad(codec);
116
117 codec->setSampleSize(fSampleSize);
reed@android.combb9aea92009-09-24 17:21:05 +0000118 codec->setDitherImage(fDoDither);
reed@google.combf790232013-12-13 19:45:58 +0000119 if (this->onDecode(codec, fStream, &fBitmap, fBitmap.config(), mode)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000120 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
reed@google.comd0419b12014-01-06 17:08:27 +0000137bool SkImageRef::onNewLockPixels(LockRec* rec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138 if (NULL == fBitmap.getPixels()) {
139 (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode);
140 }
141
reed@google.comd0419b12014-01-06 17:08:27 +0000142 if (NULL == fBitmap.getPixels()) {
143 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144 }
reed@google.comd0419b12014-01-06 17:08:27 +0000145 rec->fPixels = fBitmap.getPixels();
146 rec->fColorTable = NULL;
147 rec->fRowBytes = fBitmap.rowBytes();
148 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149}
150
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151size_t SkImageRef::ramUsed() const {
152 size_t size = 0;
153
154 if (fBitmap.getPixels()) {
155 size = fBitmap.getSize();
156 if (fBitmap.getColorTable()) {
157 size += fBitmap.getColorTable()->count() * sizeof(SkPMColor);
158 }
159 }
160 return size;
161}
162
163///////////////////////////////////////////////////////////////////////////////
164
djsollen@google.com528a5562013-02-01 15:57:13 +0000165SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
166 : INHERITED(buffer, mutex), fErrorInDecoding(false) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000167 fSampleSize = buffer.readInt();
reed@android.comc6ddc112009-11-10 15:54:55 +0000168 fDoDither = buffer.readBool();
169
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000170 size_t length = buffer.getArrayCount();
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000171 if (buffer.validateAvailable(length)) {
172 fStream = SkNEW_ARGS(SkMemoryStream, (length));
173 buffer.readByteArray((void*)fStream->getMemoryBase(), length);
174 } else {
175 fStream = NULL;
176 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177
178 fPrev = fNext = NULL;
reed@android.com797d51a2009-03-20 12:08:57 +0000179 fFactory = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180}
181
djsollen@google.com54924242012-03-29 15:18:04 +0000182void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183 this->INHERITED::flatten(buffer);
184
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000185 buffer.writeInt(fSampleSize);
reed@android.comc6ddc112009-11-10 15:54:55 +0000186 buffer.writeBool(fDoDither);
scroggo@google.com4d213ab2013-08-28 13:08:54 +0000187 // FIXME: Consider moving this logic should go into writeStream itself.
188 // writeStream currently has no other callers, so this may be fine for
189 // now.
190 if (!fStream->rewind()) {
191 SkDEBUGF(("Failed to rewind SkImageRef stream!"));
192 buffer.write32(0);
193 } else {
194 // FIXME: Handle getLength properly here. Perhaps this class should
195 // take an SkStreamAsset.
196 buffer.writeStream(fStream, fStream->getLength());
197 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198}