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 21 SkImageRef::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 // This sets the colortype/alphatype to exactly match our info, so that this 33 // can get communicated down to the codec. 34 fBitmap.setConfig(info); 35 36 #ifdef DUMP_IMAGEREF_LIFECYCLE 37 SkDebugf("add ImageRef %p [%d] data=%d\n", 38 this, this->info().fColorType, (int)stream->getLength()); 39 #endif 40 } 41 42 SkImageRef::~SkImageRef() { 43 44 #ifdef DUMP_IMAGEREF_LIFECYCLE 45 SkDebugf("delete ImageRef %p [%d] data=%d\n", 46 this, fConfig, (int)fStream->getLength()); 47 #endif 48 49 fStream->unref(); 50 SkSafeUnref(fFactory); 51 } 52 53 bool SkImageRef::getInfo(SkBitmap* bitmap) { 54 SkAutoMutexAcquire ac(this->mutex()); 55 56 if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) { 57 return false; 58 } 59 60 SkASSERT(SkBitmap::kNo_Config != fBitmap.config()); 61 if (bitmap) { 62 bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height()); 63 } 64 return true; 65 } 66 67 bool SkImageRef::isOpaque(SkBitmap* bitmap) { 68 if (bitmap && bitmap->pixelRef() == this) { 69 bitmap->lockPixels(); 70 // what about colortables?????? 71 bitmap->setAlphaType(fBitmap.alphaType()); 72 bitmap->unlockPixels(); 73 return true; 74 } 75 return false; 76 } 77 78 SkImageDecoderFactory* SkImageRef::setDecoderFactory( 79 SkImageDecoderFactory* fact) { 80 SkRefCnt_SafeAssign(fFactory, fact); 81 return fact; 82 } 83 84 /////////////////////////////////////////////////////////////////////////////// 85 86 bool SkImageRef::onDecode(SkImageDecoder* codec, SkStreamRewindable* stream, 87 SkBitmap* bitmap, SkBitmap::Config config, 88 SkImageDecoder::Mode mode) { 89 return codec->decode(stream, bitmap, config, mode); 90 } 91 92 bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) { 93 94 if (fErrorInDecoding) { 95 return false; 96 } 97 98 if (NULL != fBitmap.getPixels() || 99 (SkBitmap::kNo_Config != fBitmap.config() && 100 SkImageDecoder::kDecodeBounds_Mode == mode)) { 101 return true; 102 } 103 104 SkASSERT(fBitmap.getPixels() == NULL); 105 106 if (!fStream->rewind()) { 107 SkDEBUGF(("Failed to rewind SkImageRef stream!")); 108 return false; 109 } 110 111 SkImageDecoder* codec; 112 if (fFactory) { 113 codec = fFactory->newDecoder(fStream); 114 } else { 115 codec = SkImageDecoder::Factory(fStream); 116 } 117 118 if (codec) { 119 SkAutoTDelete<SkImageDecoder> ad(codec); 120 121 codec->setSampleSize(fSampleSize); 122 codec->setDitherImage(fDoDither); 123 if (this->onDecode(codec, fStream, &fBitmap, fBitmap.config(), mode)) { 124 SkDEBUGCODE(SkImageInfo info;) 125 SkASSERT(!fBitmap.asImageInfo(&info) || this->info().fColorType == info.fColorType); 126 SkASSERT(this->info().fWidth == fBitmap.width()); 127 SkASSERT(this->info().fHeight == fBitmap.height()); 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 145 void* 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 156 size_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 170 SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex) 171 : INHERITED(buffer, mutex), fErrorInDecoding(false) { 172 fSampleSize = buffer.readInt(); 173 fDoDither = buffer.readBool(); 174 175 size_t length = buffer.getArrayCount(); 176 fStream = SkNEW_ARGS(SkMemoryStream, (length)); 177 buffer.readByteArray((void*)fStream->getMemoryBase(), length); 178 179 fPrev = fNext = NULL; 180 fFactory = NULL; 181 182 // This sets the colortype/alphatype to exactly match our info, so that this 183 // can get communicated down to the codec. 184 fBitmap.setConfig(this->info()); 185 } 186 187 void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const { 188 this->INHERITED::flatten(buffer); 189 190 buffer.writeInt(fSampleSize); 191 buffer.writeBool(fDoDither); 192 // FIXME: Consider moving this logic should go into writeStream itself. 193 // writeStream currently has no other callers, so this may be fine for 194 // now. 195 if (!fStream->rewind()) { 196 SkDEBUGF(("Failed to rewind SkImageRef stream!")); 197 buffer.write32(0); 198 } else { 199 // FIXME: Handle getLength properly here. Perhaps this class should 200 // take an SkStreamAsset. 201 buffer.writeStream(fStream, fStream->getLength()); 202 } 203 } 204