blob: 843f4c01f941d3aa9b962d785ba095122397bae0 [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@google.comba82bd12014-01-06 13:34:39 +000018
reed@android.com8a1c16f2008-12-17 15:59:43 +000019///////////////////////////////////////////////////////////////////////////////
20
reed@google.combf790232013-12-13 19:45:58 +000021SkImageRef::SkImageRef(const SkImageInfo& info, SkStreamRewindable* stream,
djsollen@google.com528a5562013-02-01 15:57:13 +000022 int sampleSize, SkBaseMutex* mutex)
reed@google.comba82bd12014-01-06 13:34:39 +000023 : SkPixelRef(info, 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;
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.comba82bd12014-01-06 13:34:39 +000042 this, fConfig, (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.comba82bd12014-01-06 13:34:39 +0000137void* SkImageRef::onLockPixels(SkColorTable** ct) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138 if (NULL == fBitmap.getPixels()) {
139 (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode);
140 }
141
reed@google.comba82bd12014-01-06 13:34:39 +0000142 if (ct) {
143 *ct = fBitmap.getColorTable();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144 }
reed@google.comba82bd12014-01-06 13:34:39 +0000145 return fBitmap.getPixels();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146}
147
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148size_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
djsollen@google.com528a5562013-02-01 15:57:13 +0000162SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
163 : INHERITED(buffer, mutex), fErrorInDecoding(false) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000164 fSampleSize = buffer.readInt();
reed@android.comc6ddc112009-11-10 15:54:55 +0000165 fDoDither = buffer.readBool();
166
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000167 size_t length = buffer.getArrayCount();
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000168 if (buffer.validateAvailable(length)) {
169 fStream = SkNEW_ARGS(SkMemoryStream, (length));
170 buffer.readByteArray((void*)fStream->getMemoryBase(), length);
171 } else {
172 fStream = NULL;
173 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174
175 fPrev = fNext = NULL;
reed@android.com797d51a2009-03-20 12:08:57 +0000176 fFactory = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177}
178
djsollen@google.com54924242012-03-29 15:18:04 +0000179void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 this->INHERITED::flatten(buffer);
181
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000182 buffer.writeInt(fSampleSize);
reed@android.comc6ddc112009-11-10 15:54:55 +0000183 buffer.writeBool(fDoDither);
scroggo@google.com4d213ab2013-08-28 13:08:54 +0000184 // FIXME: Consider moving this logic should go into writeStream itself.
185 // writeStream currently has no other callers, so this may be fine for
186 // now.
187 if (!fStream->rewind()) {
188 SkDEBUGF(("Failed to rewind SkImageRef stream!"));
189 buffer.write32(0);
190 } else {
191 // FIXME: Handle getLength properly here. Perhaps this class should
192 // take an SkStreamAsset.
193 buffer.writeStream(fStream, fStream->getLength());
194 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195}