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

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

Issue 1153123003: refactor bitmapshader to use a controller (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 6 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
OLDNEW
(Empty)
1 /*
2 * Copyright 2015 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 "SkBitmap.h"
9 #include "SkBitmapController.h"
10 #include "SkMatrix.h"
11
12 //////////////////////////////////////////////////////////////////////////////// ///////////////////
13
14 static bool valid_for_drawing(const SkBitmap& bm) {
15 if (0 == bm.width() || 0 == bm.height()) {
16 return false; // nothing to draw
17 }
18 if (NULL == bm.pixelRef()) {
19 return false; // no pixels to read
20 }
21 if (bm.getTexture()) {
22 // we can handle texture (ugh) since lockPixels will perform a read-back
23 return true;
24 }
25 if (kIndex_8_SkColorType == bm.colorType()) {
26 SkAutoLockPixels alp(bm); // but we need to call it before getColorTable () is safe.
27 if (!bm.getColorTable()) {
28 return false;
29 }
30 }
31 return true;
32 }
33
34 SkBitmapController::State* SkBitmapController::requestBitmap(const SkBitmap& bm,
35 const SkMatrix& inv ,
36 SkFilterQuality qua lity,
37 void* storage, size _t storageSize) {
38
39 if (!valid_for_drawing(bm)) {
40 return NULL;
41 }
42
43 State* state = this->onRequestBitmap(bm, inv, quality, storage, storageSize) ;
44 if (state) {
45 if (!state->fLockedBitmap.getPixels()) {
46 state->fLockedBitmap.lockPixels();
47 if (!state->fLockedBitmap.getPixels()) {
48 SkInPlaceDeleteCheck(state, storage);
49 state = NULL;
50 }
51 }
52 }
53 return state;
54 }
55
56 //////////////////////////////////////////////////////////////////////////////// ///////////////////
57
58 #include "SkBitmapCache.h"
59 #include "SkBitmapScaler.h"
60 #include "SkMipMap.h"
61 #include "SkResourceCache.h"
62
63 class SkDefaultBitmapControllerState : public SkBitmapController::State {
64 public:
65 SkDefaultBitmapControllerState(const SkBitmap& src, const SkMatrix& inv, SkF ilterQuality qual);
66
67 private:
68 SkAutoTUnref<const SkMipMap> fCurrMip;
69
70 bool processHQRequest(const SkBitmap& orig);
71 bool processMediumRequest(const SkBitmap& orig);
72 };
73
74 // Check to see that the size of the bitmap that would be produced by
75 // scaling by the given inverted matrix is less than the maximum allowed.
76 static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) {
77 size_t maximumAllocation = SkResourceCache::GetEffectiveSingleAllocationByte Limit();
78 if (0 == maximumAllocation) {
79 return true;
80 }
81 // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY);
82 // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize);
83 // Skip the division step:
84 const size_t size = bm.info().getSafeSize(bm.info().minRowBytes());
85 return size < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY());
86 }
87
88 /*
89 * High quality is implemented by performing up-right scale-only filtering and then
90 * using bilerp for any remaining transformations.
91 */
92 bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmap& origBitmap ) {
93 if (fQuality != kHigh_SkFilterQuality) {
94 return false;
95 }
96
97 // Our default return state is to downgrade the request to Medium, w/ or w/o setting fBitmap
98 // to a valid bitmap. If we succeed, we will set this to Low instead.
99 fQuality = kMedium_SkFilterQuality;
100
101 if (kN32_SkColorType != origBitmap.colorType() || !cache_size_okay(origBitma p, fInvMatrix) ||
102 fInvMatrix.hasPerspective())
103 {
104 return false; // can't handle the reqeust
105 }
106
107 SkScalar invScaleX = fInvMatrix.getScaleX();
108 SkScalar invScaleY = fInvMatrix.getScaleY();
109 if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) {
110 SkSize scale;
111 if (!fInvMatrix.decomposeScale(&scale)) {
112 return false;
113 }
114 invScaleX = scale.width();
115 invScaleY = scale.height();
116 }
117 if (SkScalarNearlyEqual(invScaleX, 1) && SkScalarNearlyEqual(invScaleY, 1)) {
118 return false; // no need for HQ
119 }
120
121 SkScalar trueDestWidth = origBitmap.width() / invScaleX;
122 SkScalar trueDestHeight = origBitmap.height() / invScaleY;
123 SkScalar roundedDestWidth = SkScalarRoundToScalar(trueDestWidth);
124 SkScalar roundedDestHeight = SkScalarRoundToScalar(trueDestHeight);
125
126 if (!SkBitmapCache::Find(origBitmap, roundedDestWidth, roundedDestHeight, &f LockedBitmap)) {
127 if (!SkBitmapScaler::Resize(&fLockedBitmap,
128 origBitmap,
129 SkBitmapScaler::RESIZE_BEST,
130 roundedDestWidth,
131 roundedDestHeight,
132 SkResourceCache::GetAllocator())) {
133 return false; // we failed to create fScaledBitmap
134 }
135
136 SkASSERT(fLockedBitmap.getPixels());
137 fLockedBitmap.setImmutable();
138 SkBitmapCache::Add(origBitmap, roundedDestWidth, roundedDestHeight, fLoc kedBitmap);
139 }
140
141 SkASSERT(fLockedBitmap.getPixels());
142
143 fInvMatrix.postScale(roundedDestWidth / origBitmap.width(),
144 roundedDestHeight / origBitmap.height());
145 fQuality = kLow_SkFilterQuality;
146 return true;
147 }
148
149 /*
150 * 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)
152 */
153 bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmap& origBi tmap) {
154 SkASSERT(fQuality <= kMedium_SkFilterQuality);
155 if (fQuality != kMedium_SkFilterQuality) {
156 return false;
157 }
158
159 // Our default return state is to downgrade the request to Low, w/ or w/o se tting fBitmap
160 // to a valid bitmap.
161 fQuality = kLow_SkFilterQuality;
162
163 SkSize invScaleSize;
164 if (!fInvMatrix.decomposeScale(&invScaleSize, NULL)) {
165 return false;
166 }
167 SkScalar invScale = SkScalarSqrt(invScaleSize.width() * invScaleSize.height( ));
168
169 if (invScale > SK_Scalar1) {
170 fCurrMip.reset(SkMipMapCache::FindAndRef(origBitmap));
171 if (NULL == fCurrMip.get()) {
172 fCurrMip.reset(SkMipMapCache::AddAndRef(origBitmap));
173 if (NULL == fCurrMip.get()) {
174 return false;
175 }
176 }
177 // diagnostic for a crasher...
178 if (NULL == fCurrMip->data()) {
179 sk_throw();
180 }
181
182 SkScalar levelScale = SkScalarInvert(invScale);
183 SkMipMap::Level level;
184 if (fCurrMip->extractLevel(levelScale, &level)) {
185 SkScalar invScaleFixup = level.fScale;
186 fInvMatrix.postScale(invScaleFixup, invScaleFixup);
187
188 const SkImageInfo info = origBitmap.info().makeWH(level.fWidth, leve l.fHeight);
189 // 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.
191 return fLockedBitmap.installPixels(info, level.fPixels, level.fRowBy tes);
192 } else {
193 // failed to extract, so release the mipmap
194 fCurrMip.reset(NULL);
195 }
196 }
197 return false;
198 }
199
200 SkDefaultBitmapControllerState::SkDefaultBitmapControllerState(const SkBitmap& s rc,
201 const SkMatrix& i nv,
202 SkFilterQuality q ual) {
203 fInvMatrix = inv;
204 fQuality = qual;
205
206 if (!this->processHQRequest(src) && !this->processMediumRequest(src)) {
207 fLockedBitmap = src;
208 }
209 SkASSERT(fQuality <= kLow_SkFilterQuality);
210 }
211
212 SkBitmapController::State* SkDefaultBitmapController::onRequestBitmap(const SkBi tmap& bm,
213 const SkMa trix& inverse,
214 SkFilterQu ality quality,
215 void* stor age, size_t size) {
216 return SkInPlaceNewCheck<SkDefaultBitmapControllerState>(storage, size, bm, inverse, quality);
217 }
218
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698