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
SkDiscardablePixelRef(const SkImageInfo & info,SkImageGenerator * generator,size_t rowBytes,SkDiscardableMemory::Factory * fact)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 , 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
~SkDiscardablePixelRef()31 SkDiscardablePixelRef::~SkDiscardablePixelRef() {
32 if (fDiscardableMemoryIsLocked) {
33 fDiscardableMemory->unlock();
34 fDiscardableMemoryIsLocked = false;
35 }
36 SkDELETE(fDiscardableMemory);
37 SkSafeUnref(fDMFactory);
38 SkDELETE(fGenerator);
39 }
40
onNewLockPixels(LockRec * rec)41 bool 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, NULL,
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
onUnlockPixels()105 void SkDiscardablePixelRef::onUnlockPixels() {
106 fDiscardableMemory->unlock();
107 fDiscardableMemoryIsLocked = false;
108 }
109
SkInstallDiscardablePixelRef(SkImageGenerator * generator,SkBitmap * dst,SkDiscardableMemory::Factory * factory)110 bool SkInstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst,
111 SkDiscardableMemory::Factory* factory) {
112 SkAutoTDelete<SkImageGenerator> autoGenerator(generator);
113 if (NULL == autoGenerator.get()) {
114 return false;
115 }
116 SkImageInfo info = autoGenerator->getInfo();
117 if (info.isEmpty() || !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
SkInstallDiscardablePixelRef(SkImageGenerator * generator,SkBitmap * dst)136 bool SkInstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst) {
137 return SkInstallDiscardablePixelRef(generator, dst, NULL);
138 }
139
SkInstallDiscardablePixelRef(SkData * encoded,SkBitmap * dst)140 bool SkInstallDiscardablePixelRef(SkData* encoded, SkBitmap* dst) {
141 SkImageGenerator* generator = SkImageGenerator::NewFromData(encoded);
142 return generator ? SkInstallDiscardablePixelRef(generator, dst, NULL) : false;
143 }
144