11cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
21cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger/*
31cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Copyright 2011 Google Inc.
41cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger *
51cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
61cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * found in the LICENSE file.
71cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger */
80910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkImageRef.h"
90910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkBitmap.h"
100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkFlattenable.h"
110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkImageDecoder.h"
120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkStream.h"
130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkTemplates.h"
140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkThread.h"
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1624fb8c7cc7b76134a25914d8f6346c89c359c621Mike Reed//#define DUMP_IMAGEREF_LIFECYCLE
1724fb8c7cc7b76134a25914d8f6346c89c359c621Mike Reed
180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// can't be static, as SkImageRef_Pool needs to see it
194f1dae40e24d57d647db01443b8bf2410514b8b5Derek SollenbergerSK_DECLARE_GLOBAL_MUTEX(gImageRefMutex);
200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkImageRef::SkImageRef(SkStream* stream, SkBitmap::Config config,
240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                       int sampleSize)
250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        : SkPixelRef(&gImageRefMutex), fErrorInDecoding(false) {
260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(stream);
27af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project    stream->ref();
280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fStream = stream;
290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fConfig = config;
300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fSampleSize = sampleSize;
3147f2621859e1e6fa9a5ed53e7ca66bc395999242Mike Reed    fDoDither = true;
320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPrev = fNext = NULL;
33af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project    fFactory = NULL;
340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef DUMP_IMAGEREF_LIFECYCLE
360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDebugf("add ImageRef %p [%d] data=%d\n",
370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project              this, config, (int)stream->getLength());
380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkImageRef::~SkImageRef() {
420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(&gImageRefMutex == this->mutex());
430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef DUMP_IMAGEREF_LIFECYCLE
450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDebugf("delete ImageRef %p [%d] data=%d\n",
460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project              this, fConfig, (int)fStream->getLength());
470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
49af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project    fStream->unref();
5040528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger    SkSafeUnref(fFactory);
510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkImageRef::getInfo(SkBitmap* bitmap) {
540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoMutexAcquire ac(gImageRefMutex);
5540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (!this->prepareBitmap(SkImageDecoder::kDecodeBounds_Mode)) {
570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5940528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(SkBitmap::kNo_Config != fBitmap.config());
610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (bitmap) {
620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        bitmap->setConfig(fBitmap.config(), fBitmap.width(), fBitmap.height());
630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return true;
650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6799d118f65a9d99c610396ea78b27faadb8d0b9cdRomain Guybool SkImageRef::isOpaque(SkBitmap* bitmap) {
6899d118f65a9d99c610396ea78b27faadb8d0b9cdRomain Guy    if (bitmap && bitmap->pixelRef() == this) {
6999d118f65a9d99c610396ea78b27faadb8d0b9cdRomain Guy        bitmap->lockPixels();
7099d118f65a9d99c610396ea78b27faadb8d0b9cdRomain Guy        bitmap->setIsOpaque(fBitmap.isOpaque());
7199d118f65a9d99c610396ea78b27faadb8d0b9cdRomain Guy        bitmap->unlockPixels();
7299d118f65a9d99c610396ea78b27faadb8d0b9cdRomain Guy        return true;
7399d118f65a9d99c610396ea78b27faadb8d0b9cdRomain Guy    }
7499d118f65a9d99c610396ea78b27faadb8d0b9cdRomain Guy    return false;
7599d118f65a9d99c610396ea78b27faadb8d0b9cdRomain Guy}
7699d118f65a9d99c610396ea78b27faadb8d0b9cdRomain Guy
77af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source ProjectSkImageDecoderFactory* SkImageRef::setDecoderFactory(
78af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project                                                SkImageDecoderFactory* fact) {
79af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project    SkRefCnt_SafeAssign(fFactory, fact);
80af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project    return fact;
81af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project}
82af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project
830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkImageRef::onDecode(SkImageDecoder* codec, SkStream* stream,
860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                          SkBitmap* bitmap, SkBitmap::Config config,
870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                          SkImageDecoder::Mode mode) {
880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return codec->decode(stream, bitmap, config, mode);
890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) {
920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(&gImageRefMutex == this->mutex());
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fErrorInDecoding) {
950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
9740528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /*  As soon as we really know our config, we record it, so that on
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        subsequent calls to the codec, we are sure we will always get the same
1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        result.
1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (SkBitmap::kNo_Config != fBitmap.config()) {
1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fConfig = fBitmap.config();
1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
10540528743dbb9ce7f39f093e0cdc47849ac8887cfDerek Sollenberger
1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (NULL != fBitmap.getPixels() ||
1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            (SkBitmap::kNo_Config != fBitmap.config() &&
1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project             SkImageDecoder::kDecodeBounds_Mode == mode)) {
1090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return true;
1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(fBitmap.getPixels() == NULL);
1130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fStream->rewind();
115af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project
116af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project    SkImageDecoder* codec;
117af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project    if (fFactory) {
118af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project        codec = fFactory->newDecoder(fStream);
119af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project    } else {
120af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project        codec = SkImageDecoder::Factory(fStream);
121af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project    }
122af527e02dce280c269d751322e9f60aac8cb97daThe Android Open Source Project
1230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (codec) {
1240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkAutoTDelete<SkImageDecoder> ad(codec);
1250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        codec->setSampleSize(fSampleSize);
12747f2621859e1e6fa9a5ed53e7ca66bc395999242Mike Reed        codec->setDitherImage(fDoDither);
1280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (this->onDecode(codec, fStream, &fBitmap, fConfig, mode)) {
1290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return true;
1300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifdef DUMP_IMAGEREF_LIFECYCLE
1340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (NULL == codec) {
1350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkDebugf("--- ImageRef: <%s> failed to find codec\n", this->getURI());
1360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
1370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkDebugf("--- ImageRef: <%s> failed in codec for %d mode\n",
1380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                 this->getURI(), mode);
1390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
1410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fErrorInDecoding = true;
1420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fBitmap.reset();
1430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return false;
1440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid* SkImageRef::onLockPixels(SkColorTable** ct) {
1470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(&gImageRefMutex == this->mutex());
1480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (NULL == fBitmap.getPixels()) {
1500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode);
1510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (ct) {
1540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *ct = fBitmap.getColorTable();
1550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return fBitmap.getPixels();
1570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkImageRef::onUnlockPixels() {
1600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // we're already have the mutex locked
1610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(&gImageRefMutex == this->mutex());
1620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectsize_t SkImageRef::ramUsed() const {
1650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    size_t size = 0;
1660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (fBitmap.getPixels()) {
1680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        size = fBitmap.getSize();
1690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (fBitmap.getColorTable()) {
1700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            size += fBitmap.getColorTable()->count() * sizeof(SkPMColor);
1710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return size;
1740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
1770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer)
1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        : INHERITED(buffer, &gImageRefMutex), fErrorInDecoding(false) {
1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fConfig = (SkBitmap::Config)buffer.readU8();
1810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fSampleSize = buffer.readU8();
18224fb8c7cc7b76134a25914d8f6346c89c359c621Mike Reed    fDoDither = buffer.readBool();
18324fb8c7cc7b76134a25914d8f6346c89c359c621Mike Reed
1840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    size_t length = buffer.readU32();
1850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fStream = SkNEW_ARGS(SkMemoryStream, (length));
1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.read((void*)fStream->getMemoryBase(), length);
1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fPrev = fNext = NULL;
189bf62c4a8cf34acfad56af81e7f8cb059ef554f74Mike Reed    fFactory = NULL;
1900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const {
1930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    this->INHERITED::flatten(buffer);
1940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.write8(fConfig);
1960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.write8(fSampleSize);
19724fb8c7cc7b76134a25914d8f6346c89c359c621Mike Reed    buffer.writeBool(fDoDither);
1980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    size_t length = fStream->getLength();
1990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.write32(length);
2000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    fStream->rewind();
2010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    buffer.readFromStream(fStream, length);
2020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
2030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
204