SkDiscardablePixelRef.cpp revision 8e65712486c66108677a9b0a55ad3e7ca94db555
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 , fDiscardableMemoryIsLocked(false) 22{ 23 SkASSERT(fGenerator != NULL); 24 SkASSERT(fRowBytes > 0); 25 // The SkImageGenerator contract requires fGenerator to always 26 // decode the same image on each call to getPixels(). 27 this->setImmutable(); 28 SkSafeRef(fDMFactory); 29} 30 31SkDiscardablePixelRef::~SkDiscardablePixelRef() { 32 if (fDiscardableMemoryIsLocked) { 33 fDiscardableMemory->unlock(); 34 fDiscardableMemoryIsLocked = false; 35 } 36 SkDELETE(fDiscardableMemory); 37 SkSafeUnref(fDMFactory); 38 SkDELETE(fGenerator); 39} 40 41bool SkDiscardablePixelRef::onNewLockPixels(LockRec* rec) { 42 if (fDiscardableMemory != NULL) { 43 if (fDiscardableMemory->lock()) { 44 fDiscardableMemoryIsLocked = true; 45 rec->fPixels = fDiscardableMemory->data(); 46 rec->fColorTable = fCTable.get(); 47 rec->fRowBytes = fRowBytes; 48 return true; 49 } 50 SkDELETE(fDiscardableMemory); 51 fDiscardableMemory = NULL; 52 fDiscardableMemoryIsLocked = false; 53 } 54 55 const size_t size = this->info().getSafeSize(fRowBytes); 56 57 if (fDMFactory != NULL) { 58 fDiscardableMemory = fDMFactory->create(size); 59 fDiscardableMemoryIsLocked = true; 60 } else { 61 fDiscardableMemory = SkDiscardableMemory::Create(size); 62 fDiscardableMemoryIsLocked = true; 63 } 64 if (NULL == fDiscardableMemory) { 65 fDiscardableMemoryIsLocked = false; 66 return false; // Memory allocation failed. 67 } 68 69 void* pixels = fDiscardableMemory->data(); 70 const SkImageInfo& info = this->info(); 71 SkPMColor colors[256]; 72 int colorCount = 0; 73 74 const SkImageGenerator::Result result = fGenerator->getPixels(info, pixels, fRowBytes, 75 colors, &colorCount); 76 switch (result) { 77 case SkImageGenerator::kSuccess: 78 case SkImageGenerator::kIncompleteInput: 79 break; 80 default: 81 fDiscardableMemory->unlock(); 82 fDiscardableMemoryIsLocked = false; 83 SkDELETE(fDiscardableMemory); 84 fDiscardableMemory = NULL; 85 return false; 86 } 87 88 // Note: our ctable is not purgeable, as it is not stored in the discardablememory block. 89 // This is because SkColorTable is refcntable, and therefore our caller could hold onto it 90 // beyond the scope of a lock/unlock. If we change the API/lifecycle for SkColorTable, we 91 // could move it into the block, but then again perhaps it is small enough that this doesn't 92 // really matter. 93 if (colorCount > 0) { 94 fCTable.reset(SkNEW_ARGS(SkColorTable, (colors, colorCount))); 95 } else { 96 fCTable.reset(NULL); 97 } 98 99 rec->fPixels = pixels; 100 rec->fColorTable = fCTable.get(); 101 rec->fRowBytes = fRowBytes; 102 return true; 103} 104 105void SkDiscardablePixelRef::onUnlockPixels() { 106 fDiscardableMemory->unlock(); 107 fDiscardableMemoryIsLocked = false; 108} 109 110bool SkInstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst, 111 SkDiscardableMemory::Factory* factory) { 112 SkImageInfo info; 113 SkAutoTDelete<SkImageGenerator> autoGenerator(generator); 114 if ((NULL == autoGenerator.get()) 115 || (!autoGenerator->getInfo(&info)) 116 || info.isEmpty() 117 || (!dst->setInfo(info))) { 118 return false; 119 } 120 // Since dst->setInfo() may have changed/fixed-up info, we copy it back from that bitmap 121 info = dst->info(); 122 123 SkASSERT(info.colorType() != kUnknown_SkColorType); 124 if (dst->empty()) { // Use a normal pixelref. 125 return dst->tryAllocPixels(); 126 } 127 SkAutoTUnref<SkDiscardablePixelRef> ref( 128 SkNEW_ARGS(SkDiscardablePixelRef, 129 (info, autoGenerator.detach(), dst->rowBytes(), factory))); 130 dst->setPixelRef(ref); 131 return true; 132} 133 134// These are the public API 135 136bool SkInstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst) { 137 return SkInstallDiscardablePixelRef(generator, dst, NULL); 138} 139 140bool SkInstallDiscardablePixelRef(SkData* encoded, SkBitmap* dst) { 141 SkImageGenerator* generator = SkImageGenerator::NewFromData(encoded); 142 return generator ? SkInstallDiscardablePixelRef(generator, dst, NULL) : false; 143} 144