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.
4
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"
13
14namespace {
15
16void SolidColorFill(skia::AnalysisCanvas& canvas) {
17  canvas.clear(SkColorSetARGB(255, 255, 255, 255));
18}
19
20void TransparentFill(skia::AnalysisCanvas& canvas) {
21  canvas.clear(SkColorSetARGB(0, 0, 0, 0));
22}
23
24} // namespace
25namespace skia {
26
27TEST(AnalysisCanvasTest, EmptyCanvas) {
28  skia::AnalysisCanvas canvas(255, 255);
29
30  SkColor color;
31  EXPECT_TRUE(canvas.GetColorIfSolid(&color));
32  EXPECT_EQ(color, SkColorSetARGB(0, 0, 0, 0));
33}
34
35TEST(AnalysisCanvasTest, ClearCanvas) {
36  skia::AnalysisCanvas canvas(255, 255);
37
38  // Transparent color
39  SkColor color = SkColorSetARGB(0, 12, 34, 56);
40  canvas.clear(color);
41
42  SkColor outputColor;
43  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
44  EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
45
46  // Solid color
47  color = SkColorSetARGB(255, 65, 43, 21);
48  canvas.clear(color);
49
50  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
51  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
52  EXPECT_EQ(outputColor, color);
53
54  // Translucent color
55  color = SkColorSetARGB(128, 11, 22, 33);
56  canvas.clear(color);
57
58  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
59
60  // Test helper methods
61  SolidColorFill(canvas);
62  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
63  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
64
65  TransparentFill(canvas);
66  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
67  EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
68}
69
70TEST(AnalysisCanvasTest, ComplexActions) {
71  skia::AnalysisCanvas canvas(255, 255);
72
73  // Draw paint test.
74  SkColor color = SkColorSetARGB(255, 11, 22, 33);
75  SkPaint paint;
76  paint.setColor(color);
77
78  canvas.drawPaint(paint);
79
80  SkColor outputColor;
81  //TODO(vmpstr): This should return true. (crbug.com/180597)
82  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
83
84  // Draw points test.
85  SkPoint points[4] = {
86    SkPoint::Make(0, 0),
87    SkPoint::Make(255, 0),
88    SkPoint::Make(255, 255),
89    SkPoint::Make(0, 255)
90  };
91
92  SolidColorFill(canvas);
93  canvas.drawPoints(SkCanvas::kLines_PointMode, 4, points, paint);
94
95  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
96
97  // Draw oval test.
98  SolidColorFill(canvas);
99  canvas.drawOval(SkRect::MakeWH(255, 255), paint);
100
101  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
102
103  // Draw bitmap test.
104  SolidColorFill(canvas);
105  SkBitmap secondBitmap;
106  secondBitmap.allocN32Pixels(255, 255);
107  canvas.drawBitmap(secondBitmap, 0, 0);
108
109  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
110}
111
112TEST(AnalysisCanvasTest, SimpleDrawRect) {
113  skia::AnalysisCanvas canvas(255, 255);
114
115  SkColor color = SkColorSetARGB(255, 11, 22, 33);
116  SkPaint paint;
117  paint.setColor(color);
118  canvas.clipRect(SkRect::MakeWH(255, 255));
119  canvas.drawRect(SkRect::MakeWH(255, 255), paint);
120
121  SkColor outputColor;
122  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
123  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
124  EXPECT_EQ(color, outputColor);
125
126  color = SkColorSetARGB(255, 22, 33, 44);
127  paint.setColor(color);
128  canvas.translate(-128, -128);
129  canvas.drawRect(SkRect::MakeWH(382, 382), paint);
130
131  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
132
133  color = SkColorSetARGB(255, 33, 44, 55);
134  paint.setColor(color);
135  canvas.drawRect(SkRect::MakeWH(383, 383), paint);
136
137  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
138  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
139  EXPECT_EQ(color, outputColor);
140
141  color = SkColorSetARGB(0, 0, 0, 0);
142  paint.setColor(color);
143  canvas.drawRect(SkRect::MakeWH(383, 383), paint);
144
145  // This test relies on canvas treating a paint with 0-color as a no-op
146  // thus not changing its "is_solid" status.
147  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
148  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
149  EXPECT_EQ(outputColor, SkColorSetARGB(255, 33, 44, 55));
150
151  color = SkColorSetARGB(128, 128, 128, 128);
152  paint.setColor(color);
153  canvas.drawRect(SkRect::MakeWH(383, 383), paint);
154
155  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
156
157  paint.setXfermodeMode(SkXfermode::kClear_Mode);
158  canvas.drawRect(SkRect::MakeWH(382, 382), paint);
159
160  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
161
162  canvas.drawRect(SkRect::MakeWH(383, 383), paint);
163
164  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
165  EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
166
167  canvas.translate(128, 128);
168  color = SkColorSetARGB(255, 11, 22, 33);
169  paint.setColor(color);
170  paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
171  canvas.drawRect(SkRect::MakeWH(255, 255), paint);
172
173  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
174  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
175  EXPECT_EQ(color, outputColor);
176
177  canvas.rotate(50);
178  canvas.drawRect(SkRect::MakeWH(255, 255), paint);
179
180  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
181}
182
183TEST(AnalysisCanvasTest, FilterPaint) {
184  skia::AnalysisCanvas canvas(255, 255);
185  SkPaint paint;
186
187  skia::RefPtr<SkImageFilter> filter = skia::AdoptRef(SkOffsetImageFilter::Create(10, 10));
188  paint.setImageFilter(filter.get());
189  canvas.drawRect(SkRect::MakeWH(255, 255), paint);
190
191  SkColor outputColor;
192  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
193}
194
195TEST(AnalysisCanvasTest, ClipPath) {
196  skia::AnalysisCanvas canvas(255, 255);
197
198  // Skia will look for paths that are actually rects and treat
199  // them as such. We add a divot to the following path to prevent
200  // this optimization and truly test clipPath's behavior.
201  SkPath path;
202  path.moveTo(0, 0);
203  path.lineTo(128, 50);
204  path.lineTo(255, 0);
205  path.lineTo(255, 255);
206  path.lineTo(0, 255);
207
208  SkColor outputColor;
209  SolidColorFill(canvas);
210  canvas.clipPath(path);
211  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
212
213  canvas.save();
214  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
215
216  canvas.clipPath(path);
217  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
218
219  canvas.restore();
220  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
221
222  SolidColorFill(canvas);
223  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
224}
225
226TEST(AnalysisCanvasTest, SaveLayerRestore) {
227  skia::AnalysisCanvas canvas(255, 255);
228
229  SkColor outputColor;
230  SolidColorFill(canvas);
231  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
232
233  SkRect bounds = SkRect::MakeWH(255, 255);
234  SkPaint paint;
235  paint.setColor(SkColorSetARGB(255, 255, 255, 255));
236  paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
237
238  // This should force non-transparency
239  canvas.saveLayer(&bounds, &paint);
240  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
241  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
242
243  TransparentFill(canvas);
244  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
245
246  SolidColorFill(canvas);
247  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
248  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
249
250  paint.setXfermodeMode(SkXfermode::kDst_Mode);
251
252  // This should force non-solid color
253  canvas.saveLayer(&bounds, &paint);
254  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
255
256  TransparentFill(canvas);
257  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
258
259  SolidColorFill(canvas);
260  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
261
262  canvas.restore();
263  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
264
265  TransparentFill(canvas);
266  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
267
268  SolidColorFill(canvas);
269  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
270  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
271
272  canvas.restore();
273  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
274  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
275
276  TransparentFill(canvas);
277  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
278  EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
279
280  SolidColorFill(canvas);
281  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
282  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
283}
284
285TEST(AnalysisCanvasTest, EarlyOutNotSolid) {
286  SkTileGridFactory::TileGridInfo tile_grid_info;
287  tile_grid_info.fTileInterval.set(256, 256);
288  tile_grid_info.fOffset.setZero();
289  tile_grid_info.fMargin.setEmpty();
290  SkTileGridFactory factory(tile_grid_info);
291  SkPictureRecorder recorder;
292
293  // Create a picture with 3 commands, last of which is non-solid.
294  skia::RefPtr<SkCanvas> record_canvas =
295      skia::SharePtr(recorder.beginRecording(256, 256, &factory));
296
297  std::string text = "text";
298  SkPoint point = SkPoint::Make(SkIntToScalar(25), SkIntToScalar(25));
299
300  SkPaint paint;
301  paint.setColor(SkColorSetARGB(255, 255, 255, 255));
302  paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
303
304  record_canvas->drawRect(SkRect::MakeWH(256, 256), paint);
305  record_canvas->drawRect(SkRect::MakeWH(256, 256), paint);
306  record_canvas->drawText(
307      text.c_str(), text.length(), point.fX, point.fY, paint);
308
309  skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
310
311  // Draw the picture into the analysis canvas, using the canvas as a callback
312  // as well.
313  skia::AnalysisCanvas canvas(256, 256);
314  picture->draw(&canvas, &canvas);
315
316  // Ensure that canvas is not solid.
317  SkColor output_color;
318  EXPECT_FALSE(canvas.GetColorIfSolid(&output_color));
319
320  // Verify that we aborted drawing.
321  EXPECT_TRUE(canvas.abortDrawing());
322
323}
324
325TEST(AnalysisCanvasTest, ClipComplexRegion) {
326  skia::AnalysisCanvas canvas(255, 255);
327
328  SkPath path;
329  path.moveTo(0, 0);
330  path.lineTo(128, 50);
331  path.lineTo(255, 0);
332  path.lineTo(255, 255);
333  path.lineTo(0, 255);
334  SkIRect pathBounds = path.getBounds().round();
335  SkRegion region;
336  region.setPath(path, SkRegion(pathBounds));
337
338  SkColor outputColor;
339  SolidColorFill(canvas);
340  canvas.clipRegion(region);
341  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
342
343  canvas.save();
344  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
345
346  canvas.clipRegion(region);
347  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
348
349  canvas.restore();
350  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
351
352  SolidColorFill(canvas);
353  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
354}
355
356}  // namespace skia
357