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