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

Side by Side Diff: skia/ext/analysis_canvas.cc

Issue 12316084: cc: Consolidate the analysis_canvas operations (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 9 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/debug/trace_event.h" 5 #include "base/debug/trace_event.h"
6 #include "skia/ext/analysis_canvas.h" 6 #include "skia/ext/analysis_canvas.h"
7 #include "third_party/skia/include/core/SkDevice.h" 7 #include "third_party/skia/include/core/SkDevice.h"
8 #include "third_party/skia/include/core/SkDraw.h" 8 #include "third_party/skia/include/core/SkDraw.h"
9 #include "third_party/skia/include/core/SkRRect.h" 9 #include "third_party/skia/include/core/SkRRect.h"
10 #include "third_party/skia/src/core/SkRasterClip.h"
10 #include "ui/gfx/rect_conversions.h" 11 #include "ui/gfx/rect_conversions.h"
11 12
12 namespace { 13 namespace {
13 14
14 // FIXME: Arbitrary number. Requires tuning & experimentation. 15 // FIXME: Arbitrary number. Requires tuning & experimentation.
15 // Probably requires per-platform tuning; N10 average draw call takes 16 // Probably requires per-platform tuning; N10 average draw call takes
16 // 25x as long as Z620. 17 // 25x as long as Z620.
17 const int gPictureCostThreshold = 1000; 18 const int gPictureCostThreshold = 1000;
18 19
20 static bool isSolidColorPaint(const SkPaint& paint) {
21 SkXfermode::Mode xferMode;
22
23 // getXfermode can return a NULL, but that is handled
24 // gracefully by AsMode (NULL turns into kSrcOver mode).
25 SkXfermode::AsMode(paint.getXfermode(), &xferMode);
26
27 // Paint is solid color if the following holds:
28 // - Alpha is 1.0, style is fill, and there are no special effects
29 // - Xfer mode is either kSrc or kSrcOver (kSrcOver is equivalent
30 // to kSrc if source alpha is 1.0, which is already checked).
31 return (paint.getAlpha() == 255 &&
32 !paint.getShader() &&
33 !paint.getLooper() &&
34 !paint.getMaskFilter() &&
35 !paint.getColorFilter() &&
36 paint.getStyle() == SkPaint::kFill_Style &&
37 (xferMode == SkXfermode::kSrc_Mode ||
38 xferMode == SkXfermode::kSrcOver_Mode));
19 } 39 }
20 40
41 static bool isFullQuad(const SkDraw& draw,
42 const SkRect& canvasRect,
43 const SkRect& drawnRect) {
44
45 // If the transform results in a non-axis aligned
46 // rect, then be conservative and return false.
47 if (!draw.fMatrix->rectStaysRect())
48 return false;
49
50 SkRect drawBitmapRect;
51 draw.fBitmap->getBounds(&drawBitmapRect);
52 SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
53 SkRect deviceRect;
54 draw.fMatrix->mapRect(&deviceRect, drawnRect);
55
56 // The drawn rect covers the full canvas, if the following conditions hold:
57 // - Clip rect is an actual rectangle.
58 // - The rect we're drawing (post-transform) contains the clip rect.
59 // That is, all of clip rect will be colored by the rect.
60 // - Clip rect contains the canvas rect.
61 // That is, we're not clipping to a portion of this canvas.
62 // - The bitmap into which the draw call happens is at least as
63 // big as the canvas rect
64 return draw.fRC->isRect() &&
Justin Novosad 2013/03/06 15:24:43 You can remove test on draw.fRC->isRect() since we
65 deviceRect.contains(clipRect) &&
66 clipRect.contains(canvasRect) &&
67 drawBitmapRect.contains(canvasRect);
68 }
69
70 } // namespace
71
21 namespace skia { 72 namespace skia {
22 73
23 AnalysisDevice::AnalysisDevice(const SkBitmap& bm) 74 AnalysisDevice::AnalysisDevice(const SkBitmap& bm)
24 : INHERITED(bm) 75 : INHERITED(bm)
25 , estimatedCost_(0) { 76 , estimatedCost_(0)
77 , isForcedNotSolid_(false)
78 , isForcedNotTransparent_(false)
79 , isSolidColor_(false)
80 , isTransparent_(false) {
26 81
27 } 82 }
28 83
29 AnalysisDevice::~AnalysisDevice() { 84 AnalysisDevice::~AnalysisDevice() {
30 85
31 } 86 }
32 87
33 int AnalysisDevice::getEstimatedCost() const { 88 int AnalysisDevice::getEstimatedCost() const {
34 return estimatedCost_; 89 return estimatedCost_;
35 } 90 }
36 91
92 bool AnalysisDevice::getColorIfSolid(SkColor* color) const {
93 if (isSolidColor_)
94 *color = color_;
95 return isSolidColor_;
96 }
97
98 bool AnalysisDevice::isTransparent() const {
99 return isTransparent_;
100 }
101
102 void AnalysisDevice::setForceNotSolid(bool flag) {
103 isForcedNotSolid_ = flag;
104 if (isForcedNotSolid_)
105 isSolidColor_ = false;
106 }
107
108 void AnalysisDevice::setForceNotTransparent(bool flag) {
109 isForcedNotTransparent_ = flag;
110 if (isForcedNotTransparent_)
111 isTransparent_ = false;
112 }
113
37 void AnalysisDevice::clear(SkColor color) { 114 void AnalysisDevice::clear(SkColor color) {
38 ++estimatedCost_; 115 ++estimatedCost_;
116
117 isTransparent_ = (!isForcedNotTransparent_ && SkColorGetA(color) == 0);
118
119 if (!isForcedNotSolid_ && SkColorGetA(color) == 255) {
120 isSolidColor_ = true;
121 color_ = color;
122 }
123 else {
124 isSolidColor_ = false;
125 }
39 } 126 }
40 127
41 void AnalysisDevice::drawPaint(const SkDraw&, const SkPaint& paint) { 128 void AnalysisDevice::drawPaint(const SkDraw&, const SkPaint& paint) {
42 ++estimatedCost_; 129 ++estimatedCost_;
130 isSolidColor_ = false;
131 isTransparent_ = false;
43 } 132 }
44 133
45 void AnalysisDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, 134 void AnalysisDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode,
46 size_t count, const SkPoint[], 135 size_t count, const SkPoint[],
47 const SkPaint& paint) { 136 const SkPaint& paint) {
48 ++estimatedCost_; 137 ++estimatedCost_;
138 isSolidColor_ = false;
139 isTransparent_ = false;
49 } 140 }
50 141
51 void AnalysisDevice::drawRect(const SkDraw&, const SkRect& r, 142 void AnalysisDevice::drawRect(const SkDraw& draw, const SkRect& rect,
52 const SkPaint& paint) { 143 const SkPaint& paint) {
144
53 // FIXME: if there's a pending image decode & resize, more expensive 145 // FIXME: if there's a pending image decode & resize, more expensive
54 if (paint.getMaskFilter()) { 146 if (paint.getMaskFilter()) {
55 estimatedCost_ += 300; 147 estimatedCost_ += 300;
56 } 148 }
57 ++estimatedCost_; 149 ++estimatedCost_;
150
151 bool doesCoverCanvas = isFullQuad(draw,
152 SkRect::MakeWH(width(), height()),
153 rect);
154
155 SkXfermode::Mode xferMode;
156 SkXfermode::AsMode(paint.getXfermode(), &xferMode);
157
158 // This canvas will become transparent if the following holds:
159 // - The quad is a full tile quad
160 // - We're not in "forced not transparent" mode
161 // - Transfer mode is clear (0 color, 0 alpha)
162 //
163 // If the paint alpha is not 0, or if the transfrer mode is
164 // not src, then this canvas will not be transparent.
165 //
166 // In all other cases, we keep the current transparent value
167 if (doesCoverCanvas &&
168 !isForcedNotTransparent_ &&
169 xferMode == SkXfermode::kClear_Mode) {
170 isTransparent_ = true;
171 }
172 else if (paint.getAlpha() != 0 ||
173 xferMode != SkXfermode::kSrc_Mode) {
174 isTransparent_ = false;
175 }
176
177 // This bitmap is solid if and only if the following holds.
178 // Note that this might be overly conservative:
179 // - We're not in "forced not solid" mode
180 // - Paint is solid color
181 // - The quad is a full tile quad
182 if (!isForcedNotSolid_ &&
183 isSolidColorPaint(paint) &&
184 doesCoverCanvas) {
185 isSolidColor_ = true;
186 color_ = paint.getColor();
187 }
188 else {
189 isSolidColor_ = false;
190 }
58 } 191 }
59 192
60 void AnalysisDevice::drawOval(const SkDraw&, const SkRect& oval, 193 void AnalysisDevice::drawOval(const SkDraw&, const SkRect& oval,
61 const SkPaint& paint) { 194 const SkPaint& paint) {
62 ++estimatedCost_; 195 ++estimatedCost_;
196 isSolidColor_ = false;
197 isTransparent_ = false;
63 } 198 }
64 199
65 void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path, 200 void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path,
66 const SkPaint& paint, 201 const SkPaint& paint,
67 const SkMatrix* prePathMatrix , 202 const SkMatrix* prePathMatrix ,
68 bool pathIsMutable ) { 203 bool pathIsMutable ) {
69 // On Z620, every antialiased path costs us about 300us. 204 // On Z620, every antialiased path costs us about 300us.
70 // We've only seen this in practice on filled paths, but 205 // We've only seen this in practice on filled paths, but
71 // we expect it to apply to all path stroking modes. 206 // we expect it to apply to all path stroking modes.
72 if (paint.getMaskFilter()) { 207 if (paint.getMaskFilter()) {
73 estimatedCost_ += 300; 208 estimatedCost_ += 300;
74 } 209 }
75 ++estimatedCost_; 210 ++estimatedCost_;
211 isSolidColor_ = false;
212 isTransparent_ = false;
76 } 213 }
77 214
78 void AnalysisDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, 215 void AnalysisDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap,
79 const SkIRect* srcRectOrNull, 216 const SkIRect* srcRectOrNull,
80 const SkMatrix& matrix, const SkPaint& paint) 217 const SkMatrix& matrix, const SkPaint& paint) {
81 {
82 ++estimatedCost_; 218 ++estimatedCost_;
219 isSolidColor_ = false;
220 isTransparent_ = false;
83 } 221 }
84 222
85 void AnalysisDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, 223 void AnalysisDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap,
86 int x, int y, const SkPaint& paint) { 224 int x, int y, const SkPaint& paint) {
87 ++estimatedCost_; 225 ++estimatedCost_;
226 isSolidColor_ = false;
227 isTransparent_ = false;
88 } 228 }
89 229
90 void AnalysisDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, 230 void AnalysisDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap&,
91 const SkRect* srcOrNull, const SkRect& dst, 231 const SkRect* srcOrNull, const SkRect& dst,
92 const SkPaint& paint) { 232 const SkPaint& paint) {
93 ++estimatedCost_; 233 ++estimatedCost_;
234
235 // Call drawRect to determine transparency,
236 // but reset solid color to false.
237 drawRect(draw, dst, paint);
238 isSolidColor_ = false;
94 } 239 }
95 240
96 241
97 void AnalysisDevice::drawText(const SkDraw&, const void* text, size_t len, 242 void AnalysisDevice::drawText(const SkDraw&, const void* text, size_t len,
98 SkScalar x, SkScalar y, const SkPaint& paint) 243 SkScalar x, SkScalar y, const SkPaint& paint) {
99 {
100 ++estimatedCost_; 244 ++estimatedCost_;
245 isSolidColor_ = false;
246 isTransparent_ = false;
101 } 247 }
102 248
103 void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, size_t le n, 249 void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, size_t le n,
104 const SkScalar pos[], SkScalar constY, 250 const SkScalar pos[], SkScalar constY,
105 int scalarsPerPos, const SkPaint& paint) { 251 int scalarsPerPos, const SkPaint& paint) {
106 // FIXME: On Z620, every glyph cache miss costs us about 10us. 252 // FIXME: On Z620, every glyph cache miss costs us about 10us.
107 // We don't have a good mechanism for predicting glyph cache misses. 253 // We don't have a good mechanism for predicting glyph cache misses.
108 ++estimatedCost_; 254 ++estimatedCost_;
255 isSolidColor_ = false;
256 isTransparent_ = false;
109 } 257 }
110 258
111 void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, 259 void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len,
112 const SkPath& path, const SkMatrix* matrix, 260 const SkPath& path, const SkMatrix* matrix,
113 const SkPaint& paint) { 261 const SkPaint& paint) {
114 ++estimatedCost_; 262 ++estimatedCost_;
263 isSolidColor_ = false;
264 isTransparent_ = false;
115 } 265 }
116 266
117 #ifdef SK_BUILD_FOR_ANDROID 267 #ifdef SK_BUILD_FOR_ANDROID
118 void AnalysisDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, 268 void AnalysisDevice::drawPosTextOnPath(const SkDraw& draw, const void* text,
119 size_t len, 269 size_t len,
120 const SkPoint pos[], const SkPaint& paint, 270 const SkPoint pos[], const SkPaint& paint,
121 const SkPath& path, const SkMatrix* matrix) 271 const SkPath& path, const SkMatrix* matrix) {
122 {
123 ++estimatedCost_; 272 ++estimatedCost_;
273 isSolidColor_ = false;
274 isTransparent_ = false;
124 } 275 }
125 #endif 276 #endif
126 277
127 void AnalysisDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, 278 void AnalysisDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode,
128 int vertexCount, 279 int vertexCount,
129 const SkPoint verts[], const SkPoint texs[], 280 const SkPoint verts[], const SkPoint texs[],
130 const SkColor colors[], SkXfermode* xmode, 281 const SkColor colors[], SkXfermode* xmode,
131 const uint16_t indices[], int indexCount, 282 const uint16_t indices[], int indexCount,
132 const SkPaint& paint) { 283 const SkPaint& paint) {
133 ++estimatedCost_; 284 ++estimatedCost_;
285 isSolidColor_ = false;
286 isTransparent_ = false;
134 } 287 }
135 288
136 void AnalysisDevice::drawDevice(const SkDraw&, SkDevice*, int x, int y, 289 void AnalysisDevice::drawDevice(const SkDraw&, SkDevice*, int x, int y,
137 const SkPaint&) { 290 const SkPaint&) {
138 ++estimatedCost_; 291 ++estimatedCost_;
292 isSolidColor_ = false;
293 isTransparent_ = false;
139 } 294 }
140 295
141 296
142 297
143
144 AnalysisCanvas::AnalysisCanvas(AnalysisDevice* device) 298 AnalysisCanvas::AnalysisCanvas(AnalysisDevice* device)
145 : INHERITED(device) { 299 : INHERITED(device)
146 300 , savedStackSize_(0)
301 , forceNotSolidStackLevel_(0)
302 , forceNotTransparentStackLevel_(0) {
147 } 303 }
148 304
149 AnalysisCanvas::~AnalysisCanvas() { 305 AnalysisCanvas::~AnalysisCanvas() {
150 } 306 }
151 307
152 308
153 bool AnalysisCanvas::isCheap() const { 309 bool AnalysisCanvas::isCheap() const {
154 return getEstimatedCost() < gPictureCostThreshold; 310 return getEstimatedCost() < gPictureCostThreshold;
155 } 311 }
156 312
313 bool AnalysisCanvas::getColorIfSolid(SkColor* color) const {
314 return (static_cast<AnalysisDevice*>(getDevice()))->getColorIfSolid(color);
315 }
316
317 bool AnalysisCanvas::isTransparent() const {
318 return (static_cast<AnalysisDevice*>(getDevice()))->isTransparent();
319 }
320
157 int AnalysisCanvas::getEstimatedCost() const { 321 int AnalysisCanvas::getEstimatedCost() const {
158 return (static_cast<AnalysisDevice*>(getDevice()))->getEstimatedCost(); 322 return (static_cast<AnalysisDevice*>(getDevice()))->getEstimatedCost();
159 } 323 }
160 324
161
162 bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op, 325 bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op,
163 bool doAA) { 326 bool doAA) {
164 return INHERITED::clipRect(rect, op, doAA); 327 return INHERITED::clipRect(rect, op, doAA);
165 } 328 }
166 329
167 bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op, 330 bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op,
168 bool doAA) { 331 bool doAA) {
332 // clipPaths can make our calls to isFullQuad invalid (ie have false
333 // positives). As a precaution, force the setting to be non-solid
334 // and non-transparent until we pop this
335 if (forceNotSolidStackLevel_ == 0) {
Justin Novosad 2013/03/06 15:24:43 There is a bug here due to '0' being ambiguous (0
336 forceNotSolidStackLevel_ = savedStackSize_;
337 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(true);
338 }
339 if (forceNotTransparentStackLevel_ == 0) {
Justin Novosad 2013/03/06 15:24:43 Bug
340 forceNotTransparentStackLevel_ = savedStackSize_;
341 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(true);
342 }
343
169 return INHERITED::clipRect(path.getBounds(), op, doAA); 344 return INHERITED::clipRect(path.getBounds(), op, doAA);
170 } 345 }
171 346
172 bool AnalysisCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, 347 bool AnalysisCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op,
173 bool doAA) { 348 bool doAA) {
349 // clipRRect can make our calls to isFullQuad invalid (ie have false
350 // positives). As a precaution, force the setting to be non-solid
351 // and non-transparent until we pop this
352 if (forceNotSolidStackLevel_ == 0) {
Justin Novosad 2013/03/06 15:24:43 Bug
353 forceNotSolidStackLevel_ = savedStackSize_;
354 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(true);
355 }
356 if (forceNotTransparentStackLevel_ == 0) {
Justin Novosad 2013/03/06 15:24:43 Bug
357 forceNotTransparentStackLevel_ = savedStackSize_;
358 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(true);
359 }
360
174 return INHERITED::clipRect(rrect.getBounds(), op, doAA); 361 return INHERITED::clipRect(rrect.getBounds(), op, doAA);
175 } 362 }
176 363
177 int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint*, 364 int AnalysisCanvas::save(SkCanvas::SaveFlags flags) {
365 INHERITED::save(flags);
366 ++savedStackSize_;
367 }
368
369 int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
178 SkCanvas::SaveFlags flags) { 370 SkCanvas::SaveFlags flags) {
371 ++savedStackSize_;
372
373 // If after we draw to the saved layer, we have to blend with the current
374 // layer, then we can conservatively say that the canvas will not be of
375 // solid color.
376 if ((paint && !isSolidColorPaint(*paint)) ||
377 (bounds && !bounds->contains(
378 SkRect::MakeWH(getDevice()->width(), getDevice()->height())))) {
379 if (forceNotSolidStackLevel_ == 0) {
380 forceNotSolidStackLevel_ = savedStackSize_;
381 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(true);
382 }
383 }
384
385 // If after we draw to the save layer, we have to blend with the current
386 // layer using any part of the current layer's alpha, then we can
387 // conservatively say that the canvas will not be transparent.
388 SkXfermode::Mode xferMode = SkXfermode::kSrc_Mode;
389 if (paint)
390 SkXfermode::AsMode(paint->getXfermode(), &xferMode);
391 if (xferMode != SkXfermode::kSrc_Mode) {
392 if (forceNotTransparentStackLevel_ == 0) {
393 forceNotTransparentStackLevel_ = savedStackSize_;
394 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(true);
395 }
396 }
397
179 // Actually saving a layer here could cause a new bitmap to be created 398 // Actually saving a layer here could cause a new bitmap to be created
180 // and real rendering to occur. 399 // and real rendering to occur.
181 int count = SkCanvas::save(flags); 400 int count = INHERITED::save(flags);
182 if (bounds) { 401 if (bounds) {
183 INHERITED::clipRectBounds(bounds, flags, NULL); 402 INHERITED::clipRectBounds(bounds, flags, NULL);
184 } 403 }
185 return count; 404 return count;
186 } 405 }
187 406
407 void AnalysisCanvas::restore() {
408 INHERITED::restore();
409
410 --savedStackSize_;
Justin Novosad 2013/03/06 15:24:43 Need to gracefully handle the case of a restore th
411 if (savedStackSize_ < forceNotSolidStackLevel_) {
412 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(false);
413 forceNotSolidStackLevel_ = 0;
414 }
415 if (savedStackSize_ < forceNotTransparentStackLevel_) {
416 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(false);
417 forceNotTransparentStackLevel_ = 0;
418 }
419 }
420
188 } // namespace skia 421 } // namespace skia
189 422
190 423
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698