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(const SkImageInfo& info, SkStreamRewindable* stream, 22 int sampleSize, SkBaseMutex* mutex) 23 : SkPixelRef(info, mutex), fErrorInDecoding(false) { 24 SkASSERT(stream); 25 stream->ref(); 26 fStream = stream; 27 fSampleSize = sampleSize; 28 fDoDither = true; 29 fPrev = fNext = NULL; 30 fFactory = NULL; 31 32#ifdef DUMP_IMAGEREF_LIFECYCLE 33 SkDebugf("add ImageRef %p [%d] data=%d\n", 34 this, this->info().fColorType, (int)stream->getLength()); 35#endif 36} 37 38SkImageRef::~SkImageRef() { 39 40#ifdef DUMP_IMAGEREF_LIFECYCLE 41 SkDebugf("delete ImageRef %p [%d] data=%d\n", 42 this, fConfig, (int)fStream->getLength()); 43#endif 44 45 fStream->unref(); 46 SkSafeUnref(fFactory); 47} 48 49bool SkImageRef::getInfo(SkBitmap* bitmap) { 50 SkAutoMutexAcquire ac(this->mutex()); 51 52 if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) { 53 return false; 54 } 55 56 SkASSERT(SkBitmap::kNo_Config != fBitmap.config()); 57 if (bitmap) { 58 bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height()); 59 } 60 return true; 61} 62 63bool SkImageRef::isOpaque(SkBitmap* bitmap) { 64 if (bitmap && bitmap->pixelRef() == this) { 65 bitmap->lockPixels(); 66 // what about colortables?????? 67 bitmap->setAlphaType(fBitmap.alphaType()); 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, SkStreamRewindable* 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 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 102 if (!fStream->rewind()) { 103 SkDEBUGF(("Failed to rewind SkImageRef stream!")); 104 return false; 105 } 106 107 SkImageDecoder* codec; 108 if (fFactory) { 109 codec = fFactory->newDecoder(fStream); 110 } else { 111 codec = SkImageDecoder::Factory(fStream); 112 } 113 114 if (codec) { 115 SkAutoTDelete<SkImageDecoder> ad(codec); 116 117 codec->setSampleSize(fSampleSize); 118 codec->setDitherImage(fDoDither); 119 if (this->onDecode(codec, fStream, &fBitmap, fBitmap.config(), mode)) { 120 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 137void* SkImageRef::onLockPixels(SkColorTable** ct) { 138 if (NULL == fBitmap.getPixels()) { 139 (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode); 140 } 141 142 if (ct) { 143 *ct = fBitmap.getColorTable(); 144 } 145 return fBitmap.getPixels(); 146} 147 148size_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 162SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex) 163 : INHERITED(buffer, mutex), fErrorInDecoding(false) { 164 fSampleSize = buffer.readInt(); 165 fDoDither = buffer.readBool(); 166 167 size_t length = buffer.getArrayCount(); 168 fStream = SkNEW_ARGS(SkMemoryStream, (length)); 169 buffer.readByteArray((void*)fStream->getMemoryBase(), length); 170 171 fPrev = fNext = NULL; 172 fFactory = NULL; 173} 174 175void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const { 176 this->INHERITED::flatten(buffer); 177 178 buffer.writeInt(fSampleSize); 179 buffer.writeBool(fDoDither); 180 // FIXME: Consider moving this logic should go into writeStream itself. 181 // writeStream currently has no other callers, so this may be fine for 182 // now. 183 if (!fStream->rewind()) { 184 SkDEBUGF(("Failed to rewind SkImageRef stream!")); 185 buffer.write32(0); 186 } else { 187 // FIXME: Handle getLength properly here. Perhaps this class should 188 // take an SkStreamAsset. 189 buffer.writeStream(fStream, fStream->getLength()); 190 } 191} 192