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(nullptr) 21 , fDiscardableMemoryIsLocked(false) 22 { 23 SkASSERT(fGenerator != nullptr); 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 31 SkDiscardablePixelRef::~SkDiscardablePixelRef() { 32 if (fDiscardableMemoryIsLocked) { 33 fDiscardableMemory->unlock(); 34 fDiscardableMemoryIsLocked = false; 35 } 36 delete fDiscardableMemory; 37 SkSafeUnref(fDMFactory); 38 delete fGenerator; 39 } 40 41 bool SkDiscardablePixelRef::onNewLockPixels(LockRec* rec) { 42 if (fDiscardableMemory != nullptr) { 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 delete fDiscardableMemory; 51 fDiscardableMemory = nullptr; 52 fDiscardableMemoryIsLocked = false; 53 } 54 55 const size_t size = this->info().getSafeSize(fRowBytes); 56 57 if (fDMFactory != nullptr) { 58 fDiscardableMemory = fDMFactory->create(size); 59 fDiscardableMemoryIsLocked = true; 60 } else { 61 fDiscardableMemory = SkDiscardableMemory::Create(size); 62 fDiscardableMemoryIsLocked = true; 63 } 64 if (nullptr == 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 if (!fGenerator->getPixels(info, pixels, fRowBytes, colors, &colorCount)) { 75 fDiscardableMemory->unlock(); 76 fDiscardableMemoryIsLocked = false; 77 delete fDiscardableMemory; 78 fDiscardableMemory = nullptr; 79 return false; 80 } 81 82 // Note: our ctable is not purgeable, as it is not stored in the discardablememory block. 83 // This is because SkColorTable is refcntable, and therefore our caller could hold onto it 84 // beyond the scope of a lock/unlock. If we change the API/lifecycle for SkColorTable, we 85 // could move it into the block, but then again perhaps it is small enough that this doesn't 86 // really matter. 87 if (colorCount > 0) { 88 fCTable.reset(new SkColorTable(colors, colorCount)); 89 } else { 90 fCTable.reset(nullptr); 91 } 92 93 rec->fPixels = pixels; 94 rec->fColorTable = fCTable.get(); 95 rec->fRowBytes = fRowBytes; 96 return true; 97 } 98 99 void SkDiscardablePixelRef::onUnlockPixels() { 100 fDiscardableMemory->unlock(); 101 fDiscardableMemoryIsLocked = false; 102 } 103 104 bool SkDEPRECATED_InstallDiscardablePixelRef(SkImageGenerator* generator, const SkIRect* subset, 105 SkBitmap* dst, SkDiscardableMemory::Factory* factory) { 106 SkAutoTDelete<SkImageGenerator> autoGenerator(generator); 107 if (nullptr == autoGenerator.get()) { 108 return false; 109 } 110 111 SkImageInfo prInfo = autoGenerator->getInfo(); 112 if (prInfo.isEmpty()) { 113 return false; 114 } 115 116 SkIPoint origin = SkIPoint::Make(0, 0); 117 SkImageInfo bmInfo = prInfo; 118 if (subset) { 119 const SkIRect prBounds = SkIRect::MakeWH(prInfo.width(), prInfo.height()); 120 if (subset->isEmpty() || !prBounds.contains(*subset)) { 121 return false; 122 } 123 bmInfo = prInfo.makeWH(subset->width(), subset->height()); 124 origin.set(subset->x(), subset->y()); 125 } 126 127 // must compute our desired rowBytes w.r.t. the pixelRef's dimensions, not ours, which may be 128 // smaller. 129 if (!dst->setInfo(bmInfo, prInfo.minRowBytes())) { 130 return false; 131 } 132 133 // Since dst->setInfo() may have changed/fixed-up info, we check from the bitmap 134 SkASSERT(dst->info().colorType() != kUnknown_SkColorType); 135 136 if (dst->empty()) { // Use a normal pixelref. 137 return dst->tryAllocPixels(); 138 } 139 SkAutoTUnref<SkDiscardablePixelRef> ref( 140 new SkDiscardablePixelRef(prInfo, autoGenerator.detach(), dst->rowBytes(), factory)); 141 dst->setPixelRef(ref, origin.x(), origin.y()); 142 return true; 143 } 144 145 // These are the public API 146 147 bool SkDEPRECATED_InstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst) { 148 return SkDEPRECATED_InstallDiscardablePixelRef(generator, nullptr, dst, nullptr); 149 } 150 151 bool SkDEPRECATED_InstallDiscardablePixelRef(SkData* encoded, SkBitmap* dst) { 152 SkImageGenerator* generator = SkImageGenerator::NewFromEncoded(encoded); 153 return generator ? 154 SkDEPRECATED_InstallDiscardablePixelRef(generator, nullptr, dst, nullptr) : false; 155 } 156