• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(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 
~SkDiscardablePixelRef()31 SkDiscardablePixelRef::~SkDiscardablePixelRef() {
32     if (fDiscardableMemoryIsLocked) {
33         fDiscardableMemory->unlock();
34         fDiscardableMemoryIsLocked = false;
35     }
36     delete fDiscardableMemory;
37     SkSafeUnref(fDMFactory);
38     delete fGenerator;
39 }
40 
onNewLockPixels(LockRec * rec)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 
onUnlockPixels()99 void SkDiscardablePixelRef::onUnlockPixels() {
100     fDiscardableMemory->unlock();
101     fDiscardableMemoryIsLocked = false;
102 }
103 
SkDEPRECATED_InstallDiscardablePixelRef(SkImageGenerator * generator,const SkIRect * subset,SkBitmap * dst,SkDiscardableMemory::Factory * factory)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 
SkDEPRECATED_InstallDiscardablePixelRef(SkImageGenerator * generator,SkBitmap * dst)147 bool SkDEPRECATED_InstallDiscardablePixelRef(SkImageGenerator* generator, SkBitmap* dst) {
148     return SkDEPRECATED_InstallDiscardablePixelRef(generator, nullptr, dst, nullptr);
149 }
150 
SkDEPRECATED_InstallDiscardablePixelRef(SkData * encoded,SkBitmap * dst)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