Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Side by Side Diff: src/core/SkBitmapController.cpp

Issue 1340223003: create SkBitmapProvider to abstract images and bitmaps (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: remove obsolete comments Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/core/SkBitmapController.h ('k') | tests/SkResourceCacheTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkBitmap.h" 8 #include "SkBitmap.h"
9 #include "SkBitmapController.h" 9 #include "SkBitmapController.h"
10 #include "SkImage_Base.h"
10 #include "SkMatrix.h" 11 #include "SkMatrix.h"
12 #include "SkPixelRef.h"
11 #include "SkTemplates.h" 13 #include "SkTemplates.h"
12 14
13 // RESIZE_LANCZOS3 is another good option, but chrome prefers mitchell at the mo ment 15 // RESIZE_LANCZOS3 is another good option, but chrome prefers mitchell at the mo ment
14 #define kHQ_RESIZE_METHOD SkBitmapScaler::RESIZE_MITCHELL 16 #define kHQ_RESIZE_METHOD SkBitmapScaler::RESIZE_MITCHELL
15 17
16 //////////////////////////////////////////////////////////////////////////////// /////////////////// 18 //////////////////////////////////////////////////////////////////////////////// ///////////////////
17 19
18 static bool valid_for_drawing(const SkBitmap& bm) { 20 int SkBitmapProvider::width() const {
19 if (0 == bm.width() || 0 == bm.height()) { 21 return fImage ? fImage->width() : fBitmap.width();
20 return false; // nothing to draw 22 }
21 } 23
22 if (nullptr == bm.pixelRef()) { 24 int SkBitmapProvider::height() const {
23 return false; // no pixels to read 25 return fImage ? fImage->height() : fBitmap.height();
24 } 26 }
25 if (bm.getTexture()) { 27
26 // we can handle texture (ugh) since lockPixels will perform a read-back 28 uint32_t SkBitmapProvider::getID() const {
27 return true; 29 return fImage ? fImage->uniqueID() : fBitmap.getGenerationID();
28 } 30 }
29 if (kIndex_8_SkColorType == bm.colorType()) { 31
30 SkAutoLockPixels alp(bm); // but we need to call it before getColorTable () is safe. 32 bool SkBitmapProvider::validForDrawing() const {
31 if (!bm.getColorTable()) { 33 if (!fImage) {
34 if (0 == fBitmap.width() || 0 == fBitmap.height()) {
32 return false; 35 return false;
33 } 36 }
37 if (nullptr == fBitmap.pixelRef()) {
38 return false; // no pixels to read
39 }
40 if (fBitmap.getTexture()) {
41 // we can handle texture (ugh) since lockPixels will perform a read- back
42 return true;
43 }
44 if (kIndex_8_SkColorType == fBitmap.colorType()) {
45 SkAutoLockPixels alp(fBitmap); // but we need to call it before getC olorTable() is safe.
46 if (!fBitmap.getColorTable()) {
47 return false;
48 }
49 }
34 } 50 }
35 return true; 51 return true;
36 } 52 }
37 53
38 SkBitmapController::State* SkBitmapController::requestBitmap(const SkBitmap& bm, 54 SkImageInfo SkBitmapProvider::info() const {
55 if (fImage) {
56 SkAlphaType at = fImage->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAl phaType;
57 return SkImageInfo::MakeN32(fImage->width(), fImage->height(), at);
58 } else {
59 return fBitmap.info();
60 }
61 }
62
63 SkBitmapCacheDesc SkBitmapProvider::makeCacheDesc(int w, int h) const {
64 return fImage ? SkBitmapCacheDesc::Make(fImage, w, h) : SkBitmapCacheDesc::M ake(fBitmap, w, h);
65 }
66
67 SkBitmapCacheDesc SkBitmapProvider::makeCacheDesc() const {
68 return fImage ? SkBitmapCacheDesc::Make(fImage) : SkBitmapCacheDesc::Make(fB itmap);
69 }
70
71 void SkBitmapProvider::notifyAddedToCache() const {
72 if (fImage) {
73 // TODO
74 } else {
75 fBitmap.pixelRef()->notifyAddedToCache();
76 }
77 }
78
79 bool SkBitmapProvider::asBitmap(SkBitmap* bm) const {
80 if (fImage) {
81 return as_IB(fImage)->getROPixels(bm);
82 } else {
83 *bm = fBitmap;
84 return true;
85 }
86 }
87
88 //////////////////////////////////////////////////////////////////////////////// ///////////////////
89
90 SkBitmapController::State* SkBitmapController::requestBitmap(const SkBitmapProvi der& provider,
39 const SkMatrix& inv , 91 const SkMatrix& inv ,
40 SkFilterQuality qua lity, 92 SkFilterQuality qua lity,
41 void* storage, size _t storageSize) { 93 void* storage, size _t storageSize) {
42 94 if (!provider.validForDrawing()) {
43 if (!valid_for_drawing(bm)) {
44 return nullptr; 95 return nullptr;
45 } 96 }
46 97
47 State* state = this->onRequestBitmap(bm, inv, quality, storage, storageSize) ; 98 State* state = this->onRequestBitmap(provider, inv, quality, storage, storag eSize);
48 if (state) { 99 if (state) {
49 if (nullptr == state->fPixmap.addr()) { 100 if (nullptr == state->fPixmap.addr()) {
50 SkInPlaceDeleteCheck(state, storage); 101 SkInPlaceDeleteCheck(state, storage);
51 state = nullptr; 102 state = nullptr;
52 } 103 }
53 } 104 }
54 return state; 105 return state;
55 } 106 }
56 107
57 //////////////////////////////////////////////////////////////////////////////// /////////////////// 108 //////////////////////////////////////////////////////////////////////////////// ///////////////////
58 109
59 #include "SkBitmapCache.h" 110 #include "SkBitmapCache.h"
60 #include "SkBitmapScaler.h" 111 #include "SkBitmapScaler.h"
61 #include "SkMipMap.h" 112 #include "SkMipMap.h"
62 #include "SkResourceCache.h" 113 #include "SkResourceCache.h"
63 114
64 class SkDefaultBitmapControllerState : public SkBitmapController::State { 115 class SkDefaultBitmapControllerState : public SkBitmapController::State {
65 public: 116 public:
66 SkDefaultBitmapControllerState(const SkBitmap& src, const SkMatrix& inv, SkF ilterQuality qual); 117 SkDefaultBitmapControllerState(const SkBitmapProvider&, const SkMatrix& inv, SkFilterQuality);
67 118
68 private: 119 private:
69 SkBitmap fResultBitmap; 120 SkBitmap fResultBitmap;
70 SkAutoTUnref<const SkMipMap> fCurrMip; 121 SkAutoTUnref<const SkMipMap> fCurrMip;
71 122
72 bool processHQRequest(const SkBitmap& orig); 123 bool processHQRequest(const SkBitmapProvider&);
73 bool processMediumRequest(const SkBitmap& orig); 124 bool processMediumRequest(const SkBitmapProvider&);
74 }; 125 };
75 126
76 // Check to see that the size of the bitmap that would be produced by 127 // Check to see that the size of the bitmap that would be produced by
77 // scaling by the given inverted matrix is less than the maximum allowed. 128 // scaling by the given inverted matrix is less than the maximum allowed.
78 static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) { 129 static inline bool cache_size_okay(const SkBitmapProvider& provider, const SkMat rix& invMat) {
79 size_t maximumAllocation = SkResourceCache::GetEffectiveSingleAllocationByte Limit(); 130 size_t maximumAllocation = SkResourceCache::GetEffectiveSingleAllocationByte Limit();
80 if (0 == maximumAllocation) { 131 if (0 == maximumAllocation) {
81 return true; 132 return true;
82 } 133 }
83 // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY); 134 // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY);
84 // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize); 135 // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize);
85 // Skip the division step: 136 // Skip the division step:
86 const size_t size = bm.info().getSafeSize(bm.info().minRowBytes()); 137 const size_t size = provider.info().getSafeSize(provider.info().minRowBytes( ));
87 return size < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY()); 138 return size < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY());
88 } 139 }
89 140
90 /* 141 /*
91 * High quality is implemented by performing up-right scale-only filtering and then 142 * High quality is implemented by performing up-right scale-only filtering and then
92 * using bilerp for any remaining transformations. 143 * using bilerp for any remaining transformations.
93 */ 144 */
94 bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmap& origBitmap ) { 145 bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmapProvider& pr ovider) {
95 if (fQuality != kHigh_SkFilterQuality) { 146 if (fQuality != kHigh_SkFilterQuality) {
96 return false; 147 return false;
97 } 148 }
98 149
99 // Our default return state is to downgrade the request to Medium, w/ or w/o setting fBitmap 150 // Our default return state is to downgrade the request to Medium, w/ or w/o setting fBitmap
100 // to a valid bitmap. If we succeed, we will set this to Low instead. 151 // to a valid bitmap. If we succeed, we will set this to Low instead.
101 fQuality = kMedium_SkFilterQuality; 152 fQuality = kMedium_SkFilterQuality;
102 153
103 if (kN32_SkColorType != origBitmap.colorType() || !cache_size_okay(origBitma p, fInvMatrix) || 154 if (kN32_SkColorType != provider.info().colorType() || !cache_size_okay(prov ider, fInvMatrix) ||
104 fInvMatrix.hasPerspective()) 155 fInvMatrix.hasPerspective())
105 { 156 {
106 return false; // can't handle the reqeust 157 return false; // can't handle the reqeust
107 } 158 }
108 159
109 SkScalar invScaleX = fInvMatrix.getScaleX(); 160 SkScalar invScaleX = fInvMatrix.getScaleX();
110 SkScalar invScaleY = fInvMatrix.getScaleY(); 161 SkScalar invScaleY = fInvMatrix.getScaleY();
111 if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) { 162 if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) {
112 SkSize scale; 163 SkSize scale;
113 if (!fInvMatrix.decomposeScale(&scale)) { 164 if (!fInvMatrix.decomposeScale(&scale)) {
114 return false; 165 return false;
115 } 166 }
116 invScaleX = scale.width(); 167 invScaleX = scale.width();
117 invScaleY = scale.height(); 168 invScaleY = scale.height();
118 } 169 }
119 if (SkScalarNearlyEqual(invScaleX, 1) && SkScalarNearlyEqual(invScaleY, 1)) { 170 if (SkScalarNearlyEqual(invScaleX, 1) && SkScalarNearlyEqual(invScaleY, 1)) {
120 return false; // no need for HQ 171 return false; // no need for HQ
121 } 172 }
122 173
123 const int dstW = SkScalarRoundToScalar(origBitmap.width() / invScaleX); 174 const int dstW = SkScalarRoundToScalar(provider.width() / invScaleX);
124 const int dstH = SkScalarRoundToScalar(origBitmap.height() / invScaleY); 175 const int dstH = SkScalarRoundToScalar(provider.height() / invScaleY);
125 176 const SkBitmapCacheDesc desc = provider.makeCacheDesc(dstW, dstH);
126 if (!SkBitmapCache::FindWH(origBitmap, dstW, dstH, &fResultBitmap)) { 177
178 if (!SkBitmapCache::FindWH(desc, &fResultBitmap)) {
179 SkBitmap orig;
180 if (!provider.asBitmap(&orig)) {
181 return false;
182 }
127 SkAutoPixmapUnlock src; 183 SkAutoPixmapUnlock src;
128 if (!origBitmap.requestLock(&src)) { 184 if (!orig.requestLock(&src)) {
129 return false; 185 return false;
130 } 186 }
131 if (!SkBitmapScaler::Resize(&fResultBitmap, src.pixmap(), kHQ_RESIZE_MET HOD, 187 if (!SkBitmapScaler::Resize(&fResultBitmap, src.pixmap(), kHQ_RESIZE_MET HOD,
132 dstW, dstH, SkResourceCache::GetAllocator()) ) { 188 dstW, dstH, SkResourceCache::GetAllocator()) ) {
133 return false; // we failed to create fScaledBitmap 189 return false; // we failed to create fScaledBitmap
134 } 190 }
135 191
136 SkASSERT(fResultBitmap.getPixels()); 192 SkASSERT(fResultBitmap.getPixels());
137 fResultBitmap.setImmutable(); 193 fResultBitmap.setImmutable();
138 SkBitmapCache::AddWH(origBitmap, dstW, dstH, fResultBitmap); 194 if (SkBitmapCache::AddWH(desc, fResultBitmap)) {
195 provider.notifyAddedToCache();
196 }
139 } 197 }
140 198
141 SkASSERT(fResultBitmap.getPixels()); 199 SkASSERT(fResultBitmap.getPixels());
142 200
143 fInvMatrix.postScale(SkIntToScalar(dstW) / origBitmap.width(), 201 fInvMatrix.postScale(SkIntToScalar(dstW) / provider.width(),
144 SkIntToScalar(dstH) / origBitmap.height()); 202 SkIntToScalar(dstH) / provider.height());
145 fQuality = kLow_SkFilterQuality; 203 fQuality = kLow_SkFilterQuality;
146 return true; 204 return true;
147 } 205 }
148 206
149 /* 207 /*
150 * Modulo internal errors, this should always succeed *if* the matrix is downsc aling 208 * Modulo internal errors, this should always succeed *if* the matrix is downsc aling
151 * (in this case, we have the inverse, so it succeeds if fInvMatrix is upscalin g) 209 * (in this case, we have the inverse, so it succeeds if fInvMatrix is upscalin g)
152 */ 210 */
153 bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmap& origBi tmap) { 211 bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmapProvider & provider) {
154 SkASSERT(fQuality <= kMedium_SkFilterQuality); 212 SkASSERT(fQuality <= kMedium_SkFilterQuality);
155 if (fQuality != kMedium_SkFilterQuality) { 213 if (fQuality != kMedium_SkFilterQuality) {
156 return false; 214 return false;
157 } 215 }
158 216
159 // Our default return state is to downgrade the request to Low, w/ or w/o se tting fBitmap 217 // Our default return state is to downgrade the request to Low, w/ or w/o se tting fBitmap
160 // to a valid bitmap. 218 // to a valid bitmap.
161 fQuality = kLow_SkFilterQuality; 219 fQuality = kLow_SkFilterQuality;
162 220
163 SkSize invScaleSize; 221 SkSize invScaleSize;
164 if (!fInvMatrix.decomposeScale(&invScaleSize, nullptr)) { 222 if (!fInvMatrix.decomposeScale(&invScaleSize, nullptr)) {
165 return false; 223 return false;
166 } 224 }
167 SkScalar invScale = SkScalarSqrt(invScaleSize.width() * invScaleSize.height( )); 225 SkScalar invScale = SkScalarSqrt(invScaleSize.width() * invScaleSize.height( ));
168 226
169 if (invScale > SK_Scalar1) { 227 if (invScale > SK_Scalar1) {
170 fCurrMip.reset(SkMipMapCache::FindAndRef(origBitmap)); 228 fCurrMip.reset(SkMipMapCache::FindAndRef(provider.makeCacheDesc()));
171 if (nullptr == fCurrMip.get()) { 229 if (nullptr == fCurrMip.get()) {
172 fCurrMip.reset(SkMipMapCache::AddAndRef(origBitmap)); 230 SkBitmap orig;
231 if (!provider.asBitmap(&orig)) {
232 return false;
233 }
234 fCurrMip.reset(SkMipMapCache::AddAndRef(orig));
173 if (nullptr == fCurrMip.get()) { 235 if (nullptr == fCurrMip.get()) {
174 return false; 236 return false;
175 } 237 }
176 } 238 }
177 // diagnostic for a crasher... 239 // diagnostic for a crasher...
178 if (nullptr == fCurrMip->data()) { 240 if (nullptr == fCurrMip->data()) {
179 sk_throw(); 241 sk_throw();
180 } 242 }
181 243
182 SkScalar levelScale = SkScalarInvert(invScale); 244 SkScalar levelScale = SkScalarInvert(invScale);
183 SkMipMap::Level level; 245 SkMipMap::Level level;
184 if (fCurrMip->extractLevel(levelScale, &level)) { 246 if (fCurrMip->extractLevel(levelScale, &level)) {
185 SkScalar invScaleFixup = level.fScale; 247 SkScalar invScaleFixup = level.fScale;
186 fInvMatrix.postScale(invScaleFixup, invScaleFixup); 248 fInvMatrix.postScale(invScaleFixup, invScaleFixup);
187 249
188 const SkImageInfo info = origBitmap.info().makeWH(level.fWidth, leve l.fHeight); 250 const SkImageInfo info = provider.info().makeWH(level.fWidth, level. fHeight);
189 // todo: if we could wrap the fCurrMip in a pixelref, then we could just install 251 // todo: if we could wrap the fCurrMip in a pixelref, then we could just install
190 // that here, and not need to explicitly track it ourselves. 252 // that here, and not need to explicitly track it ourselves.
191 return fResultBitmap.installPixels(info, level.fPixels, level.fRowBy tes); 253 return fResultBitmap.installPixels(info, level.fPixels, level.fRowBy tes);
192 } else { 254 } else {
193 // failed to extract, so release the mipmap 255 // failed to extract, so release the mipmap
194 fCurrMip.reset(nullptr); 256 fCurrMip.reset(nullptr);
195 } 257 }
196 } 258 }
197 return false; 259 return false;
198 } 260 }
199 261
200 SkDefaultBitmapControllerState::SkDefaultBitmapControllerState(const SkBitmap& s rc, 262 SkDefaultBitmapControllerState::SkDefaultBitmapControllerState(const SkBitmapPro vider& provider,
201 const SkMatrix& i nv, 263 const SkMatrix& i nv,
202 SkFilterQuality q ual) { 264 SkFilterQuality q ual) {
203 fInvMatrix = inv; 265 fInvMatrix = inv;
204 fQuality = qual; 266 fQuality = qual;
205 267
206 if (this->processHQRequest(src) || this->processMediumRequest(src)) { 268 if (this->processHQRequest(provider) || this->processMediumRequest(provider) ) {
207 SkASSERT(fResultBitmap.getPixels()); 269 SkASSERT(fResultBitmap.getPixels());
208 } else { 270 } else {
209 fResultBitmap = src; 271 (void)provider.asBitmap(&fResultBitmap);
210 fResultBitmap.lockPixels(); 272 fResultBitmap.lockPixels();
211 // lock may fail to give us pixels 273 // lock may fail to give us pixels
212 } 274 }
213 SkASSERT(fQuality <= kLow_SkFilterQuality); 275 SkASSERT(fQuality <= kLow_SkFilterQuality);
214 276
215 // fResultBitmap.getPixels() may be null, but our caller knows to check fPix map.addr() 277 // fResultBitmap.getPixels() may be null, but our caller knows to check fPix map.addr()
216 // and will destroy us if it is nullptr. 278 // and will destroy us if it is nullptr.
217 fPixmap.reset(fResultBitmap.info(), fResultBitmap.getPixels(), fResultBitmap .rowBytes(), 279 fPixmap.reset(fResultBitmap.info(), fResultBitmap.getPixels(), fResultBitmap .rowBytes(),
218 fResultBitmap.getColorTable()); 280 fResultBitmap.getColorTable());
219 } 281 }
220 282
221 SkBitmapController::State* SkDefaultBitmapController::onRequestBitmap(const SkBi tmap& bm, 283 SkBitmapController::State* SkDefaultBitmapController::onRequestBitmap(const SkBi tmapProvider& bm,
222 const SkMa trix& inverse, 284 const SkMa trix& inverse,
223 SkFilterQu ality quality, 285 SkFilterQu ality quality,
224 void* stor age, size_t size) { 286 void* stor age, size_t size) {
225 return SkInPlaceNewCheck<SkDefaultBitmapControllerState>(storage, size, bm, inverse, quality); 287 return SkInPlaceNewCheck<SkDefaultBitmapControllerState>(storage, size, bm, inverse, quality);
226 } 288 }
227 289
OLDNEW
« no previous file with comments | « src/core/SkBitmapController.h ('k') | tests/SkResourceCacheTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698