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/SkShader.h"
10#include "third_party/skia/include/effects/SkOffsetImageFilter.h"
11
12namespace {
13
14void SolidColorFill(skia::AnalysisCanvas& canvas) {
15  canvas.clear(SkColorSetARGB(255, 255, 255, 255));
16}
17
18void TransparentFill(skia::AnalysisCanvas& canvas) {
19  canvas.clear(SkColorSetARGB(0, 0, 0, 0));
20}
21
22} // namespace
23namespace skia {
24
25TEST(AnalysisCanvasTest, EmptyCanvas) {
26  skia::AnalysisCanvas canvas(255, 255);
27
28  SkColor color;
29  EXPECT_TRUE(canvas.GetColorIfSolid(&color));
30  EXPECT_EQ(color, SkColorSetARGB(0, 0, 0, 0));
31}
32
33TEST(AnalysisCanvasTest, ClearCanvas) {
34  skia::AnalysisCanvas canvas(255, 255);
35
36  // Transparent color
37  SkColor color = SkColorSetARGB(0, 12, 34, 56);
38  canvas.clear(color);
39
40  SkColor outputColor;
41  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
42  EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
43
44  // Solid color
45  color = SkColorSetARGB(255, 65, 43, 21);
46  canvas.clear(color);
47
48  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
49  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
50  EXPECT_EQ(outputColor, color);
51
52  // Translucent color
53  color = SkColorSetARGB(128, 11, 22, 33);
54  canvas.clear(color);
55
56  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
57
58  // Test helper methods
59  SolidColorFill(canvas);
60  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
61  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
62
63  TransparentFill(canvas);
64  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
65  EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
66}
67
68TEST(AnalysisCanvasTest, ComplexActions) {
69  skia::AnalysisCanvas canvas(255, 255);
70
71  // Draw paint test.
72  SkColor color = SkColorSetARGB(255, 11, 22, 33);
73  SkPaint paint;
74  paint.setColor(color);
75
76  canvas.drawPaint(paint);
77
78  SkColor outputColor;
79  //TODO(vmpstr): This should return true. (crbug.com/180597)
80  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
81
82  // Draw points test.
83  SkPoint points[4] = {
84    SkPoint::Make(0, 0),
85    SkPoint::Make(255, 0),
86    SkPoint::Make(255, 255),
87    SkPoint::Make(0, 255)
88  };
89
90  SolidColorFill(canvas);
91  canvas.drawPoints(SkCanvas::kLines_PointMode, 4, points, paint);
92
93  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
94
95  // Draw oval test.
96  SolidColorFill(canvas);
97  canvas.drawOval(SkRect::MakeWH(255, 255), paint);
98
99  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
100
101  // Draw bitmap test.
102  SolidColorFill(canvas);
103  SkBitmap secondBitmap;
104  secondBitmap.allocN32Pixels(255, 255);
105  canvas.drawBitmap(secondBitmap, 0, 0);
106
107  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
108}
109
110TEST(AnalysisCanvasTest, SimpleDrawRect) {
111  skia::AnalysisCanvas canvas(255, 255);
112
113  SkColor color = SkColorSetARGB(255, 11, 22, 33);
114  SkPaint paint;
115  paint.setColor(color);
116  canvas.clipRect(SkRect::MakeWH(255, 255));
117  canvas.drawRect(SkRect::MakeWH(255, 255), paint);
118
119  SkColor outputColor;
120  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
121  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
122  EXPECT_EQ(color, outputColor);
123
124  color = SkColorSetARGB(255, 22, 33, 44);
125  paint.setColor(color);
126  canvas.translate(-128, -128);
127  canvas.drawRect(SkRect::MakeWH(382, 382), paint);
128
129  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
130
131  color = SkColorSetARGB(255, 33, 44, 55);
132  paint.setColor(color);
133  canvas.drawRect(SkRect::MakeWH(383, 383), paint);
134
135  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
136  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
137  EXPECT_EQ(color, outputColor);
138
139  color = SkColorSetARGB(0, 0, 0, 0);
140  paint.setColor(color);
141  canvas.drawRect(SkRect::MakeWH(383, 383), paint);
142
143  // This test relies on canvas treating a paint with 0-color as a no-op
144  // thus not changing its "is_solid" status.
145  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
146  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
147  EXPECT_EQ(outputColor, SkColorSetARGB(255, 33, 44, 55));
148
149  color = SkColorSetARGB(128, 128, 128, 128);
150  paint.setColor(color);
151  canvas.drawRect(SkRect::MakeWH(383, 383), paint);
152
153  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
154
155  paint.setXfermodeMode(SkXfermode::kClear_Mode);
156  canvas.drawRect(SkRect::MakeWH(382, 382), paint);
157
158  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
159
160  canvas.drawRect(SkRect::MakeWH(383, 383), paint);
161
162  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
163  EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
164
165  canvas.translate(128, 128);
166  color = SkColorSetARGB(255, 11, 22, 33);
167  paint.setColor(color);
168  paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
169  canvas.drawRect(SkRect::MakeWH(255, 255), paint);
170
171  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
172  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
173  EXPECT_EQ(color, outputColor);
174
175  canvas.rotate(50);
176  canvas.drawRect(SkRect::MakeWH(255, 255), paint);
177
178  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
179}
180
181TEST(AnalysisCanvasTest, FilterPaint) {
182  skia::AnalysisCanvas canvas(255, 255);
183  SkPaint paint;
184
185  skia::RefPtr<SkImageFilter> filter = skia::AdoptRef(SkOffsetImageFilter::Create(10, 10));
186  paint.setImageFilter(filter.get());
187  canvas.drawRect(SkRect::MakeWH(255, 255), paint);
188
189  SkColor outputColor;
190  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
191}
192
193TEST(AnalysisCanvasTest, ClipPath) {
194  skia::AnalysisCanvas canvas(255, 255);
195
196  // Skia will look for paths that are actually rects and treat
197  // them as such. We add a divot to the following path to prevent
198  // this optimization and truly test clipPath's behavior.
199  SkPath path;
200  path.moveTo(0, 0);
201  path.lineTo(128, 50);
202  path.lineTo(255, 0);
203  path.lineTo(255, 255);
204  path.lineTo(0, 255);
205
206  SkColor outputColor;
207  SolidColorFill(canvas);
208  canvas.clipPath(path);
209  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
210
211  canvas.save();
212  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
213
214  canvas.clipPath(path);
215  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
216
217  canvas.restore();
218  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
219
220  SolidColorFill(canvas);
221  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
222}
223
224TEST(AnalysisCanvasTest, SaveLayerRestore) {
225  skia::AnalysisCanvas canvas(255, 255);
226
227  SkColor outputColor;
228  SolidColorFill(canvas);
229  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
230
231  SkRect bounds = SkRect::MakeWH(255, 255);
232  SkPaint paint;
233  paint.setColor(SkColorSetARGB(255, 255, 255, 255));
234  paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
235
236  // This should force non-transparency
237  canvas.saveLayer(&bounds, &paint);
238  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
239  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
240
241  TransparentFill(canvas);
242  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
243
244  SolidColorFill(canvas);
245  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
246  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
247
248  paint.setXfermodeMode(SkXfermode::kDst_Mode);
249
250  // This should force non-solid color
251  canvas.saveLayer(&bounds, &paint);
252  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
253
254  TransparentFill(canvas);
255  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
256
257  SolidColorFill(canvas);
258  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
259
260  canvas.restore();
261  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
262
263  TransparentFill(canvas);
264  EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor));
265
266  SolidColorFill(canvas);
267  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
268  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
269
270  canvas.restore();
271  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
272  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
273
274  TransparentFill(canvas);
275  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
276  EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
277
278  SolidColorFill(canvas);
279  EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor));
280  EXPECT_NE(static_cast<SkColor>(SK_ColorTRANSPARENT), outputColor);
281}
282
283TEST(AnalysisCanvasTest, HasText) {
284  int width = 200;
285  int height = 100;
286
287  const char* text = "A";
288  size_t byteLength = 1;
289
290  SkPoint point = SkPoint::Make(SkIntToScalar(25), SkIntToScalar(25));
291  SkPath path;
292  path.moveTo(point);
293  path.lineTo(SkIntToScalar(75), SkIntToScalar(75));
294
295  SkPaint paint;
296  paint.setColor(SK_ColorGRAY);
297  paint.setTextSize(SkIntToScalar(10));
298
299  {
300    skia::AnalysisCanvas canvas(width, height);
301    // Test after initialization.
302    EXPECT_FALSE(canvas.HasText());
303    // Test drawing anything other than text.
304    canvas.drawRect(SkRect::MakeWH(width/2, height), paint);
305    EXPECT_FALSE(canvas.HasText());
306  }
307  {
308    // Test SkCanvas::drawText.
309    skia::AnalysisCanvas canvas(width, height);
310    canvas.drawText(text, byteLength, point.fX, point.fY, paint);
311    EXPECT_TRUE(canvas.HasText());
312  }
313  {
314    // Test SkCanvas::drawPosText.
315    skia::AnalysisCanvas canvas(width, height);
316    canvas.drawPosText(text, byteLength, &point, paint);
317    EXPECT_TRUE(canvas.HasText());
318  }
319  {
320    // Test SkCanvas::drawPosTextH.
321    skia::AnalysisCanvas canvas(width, height);
322    canvas.drawPosTextH(text, byteLength, &point.fX, point.fY, paint);
323    EXPECT_TRUE(canvas.HasText());
324  }
325  {
326    // Test SkCanvas::drawTextOnPathHV.
327    skia::AnalysisCanvas canvas(width, height);
328    canvas.drawTextOnPathHV(text, byteLength, path, point.fX, point.fY, paint);
329    EXPECT_TRUE(canvas.HasText());
330  }
331  {
332    // Test SkCanvas::drawTextOnPath.
333    skia::AnalysisCanvas canvas(width, height);
334    canvas.drawTextOnPath(text, byteLength, path, NULL, paint);
335    EXPECT_TRUE(canvas.HasText());
336  }
337  {
338    // Text under opaque rect.
339    skia::AnalysisCanvas canvas(width, height);
340    canvas.drawText(text, byteLength, point.fX, point.fY, paint);
341    EXPECT_TRUE(canvas.HasText());
342    canvas.drawRect(SkRect::MakeWH(width, height), paint);
343    EXPECT_FALSE(canvas.HasText());
344  }
345  {
346    // Text under translucent rect.
347    skia::AnalysisCanvas canvas(width, height);
348    canvas.drawText(text, byteLength, point.fX, point.fY, paint);
349    EXPECT_TRUE(canvas.HasText());
350    SkPaint translucentPaint;
351    translucentPaint.setColor(0x88FFFFFF);
352    canvas.drawRect(SkRect::MakeWH(width, height), translucentPaint);
353    EXPECT_TRUE(canvas.HasText());
354  }
355  {
356    // Text under rect in clear mode.
357    skia::AnalysisCanvas canvas(width, height);
358    canvas.drawText(text, byteLength, point.fX, point.fY, paint);
359    EXPECT_TRUE(canvas.HasText());
360    SkPaint clearModePaint;
361    clearModePaint.setXfermodeMode(SkXfermode::kClear_Mode);
362    canvas.drawRect(SkRect::MakeWH(width, height), clearModePaint);
363    EXPECT_FALSE(canvas.HasText());
364  }
365  {
366    // Clear.
367    skia::AnalysisCanvas canvas(width, height);
368    canvas.drawText(text, byteLength, point.fX, point.fY, paint);
369    EXPECT_TRUE(canvas.HasText());
370    canvas.clear(SK_ColorGRAY);
371    EXPECT_FALSE(canvas.HasText());
372  }
373  {
374    // Text inside clip region.
375    skia::AnalysisCanvas canvas(width, height);
376    canvas.clipRect(SkRect::MakeWH(100, 100));
377    canvas.drawText(text, byteLength, point.fX, point.fY, paint);
378    EXPECT_TRUE(canvas.HasText());
379  }
380  {
381    // Text outside clip region.
382    skia::AnalysisCanvas canvas(width, height);
383    canvas.clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
384    canvas.drawText(text, byteLength, point.fX, point.fY, paint);
385    // Analysis device does not do any clipping.
386    // So even when text is outside the clip region,
387    // it is marked as having the text.
388    // TODO(alokp): We may be able to do some trivial rejection.
389    EXPECT_TRUE(canvas.HasText());
390  }
391}
392
393}  // namespace skia
394