blob: ef73614c6bbb9259301191f8932d9fe741000712 [file] [log] [blame]
tomhudson@google.comef279d32011-12-21 14:27:14 +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 "gm.h"
9#include "SkCanvas.h"
10#include "SkPath.h"
11
reed@google.com10f9f4a2012-09-18 14:04:54 +000012#if 0
13def unpremul(x,alpha):
14assert x <= alpha
15if alpha == 0:
16return 0
17else:
18return math.floor(x*MAXVAL/alpha)
19
20def premul(X,alpha):
21return math.ceil(X*alpha/MAXVAL)
22#endif
23
24static int premul(int r, int a) {
25 SkASSERT(a >= 0 && a <= 255);
26 SkASSERT(r >= 0 && r <= 255);
27 return (int)ceil(r * a / 255.0);
28}
29
30static int unpremul(int r, int a) {
31 SkASSERT(a >= 0 && a <= 255);
32 SkASSERT(r >= 0 && r <= a);
33 if (0 == a) {
34 return 0;
35 }
36 return (int)floor(r * 255.0 / a);
37}
38
39static void test_premul() {
40 for (int a = 0; a <= 255; ++a) {
41 for (int r = 0; r <= a; ++r) {
42 int tmpr = unpremul(r, a);
43 int newr = premul(tmpr, a);
44 SkASSERT(newr == r);
45 }
46 }
47}
48
reed@google.com5aff0ef2012-05-09 15:04:11 +000049static SkCanvas* MakeCanvas(const SkIRect& bounds) {
50 SkBitmap bm;
51 bm.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(), bounds.height());
52 bm.allocPixels();
53 bm.eraseColor(0);
54
55 SkCanvas* canvas = new SkCanvas(bm);
56 canvas->translate(-SkIntToScalar(bounds.fLeft), -SkIntToScalar(bounds.fTop));
57 return canvas;
58}
59
60static void GetBitmap(const SkCanvas* canvas, SkBitmap* bm) {
61 *bm = canvas->getDevice()->accessBitmap(false);
62}
63
64static void compare_canvas(const SkCanvas* a, const SkCanvas* b) {
65 SkBitmap bma, bmb;
66 GetBitmap(a, &bma);
67 GetBitmap(b, &bmb);
68
69 SkASSERT(bma.width() == bmb.width());
70 SkASSERT(bma.height() == bmb.height());
71
72 bma.lockPixels();
73 bmb.lockPixels();
74 for (int y = 0; y < bma.height(); ++y) {
75 const SkPMColor* rowa = bma.getAddr32(0, y);
76 const SkPMColor* rowb = bmb.getAddr32(0, y);
77 SkASSERT(!memcmp(rowa, rowb, bma.width() << 2));
rmistry@google.comd6176b02012-08-23 18:14:13 +000078
reed@google.com5aff0ef2012-05-09 15:04:11 +000079 for (int x = 1; x < bma.width() - 1; ++x) {
80 SkASSERT(0xFF000000 == rowa[x]);
81 SkASSERT(0xFF000000 == rowb[x]);
82 }
83 }
84}
85
86static void drawRectAsPath(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
87 SkPath path;
88 path.addRect(r);
89 canvas->drawPath(path, p);
90}
91
92static void test_maskFromPath(const SkPath& path) {
93 SkIRect bounds;
94 path.getBounds().roundOut(&bounds);
95
96 SkPaint paint;
97 paint.setAntiAlias(true);
98
99 SkAutoTUnref<SkCanvas> path_canvas(MakeCanvas(bounds));
100 path_canvas->drawPath(path, paint);
101
102 SkAutoTUnref<SkCanvas> rect_canvas(MakeCanvas(bounds));
103 drawRectAsPath(rect_canvas, path.getBounds(), paint);
104
105 compare_canvas(path_canvas, rect_canvas);
106}
107
108static void test_mask() {
109 for (int i = 1; i <= 20; ++i) {
110 const SkScalar dx = SK_Scalar1 / i;
111 const SkRect constr = SkRect::MakeWH(dx, SkIntToScalar(2));
112 for (int n = 2; n < 20; ++n) {
113 SkPath path;
114 path.setFillType(SkPath::kEvenOdd_FillType);
115 SkRect r = constr;
116 while (r.fRight < SkIntToScalar(4)) {
117 path.addRect(r);
118 r.offset(dx, 0);
119 }
120 test_maskFromPath(path);
121 }
122 }
123}
124
tomhudson@google.comef279d32011-12-21 14:27:14 +0000125namespace skiagm {
126
127/** Draw a 2px border around the target, then red behind the target;
128 set the clip to match the target, then draw >> the target in blue.
129*/
130
caryclark@google.com13130862012-06-06 12:10:45 +0000131static void draw (SkCanvas* canvas, SkRect& target, int x, int y) {
tomhudson@google.comef279d32011-12-21 14:27:14 +0000132 SkPaint borderPaint;
133 borderPaint.setColor(SkColorSetRGB(0x0, 0xDD, 0x0));
134 borderPaint.setAntiAlias(true);
135 SkPaint backgroundPaint;
136 backgroundPaint.setColor(SkColorSetRGB(0xDD, 0x0, 0x0));
137 backgroundPaint.setAntiAlias(true);
138 SkPaint foregroundPaint;
139 foregroundPaint.setColor(SkColorSetRGB(0x0, 0x0, 0xDD));
140 foregroundPaint.setAntiAlias(true);
141
142 canvas->save();
tomhudson@google.comabfa8d12011-12-28 19:40:48 +0000143 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
144 target.inset(SkIntToScalar(-2), SkIntToScalar(-2));
tomhudson@google.comef279d32011-12-21 14:27:14 +0000145 canvas->drawRect(target, borderPaint);
tomhudson@google.comabfa8d12011-12-28 19:40:48 +0000146 target.inset(SkIntToScalar(2), SkIntToScalar(2));
tomhudson@google.comef279d32011-12-21 14:27:14 +0000147 canvas->drawRect(target, backgroundPaint);
148 canvas->clipRect(target, SkRegion::kIntersect_Op, true);
tomhudson@google.comabfa8d12011-12-28 19:40:48 +0000149 target.inset(SkIntToScalar(-4), SkIntToScalar(-4));
tomhudson@google.comef279d32011-12-21 14:27:14 +0000150 canvas->drawRect(target, foregroundPaint);
151 canvas->restore();
152}
153
caryclark@google.com13130862012-06-06 12:10:45 +0000154static void draw_square (SkCanvas* canvas, int x, int y) {
tomhudson@google.comef279d32011-12-21 14:27:14 +0000155 SkRect target (SkRect::MakeWH(10 * SK_Scalar1, 10 * SK_Scalar1));
156 draw(canvas, target, x, y);
157}
158
caryclark@google.com13130862012-06-06 12:10:45 +0000159static void draw_column (SkCanvas* canvas, int x, int y) {
tomhudson@google.comef279d32011-12-21 14:27:14 +0000160 SkRect target (SkRect::MakeWH(1 * SK_Scalar1, 10 * SK_Scalar1));
161 draw(canvas, target, x, y);
162}
163
caryclark@google.com13130862012-06-06 12:10:45 +0000164static void draw_bar (SkCanvas* canvas, int x, int y) {
tomhudson@google.comef279d32011-12-21 14:27:14 +0000165 SkRect target (SkRect::MakeWH(10 * SK_Scalar1, 1 * SK_Scalar1));
166 draw(canvas, target, x, y);
167}
168
caryclark@google.com13130862012-06-06 12:10:45 +0000169static void draw_rect_tests (SkCanvas* canvas) {
tomhudson@google.comef279d32011-12-21 14:27:14 +0000170 draw_square(canvas, 10, 10);
171 draw_column(canvas, 30, 10);
172 draw_bar(canvas, 10, 30);
173}
174
175/**
176 Test a set of clipping problems discovered while writing blitAntiRect,
177 and test all the code paths through the clipping blitters.
178 Each region should show as a blue center surrounded by a 2px green
179 border, with no red.
180*/
181
182class AAClipGM : public GM {
183public:
184 AAClipGM() {
reed@google.com10f9f4a2012-09-18 14:04:54 +0000185 test_premul();
tomhudson@google.comef279d32011-12-21 14:27:14 +0000186 }
187
188protected:
189 virtual SkString onShortName() {
190 return SkString("aaclip");
191 }
192
193 virtual SkISize onISize() {
194 return make_isize(640, 480);
195 }
196
197 virtual void onDraw(SkCanvas* canvas) {
caryclark@google.com13130862012-06-06 12:10:45 +0000198 if (false) { // avoid bit rot, suppress warning
199 test_mask();
200 }
reed@google.com5aff0ef2012-05-09 15:04:11 +0000201
tomhudson@google.comef279d32011-12-21 14:27:14 +0000202 // Initial pixel-boundary-aligned draw
203 draw_rect_tests(canvas);
204
205 // Repeat 4x with .2, .4, .6, .8 px offsets
206 canvas->translate(SK_Scalar1 / 5, SK_Scalar1 / 5);
tomhudson@google.comabfa8d12011-12-28 19:40:48 +0000207 canvas->translate(SkIntToScalar(50), 0);
tomhudson@google.comef279d32011-12-21 14:27:14 +0000208 draw_rect_tests(canvas);
209
210 canvas->translate(SK_Scalar1 / 5, SK_Scalar1 / 5);
tomhudson@google.comabfa8d12011-12-28 19:40:48 +0000211 canvas->translate(SkIntToScalar(50), 0);
tomhudson@google.comef279d32011-12-21 14:27:14 +0000212 draw_rect_tests(canvas);
213
214 canvas->translate(SK_Scalar1 / 5, SK_Scalar1 / 5);
tomhudson@google.comabfa8d12011-12-28 19:40:48 +0000215 canvas->translate(SkIntToScalar(50), 0);
tomhudson@google.comef279d32011-12-21 14:27:14 +0000216 draw_rect_tests(canvas);
217
218 canvas->translate(SK_Scalar1 / 5, SK_Scalar1 / 5);
tomhudson@google.comabfa8d12011-12-28 19:40:48 +0000219 canvas->translate(SkIntToScalar(50), 0);
tomhudson@google.comef279d32011-12-21 14:27:14 +0000220 draw_rect_tests(canvas);
221 }
222
borenet@google.comb4e70432012-07-20 18:45:10 +0000223 virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; }
224
tomhudson@google.comef279d32011-12-21 14:27:14 +0000225private:
226 typedef GM INHERITED;
227};
228
229//////////////////////////////////////////////////////////////////////////////
230
231static GM* MyFactory(void*) { return new AAClipGM; }
232static GMRegistry reg(MyFactory);
233
234}