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

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: win warning fix 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
« no previous file with comments | « skia/ext/analysis_canvas.h ('k') | skia/ext/analysis_canvas_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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() &&
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 const int AnalysisCanvas::kNoLayer = -1;
143 298
144 AnalysisCanvas::AnalysisCanvas(AnalysisDevice* device) 299 AnalysisCanvas::AnalysisCanvas(AnalysisDevice* device)
145 : INHERITED(device) { 300 : INHERITED(device)
146 301 , savedStackSize_(0)
302 , forceNotSolidStackLevel_(kNoLayer)
303 , forceNotTransparentStackLevel_(kNoLayer) {
147 } 304 }
148 305
149 AnalysisCanvas::~AnalysisCanvas() { 306 AnalysisCanvas::~AnalysisCanvas() {
150 } 307 }
151 308
152 309
153 bool AnalysisCanvas::isCheap() const { 310 bool AnalysisCanvas::isCheap() const {
154 return getEstimatedCost() < gPictureCostThreshold; 311 return getEstimatedCost() < gPictureCostThreshold;
155 } 312 }
156 313
314 bool AnalysisCanvas::getColorIfSolid(SkColor* color) const {
315 return (static_cast<AnalysisDevice*>(getDevice()))->getColorIfSolid(color);
316 }
317
318 bool AnalysisCanvas::isTransparent() const {
319 return (static_cast<AnalysisDevice*>(getDevice()))->isTransparent();
320 }
321
157 int AnalysisCanvas::getEstimatedCost() const { 322 int AnalysisCanvas::getEstimatedCost() const {
158 return (static_cast<AnalysisDevice*>(getDevice()))->getEstimatedCost(); 323 return (static_cast<AnalysisDevice*>(getDevice()))->getEstimatedCost();
159 } 324 }
160 325
161
162 bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op, 326 bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op,
163 bool doAA) { 327 bool doAA) {
164 return INHERITED::clipRect(rect, op, doAA); 328 return INHERITED::clipRect(rect, op, doAA);
165 } 329 }
166 330
167 bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op, 331 bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op,
168 bool doAA) { 332 bool doAA) {
333 // clipPaths can make our calls to isFullQuad invalid (ie have false
334 // positives). As a precaution, force the setting to be non-solid
335 // and non-transparent until we pop this
336 if (forceNotSolidStackLevel_ == kNoLayer) {
337 forceNotSolidStackLevel_ = savedStackSize_;
338 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(true);
339 }
340 if (forceNotTransparentStackLevel_ == kNoLayer) {
341 forceNotTransparentStackLevel_ = savedStackSize_;
342 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(true);
343 }
344
169 return INHERITED::clipRect(path.getBounds(), op, doAA); 345 return INHERITED::clipRect(path.getBounds(), op, doAA);
170 } 346 }
171 347
172 bool AnalysisCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, 348 bool AnalysisCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op,
173 bool doAA) { 349 bool doAA) {
350 // clipRRect can make our calls to isFullQuad invalid (ie have false
351 // positives). As a precaution, force the setting to be non-solid
352 // and non-transparent until we pop this
353 if (forceNotSolidStackLevel_ == kNoLayer) {
354 forceNotSolidStackLevel_ = savedStackSize_;
355 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(true);
356 }
357 if (forceNotTransparentStackLevel_ == kNoLayer) {
358 forceNotTransparentStackLevel_ = savedStackSize_;
359 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(true);
360 }
361
174 return INHERITED::clipRect(rrect.getBounds(), op, doAA); 362 return INHERITED::clipRect(rrect.getBounds(), op, doAA);
175 } 363 }
176 364
177 int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint*, 365 int AnalysisCanvas::save(SkCanvas::SaveFlags flags) {
366 ++savedStackSize_;
367 return INHERITED::save(flags);
368 }
369
370 int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
178 SkCanvas::SaveFlags flags) { 371 SkCanvas::SaveFlags flags) {
372 ++savedStackSize_;
373
374 // If after we draw to the saved layer, we have to blend with the current
375 // layer, then we can conservatively say that the canvas will not be of
376 // solid color.
377 if ((paint && !isSolidColorPaint(*paint)) ||
378 (bounds && !bounds->contains(
379 SkRect::MakeWH(getDevice()->width(), getDevice()->height())))) {
380 if (forceNotSolidStackLevel_ == kNoLayer) {
381 forceNotSolidStackLevel_ = savedStackSize_;
382 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(true);
383 }
384 }
385
386 // If after we draw to the save layer, we have to blend with the current
387 // layer using any part of the current layer's alpha, then we can
388 // conservatively say that the canvas will not be transparent.
389 SkXfermode::Mode xferMode = SkXfermode::kSrc_Mode;
390 if (paint)
391 SkXfermode::AsMode(paint->getXfermode(), &xferMode);
392 if (xferMode != SkXfermode::kSrc_Mode) {
393 if (forceNotTransparentStackLevel_ == kNoLayer) {
394 forceNotTransparentStackLevel_ = savedStackSize_;
395 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(true);
396 }
397 }
398
179 // Actually saving a layer here could cause a new bitmap to be created 399 // Actually saving a layer here could cause a new bitmap to be created
180 // and real rendering to occur. 400 // and real rendering to occur.
181 int count = SkCanvas::save(flags); 401 int count = INHERITED::save(flags);
182 if (bounds) { 402 if (bounds) {
183 INHERITED::clipRectBounds(bounds, flags, NULL); 403 INHERITED::clipRectBounds(bounds, flags, NULL);
184 } 404 }
185 return count; 405 return count;
186 } 406 }
187 407
408 void AnalysisCanvas::restore() {
409 INHERITED::restore();
410
411 DCHECK(savedStackSize_);
412 if (savedStackSize_) {
413 --savedStackSize_;
414 if (savedStackSize_ < forceNotSolidStackLevel_) {
415 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(false);
416 forceNotSolidStackLevel_ = kNoLayer;
417 }
418 if (savedStackSize_ < forceNotTransparentStackLevel_) {
419 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(false) ;
420 forceNotTransparentStackLevel_ = kNoLayer;
421 }
422 }
423 }
424
188 } // namespace skia 425 } // namespace skia
189 426
190 427
OLDNEW
« no previous file with comments | « skia/ext/analysis_canvas.h ('k') | skia/ext/analysis_canvas_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698