1 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 */ 8#include "SkImageRef.h" 9#include "SkBitmap.h" 10#include "SkFlattenableBuffers.h" 11#include "SkImageDecoder.h" 12#include "SkStream.h" 13#include "SkTemplates.h" 14#include "SkThread.h" 15 16//#define DUMP_IMAGEREF_LIFECYCLE 17 18 19/////////////////////////////////////////////////////////////////////////////// 20 21SkImageRef::SkImageRef(SkStream* stream, SkBitmap::Config config, 22 int sampleSize, SkBaseMutex* mutex) 23 : SkPixelRef(mutex), fErrorInDecoding(false) { 24 SkASSERT(stream); 25 stream->ref(); 26 fStream = stream; 27 fConfig = config; 28 fSampleSize = sampleSize; 29 fDoDither = true; 30 fPrev = fNext = NULL; 31 fFactory = NULL; 32 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() { 40 41#ifdef DUMP_IMAGEREF_LIFECYCLE 42 SkDebugf("delete ImageRef %p [%d] data=%d\n", 43 this, fConfig, (int)fStream->getLength()); 44#endif 45 46 fStream->unref(); 47 SkSafeUnref(fFactory); 48} 49 50bool SkImageRef::getInfo(SkBitmap* bitmap) { 51 SkAutoMutexAcquire ac(this->mutex()); 52 53 if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) { 54 return false; 55 } 56 57 SkASSERT(SkBitmap::kNo_Config != fBitmap.config()); 58 if (bitmap) { 59 bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height()); 60 } 61 return true; 62} 63 64bool 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 74SkImageDecoderFactory* SkImageRef::setDecoderFactory( 75 SkImageDecoderFactory* fact) { 76 SkRefCnt_SafeAssign(fFactory, fact); 77 return fact; 78} 79 80/////////////////////////////////////////////////////////////////////////////// 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) { 89 90 if (fErrorInDecoding) { 91 return false; 92 } 93 94 /* 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 } 101 102 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 if (!fStream->rewind()) { 111 SkDEBUGF(("Failed to rewind SkImageRef stream!")); 112 return false; 113 } 114 115 SkImageDecoder* codec; 116 if (fFactory) { 117 codec = fFactory->newDecoder(fStream); 118 } else { 119 codec = SkImageDecoder::Factory(fStream); 120 } 121 122 if (codec) { 123 SkAutoTDelete<SkImageDecoder> ad(codec); 124 125 codec->setSampleSize(fSampleSize); 126 codec->setDitherImage(fDoDither); 127 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) { 146 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 156size_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 170SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex) 171 : INHERITED(buffer, mutex), fErrorInDecoding(false) { 172 fConfig = (SkBitmap::Config)buffer.readUInt(); 173 fSampleSize = buffer.readInt(); 174 fDoDither = buffer.readBool(); 175 176 size_t length = buffer.getArrayCount(); 177 fStream = SkNEW_ARGS(SkMemoryStream, (length)); 178 buffer.readByteArray((void*)fStream->getMemoryBase()); 179 180 fPrev = fNext = NULL; 181 fFactory = NULL; 182} 183 184void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const { 185 this->INHERITED::flatten(buffer); 186 187 buffer.writeUInt(fConfig); 188 buffer.writeInt(fSampleSize); 189 buffer.writeBool(fDoDither); 190 // 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 } 201} 202