OLD | NEW |
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 "base/logging.h" | 6 #include "base/logging.h" |
7 #include "skia/ext/analysis_canvas.h" | 7 #include "skia/ext/analysis_canvas.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/include/core/SkShader.h" | 10 #include "third_party/skia/include/core/SkShader.h" |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 } | 73 } |
74 | 74 |
75 void AnalysisCanvas::SetForceNotTransparent(bool flag) { | 75 void AnalysisCanvas::SetForceNotTransparent(bool flag) { |
76 is_forced_not_transparent_ = flag; | 76 is_forced_not_transparent_ = flag; |
77 if (is_forced_not_transparent_) | 77 if (is_forced_not_transparent_) |
78 is_transparent_ = false; | 78 is_transparent_ = false; |
79 } | 79 } |
80 | 80 |
81 void AnalysisCanvas::clear(SkColor color) { | 81 void AnalysisCanvas::clear(SkColor color) { |
82 is_transparent_ = (!is_forced_not_transparent_ && SkColorGetA(color) == 0); | 82 is_transparent_ = (!is_forced_not_transparent_ && SkColorGetA(color) == 0); |
| 83 has_text_ = false; |
83 | 84 |
84 if (!is_forced_not_solid_ && SkColorGetA(color) == 255) { | 85 if (!is_forced_not_solid_ && SkColorGetA(color) == 255) { |
85 is_solid_color_ = true; | 86 is_solid_color_ = true; |
86 color_ = color; | 87 color_ = color; |
87 } else { | 88 } else { |
88 is_solid_color_ = false; | 89 is_solid_color_ = false; |
89 } | 90 } |
90 } | 91 } |
91 | 92 |
92 void AnalysisCanvas::drawPaint(const SkPaint& paint) { | 93 void AnalysisCanvas::drawPaint(const SkPaint& paint) { |
93 // This check is in SkCanvas::drawPaint(), and some of our unittests rely on | 94 // This check is in SkCanvas::drawPaint(), and some of our unittests rely on |
94 // on this, so we reproduce it here. | 95 // on this, so we reproduce it here. |
95 if (isClipEmpty()) | 96 if (isClipEmpty()) |
96 return; | 97 return; |
97 | 98 |
98 is_solid_color_ = false; | 99 is_solid_color_ = false; |
99 is_transparent_ = false; | 100 is_transparent_ = false; |
100 ++draw_op_count_; | |
101 } | 101 } |
102 | 102 |
103 void AnalysisCanvas::drawPoints(SkCanvas::PointMode mode, | 103 void AnalysisCanvas::drawPoints(SkCanvas::PointMode mode, |
104 size_t count, | 104 size_t count, |
105 const SkPoint points[], | 105 const SkPoint points[], |
106 const SkPaint& paint) { | 106 const SkPaint& paint) { |
107 is_solid_color_ = false; | 107 is_solid_color_ = false; |
108 is_transparent_ = false; | 108 is_transparent_ = false; |
109 ++draw_op_count_; | |
110 } | 109 } |
111 | 110 |
112 void AnalysisCanvas::drawRect(const SkRect& rect, const SkPaint& paint) { | 111 void AnalysisCanvas::drawRect(const SkRect& rect, const SkPaint& paint) { |
113 // This recreates the early-exit logic in SkCanvas.cpp, which aborts early | 112 // This recreates the early-exit logic in SkCanvas.cpp, which aborts early |
114 // if the paint will "draw nothing". | 113 // if the paint will "draw nothing". |
115 if (paint.nothingToDraw()) | 114 if (paint.nothingToDraw()) |
116 return; | 115 return; |
117 | 116 |
118 bool does_cover_canvas = IsFullQuad(this, rect); | 117 bool does_cover_canvas = IsFullQuad(this, rect); |
119 | 118 |
120 SkXfermode::Mode xfermode; | 119 SkXfermode::Mode xfermode; |
121 SkXfermode::AsMode(paint.getXfermode(), &xfermode); | 120 SkXfermode::AsMode(paint.getXfermode(), &xfermode); |
122 | 121 |
123 // This canvas will become transparent if the following holds: | 122 // This canvas will become transparent if the following holds: |
124 // - The quad is a full tile quad | 123 // - The quad is a full tile quad |
125 // - We're not in "forced not transparent" mode | 124 // - We're not in "forced not transparent" mode |
126 // - Transfer mode is clear (0 color, 0 alpha) | 125 // - Transfer mode is clear (0 color, 0 alpha) |
127 // | 126 // |
128 // If the paint alpha is not 0, or if the transfrer mode is | 127 // If the paint alpha is not 0, or if the transfrer mode is |
129 // not src, then this canvas will not be transparent. | 128 // not src, then this canvas will not be transparent. |
130 // | 129 // |
131 // In all other cases, we keep the current transparent value | 130 // In all other cases, we keep the current transparent value |
132 if (does_cover_canvas && | 131 if (does_cover_canvas && |
133 !is_forced_not_transparent_ && | 132 !is_forced_not_transparent_ && |
134 xfermode == SkXfermode::kClear_Mode) { | 133 xfermode == SkXfermode::kClear_Mode) { |
135 is_transparent_ = true; | 134 is_transparent_ = true; |
| 135 has_text_ = false; |
136 } else if (paint.getAlpha() != 0 || xfermode != SkXfermode::kSrc_Mode) { | 136 } else if (paint.getAlpha() != 0 || xfermode != SkXfermode::kSrc_Mode) { |
137 is_transparent_ = false; | 137 is_transparent_ = false; |
138 } | 138 } |
139 | 139 |
140 // This bitmap is solid if and only if the following holds. | 140 // This bitmap is solid if and only if the following holds. |
141 // Note that this might be overly conservative: | 141 // Note that this might be overly conservative: |
142 // - We're not in "forced not solid" mode | 142 // - We're not in "forced not solid" mode |
143 // - Paint is solid color | 143 // - Paint is solid color |
144 // - The quad is a full tile quad | 144 // - The quad is a full tile quad |
145 if (!is_forced_not_solid_ && IsSolidColorPaint(paint) && does_cover_canvas) { | 145 if (!is_forced_not_solid_ && IsSolidColorPaint(paint) && does_cover_canvas) { |
146 is_solid_color_ = true; | 146 is_solid_color_ = true; |
147 color_ = paint.getColor(); | 147 color_ = paint.getColor(); |
| 148 has_text_ = false; |
148 } else { | 149 } else { |
149 is_solid_color_ = false; | 150 is_solid_color_ = false; |
150 } | 151 } |
151 ++draw_op_count_; | |
152 } | 152 } |
153 | 153 |
154 void AnalysisCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { | 154 void AnalysisCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { |
155 is_solid_color_ = false; | 155 is_solid_color_ = false; |
156 is_transparent_ = false; | 156 is_transparent_ = false; |
157 ++draw_op_count_; | |
158 } | 157 } |
159 | 158 |
160 void AnalysisCanvas::drawRRect(const SkRRect& rr, const SkPaint& paint) { | 159 void AnalysisCanvas::drawRRect(const SkRRect& rr, const SkPaint& paint) { |
161 // This should add the SkRRect to an SkPath, and call | 160 // This should add the SkRRect to an SkPath, and call |
162 // drawPath, but since drawPath ignores the SkPath, just | 161 // drawPath, but since drawPath ignores the SkPath, just |
163 // do the same work here. | 162 // do the same work here. |
164 is_solid_color_ = false; | 163 is_solid_color_ = false; |
165 is_transparent_ = false; | 164 is_transparent_ = false; |
166 ++draw_op_count_; | |
167 } | 165 } |
168 | 166 |
169 void AnalysisCanvas::drawPath(const SkPath& path, const SkPaint& paint) { | 167 void AnalysisCanvas::drawPath(const SkPath& path, const SkPaint& paint) { |
170 is_solid_color_ = false; | 168 is_solid_color_ = false; |
171 is_transparent_ = false; | 169 is_transparent_ = false; |
172 ++draw_op_count_; | |
173 } | 170 } |
174 | 171 |
175 void AnalysisCanvas::drawBitmap(const SkBitmap& bitmap, | 172 void AnalysisCanvas::drawBitmap(const SkBitmap& bitmap, |
176 SkScalar left, | 173 SkScalar left, |
177 SkScalar top, | 174 SkScalar top, |
178 const SkPaint*) { | 175 const SkPaint*) { |
179 is_solid_color_ = false; | 176 is_solid_color_ = false; |
180 is_transparent_ = false; | 177 is_transparent_ = false; |
181 ++draw_op_count_; | |
182 } | 178 } |
183 | 179 |
184 void AnalysisCanvas::drawBitmapRectToRect(const SkBitmap&, | 180 void AnalysisCanvas::drawBitmapRectToRect(const SkBitmap&, |
185 const SkRect* src, | 181 const SkRect* src, |
186 const SkRect& dst, | 182 const SkRect& dst, |
187 const SkPaint* paint, | 183 const SkPaint* paint, |
188 DrawBitmapRectFlags flags) { | 184 DrawBitmapRectFlags flags) { |
189 // Call drawRect to determine transparency, | 185 // Call drawRect to determine transparency, |
190 // but reset solid color to false. | 186 // but reset solid color to false. |
191 SkPaint tmpPaint; | 187 SkPaint tmpPaint; |
192 if (!paint) | 188 if (!paint) |
193 paint = &tmpPaint; | 189 paint = &tmpPaint; |
194 drawRect(dst, *paint); | 190 drawRect(dst, *paint); |
195 is_solid_color_ = false; | 191 is_solid_color_ = false; |
196 ++draw_op_count_; | |
197 } | 192 } |
198 | 193 |
199 void AnalysisCanvas::drawBitmapMatrix(const SkBitmap& bitmap, | 194 void AnalysisCanvas::drawBitmapMatrix(const SkBitmap& bitmap, |
200 const SkMatrix& matrix, | 195 const SkMatrix& matrix, |
201 const SkPaint* paint) { | 196 const SkPaint* paint) { |
202 is_solid_color_ = false; | 197 is_solid_color_ = false; |
203 is_transparent_ = false; | 198 is_transparent_ = false; |
204 ++draw_op_count_; | |
205 } | 199 } |
206 | 200 |
207 void AnalysisCanvas::drawBitmapNine(const SkBitmap& bitmap, | 201 void AnalysisCanvas::drawBitmapNine(const SkBitmap& bitmap, |
208 const SkIRect& center, | 202 const SkIRect& center, |
209 const SkRect& dst, | 203 const SkRect& dst, |
210 const SkPaint* paint) { | 204 const SkPaint* paint) { |
211 is_solid_color_ = false; | 205 is_solid_color_ = false; |
212 is_transparent_ = false; | 206 is_transparent_ = false; |
213 ++draw_op_count_; | |
214 } | 207 } |
215 | 208 |
216 void AnalysisCanvas::drawSprite(const SkBitmap& bitmap, | 209 void AnalysisCanvas::drawSprite(const SkBitmap& bitmap, |
217 int left, | 210 int left, |
218 int top, | 211 int top, |
219 const SkPaint* paint) { | 212 const SkPaint* paint) { |
220 is_solid_color_ = false; | 213 is_solid_color_ = false; |
221 is_transparent_ = false; | 214 is_transparent_ = false; |
222 ++draw_op_count_; | |
223 } | 215 } |
224 | 216 |
225 void AnalysisCanvas::onDrawText(const void* text, | 217 void AnalysisCanvas::onDrawText(const void* text, |
226 size_t len, | 218 size_t len, |
227 SkScalar x, | 219 SkScalar x, |
228 SkScalar y, | 220 SkScalar y, |
229 const SkPaint& paint) { | 221 const SkPaint& paint) { |
230 is_solid_color_ = false; | 222 is_solid_color_ = false; |
231 is_transparent_ = false; | 223 is_transparent_ = false; |
232 ++draw_op_count_; | 224 has_text_ = true; |
233 } | 225 } |
234 | 226 |
235 void AnalysisCanvas::onDrawPosText(const void* text, | 227 void AnalysisCanvas::onDrawPosText(const void* text, |
236 size_t byteLength, | 228 size_t byteLength, |
237 const SkPoint pos[], | 229 const SkPoint pos[], |
238 const SkPaint& paint) { | 230 const SkPaint& paint) { |
239 is_solid_color_ = false; | 231 is_solid_color_ = false; |
240 is_transparent_ = false; | 232 is_transparent_ = false; |
241 ++draw_op_count_; | 233 has_text_ = true; |
242 } | 234 } |
243 | 235 |
244 void AnalysisCanvas::onDrawPosTextH(const void* text, | 236 void AnalysisCanvas::onDrawPosTextH(const void* text, |
245 size_t byteLength, | 237 size_t byteLength, |
246 const SkScalar xpos[], | 238 const SkScalar xpos[], |
247 SkScalar constY, | 239 SkScalar constY, |
248 const SkPaint& paint) { | 240 const SkPaint& paint) { |
249 is_solid_color_ = false; | 241 is_solid_color_ = false; |
250 is_transparent_ = false; | 242 is_transparent_ = false; |
251 ++draw_op_count_; | 243 has_text_ = true; |
252 } | 244 } |
253 | 245 |
254 void AnalysisCanvas::onDrawTextOnPath(const void* text, | 246 void AnalysisCanvas::onDrawTextOnPath(const void* text, |
255 size_t len, | 247 size_t len, |
256 const SkPath& path, | 248 const SkPath& path, |
257 const SkMatrix* matrix, | 249 const SkMatrix* matrix, |
258 const SkPaint& paint) { | 250 const SkPaint& paint) { |
259 is_solid_color_ = false; | 251 is_solid_color_ = false; |
260 is_transparent_ = false; | 252 is_transparent_ = false; |
261 ++draw_op_count_; | 253 has_text_ = true; |
262 } | 254 } |
263 | 255 |
264 void AnalysisCanvas::onDrawDRRect(const SkRRect& outer, | 256 void AnalysisCanvas::onDrawDRRect(const SkRRect& outer, |
265 const SkRRect& inner, | 257 const SkRRect& inner, |
266 const SkPaint& paint) { | 258 const SkPaint& paint) { |
267 is_solid_color_ = false; | 259 is_solid_color_ = false; |
268 is_transparent_ = false; | 260 is_transparent_ = false; |
269 ++draw_op_count_; | |
270 } | 261 } |
271 | 262 |
272 void AnalysisCanvas::drawVertices(SkCanvas::VertexMode, | 263 void AnalysisCanvas::drawVertices(SkCanvas::VertexMode, |
273 int vertex_count, | 264 int vertex_count, |
274 const SkPoint verts[], | 265 const SkPoint verts[], |
275 const SkPoint texs[], | 266 const SkPoint texs[], |
276 const SkColor colors[], | 267 const SkColor colors[], |
277 SkXfermode* xmode, | 268 SkXfermode* xmode, |
278 const uint16_t indices[], | 269 const uint16_t indices[], |
279 int index_count, | 270 int index_count, |
280 const SkPaint& paint) { | 271 const SkPaint& paint) { |
281 is_solid_color_ = false; | 272 is_solid_color_ = false; |
282 is_transparent_ = false; | 273 is_transparent_ = false; |
283 ++draw_op_count_; | |
284 } | 274 } |
285 | 275 |
286 // Needed for now, since SkCanvas requires a bitmap, even if it is not backed | 276 // Needed for now, since SkCanvas requires a bitmap, even if it is not backed |
287 // by any pixels | 277 // by any pixels |
288 static SkBitmap MakeEmptyBitmap(int width, int height) { | 278 static SkBitmap MakeEmptyBitmap(int width, int height) { |
289 SkBitmap bitmap; | 279 SkBitmap bitmap; |
290 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height)); | 280 bitmap.setInfo(SkImageInfo::MakeUnknown(width, height)); |
291 return bitmap; | 281 return bitmap; |
292 } | 282 } |
293 | 283 |
294 AnalysisCanvas::AnalysisCanvas(int width, int height) | 284 AnalysisCanvas::AnalysisCanvas(int width, int height) |
295 : INHERITED(MakeEmptyBitmap(width, height)), | 285 : INHERITED(MakeEmptyBitmap(width, height)), |
296 saved_stack_size_(0), | 286 saved_stack_size_(0), |
297 force_not_solid_stack_level_(kNoLayer), | 287 force_not_solid_stack_level_(kNoLayer), |
298 force_not_transparent_stack_level_(kNoLayer), | 288 force_not_transparent_stack_level_(kNoLayer), |
299 is_forced_not_solid_(false), | 289 is_forced_not_solid_(false), |
300 is_forced_not_transparent_(false), | 290 is_forced_not_transparent_(false), |
301 is_solid_color_(true), | 291 is_solid_color_(true), |
302 is_transparent_(true), | 292 is_transparent_(true), |
303 draw_op_count_(0) {} | 293 has_text_(false) {} |
304 | 294 |
305 AnalysisCanvas::~AnalysisCanvas() {} | 295 AnalysisCanvas::~AnalysisCanvas() {} |
306 | 296 |
307 bool AnalysisCanvas::GetColorIfSolid(SkColor* color) const { | 297 bool AnalysisCanvas::GetColorIfSolid(SkColor* color) const { |
308 if (is_transparent_) { | 298 if (is_transparent_) { |
309 *color = SK_ColorTRANSPARENT; | 299 *color = SK_ColorTRANSPARENT; |
310 return true; | 300 return true; |
311 } | 301 } |
312 if (is_solid_color_) { | 302 if (is_solid_color_) { |
313 *color = color_; | 303 *color = color_; |
314 return true; | 304 return true; |
315 } | 305 } |
316 return false; | 306 return false; |
317 } | 307 } |
318 | 308 |
| 309 bool AnalysisCanvas::HasText() const { return has_text_; } |
| 310 |
319 bool AnalysisCanvas::abortDrawing() { | 311 bool AnalysisCanvas::abortDrawing() { |
320 // Early out as soon as we have more than one draw op. | 312 // Early out as soon as we have detected that the tile has text. |
321 // TODO(vmpstr): Investigate if 1 is the correct metric here. We need to | 313 return HasText(); |
322 // balance the amount of time we spend analyzing vs how many tiles would be | |
323 // solid if the number was higher. | |
324 return draw_op_count_ > 1; | |
325 } | 314 } |
326 | 315 |
327 void AnalysisCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, | 316 void AnalysisCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, |
328 ClipEdgeStyle edge_style) { | 317 ClipEdgeStyle edge_style) { |
329 | 318 |
330 INHERITED::onClipRect(rect, op, edge_style); | 319 INHERITED::onClipRect(rect, op, edge_style); |
331 } | 320 } |
332 | 321 |
333 void AnalysisCanvas::onClipPath(const SkPath& path, SkRegion::Op op, | 322 void AnalysisCanvas::onClipPath(const SkPath& path, SkRegion::Op op, |
334 ClipEdgeStyle edge_style) { | 323 ClipEdgeStyle edge_style) { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
424 force_not_transparent_stack_level_ = kNoLayer; | 413 force_not_transparent_stack_level_ = kNoLayer; |
425 } | 414 } |
426 } | 415 } |
427 | 416 |
428 INHERITED::willRestore(); | 417 INHERITED::willRestore(); |
429 } | 418 } |
430 | 419 |
431 } // namespace skia | 420 } // namespace skia |
432 | 421 |
433 | 422 |
OLD | NEW |