1/* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkDiscardablePixelRef.h" 9#include "SkDiscardableMemory.h" 10#include "SkImageGenerator.h" 11 12SkDiscardablePixelRef::SkDiscardablePixelRef(const SkImageInfo& info, 13 SkImageGenerator* generator, 14 size_t rowBytes, 15 SkDiscardableMemory::Factory* fact) 16 : INHERITED(info) 17 , fGenerator(generator) 18 , fDMFactory(fact) 19 , fRowBytes(rowBytes) 20 , fDiscardableMemory(NULL) 21{ 22 SkASSERT(fGenerator != NULL); 23 SkASSERT(fRowBytes > 0); 24 // The SkImageGenerator contract requires fGenerator to always 25 // decode the same image on each call to getPixels(). 26 this->setImmutable(); 27 SkSafeRef(fDMFactory); 28} 29 30SkDiscardablePixelRef::~SkDiscardablePixelRef() { 31 if (this->isLocked()) { 32 fDiscardableMemory->unlock(); 33 } 34 SkDELETE(fDiscardableMemory); 35 SkSafeUnref(fDMFactory); 36 SkDELETE(fGenerator); 37} 38 39bool SkDiscardablePixelRef::onNewLockPixels(LockRec* rec) { 40 if (fDiscardableMemory != NULL) { 41 if (fDiscardableMemory->lock()) { 42 rec->fPixels = fDiscardableMemory->data(); 43 rec->fColorTable = NULL; 44 rec->fRowBytes = fRowBytes; 45 return true; 46 } 47 SkDELETE(fDiscardableMemory); 48 fDiscardableMemory = NULL; 49 } 50 51 const size_t size = this->info().getSafeSize(fRowBytes); 52 53 if (fDMFactory != NULL) { 54 fDiscardableMemory = fDMFactory->create(size); 55 } else { 56 fDiscardableMemory = SkDiscardableMemory::Create(size); 57 } 58 if (NULL == fDiscardableMemory) { 59 return false; // Memory allocation failed. 60 } 61 62 void* pixels = fDiscardableMemory->data(); 63 const SkImageInfo& info = this->info(); 64 SkPMColor colors[256]; 65 int colorCount = 0; 66 67#ifdef SK_SUPPORT_LEGACY_IMAGEGENERATORAPI 68 if (!fGenerator->getPixels(info, pixels, fRowBytes)) { 69#else 70 if (!fGenerator->getPixels(info, pixels, fRowBytes, colors, &colorCount)) { 71#endif 72 fDiscardableMemory->unlock(); 73 SkDELETE(fDiscardableMemory); 74 fDiscardableMemory = NULL; 75 return false; 76 } 77 78 // Note: our ctable is not purgable, as it is not stored in the discardablememory block. 79 // This is because SkColorTable is refcntable, and therefore our caller could hold onto it 80 // beyond the scope of a lock/unlock. If we change the API/lifecycle for SkColorTable, we 81 // could move it into the block, but then again perhaps it is small enough that this doesn't 82 // really matter. 83 if (colorCount > 0) { 84 fCTable.reset(SkNEW_ARGS(SkColorTable, (colors, colorCount))); 85 } else { 86 fCTable.reset(NULL); 87 } 88 89 rec->fPixels = pixels; 90 rec->fColorTable = fCTable.get(); 91 rec->fRowBytes = fRowBytes; 92 return true; 93} 94 95void SkDiscardablePixelRef::onUnlockPixels() { 96 fDiscardableMemory->unlock(); 97} 98 99bool SkInstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst, 100 SkDiscardableMemory::Factory* factory) { 101 SkImageInfo info; 102 SkAutoTDelete<SkImageGenerator> autoGenerator(generator); 103 if ((NULL == autoGenerator.get()) 104 || (!autoGenerator->getInfo(&info)) 105 || (!dst->setInfo(info))) { 106 return false; 107 } 108 SkASSERT(dst->colorType() != kUnknown_SkColorType); 109 if (dst->empty()) { // Use a normal pixelref. 110 return dst->allocPixels(); 111 } 112 SkAutoTUnref<SkDiscardablePixelRef> ref( 113 SkNEW_ARGS(SkDiscardablePixelRef, 114 (info, autoGenerator.detach(), dst->rowBytes(), factory))); 115 dst->setPixelRef(ref); 116 return true; 117} 118 119// This is the public API 120bool SkInstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst) { 121 return SkInstallDiscardablePixelRef(generator, dst, NULL); 122} 123