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 "testing/gtest/include/gtest/gtest.h"
8 #include "third_party/skia/include/core/SkShader.h"
12 void solidColorFill(skia::AnalysisCanvas
& canvas
) {
13 canvas
.clear(SkColorSetARGB(255, 255, 255, 255));
16 void transparentFill(skia::AnalysisCanvas
& canvas
) {
17 canvas
.clear(SkColorSetARGB(0, 0, 0, 0));
23 class TestPixelRef
: public SkPixelRef
{
25 // Pure virtual implementation.
26 virtual SkFlattenable::Factory
getFactory() OVERRIDE
{ return NULL
; }
27 virtual void* onLockPixels(SkColorTable
**) OVERRIDE
{ return NULL
; }
28 virtual void onUnlockPixels() OVERRIDE
{}
31 class TestLazyPixelRef
: public LazyPixelRef
{
33 // Pure virtual implementation.
34 virtual SkFlattenable::Factory
getFactory() OVERRIDE
{ return NULL
; }
35 virtual void* onLockPixels(SkColorTable
**) OVERRIDE
{ return NULL
; }
36 virtual void onUnlockPixels() OVERRIDE
{}
37 virtual bool PrepareToDecode(const PrepareParams
& params
) OVERRIDE
{
40 virtual void Decode() OVERRIDE
{}
43 class TestShader
: public SkShader
{
45 TestShader(SkBitmap
* bitmap
)
49 virtual SkShader::BitmapType
asABitmap(
52 TileMode xy
[2]) const OVERRIDE
{
55 return SkShader::kDefault_BitmapType
;
58 // Pure virtual implementation.
59 virtual void shadeSpan(int x
, int y
, SkPMColor
[], int count
) OVERRIDE
{}
60 virtual SkFlattenable::Factory
getFactory() OVERRIDE
{ return NULL
; }
67 TEST(AnalysisCanvasTest
, EmptyCanvas
) {
69 emptyBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
70 skia::AnalysisDevice
device(emptyBitmap
);
71 skia::AnalysisCanvas
canvas(&device
);
74 EXPECT_FALSE(canvas
.getColorIfSolid(&color
));
75 EXPECT_FALSE(canvas
.isTransparent());
76 EXPECT_TRUE(canvas
.isCheap());
79 TEST(AnalysisCanvasTest
, ClearCanvas
) {
81 emptyBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
82 skia::AnalysisDevice
device(emptyBitmap
);
83 skia::AnalysisCanvas
canvas(&device
);
86 SkColor color
= SkColorSetARGB(0, 12, 34, 56);
90 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
91 EXPECT_TRUE(canvas
.isTransparent());
92 EXPECT_TRUE(canvas
.isCheap());
95 color
= SkColorSetARGB(255, 65, 43, 21);
98 EXPECT_TRUE(canvas
.getColorIfSolid(&outputColor
));
99 EXPECT_FALSE(canvas
.isTransparent());
100 EXPECT_FALSE(canvas
.isCheap());
101 EXPECT_EQ(outputColor
, color
);
104 color
= SkColorSetARGB(128, 11, 22, 33);
107 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
108 EXPECT_FALSE(canvas
.isTransparent());
109 EXPECT_FALSE(canvas
.isCheap());
111 // Test helper methods
112 solidColorFill(canvas
);
113 EXPECT_TRUE(canvas
.getColorIfSolid(&outputColor
));
114 EXPECT_FALSE(canvas
.isTransparent());
116 transparentFill(canvas
);
117 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
118 EXPECT_TRUE(canvas
.isTransparent());
121 TEST(AnalysisCanvasTest
, ComplexActions
) {
122 SkBitmap emptyBitmap
;
123 emptyBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
124 skia::AnalysisDevice
device(emptyBitmap
);
125 skia::AnalysisCanvas
canvas(&device
);
128 SkColor color
= SkColorSetARGB(255, 11, 22, 33);
130 paint
.setColor(color
);
132 canvas
.drawPaint(paint
);
135 //TODO(vmpstr): This should return true. (crbug.com/180597)
136 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
137 EXPECT_FALSE(canvas
.isTransparent());
138 EXPECT_TRUE(canvas
.isCheap());
141 SkPoint points
[4] = {
143 SkPoint::Make(255, 0),
144 SkPoint::Make(255, 255),
145 SkPoint::Make(0, 255)
148 solidColorFill(canvas
);
149 canvas
.drawPoints(SkCanvas::kLines_PointMode
, 4, points
, paint
);
151 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
152 EXPECT_FALSE(canvas
.isTransparent());
153 EXPECT_FALSE(canvas
.isCheap());
156 solidColorFill(canvas
);
157 canvas
.drawOval(SkRect::MakeWH(255, 255), paint
);
159 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
160 EXPECT_FALSE(canvas
.isTransparent());
161 EXPECT_FALSE(canvas
.isCheap());
164 solidColorFill(canvas
);
165 SkBitmap secondBitmap
;
166 secondBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
167 canvas
.drawBitmap(secondBitmap
, 0, 0);
169 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
170 EXPECT_FALSE(canvas
.isTransparent());
171 EXPECT_FALSE(canvas
.isCheap());
174 TEST(AnalysisCanvasTest
, SimpleDrawRect
) {
175 SkBitmap emptyBitmap
;
176 emptyBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
177 skia::AnalysisDevice
device(emptyBitmap
);
178 skia::AnalysisCanvas
canvas(&device
);
180 SkColor color
= SkColorSetARGB(255, 11, 22, 33);
182 paint
.setColor(color
);
183 canvas
.clipRect(SkRect::MakeWH(255, 255));
184 canvas
.drawRect(SkRect::MakeWH(255, 255), paint
);
187 EXPECT_TRUE(canvas
.getColorIfSolid(&outputColor
));
188 EXPECT_FALSE(canvas
.isTransparent());
189 EXPECT_TRUE(canvas
.isCheap());
190 EXPECT_EQ(color
, outputColor
);
192 color
= SkColorSetARGB(255, 22, 33, 44);
193 paint
.setColor(color
);
194 canvas
.translate(-128, -128);
195 canvas
.drawRect(SkRect::MakeWH(382, 382), paint
);
197 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
198 EXPECT_FALSE(canvas
.isTransparent());
199 EXPECT_TRUE(canvas
.isCheap());
201 color
= SkColorSetARGB(255, 33, 44, 55);
202 paint
.setColor(color
);
203 canvas
.drawRect(SkRect::MakeWH(383, 383), paint
);
205 EXPECT_TRUE(canvas
.getColorIfSolid(&outputColor
));
206 EXPECT_FALSE(canvas
.isTransparent());
207 EXPECT_TRUE(canvas
.isCheap());
208 EXPECT_EQ(color
, outputColor
);
210 color
= SkColorSetARGB(0, 0, 0, 0);
211 paint
.setColor(color
);
212 canvas
.drawRect(SkRect::MakeWH(383, 383), paint
);
214 EXPECT_TRUE(canvas
.getColorIfSolid(&outputColor
));
215 EXPECT_FALSE(canvas
.isTransparent());
216 EXPECT_TRUE(canvas
.isCheap());
217 EXPECT_EQ(outputColor
, SkColorSetARGB(255, 33, 44, 55));
219 color
= SkColorSetARGB(128, 128, 128, 128);
220 paint
.setColor(color
);
221 canvas
.drawRect(SkRect::MakeWH(383, 383), paint
);
223 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
224 EXPECT_FALSE(canvas
.isTransparent());
225 EXPECT_TRUE(canvas
.isCheap());
227 paint
.setXfermodeMode(SkXfermode::kClear_Mode
);
228 canvas
.drawRect(SkRect::MakeWH(382, 382), paint
);
230 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
231 EXPECT_FALSE(canvas
.isTransparent());
232 EXPECT_TRUE(canvas
.isCheap());
234 canvas
.drawRect(SkRect::MakeWH(383, 383), paint
);
236 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
237 EXPECT_TRUE(canvas
.isTransparent());
238 EXPECT_TRUE(canvas
.isCheap());
240 canvas
.translate(128, 128);
241 color
= SkColorSetARGB(255, 11, 22, 33);
242 paint
.setColor(color
);
243 paint
.setXfermodeMode(SkXfermode::kSrcOver_Mode
);
244 canvas
.drawRect(SkRect::MakeWH(255, 255), paint
);
246 EXPECT_TRUE(canvas
.getColorIfSolid(&outputColor
));
247 EXPECT_FALSE(canvas
.isTransparent());
248 EXPECT_TRUE(canvas
.isCheap());
249 EXPECT_EQ(color
, outputColor
);
252 canvas
.drawRect(SkRect::MakeWH(255, 255), paint
);
254 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
255 EXPECT_FALSE(canvas
.isTransparent());
256 EXPECT_TRUE(canvas
.isCheap());
259 TEST(AnalysisCanvasTest
, ClipPath
) {
260 SkBitmap emptyBitmap
;
261 emptyBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
262 skia::AnalysisDevice
device(emptyBitmap
);
263 skia::AnalysisCanvas
canvas(&device
);
268 path
.lineTo(255, 255);
272 solidColorFill(canvas
);
273 canvas
.clipPath(path
);
274 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
277 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
279 canvas
.clipPath(path
);
280 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
283 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
285 solidColorFill(canvas
);
286 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
289 TEST(AnalysisCanvasTest
, SaveLayerRestore
) {
290 SkBitmap emptyBitmap
;
291 emptyBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
292 skia::AnalysisDevice
device(emptyBitmap
);
293 skia::AnalysisCanvas
canvas(&device
);
296 solidColorFill(canvas
);
297 EXPECT_TRUE(canvas
.getColorIfSolid(&outputColor
));
299 SkRect bounds
= SkRect::MakeWH(255, 255);
301 paint
.setColor(SkColorSetARGB(255, 255, 255, 255));
302 paint
.setXfermodeMode(SkXfermode::kSrcOver_Mode
);
304 // This should force non-transparency
305 canvas
.saveLayer(&bounds
, &paint
, SkCanvas::kMatrix_SaveFlag
);
306 EXPECT_TRUE(canvas
.getColorIfSolid(&outputColor
));
307 EXPECT_FALSE(canvas
.isTransparent());
309 transparentFill(canvas
);
310 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
311 EXPECT_FALSE(canvas
.isTransparent());
313 solidColorFill(canvas
);
314 EXPECT_TRUE(canvas
.getColorIfSolid(&outputColor
));
315 EXPECT_FALSE(canvas
.isTransparent());
317 paint
.setXfermodeMode(SkXfermode::kDst_Mode
);
319 // This should force non-solid color
320 canvas
.saveLayer(&bounds
, &paint
, SkCanvas::kMatrix_SaveFlag
);
321 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
322 EXPECT_FALSE(canvas
.isTransparent());
324 transparentFill(canvas
);
325 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
326 EXPECT_FALSE(canvas
.isTransparent());
328 solidColorFill(canvas
);
329 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
330 EXPECT_FALSE(canvas
.isTransparent());
333 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
334 EXPECT_FALSE(canvas
.isTransparent());
336 transparentFill(canvas
);
337 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
338 EXPECT_FALSE(canvas
.isTransparent());
340 solidColorFill(canvas
);
341 EXPECT_TRUE(canvas
.getColorIfSolid(&outputColor
));
342 EXPECT_FALSE(canvas
.isTransparent());
345 EXPECT_TRUE(canvas
.getColorIfSolid(&outputColor
));
346 EXPECT_FALSE(canvas
.isTransparent());
348 transparentFill(canvas
);
349 EXPECT_FALSE(canvas
.getColorIfSolid(&outputColor
));
350 EXPECT_TRUE(canvas
.isTransparent());
352 solidColorFill(canvas
);
353 EXPECT_TRUE(canvas
.getColorIfSolid(&outputColor
));
354 EXPECT_FALSE(canvas
.isTransparent());
357 TEST(AnalysisCanvasTest
, LazyPixelRefs
) {
358 // Set up two lazy and two non-lazy pixel refs and the corresponding bitmaps.
359 TestLazyPixelRef firstLazyPixelRef
;
360 firstLazyPixelRef
.setURI("lazy");
361 TestLazyPixelRef secondLazyPixelRef
;
362 secondLazyPixelRef
.setURI("lazy");
364 TestPixelRef firstNonLazyPixelRef
;
365 TestPixelRef secondNonLazyPixelRef
;
366 secondNonLazyPixelRef
.setURI("notsolazy");
368 SkBitmap firstLazyBitmap
;
369 firstLazyBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
370 firstLazyBitmap
.setPixelRef(&firstLazyPixelRef
);
371 SkBitmap secondLazyBitmap
;
372 secondLazyBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
373 secondLazyBitmap
.setPixelRef(&secondLazyPixelRef
);
375 SkBitmap firstNonLazyBitmap
;
376 firstNonLazyBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
377 SkBitmap secondNonLazyBitmap
;
378 secondNonLazyBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
379 secondNonLazyBitmap
.setPixelRef(&secondNonLazyPixelRef
);
381 // The testcase starts here.
382 SkBitmap emptyBitmap
;
383 emptyBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
384 skia::AnalysisDevice
device(emptyBitmap
);
385 skia::AnalysisCanvas
canvas(&device
);
387 // This should be the first ref.
388 canvas
.drawBitmap(firstLazyBitmap
, 0, 0);
389 // The following will be ignored (non-lazy).
390 canvas
.drawBitmap(firstNonLazyBitmap
, 0, 0);
391 canvas
.drawBitmap(firstNonLazyBitmap
, 0, 0);
392 canvas
.drawBitmap(secondNonLazyBitmap
, 0, 0);
393 canvas
.drawBitmap(secondNonLazyBitmap
, 0, 0);
394 // This one will be ignored (already exists).
395 canvas
.drawBitmap(firstLazyBitmap
, 0, 0);
396 // This should be the second ref.
397 canvas
.drawBitmap(secondLazyBitmap
, 0, 0);
399 std::list
<skia::LazyPixelRef
*> pixelRefs
;
400 canvas
.consumeLazyPixelRefs(&pixelRefs
);
402 // We expect to get only lazy pixel refs and only unique results.
403 EXPECT_EQ(pixelRefs
.size(), 2u);
404 if (!pixelRefs
.empty()) {
405 EXPECT_EQ(pixelRefs
.front(),
406 static_cast<LazyPixelRef
*>(&firstLazyPixelRef
));
407 EXPECT_EQ(pixelRefs
.back(),
408 static_cast<LazyPixelRef
*>(&secondLazyPixelRef
));
412 TEST(AnalysisCanvasTest
, PixelRefsFromPaint
) {
413 TestLazyPixelRef lazyPixelRef
;
414 lazyPixelRef
.setURI("lazy");
416 TestPixelRef nonLazyPixelRef
;
417 nonLazyPixelRef
.setURI("notsolazy");
420 lazyBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
421 lazyBitmap
.setPixelRef(&lazyPixelRef
);
423 SkBitmap nonLazyBitmap
;
424 nonLazyBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
425 nonLazyBitmap
.setPixelRef(&nonLazyPixelRef
);
427 TestShader
lazyShader(&lazyBitmap
);
428 TestShader
nonLazyShader(&nonLazyBitmap
);
431 lazyPaint
.setShader(&lazyShader
);
432 SkPaint nonLazyPaint
;
433 nonLazyPaint
.setShader(&nonLazyShader
);
435 SkBitmap emptyBitmap
;
436 emptyBitmap
.setConfig(SkBitmap::kNo_Config
, 255, 255);
437 skia::AnalysisDevice
device(emptyBitmap
);
438 skia::AnalysisCanvas
canvas(&device
);
440 canvas
.drawRect(SkRect::MakeWH(255, 255), lazyPaint
);
441 canvas
.drawRect(SkRect::MakeWH(255, 255), lazyPaint
);
442 canvas
.drawRect(SkRect::MakeWH(255, 255), lazyPaint
);
443 canvas
.drawRect(SkRect::MakeWH(255, 255), nonLazyPaint
);
444 canvas
.drawRect(SkRect::MakeWH(255, 255), nonLazyPaint
);
445 canvas
.drawRect(SkRect::MakeWH(255, 255), nonLazyPaint
);
447 std::list
<skia::LazyPixelRef
*> pixelRefs
;
448 canvas
.consumeLazyPixelRefs(&pixelRefs
);
450 // We expect to get only lazy pixel refs and only unique results.
451 EXPECT_EQ(pixelRefs
.size(), 1u);
452 if (!pixelRefs
.empty()) {
453 EXPECT_EQ(pixelRefs
.front(), static_cast<LazyPixelRef
*>(&lazyPixelRef
));
457 TEST(AnalysisCanvasTest
, HasText
) {
462 bitmap
.setConfig(SkBitmap::kNo_Config
, width
, height
);
464 const char* text
= "A";
465 size_t byteLength
= 1;
467 SkPoint point
= SkPoint::Make(SkIntToScalar(25), SkIntToScalar(25));
470 path
.lineTo(SkIntToScalar(75), SkIntToScalar(75));
473 paint
.setColor(SK_ColorGRAY
);
474 paint
.setTextSize(SkIntToScalar(10));
477 skia::AnalysisDevice
device(bitmap
);
478 skia::AnalysisCanvas
canvas(&device
);
479 // Test after initialization.
480 EXPECT_FALSE(canvas
.hasText());
481 // Test drawing anything other than text.
482 canvas
.drawRect(SkRect::MakeWH(width
/2, height
), paint
);
483 EXPECT_FALSE(canvas
.hasText());
486 // Test SkCanvas::drawText.
487 skia::AnalysisDevice
device(bitmap
);
488 skia::AnalysisCanvas
canvas(&device
);
489 canvas
.drawText(text
, byteLength
, point
.fX
, point
.fY
, paint
);
490 EXPECT_TRUE(canvas
.hasText());
493 // Test SkCanvas::drawPosText.
494 skia::AnalysisDevice
device(bitmap
);
495 skia::AnalysisCanvas
canvas(&device
);
496 canvas
.drawPosText(text
, byteLength
, &point
, paint
);
497 EXPECT_TRUE(canvas
.hasText());
500 // Test SkCanvas::drawPosTextH.
501 skia::AnalysisDevice
device(bitmap
);
502 skia::AnalysisCanvas
canvas(&device
);
503 canvas
.drawPosTextH(text
, byteLength
, &point
.fX
, point
.fY
, paint
);
504 EXPECT_TRUE(canvas
.hasText());
507 // Test SkCanvas::drawTextOnPathHV.
508 skia::AnalysisDevice
device(bitmap
);
509 skia::AnalysisCanvas
canvas(&device
);
510 canvas
.drawTextOnPathHV(text
, byteLength
, path
, point
.fX
, point
.fY
, paint
);
511 EXPECT_TRUE(canvas
.hasText());
514 // Test SkCanvas::drawTextOnPath.
515 skia::AnalysisDevice
device(bitmap
);
516 skia::AnalysisCanvas
canvas(&device
);
517 canvas
.drawTextOnPath(text
, byteLength
, path
, NULL
, paint
);
518 EXPECT_TRUE(canvas
.hasText());
521 // Text under opaque rect.
522 skia::AnalysisDevice
device(bitmap
);
523 skia::AnalysisCanvas
canvas(&device
);
524 canvas
.drawText(text
, byteLength
, point
.fX
, point
.fY
, paint
);
525 EXPECT_TRUE(canvas
.hasText());
526 canvas
.drawRect(SkRect::MakeWH(width
, height
), paint
);
527 EXPECT_FALSE(canvas
.hasText());
530 // Text under translucent rect.
531 skia::AnalysisDevice
device(bitmap
);
532 skia::AnalysisCanvas
canvas(&device
);
533 canvas
.drawText(text
, byteLength
, point
.fX
, point
.fY
, paint
);
534 EXPECT_TRUE(canvas
.hasText());
535 SkPaint translucentPaint
;
536 translucentPaint
.setColor(0x88FFFFFF);
537 canvas
.drawRect(SkRect::MakeWH(width
, height
), translucentPaint
);
538 EXPECT_TRUE(canvas
.hasText());
541 // Text under rect in clear mode.
542 skia::AnalysisDevice
device(bitmap
);
543 skia::AnalysisCanvas
canvas(&device
);
544 canvas
.drawText(text
, byteLength
, point
.fX
, point
.fY
, paint
);
545 EXPECT_TRUE(canvas
.hasText());
546 SkPaint clearModePaint
;
547 clearModePaint
.setXfermodeMode(SkXfermode::kClear_Mode
);
548 canvas
.drawRect(SkRect::MakeWH(width
, height
), clearModePaint
);
549 EXPECT_FALSE(canvas
.hasText());
553 skia::AnalysisDevice
device(bitmap
);
554 skia::AnalysisCanvas
canvas(&device
);
555 canvas
.drawText(text
, byteLength
, point
.fX
, point
.fY
, paint
);
556 EXPECT_TRUE(canvas
.hasText());
557 canvas
.clear(SK_ColorGRAY
);
558 EXPECT_FALSE(canvas
.hasText());
561 // Text inside clip region.
562 skia::AnalysisDevice
device(bitmap
);
563 skia::AnalysisCanvas
canvas(&device
);
564 canvas
.clipRect(SkRect::MakeWH(100, 100));
565 canvas
.drawText(text
, byteLength
, point
.fX
, point
.fY
, paint
);
566 EXPECT_TRUE(canvas
.hasText());
569 // Text outside clip region.
570 skia::AnalysisDevice
device(bitmap
);
571 skia::AnalysisCanvas
canvas(&device
);
572 canvas
.clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
573 canvas
.drawText(text
, byteLength
, point
.fX
, point
.fY
, paint
);
574 // Analysis device does not do any clipping.
575 // So even when text is outside the clip region,
576 // it is marked as having the text.
577 // TODO(alokp): We may be able to do some trivial rejection.
578 EXPECT_TRUE(canvas
.hasText());