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/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 // NULL turns into kSrcOver mode. | |
Tom Hudson
2013/02/25 17:16:04
This comment is unclear, since NULL is nowhere in
| |
24 SkXfermode::AsMode(paint.getXfermode(), &xferMode); | |
25 | |
26 // Paint is solid color if the following holds: | |
27 // - Alpha is 1.0, style is fill, and there are no special effects | |
28 // - Xfer mode is either kSrc or kSrcOver (kSrcOver is equivalent | |
29 // to kSrc if source alpha is 1.0, which is already checked). | |
30 return (paint.getAlpha() == 255 && | |
31 !paint.getShader() && | |
32 !paint.getLooper() && | |
33 !paint.getMaskFilter() && | |
34 !paint.getColorFilter() && | |
35 paint.getStyle() == SkPaint::kFill_Style && | |
36 (xferMode == SkXfermode::kSrc_Mode || | |
37 xferMode == SkXfermode::kSrcOver_Mode)); | |
19 } | 38 } |
20 | 39 |
40 } // namespace | |
41 | |
21 namespace skia { | 42 namespace skia { |
22 | 43 |
23 AnalysisDevice::AnalysisDevice(const SkBitmap& bm) | 44 AnalysisDevice::AnalysisDevice(const SkBitmap& bm) |
24 : INHERITED(bm) | 45 : INHERITED(bm) |
25 , estimatedCost_(0) { | 46 , estimatedCost_(0) |
47 , isForcedNotSolid_(false) | |
48 , isSolidColor_(false) { | |
26 | 49 |
27 } | 50 } |
28 | 51 |
29 AnalysisDevice::~AnalysisDevice() { | 52 AnalysisDevice::~AnalysisDevice() { |
30 | |
31 } | 53 } |
32 | 54 |
33 int AnalysisDevice::getEstimatedCost() const { | 55 int AnalysisDevice::getEstimatedCost() const { |
34 return estimatedCost_; | 56 return estimatedCost_; |
35 } | 57 } |
36 | 58 |
59 bool AnalysisDevice::getColorIfSolid(SkColor* color) const { | |
60 if (isSolidColor_) | |
61 *color = color_; | |
62 return isSolidColor_; | |
63 } | |
64 | |
65 bool AnalysisDevice::isTransparent() const { | |
66 //TODO(vmpstr) implement | |
67 return false; | |
68 } | |
69 | |
70 void AnalysisDevice::setForceNotSolid(bool flag) { | |
71 isForcedNotSolid_ = flag; | |
72 if (isForcedNotSolid_) | |
73 isSolidColor_ = false; | |
74 } | |
75 | |
37 void AnalysisDevice::clear(SkColor color) { | 76 void AnalysisDevice::clear(SkColor color) { |
38 ++estimatedCost_; | 77 ++estimatedCost_; |
78 if (!isForcedNotSolid_ && SkColorGetA(color) == 255) { | |
79 isSolidColor_ = true; | |
80 color_ = color; | |
81 } | |
82 else { | |
83 isSolidColor_ = false; | |
84 } | |
39 } | 85 } |
40 | 86 |
41 void AnalysisDevice::drawPaint(const SkDraw&, const SkPaint& paint) { | 87 void AnalysisDevice::drawPaint(const SkDraw&, const SkPaint& paint) { |
42 ++estimatedCost_; | 88 ++estimatedCost_; |
89 isSolidColor_ = false; | |
43 } | 90 } |
44 | 91 |
45 void AnalysisDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, | 92 void AnalysisDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, |
46 size_t count, const SkPoint[], | 93 size_t count, const SkPoint[], |
47 const SkPaint& paint) { | 94 const SkPaint& paint) { |
48 ++estimatedCost_; | 95 ++estimatedCost_; |
96 isSolidColor_ = false; | |
49 } | 97 } |
50 | 98 |
51 void AnalysisDevice::drawRect(const SkDraw&, const SkRect& r, | 99 void AnalysisDevice::drawRect(const SkDraw& draw, const SkRect& rect, |
52 const SkPaint& paint) { | 100 const SkPaint& paint) { |
53 // FIXME: if there's a pending image decode & resize, more expensive | 101 // FIXME: if there's a pending image decode & resize, more expensive |
54 if (paint.getMaskFilter()) { | 102 if (paint.getMaskFilter()) { |
55 estimatedCost_ += 300; | 103 estimatedCost_ += 300; |
56 } | 104 } |
57 ++estimatedCost_; | 105 ++estimatedCost_; |
106 | |
107 if (isForcedNotSolid_) | |
108 return; | |
109 | |
110 SkRect clipRect = SkRect::Make(draw.fRC->getBounds()); | |
111 SkRect bitmapRect = SkRect::MakeWH(width(), height()); | |
112 | |
113 // This bitmap is solid if and only if the following holds. | |
114 // Note that this might be overly conservative: | |
115 // - Paint is solid color | |
116 // - Clip rect is an actual rectangle. | |
117 // - The rect we're drawing contains the clip rect. | |
118 // That is, all of clip rect will be colored by the rect. | |
119 // - Clip rect contains the bitmap rect. | |
120 // That is, we're not clipping to a portion of this bitmap. | |
Tom Hudson
2013/02/25 17:16:04
You mention "bitmap", but when we're on the border
| |
121 if (isSolidColorPaint(paint) && | |
122 draw.fRC->isRect() && | |
123 rect.contains(clipRect) && | |
124 clipRect.contains(bitmapRect)) { | |
125 isSolidColor_ = true; | |
126 color_ = paint.getColor(); | |
127 } | |
128 else { | |
129 isSolidColor_ = false; | |
130 } | |
58 } | 131 } |
59 | 132 |
60 void AnalysisDevice::drawOval(const SkDraw&, const SkRect& oval, | 133 void AnalysisDevice::drawOval(const SkDraw&, const SkRect& oval, |
61 const SkPaint& paint) { | 134 const SkPaint& paint) { |
62 ++estimatedCost_; | 135 ++estimatedCost_; |
136 isSolidColor_ = false; | |
63 } | 137 } |
64 | 138 |
65 void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path, | 139 void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path, |
66 const SkPaint& paint, | 140 const SkPaint& paint, |
67 const SkMatrix* prePathMatrix , | 141 const SkMatrix* prePathMatrix , |
68 bool pathIsMutable ) { | 142 bool pathIsMutable ) { |
69 // On Z620, every antialiased path costs us about 300us. | 143 // On Z620, every antialiased path costs us about 300us. |
70 // We've only seen this in practice on filled paths, but | 144 // We've only seen this in practice on filled paths, but |
71 // we expect it to apply to all path stroking modes. | 145 // we expect it to apply to all path stroking modes. |
72 if (paint.getMaskFilter()) { | 146 if (paint.getMaskFilter()) { |
73 estimatedCost_ += 300; | 147 estimatedCost_ += 300; |
74 } | 148 } |
75 ++estimatedCost_; | 149 ++estimatedCost_; |
150 isSolidColor_ = false; | |
76 } | 151 } |
77 | 152 |
78 void AnalysisDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, | 153 void AnalysisDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, |
79 const SkIRect* srcRectOrNull, | 154 const SkIRect* srcRectOrNull, |
80 const SkMatrix& matrix, const SkPaint& paint) | 155 const SkMatrix& matrix, const SkPaint& paint) |
81 { | 156 { |
82 ++estimatedCost_; | 157 ++estimatedCost_; |
158 isSolidColor_ = false; | |
83 } | 159 } |
84 | 160 |
85 void AnalysisDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, | 161 void AnalysisDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, |
86 int x, int y, const SkPaint& paint) { | 162 int x, int y, const SkPaint& paint) { |
87 ++estimatedCost_; | 163 ++estimatedCost_; |
164 isSolidColor_ = false; | |
88 } | 165 } |
89 | 166 |
90 void AnalysisDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, | 167 void AnalysisDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, |
91 const SkRect* srcOrNull, const SkRect& dst, | 168 const SkRect* srcOrNull, const SkRect& dst, |
92 const SkPaint& paint) { | 169 const SkPaint& paint) { |
93 ++estimatedCost_; | 170 ++estimatedCost_; |
171 isSolidColor_ = false; | |
94 } | 172 } |
95 | 173 |
96 | 174 |
97 void AnalysisDevice::drawText(const SkDraw&, const void* text, size_t len, | 175 void AnalysisDevice::drawText(const SkDraw&, const void* text, size_t len, |
98 SkScalar x, SkScalar y, const SkPaint& paint) | 176 SkScalar x, SkScalar y, const SkPaint& paint) |
99 { | 177 { |
100 ++estimatedCost_; | 178 ++estimatedCost_; |
179 isSolidColor_ = false; | |
101 } | 180 } |
102 | 181 |
103 void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, size_t le n, | 182 void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, size_t le n, |
104 const SkScalar pos[], SkScalar constY, | 183 const SkScalar pos[], SkScalar constY, |
105 int scalarsPerPos, const SkPaint& paint) { | 184 int scalarsPerPos, const SkPaint& paint) { |
106 // FIXME: On Z620, every glyph cache miss costs us about 10us. | 185 // FIXME: On Z620, every glyph cache miss costs us about 10us. |
107 // We don't have a good mechanism for predicting glyph cache misses. | 186 // We don't have a good mechanism for predicting glyph cache misses. |
108 ++estimatedCost_; | 187 ++estimatedCost_; |
188 isSolidColor_ = false; | |
109 } | 189 } |
110 | 190 |
111 void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, | 191 void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, |
112 const SkPath& path, const SkMatrix* matrix, | 192 const SkPath& path, const SkMatrix* matrix, |
113 const SkPaint& paint) { | 193 const SkPaint& paint) { |
114 ++estimatedCost_; | 194 ++estimatedCost_; |
195 isSolidColor_ = false; | |
115 } | 196 } |
116 | 197 |
117 #ifdef SK_BUILD_FOR_ANDROID | 198 #ifdef SK_BUILD_FOR_ANDROID |
118 void AnalysisDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, | 199 void AnalysisDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, |
119 size_t len, | 200 size_t len, |
120 const SkPoint pos[], const SkPaint& paint, | 201 const SkPoint pos[], const SkPaint& paint, |
121 const SkPath& path, const SkMatrix* matrix) | 202 const SkPath& path, const SkMatrix* matrix) |
122 { | 203 { |
123 ++estimatedCost_; | 204 ++estimatedCost_; |
205 isSolidColor_ = false; | |
124 } | 206 } |
125 #endif | 207 #endif |
126 | 208 |
127 void AnalysisDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, | 209 void AnalysisDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, |
128 int vertexCount, | 210 int vertexCount, |
129 const SkPoint verts[], const SkPoint texs[], | 211 const SkPoint verts[], const SkPoint texs[], |
130 const SkColor colors[], SkXfermode* xmode, | 212 const SkColor colors[], SkXfermode* xmode, |
131 const uint16_t indices[], int indexCount, | 213 const uint16_t indices[], int indexCount, |
132 const SkPaint& paint) { | 214 const SkPaint& paint) { |
133 ++estimatedCost_; | 215 ++estimatedCost_; |
216 isSolidColor_ = false; | |
134 } | 217 } |
135 | 218 |
136 void AnalysisDevice::drawDevice(const SkDraw&, SkDevice*, int x, int y, | 219 void AnalysisDevice::drawDevice(const SkDraw&, SkDevice*, int x, int y, |
137 const SkPaint&) { | 220 const SkPaint&) { |
138 ++estimatedCost_; | 221 ++estimatedCost_; |
222 isSolidColor_ = false; | |
139 } | 223 } |
140 | 224 |
141 | 225 |
142 | 226 |
143 | 227 |
144 AnalysisCanvas::AnalysisCanvas(AnalysisDevice* device) | 228 AnalysisCanvas::AnalysisCanvas(AnalysisDevice* device) |
145 : INHERITED(device) { | 229 : INHERITED(device) |
146 | 230 , saveDepth_(0) { |
147 } | 231 } |
148 | 232 |
149 AnalysisCanvas::~AnalysisCanvas() { | 233 AnalysisCanvas::~AnalysisCanvas() { |
150 } | 234 } |
151 | 235 |
152 | 236 |
153 bool AnalysisCanvas::isCheap() const { | 237 bool AnalysisCanvas::isCheap() const { |
154 return getEstimatedCost() < gPictureCostThreshold; | 238 return getEstimatedCost() < gPictureCostThreshold; |
155 } | 239 } |
156 | 240 |
241 bool AnalysisCanvas::getColorIfSolid(SkColor* color) const { | |
242 return (static_cast<AnalysisDevice*>(getDevice()))->getColorIfSolid(color); | |
243 } | |
244 | |
245 bool AnalysisCanvas::isTransparent() const { | |
246 return (static_cast<AnalysisDevice*>(getDevice()))->isTransparent(); | |
247 } | |
248 | |
157 int AnalysisCanvas::getEstimatedCost() const { | 249 int AnalysisCanvas::getEstimatedCost() const { |
158 return (static_cast<AnalysisDevice*>(getDevice()))->getEstimatedCost(); | 250 return (static_cast<AnalysisDevice*>(getDevice()))->getEstimatedCost(); |
159 } | 251 } |
160 | 252 |
161 | |
162 bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op, | 253 bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op, |
163 bool doAA) { | 254 bool doAA) { |
164 return INHERITED::clipRect(rect, op, doAA); | 255 return INHERITED::clipRect(rect, op, doAA); |
165 } | 256 } |
166 | 257 |
167 bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op, | 258 bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op, |
168 bool doAA) { | 259 bool doAA) { |
169 return INHERITED::clipRect(path.getBounds(), op, doAA); | 260 return INHERITED::clipRect(path.getBounds(), op, doAA); |
170 } | 261 } |
171 | 262 |
172 bool AnalysisCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, | 263 bool AnalysisCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, |
173 bool doAA) { | 264 bool doAA) { |
174 return INHERITED::clipRect(rrect.getBounds(), op, doAA); | 265 return INHERITED::clipRect(rrect.getBounds(), op, doAA); |
175 } | 266 } |
176 | 267 |
177 int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint*, | 268 int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, |
178 SkCanvas::SaveFlags flags) { | 269 SkCanvas::SaveFlags flags) { |
270 if (paint && !isSolidColorPaint(*paint)) | |
271 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(true); | |
272 ++saveDepth_; | |
273 | |
179 // Actually saving a layer here could cause a new bitmap to be created | 274 // Actually saving a layer here could cause a new bitmap to be created |
180 // and real rendering to occur. | 275 // and real rendering to occur. |
181 int count = SkCanvas::save(flags); | 276 int count = INHERITED::save(flags); |
182 if (bounds) { | 277 if (bounds) { |
183 INHERITED::clipRectBounds(bounds, flags, NULL); | 278 INHERITED::clipRectBounds(bounds, flags, NULL); |
184 } | 279 } |
185 return count; | 280 return count; |
186 } | 281 } |
187 | 282 |
283 void AnalysisCanvas::restore() { | |
284 INHERITED::restore(); | |
285 if (--saveDepth_ == 0) | |
286 (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(false); | |
Tom Hudson
2013/02/25 17:16:04
This looks really conservative: if we ever save a
| |
287 } | |
288 | |
188 } // namespace skia | 289 } // namespace skia |
189 | 290 |
190 | 291 |
OLD | NEW |