1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/compiler_specific.h"
6 #include "skia/ext/analysis_canvas.h"
7 #include "skia/ext/refptr.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "third_party/skia/include/core/SkPicture.h"
10 #include "third_party/skia/include/core/SkPictureRecorder.h"
11 #include "third_party/skia/include/core/SkShader.h"
12 #include "third_party/skia/include/effects/SkOffsetImageFilter.h"
16 void SolidColorFill(skia::AnalysisCanvas
& canvas
) {
17 canvas
.clear(SkColorSetARGB(255, 255, 255, 255));
20 void TransparentFill(skia::AnalysisCanvas
& canvas
) {
21 canvas
.clear(SkColorSetARGB(0, 0, 0, 0));
27 TEST(AnalysisCanvasTest
, EmptyCanvas
) {
28 skia::AnalysisCanvas
canvas(255, 255);
31 EXPECT_TRUE(canvas
.GetColorIfSolid(&color
));
32 EXPECT_EQ(color
, SkColorSetARGB(0, 0, 0, 0));
35 TEST(AnalysisCanvasTest
, ClearCanvas
) {
36 skia::AnalysisCanvas
canvas(255, 255);
39 SkColor color
= SkColorSetARGB(0, 12, 34, 56);
43 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
44 EXPECT_EQ(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
47 color
= SkColorSetARGB(255, 65, 43, 21);
50 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
51 EXPECT_NE(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
52 EXPECT_EQ(outputColor
, color
);
55 color
= SkColorSetARGB(128, 11, 22, 33);
58 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
60 // Test helper methods
61 SolidColorFill(canvas
);
62 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
63 EXPECT_NE(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
65 TransparentFill(canvas
);
66 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
67 EXPECT_EQ(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
70 TEST(AnalysisCanvasTest
, ComplexActions
) {
71 skia::AnalysisCanvas
canvas(255, 255);
74 SkColor color
= SkColorSetARGB(255, 11, 22, 33);
76 paint
.setColor(color
);
78 canvas
.drawPaint(paint
);
81 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
86 SkPoint::Make(255, 0),
87 SkPoint::Make(255, 255),
91 SolidColorFill(canvas
);
92 canvas
.drawPoints(SkCanvas::kLines_PointMode
, 4, points
, paint
);
94 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
97 SolidColorFill(canvas
);
98 canvas
.drawOval(SkRect::MakeWH(255, 255), paint
);
100 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
103 SolidColorFill(canvas
);
104 SkBitmap secondBitmap
;
105 secondBitmap
.allocN32Pixels(255, 255);
106 canvas
.drawBitmap(secondBitmap
, 0, 0);
108 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
111 TEST(AnalysisCanvasTest
, SimpleDrawRect
) {
112 skia::AnalysisCanvas
canvas(255, 255);
114 SkColor color
= SkColorSetARGB(255, 11, 22, 33);
116 paint
.setColor(color
);
117 canvas
.clipRect(SkRect::MakeWH(255, 255));
118 canvas
.drawRect(SkRect::MakeWH(255, 255), paint
);
121 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
122 EXPECT_NE(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
123 EXPECT_EQ(color
, outputColor
);
125 color
= SkColorSetARGB(255, 22, 33, 44);
126 paint
.setColor(color
);
127 canvas
.translate(-128, -128);
128 canvas
.drawRect(SkRect::MakeWH(382, 382), paint
);
130 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
132 color
= SkColorSetARGB(255, 33, 44, 55);
133 paint
.setColor(color
);
134 canvas
.drawRect(SkRect::MakeWH(383, 383), paint
);
136 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
137 EXPECT_NE(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
138 EXPECT_EQ(color
, outputColor
);
140 color
= SkColorSetARGB(0, 0, 0, 0);
141 paint
.setColor(color
);
142 canvas
.drawRect(SkRect::MakeWH(383, 383), paint
);
144 // This test relies on canvas treating a paint with 0-color as a no-op
145 // thus not changing its "is_solid" status.
146 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
147 EXPECT_NE(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
148 EXPECT_EQ(outputColor
, SkColorSetARGB(255, 33, 44, 55));
150 color
= SkColorSetARGB(128, 128, 128, 128);
151 paint
.setColor(color
);
152 canvas
.drawRect(SkRect::MakeWH(383, 383), paint
);
154 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
156 paint
.setXfermodeMode(SkXfermode::kClear_Mode
);
157 canvas
.drawRect(SkRect::MakeWH(382, 382), paint
);
159 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
161 canvas
.drawRect(SkRect::MakeWH(383, 383), paint
);
163 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
164 EXPECT_EQ(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
166 canvas
.translate(128, 128);
167 color
= SkColorSetARGB(255, 11, 22, 33);
168 paint
.setColor(color
);
169 paint
.setXfermodeMode(SkXfermode::kSrcOver_Mode
);
170 canvas
.drawRect(SkRect::MakeWH(255, 255), paint
);
172 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
173 EXPECT_NE(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
174 EXPECT_EQ(color
, outputColor
);
177 canvas
.drawRect(SkRect::MakeWH(255, 255), paint
);
179 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
182 TEST(AnalysisCanvasTest
, FilterPaint
) {
183 skia::AnalysisCanvas
canvas(255, 255);
186 skia::RefPtr
<SkImageFilter
> filter
= skia::AdoptRef(SkOffsetImageFilter::Create(10, 10));
187 paint
.setImageFilter(filter
.get());
188 canvas
.drawRect(SkRect::MakeWH(255, 255), paint
);
191 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
194 TEST(AnalysisCanvasTest
, ClipPath
) {
195 skia::AnalysisCanvas
canvas(255, 255);
197 // Skia will look for paths that are actually rects and treat
198 // them as such. We add a divot to the following path to prevent
199 // this optimization and truly test clipPath's behavior.
202 path
.lineTo(128, 50);
204 path
.lineTo(255, 255);
208 SolidColorFill(canvas
);
209 canvas
.clipPath(path
);
210 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
213 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
215 canvas
.clipPath(path
);
216 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
219 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
221 SolidColorFill(canvas
);
222 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
225 TEST(AnalysisCanvasTest
, SaveLayerWithXfermode
) {
226 skia::AnalysisCanvas
canvas(255, 255);
227 SkRect bounds
= SkRect::MakeWH(255, 255);
230 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
231 EXPECT_EQ(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
234 // Note: nothing is draw to the the save layer, but solid color
235 // and transparency are handled conservatively in case the layer's
236 // SkPaint draws something. For example, there could be an
237 // SkPictureImageFilter. If someday analysis_canvas starts doing
238 // a deeper analysis of the SkPaint, this test may need to be
240 TransparentFill(canvas
);
241 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
242 EXPECT_EQ(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
243 paint
.setXfermodeMode(SkXfermode::kSrc_Mode
);
244 canvas
.saveLayer(&bounds
, &paint
);
246 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
248 TransparentFill(canvas
);
249 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
250 EXPECT_EQ(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
251 paint
.setXfermodeMode(SkXfermode::kSrcOver_Mode
);
252 canvas
.saveLayer(&bounds
, &paint
);
254 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
256 // Layer with dst xfermode is a no-op, so this is the only case
257 // where solid color is unaffected by the layer.
258 TransparentFill(canvas
);
259 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
260 EXPECT_EQ(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
261 paint
.setXfermodeMode(SkXfermode::kDst_Mode
);
262 canvas
.saveLayer(&bounds
, &paint
);
264 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
265 EXPECT_EQ(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
268 TEST(AnalysisCanvasTest
, SaveLayerRestore
) {
269 skia::AnalysisCanvas
canvas(255, 255);
272 SolidColorFill(canvas
);
273 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
275 SkRect bounds
= SkRect::MakeWH(255, 255);
277 paint
.setColor(SkColorSetARGB(255, 255, 255, 255));
278 paint
.setXfermodeMode(SkXfermode::kSrcOver_Mode
);
280 // This should force non-transparency
281 canvas
.saveLayer(&bounds
, &paint
);
282 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
283 EXPECT_NE(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
285 TransparentFill(canvas
);
286 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
288 SolidColorFill(canvas
);
289 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
290 EXPECT_NE(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
292 paint
.setXfermodeMode(SkXfermode::kDst_Mode
);
294 // This should force non-solid color
295 canvas
.saveLayer(&bounds
, &paint
);
296 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
298 TransparentFill(canvas
);
299 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
301 SolidColorFill(canvas
);
302 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
305 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
307 TransparentFill(canvas
);
308 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
310 SolidColorFill(canvas
);
311 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
312 EXPECT_NE(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
315 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
316 EXPECT_NE(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
318 TransparentFill(canvas
);
319 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
320 EXPECT_EQ(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
322 SolidColorFill(canvas
);
323 EXPECT_TRUE(canvas
.GetColorIfSolid(&outputColor
));
324 EXPECT_NE(static_cast<SkColor
>(SK_ColorTRANSPARENT
), outputColor
);
327 TEST(AnalysisCanvasTest
, EarlyOutNotSolid
) {
328 SkRTreeFactory factory
;
329 SkPictureRecorder recorder
;
331 // Create a picture with 3 commands, last of which is non-solid.
332 skia::RefPtr
<SkCanvas
> record_canvas
=
333 skia::SharePtr(recorder
.beginRecording(256, 256, &factory
));
335 std::string text
= "text";
336 SkPoint point
= SkPoint::Make(SkIntToScalar(25), SkIntToScalar(25));
339 paint
.setColor(SkColorSetARGB(255, 255, 255, 255));
340 paint
.setXfermodeMode(SkXfermode::kSrcOver_Mode
);
342 record_canvas
->drawRect(SkRect::MakeWH(256, 256), paint
);
343 record_canvas
->drawRect(SkRect::MakeWH(256, 256), paint
);
344 record_canvas
->drawText(
345 text
.c_str(), text
.length(), point
.fX
, point
.fY
, paint
);
347 skia::RefPtr
<SkPicture
> picture
= skia::AdoptRef(recorder
.endRecording());
349 // Draw the picture into the analysis canvas, using the canvas as a callback
351 skia::AnalysisCanvas
canvas(256, 256);
352 picture
->playback(&canvas
, &canvas
);
354 // Ensure that canvas is not solid.
355 SkColor output_color
;
356 EXPECT_FALSE(canvas
.GetColorIfSolid(&output_color
));
358 // Verify that we aborted drawing.
359 EXPECT_TRUE(canvas
.abortDrawing());
363 TEST(AnalysisCanvasTest
, ClipComplexRegion
) {
364 skia::AnalysisCanvas
canvas(255, 255);
368 path
.lineTo(128, 50);
370 path
.lineTo(255, 255);
372 SkIRect pathBounds
= path
.getBounds().round();
374 region
.setPath(path
, SkRegion(pathBounds
));
377 SolidColorFill(canvas
);
378 canvas
.clipRegion(region
);
379 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
382 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
384 canvas
.clipRegion(region
);
385 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
388 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));
390 SolidColorFill(canvas
);
391 EXPECT_FALSE(canvas
.GetColorIfSolid(&outputColor
));