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 12 SkDiscardablePixelRef::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 30 SkDiscardablePixelRef::~SkDiscardablePixelRef() { 31 if (this->isLocked()) { 32 fDiscardableMemory->unlock(); 33 } 34 SkDELETE(fDiscardableMemory); 35 SkSafeUnref(fDMFactory); 36 SkDELETE(fGenerator); 37 } 38 39 bool SkDiscardablePixelRef::onNewLockPixels(LockRec* rec) { 40 if (fDiscardableMemory != NULL) { 41 if (fDiscardableMemory->lock()) { 42 rec->fPixels = fDiscardableMemory->data(); 43 rec->fColorTable = fCTable.get(); 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 95 void SkDiscardablePixelRef::onUnlockPixels() { 96 fDiscardableMemory->unlock(); 97 } 98 99 bool 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 // Since dst->setInfo() may have changed/fixed-up info, we copy it back from that bitmap 109 info = dst->info(); 110 111 SkASSERT(info.colorType() != kUnknown_SkColorType); 112 if (dst->empty()) { // Use a normal pixelref. 113 return dst->tryAllocPixels(); 114 } 115 SkAutoTUnref<SkDiscardablePixelRef> ref( 116 SkNEW_ARGS(SkDiscardablePixelRef, 117 (info, autoGenerator.detach(), dst->rowBytes(), factory))); 118 dst->setPixelRef(ref); 119 return true; 120 } 121 122 // This is the public API 123 bool SkInstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst) { 124 return SkInstallDiscardablePixelRef(generator, dst, NULL); 125 } 126