blob: 1d6aecae1061e3842f58465395bedd6647308ae8 [file] [log] [blame]
reed@google.com209c4152011-10-26 15:03:48 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "Test.h"
9#include "SkAAClip.h"
10#include "SkPath.h"
reed@google.comd8676d22011-10-26 18:01:25 +000011#include "SkRandom.h"
12
13static const SkRegion::Op gRgnOps[] = {
14// SkRegion::kDifference_Op,
15 SkRegion::kIntersect_Op,
16 SkRegion::kUnion_Op,
17 SkRegion::kXOR_Op,
18// SkRegion::kReverseDifference_Op,
19 SkRegion::kReplace_Op
20};
21
22static const char* gRgnOpNames[] = {
23// "DIFF",
24 "SECT", "UNION", "XOR",
25// "RDIFF",
26 "REPLACE"
27};
reed@google.com209c4152011-10-26 15:03:48 +000028
reed@google.com12e15252011-10-26 15:19:36 +000029static void imoveTo(SkPath& path, int x, int y) {
30 path.moveTo(SkIntToScalar(x), SkIntToScalar(y));
31}
32
33static void icubicTo(SkPath& path, int x0, int y0, int x1, int y1, int x2, int y2) {
34 path.cubicTo(SkIntToScalar(x0), SkIntToScalar(y0),
35 SkIntToScalar(x1), SkIntToScalar(y1),
36 SkIntToScalar(x2), SkIntToScalar(y2));
37}
38
reed@google.comd8676d22011-10-26 18:01:25 +000039static void test_path_bounds(skiatest::Reporter* reporter) {
reed@google.com209c4152011-10-26 15:03:48 +000040 SkPath path;
41 SkAAClip clip;
42 const int height = 40;
43 const SkScalar sheight = SkIntToScalar(height);
44
45 path.addOval(SkRect::MakeWH(sheight, sheight));
46 REPORTER_ASSERT(reporter, sheight == path.getBounds().height());
47 clip.setPath(path, NULL, true);
48 REPORTER_ASSERT(reporter, height == clip.getBounds().height());
49
50 // this is the trimmed height of this cubic (with aa). The critical thing
51 // for this test is that it is less than height, which represents just
52 // the bounds of the path's control-points.
53 //
54 // This used to fail until we tracked the MinY in the BuilderBlitter.
55 //
56 const int teardrop_height = 12;
57 path.reset();
reed@google.com12e15252011-10-26 15:19:36 +000058 imoveTo(path, 0, 20);
59 icubicTo(path, 40, 40, 40, 0, 0, 20);
reed@google.com209c4152011-10-26 15:03:48 +000060 REPORTER_ASSERT(reporter, sheight == path.getBounds().height());
61 clip.setPath(path, NULL, true);
62 REPORTER_ASSERT(reporter, teardrop_height == clip.getBounds().height());
63}
64
reed@google.comd8676d22011-10-26 18:01:25 +000065static void test_empty(skiatest::Reporter* reporter) {
66 SkAAClip clip0, clip1;
67
68 REPORTER_ASSERT(reporter, clip0.isEmpty());
69 REPORTER_ASSERT(reporter, clip0.getBounds().isEmpty());
70 REPORTER_ASSERT(reporter, clip1 == clip0);
71
72 clip0.translate(10, 10); // should have no effect on empty
73 REPORTER_ASSERT(reporter, clip0.isEmpty());
74 REPORTER_ASSERT(reporter, clip0.getBounds().isEmpty());
75 REPORTER_ASSERT(reporter, clip1 == clip0);
76
77 SkIRect r = { 10, 10, 40, 50 };
78 clip0.setRect(r);
79 REPORTER_ASSERT(reporter, !clip0.isEmpty());
80 REPORTER_ASSERT(reporter, !clip0.getBounds().isEmpty());
81 REPORTER_ASSERT(reporter, clip0 != clip1);
82 REPORTER_ASSERT(reporter, clip0.getBounds() == r);
83
84 clip0.setEmpty();
85 REPORTER_ASSERT(reporter, clip0.isEmpty());
86 REPORTER_ASSERT(reporter, clip0.getBounds().isEmpty());
87 REPORTER_ASSERT(reporter, clip1 == clip0);
88
89 SkMask mask;
90 mask.fImage = NULL;
91 clip0.copyToMask(&mask);
92 REPORTER_ASSERT(reporter, NULL == mask.fImage);
93 REPORTER_ASSERT(reporter, mask.fBounds.isEmpty());
94}
95
96static void rand_irect(SkIRect* r, int N, SkRandom& rand) {
97 r->setXYWH(0, 0, rand.nextU() % N, rand.nextU() % N);
98 int dx = rand.nextU() % (2*N);
99 int dy = rand.nextU() % (2*N);
100 // use int dx,dy to make the subtract be signed
101 r->offset(N - dx, N - dy);
102}
103
104static void test_irect(skiatest::Reporter* reporter) {
105 SkRandom rand;
106
107 for (int i = 0; i < 100; i++) {
108 SkAAClip clip0, clip1;
109 SkRegion rgn0, rgn1;
110 SkIRect r0, r1;
111
112 rand_irect(&r0, 10, rand);
113 rand_irect(&r1, 10, rand);
114 clip0.setRect(r0);
115 clip1.setRect(r1);
116 rgn0.setRect(r0);
117 rgn1.setRect(r1);
118 for (size_t j = 0; j < SK_ARRAY_COUNT(gRgnOps); ++j) {
119 SkRegion::Op op = gRgnOps[j];
120 SkAAClip clip2;
121 SkRegion rgn2;
122 bool nonEmptyAA = clip2.op(clip0, clip1, op);
123 bool nonEmptyBW = rgn2.op(rgn0, rgn1, op);
124 if (nonEmptyAA != nonEmptyBW || clip2.getBounds() != rgn2.getBounds()) {
125 SkDebugf("[%d %d %d %d] %s [%d %d %d %d] = BW:[%d %d %d %d] AA:[%d %d %d %d]\n",
126 r0.fLeft, r0.fTop, r0.right(), r0.bottom(),
127 gRgnOpNames[j],
128 r1.fLeft, r1.fTop, r1.right(), r1.bottom(),
129 rgn2.getBounds().fLeft, rgn2.getBounds().fTop,
130 rgn2.getBounds().right(), rgn2.getBounds().bottom(),
131 clip2.getBounds().fLeft, clip2.getBounds().fTop,
132 clip2.getBounds().right(), clip2.getBounds().bottom());
133 }
134 REPORTER_ASSERT(reporter, nonEmptyAA == nonEmptyBW);
135 REPORTER_ASSERT(reporter, clip2.getBounds() == rgn2.getBounds());
136 }
137 }
138}
139
reed@google.com209c4152011-10-26 15:03:48 +0000140static void TestAAClip(skiatest::Reporter* reporter) {
reed@google.comd8676d22011-10-26 18:01:25 +0000141 test_empty(reporter);
142 test_path_bounds(reporter);
143 test_irect(reporter);
reed@google.com209c4152011-10-26 15:03:48 +0000144}
145
146#include "TestClassDef.h"
147DEFINE_TESTCLASS("AAClip", AAClipTestClass, TestAAClip)