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 "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/include/core/SkShader.h" |
10 #include "third_party/skia/src/core/SkRasterClip.h" | 11 #include "third_party/skia/src/core/SkRasterClip.h" |
11 #include "ui/gfx/rect_conversions.h" | 12 #include "ui/gfx/rect_conversions.h" |
12 | 13 |
13 namespace { | 14 namespace { |
14 | 15 |
15 // FIXME: Arbitrary number. Requires tuning & experimentation. | 16 // FIXME: Arbitrary number. Requires tuning & experimentation. |
16 // Probably requires per-platform tuning; N10 average draw call takes | 17 // Probably requires per-platform tuning; N10 average draw call takes |
17 // 25x as long as Z620. | 18 // 25x as long as Z620. |
18 const int gPictureCostThreshold = 1000; | 19 const int gPictureCostThreshold = 1000; |
19 | 20 |
| 21 // URI label for a lazily decoded SkPixelRef. |
| 22 const char kLabelLazyDecoded[] = "lazy"; |
| 23 const int kLabelLazyDecodedLength = 4; |
| 24 |
20 static bool isSolidColorPaint(const SkPaint& paint) { | 25 static bool isSolidColorPaint(const SkPaint& paint) { |
21 SkXfermode::Mode xferMode; | 26 SkXfermode::Mode xferMode; |
22 | 27 |
23 // getXfermode can return a NULL, but that is handled | 28 // getXfermode can return a NULL, but that is handled |
24 // gracefully by AsMode (NULL turns into kSrcOver mode). | 29 // gracefully by AsMode (NULL turns into kSrcOver mode). |
25 SkXfermode::AsMode(paint.getXfermode(), &xferMode); | 30 SkXfermode::AsMode(paint.getXfermode(), &xferMode); |
26 | 31 |
27 // Paint is solid color if the following holds: | 32 // Paint is solid color if the following holds: |
28 // - Alpha is 1.0, style is fill, and there are no special effects | 33 // - Alpha is 1.0, style is fill, and there are no special effects |
29 // - Xfer mode is either kSrc or kSrcOver (kSrcOver is equivalent | 34 // - Xfer mode is either kSrc or kSrcOver (kSrcOver is equivalent |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 if (isForcedNotSolid_) | 109 if (isForcedNotSolid_) |
105 isSolidColor_ = false; | 110 isSolidColor_ = false; |
106 } | 111 } |
107 | 112 |
108 void AnalysisDevice::setForceNotTransparent(bool flag) { | 113 void AnalysisDevice::setForceNotTransparent(bool flag) { |
109 isForcedNotTransparent_ = flag; | 114 isForcedNotTransparent_ = flag; |
110 if (isForcedNotTransparent_) | 115 if (isForcedNotTransparent_) |
111 isTransparent_ = false; | 116 isTransparent_ = false; |
112 } | 117 } |
113 | 118 |
| 119 void AnalysisDevice::addPixelRefIfLazy(SkPixelRef* pixelRef) { |
| 120 if (!pixelRef) |
| 121 return; |
| 122 |
| 123 uint32_t genID = pixelRef->getGenerationID(); |
| 124 |
| 125 // If this ID exists (whether it is lazy pixel ref or not), |
| 126 // we can return early. |
| 127 std::pair<IdSet::iterator, bool> insertionResult = |
| 128 existingPixelRefIDs_.insert(genID); |
| 129 if (!insertionResult.second) |
| 130 return; |
| 131 |
| 132 if (pixelRef->getURI() && |
| 133 !strncmp(pixelRef->getURI(), |
| 134 kLabelLazyDecoded, |
| 135 kLabelLazyDecodedLength)) { |
| 136 lazyPixelRefs_.push_back(static_cast<skia::LazyPixelRef*>(pixelRef)); |
| 137 } |
| 138 } |
| 139 |
| 140 void AnalysisDevice::addBitmap(const SkBitmap& bitmap) { |
| 141 addPixelRefIfLazy(bitmap.pixelRef()); |
| 142 } |
| 143 |
| 144 void AnalysisDevice::addBitmapFromPaint(const SkPaint& paint) { |
| 145 SkShader* shader = paint.getShader(); |
| 146 if (shader) { |
| 147 SkBitmap bitmap; |
| 148 // Check whether the shader is a gradient in order to short-circuit |
| 149 // call to asABitmap to prevent generation of bitmaps from |
| 150 // gradient shaders, which implement asABitmap. |
| 151 if (SkShader::kNone_GradientType == shader->asAGradient(NULL) && |
| 152 SkShader::kNone_BitmapType != shader->asABitmap(&bitmap, NULL, NULL)) { |
| 153 addPixelRefIfLazy(bitmap.pixelRef()); |
| 154 } |
| 155 } |
| 156 } |
| 157 |
| 158 void AnalysisDevice::consumeLazyPixelRefs(LazyPixelRefList* pixelRefs) { |
| 159 DCHECK(pixelRefs); |
| 160 DCHECK(pixelRefs->empty()); |
| 161 lazyPixelRefs_.swap(*pixelRefs); |
| 162 existingPixelRefIDs_.clear(); |
| 163 } |
| 164 |
114 void AnalysisDevice::clear(SkColor color) { | 165 void AnalysisDevice::clear(SkColor color) { |
115 ++estimatedCost_; | 166 ++estimatedCost_; |
116 | 167 |
117 isTransparent_ = (!isForcedNotTransparent_ && SkColorGetA(color) == 0); | 168 isTransparent_ = (!isForcedNotTransparent_ && SkColorGetA(color) == 0); |
118 | 169 |
119 if (!isForcedNotSolid_ && SkColorGetA(color) == 255) { | 170 if (!isForcedNotSolid_ && SkColorGetA(color) == 255) { |
120 isSolidColor_ = true; | 171 isSolidColor_ = true; |
121 color_ = color; | 172 color_ = color; |
122 } | 173 } |
123 else { | 174 else { |
124 isSolidColor_ = false; | 175 isSolidColor_ = false; |
125 } | 176 } |
126 } | 177 } |
127 | 178 |
128 void AnalysisDevice::drawPaint(const SkDraw&, const SkPaint& paint) { | 179 void AnalysisDevice::drawPaint(const SkDraw&, const SkPaint& paint) { |
129 ++estimatedCost_; | 180 ++estimatedCost_; |
130 isSolidColor_ = false; | 181 isSolidColor_ = false; |
131 isTransparent_ = false; | 182 isTransparent_ = false; |
| 183 addBitmapFromPaint(paint); |
132 } | 184 } |
133 | 185 |
134 void AnalysisDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, | 186 void AnalysisDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, |
135 size_t count, const SkPoint[], | 187 size_t count, const SkPoint[], |
136 const SkPaint& paint) { | 188 const SkPaint& paint) { |
137 ++estimatedCost_; | 189 ++estimatedCost_; |
138 isSolidColor_ = false; | 190 isSolidColor_ = false; |
139 isTransparent_ = false; | 191 isTransparent_ = false; |
| 192 addBitmapFromPaint(paint); |
140 } | 193 } |
141 | 194 |
142 void AnalysisDevice::drawRect(const SkDraw& draw, const SkRect& rect, | 195 void AnalysisDevice::drawRect(const SkDraw& draw, const SkRect& rect, |
143 const SkPaint& paint) { | 196 const SkPaint& paint) { |
144 | 197 |
145 // FIXME: if there's a pending image decode & resize, more expensive | 198 // FIXME: if there's a pending image decode & resize, more expensive |
146 if (paint.getMaskFilter()) { | 199 if (paint.getMaskFilter()) { |
147 estimatedCost_ += 300; | 200 estimatedCost_ += 300; |
148 } | 201 } |
149 ++estimatedCost_; | 202 ++estimatedCost_; |
150 | 203 addBitmapFromPaint(paint); |
151 bool doesCoverCanvas = isFullQuad(draw, | 204 bool doesCoverCanvas = isFullQuad(draw, |
152 SkRect::MakeWH(width(), height()), | 205 SkRect::MakeWH(width(), height()), |
153 rect); | 206 rect); |
154 | 207 |
155 SkXfermode::Mode xferMode; | 208 SkXfermode::Mode xferMode; |
156 SkXfermode::AsMode(paint.getXfermode(), &xferMode); | 209 SkXfermode::AsMode(paint.getXfermode(), &xferMode); |
157 | 210 |
158 // This canvas will become transparent if the following holds: | 211 // This canvas will become transparent if the following holds: |
159 // - The quad is a full tile quad | 212 // - The quad is a full tile quad |
160 // - We're not in "forced not transparent" mode | 213 // - We're not in "forced not transparent" mode |
(...skipping 27 matching lines...) Expand all Loading... |
188 else { | 241 else { |
189 isSolidColor_ = false; | 242 isSolidColor_ = false; |
190 } | 243 } |
191 } | 244 } |
192 | 245 |
193 void AnalysisDevice::drawOval(const SkDraw&, const SkRect& oval, | 246 void AnalysisDevice::drawOval(const SkDraw&, const SkRect& oval, |
194 const SkPaint& paint) { | 247 const SkPaint& paint) { |
195 ++estimatedCost_; | 248 ++estimatedCost_; |
196 isSolidColor_ = false; | 249 isSolidColor_ = false; |
197 isTransparent_ = false; | 250 isTransparent_ = false; |
| 251 addBitmapFromPaint(paint); |
198 } | 252 } |
199 | 253 |
200 void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path, | 254 void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path, |
201 const SkPaint& paint, | 255 const SkPaint& paint, |
202 const SkMatrix* prePathMatrix , | 256 const SkMatrix* prePathMatrix , |
203 bool pathIsMutable ) { | 257 bool pathIsMutable ) { |
204 // On Z620, every antialiased path costs us about 300us. | 258 // On Z620, every antialiased path costs us about 300us. |
205 // We've only seen this in practice on filled paths, but | 259 // We've only seen this in practice on filled paths, but |
206 // we expect it to apply to all path stroking modes. | 260 // we expect it to apply to all path stroking modes. |
207 if (paint.getMaskFilter()) { | 261 if (paint.getMaskFilter()) { |
208 estimatedCost_ += 300; | 262 estimatedCost_ += 300; |
209 } | 263 } |
210 ++estimatedCost_; | 264 ++estimatedCost_; |
211 isSolidColor_ = false; | 265 isSolidColor_ = false; |
212 isTransparent_ = false; | 266 isTransparent_ = false; |
| 267 addBitmapFromPaint(paint); |
213 } | 268 } |
214 | 269 |
215 void AnalysisDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, | 270 void AnalysisDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, |
216 const SkIRect* srcRectOrNull, | 271 const SkIRect* srcRectOrNull, |
217 const SkMatrix& matrix, const SkPaint& paint) { | 272 const SkMatrix& matrix, const SkPaint& paint) { |
218 ++estimatedCost_; | 273 ++estimatedCost_; |
219 isSolidColor_ = false; | 274 isSolidColor_ = false; |
220 isTransparent_ = false; | 275 isTransparent_ = false; |
| 276 addBitmap(bitmap); |
221 } | 277 } |
222 | 278 |
223 void AnalysisDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, | 279 void AnalysisDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, |
224 int x, int y, const SkPaint& paint) { | 280 int x, int y, const SkPaint& paint) { |
225 ++estimatedCost_; | 281 ++estimatedCost_; |
226 isSolidColor_ = false; | 282 isSolidColor_ = false; |
227 isTransparent_ = false; | 283 isTransparent_ = false; |
| 284 addBitmap(bitmap); |
228 } | 285 } |
229 | 286 |
230 void AnalysisDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap&, | 287 void AnalysisDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, |
231 const SkRect* srcOrNull, const SkRect& dst, | 288 const SkRect* srcOrNull, const SkRect& dst, |
232 const SkPaint& paint) { | 289 const SkPaint& paint) { |
233 ++estimatedCost_; | 290 ++estimatedCost_; |
234 | 291 |
235 // Call drawRect to determine transparency, | 292 // Call drawRect to determine transparency, |
236 // but reset solid color to false. | 293 // but reset solid color to false. |
237 drawRect(draw, dst, paint); | 294 drawRect(draw, dst, paint); |
238 isSolidColor_ = false; | 295 isSolidColor_ = false; |
| 296 addBitmap(bitmap); |
239 } | 297 } |
240 | 298 |
241 | 299 |
242 void AnalysisDevice::drawText(const SkDraw&, const void* text, size_t len, | 300 void AnalysisDevice::drawText(const SkDraw&, const void* text, size_t len, |
243 SkScalar x, SkScalar y, const SkPaint& paint) { | 301 SkScalar x, SkScalar y, const SkPaint& paint) { |
244 ++estimatedCost_; | 302 ++estimatedCost_; |
245 isSolidColor_ = false; | 303 isSolidColor_ = false; |
246 isTransparent_ = false; | 304 isTransparent_ = false; |
| 305 addBitmapFromPaint(paint); |
247 } | 306 } |
248 | 307 |
249 void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, size_t le
n, | 308 void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, size_t le
n, |
250 const SkScalar pos[], SkScalar constY, | 309 const SkScalar pos[], SkScalar constY, |
251 int scalarsPerPos, const SkPaint& paint) { | 310 int scalarsPerPos, const SkPaint& paint) { |
252 // FIXME: On Z620, every glyph cache miss costs us about 10us. | 311 // FIXME: On Z620, every glyph cache miss costs us about 10us. |
253 // We don't have a good mechanism for predicting glyph cache misses. | 312 // We don't have a good mechanism for predicting glyph cache misses. |
254 ++estimatedCost_; | 313 ++estimatedCost_; |
255 isSolidColor_ = false; | 314 isSolidColor_ = false; |
256 isTransparent_ = false; | 315 isTransparent_ = false; |
| 316 addBitmapFromPaint(paint); |
257 } | 317 } |
258 | 318 |
259 void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, | 319 void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, |
260 const SkPath& path, const SkMatrix* matrix, | 320 const SkPath& path, const SkMatrix* matrix, |
261 const SkPaint& paint) { | 321 const SkPaint& paint) { |
262 ++estimatedCost_; | 322 ++estimatedCost_; |
263 isSolidColor_ = false; | 323 isSolidColor_ = false; |
264 isTransparent_ = false; | 324 isTransparent_ = false; |
| 325 addBitmapFromPaint(paint); |
265 } | 326 } |
266 | 327 |
267 #ifdef SK_BUILD_FOR_ANDROID | 328 #ifdef SK_BUILD_FOR_ANDROID |
268 void AnalysisDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, | 329 void AnalysisDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, |
269 size_t len, | 330 size_t len, |
270 const SkPoint pos[], const SkPaint& paint, | 331 const SkPoint pos[], const SkPaint& paint, |
271 const SkPath& path, const SkMatrix* matrix) { | 332 const SkPath& path, const SkMatrix* matrix) { |
272 ++estimatedCost_; | 333 ++estimatedCost_; |
273 isSolidColor_ = false; | 334 isSolidColor_ = false; |
274 isTransparent_ = false; | 335 isTransparent_ = false; |
| 336 addBitmapFromPaint(paint); |
275 } | 337 } |
276 #endif | 338 #endif |
277 | 339 |
278 void AnalysisDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, | 340 void AnalysisDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, |
279 int vertexCount, | 341 int vertexCount, |
280 const SkPoint verts[], const SkPoint texs[], | 342 const SkPoint verts[], const SkPoint texs[], |
281 const SkColor colors[], SkXfermode* xmode, | 343 const SkColor colors[], SkXfermode* xmode, |
282 const uint16_t indices[], int indexCount, | 344 const uint16_t indices[], int indexCount, |
283 const SkPaint& paint) { | 345 const SkPaint& paint) { |
284 ++estimatedCost_; | 346 ++estimatedCost_; |
285 isSolidColor_ = false; | 347 isSolidColor_ = false; |
286 isTransparent_ = false; | 348 isTransparent_ = false; |
| 349 addBitmapFromPaint(paint); |
287 } | 350 } |
288 | 351 |
289 void AnalysisDevice::drawDevice(const SkDraw&, SkDevice*, int x, int y, | 352 void AnalysisDevice::drawDevice(const SkDraw&, SkDevice*, int x, int y, |
290 const SkPaint&) { | 353 const SkPaint&) { |
291 ++estimatedCost_; | 354 ++estimatedCost_; |
292 isSolidColor_ = false; | 355 isSolidColor_ = false; |
293 isTransparent_ = false; | 356 isTransparent_ = false; |
294 } | 357 } |
295 | 358 |
296 | 359 |
(...skipping 19 matching lines...) Expand all Loading... |
316 } | 379 } |
317 | 380 |
318 bool AnalysisCanvas::isTransparent() const { | 381 bool AnalysisCanvas::isTransparent() const { |
319 return (static_cast<AnalysisDevice*>(getDevice()))->isTransparent(); | 382 return (static_cast<AnalysisDevice*>(getDevice()))->isTransparent(); |
320 } | 383 } |
321 | 384 |
322 int AnalysisCanvas::getEstimatedCost() const { | 385 int AnalysisCanvas::getEstimatedCost() const { |
323 return (static_cast<AnalysisDevice*>(getDevice()))->getEstimatedCost(); | 386 return (static_cast<AnalysisDevice*>(getDevice()))->getEstimatedCost(); |
324 } | 387 } |
325 | 388 |
| 389 void AnalysisCanvas::consumeLazyPixelRefs(LazyPixelRefList* pixelRefs) { |
| 390 static_cast<AnalysisDevice*>(getDevice())->consumeLazyPixelRefs(pixelRefs); |
| 391 } |
| 392 |
326 bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op, | 393 bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op, |
327 bool doAA) { | 394 bool doAA) { |
328 return INHERITED::clipRect(rect, op, doAA); | 395 return INHERITED::clipRect(rect, op, doAA); |
329 } | 396 } |
330 | 397 |
331 bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op, | 398 bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op, |
332 bool doAA) { | 399 bool doAA) { |
333 // clipPaths can make our calls to isFullQuad invalid (ie have false | 400 // clipPaths can make our calls to isFullQuad invalid (ie have false |
334 // positives). As a precaution, force the setting to be non-solid | 401 // positives). As a precaution, force the setting to be non-solid |
335 // and non-transparent until we pop this | 402 // and non-transparent until we pop this |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 if (savedStackSize_ < forceNotTransparentStackLevel_) { | 485 if (savedStackSize_ < forceNotTransparentStackLevel_) { |
419 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(false)
; | 486 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(false)
; |
420 forceNotTransparentStackLevel_ = kNoLayer; | 487 forceNotTransparentStackLevel_ = kNoLayer; |
421 } | 488 } |
422 } | 489 } |
423 } | 490 } |
424 | 491 |
425 } // namespace skia | 492 } // namespace skia |
426 | 493 |
427 | 494 |
OLD | NEW |