1/*
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
10class SkJSCanvas {
11public:
12    SkJSCanvas(SkCanvas* target);
13    ~SkJSCanvas();
14
15    void save();
16    void restore();
17
18    double lineWidth;
19    void setLineWidth(double);
20
21    void beginPath();
22    void moveTo(double x, double y);
23    void lineTo(double x, double y);
24    void closePath();
25
26    void fill();
27    void stroke();
28
29    void fillText(const char text[], double x, double y);
30
31private:
32    SkCanvas*   fTarget;
33    SkPaint     fFillPaint;
34    SkPaint     fStrokePaint;
35    SkPath      fPath;
36};
37
38SkJSCanvas::SkJSCanvas(SkCanvas* target) : fTarget(target) {
39    fFillPaint.setAntiAlias(true);
40    sk_tool_utils::set_portable_typeface(&fFillPaint);
41    fStrokePaint.setAntiAlias(true);
42    fStrokePaint.setStyle(SkPaint::kStroke_Style);
43    fStrokePaint.setStrokeWidth(SK_Scalar1);
44}
45
46SkJSCanvas::~SkJSCanvas() {}
47
48void SkJSCanvas::save() { fTarget->save(); }
49void SkJSCanvas::restore() { fTarget->restore(); }
50
51void SkJSCanvas::beginPath() { fPath.reset(); }
52void SkJSCanvas::moveTo(double x, double y) {
53    fPath.moveTo(SkDoubleToScalar(x), SkDoubleToScalar(y));
54}
55
56void SkJSCanvas::lineTo(double x, double y) {
57    fPath.lineTo(SkDoubleToScalar(x), SkDoubleToScalar(y));
58}
59
60void SkJSCanvas::closePath() { fPath.close(); }
61
62void SkJSCanvas::fill() {
63    fTarget->drawPath(fPath, fFillPaint);
64}
65
66void SkJSCanvas::stroke() {
67    fStrokePaint.setStrokeWidth(SkDoubleToScalar(lineWidth));
68    fTarget->drawPath(fPath, fStrokePaint);
69}
70
71void SkJSCanvas::fillText(const char text[], double x, double y) {
72    fTarget->drawText(text, strlen(text),
73                      SkDoubleToScalar(x), SkDoubleToScalar(y), fFillPaint);
74}
75
76///////////////////////////////////////////////////////////////////////////////
77
78static void dump(const SkPath& path) {
79    const SkRect& r = path.getBounds();
80    SkDebugf("isEmpty %d, bounds [%g %g %g %g]\n", path.isEmpty(),
81             r.fLeft, r.fTop, r.fRight, r.fBottom);
82}
83
84static void test_stroke(SkCanvas* canvas) {
85    if (true) {
86        SkPath path;
87        dump(path);
88        path.reset(); path.moveTo(0, 0);
89        dump(path);
90        path.reset(); path.moveTo(100, 100);
91        dump(path);
92        path.reset(); path.moveTo(0, 0); path.moveTo(100, 100);
93        dump(path);
94        path.reset(); path.moveTo(0, 0); path.lineTo(100, 100);
95        dump(path);
96        path.reset(); path.moveTo(0, 0); path.lineTo(100, 100); path.moveTo(200, 200);
97        dump(path);
98    }
99
100#if 0
101    // TEST 1 - The rectangle as it's expected to look
102    var canvas = document.createElement('canvas');
103    document.body.appendChild(canvas);
104    var ctx = canvas.getContext("2d");
105#else
106    SkJSCanvas ctx(canvas);
107#endif
108
109    ctx.save();
110    ctx.lineWidth = 2;
111    ctx.beginPath();
112    ctx.moveTo(10, 100);
113    ctx.lineTo(150, 100);
114    ctx.lineTo(150, 15);
115    ctx.lineTo(10, 15);
116    ctx.closePath();
117
118    // no extra moveTo here
119    // ctx.moveTo(175, 125);
120
121    ctx.stroke();
122    ctx.restore();
123
124    ctx.fillText("As Expected", 10, 10);
125
126#if 0
127    // TEST 2 - Includes an extra moveTo call before stroke; the rectangle appears larger
128    canvas = document.createElement('canvas');
129    document.body.appendChild(canvas);
130    ctx = canvas.getContext("2d");
131#else
132    canvas->translate(200, 0);
133#endif
134
135    ctx.save();
136    ctx.lineWidth = 2;
137    ctx.beginPath();
138    ctx.moveTo(10, 100);
139    ctx.lineTo(150, 100);
140    ctx.lineTo(150, 15);
141    ctx.lineTo(10, 15);
142    ctx.closePath();
143
144    ctx.moveTo(175, 125);
145
146    ctx.stroke();
147    ctx.restore();
148
149    ctx.fillText("Larger Rectangle", 10, 10);
150
151#if 0
152    // TEST 3 - Identical to test 2 except the line width is 1
153    canvas = document.createElement('canvas');
154    document.body.appendChild(canvas);
155    ctx = canvas.getContext("2d");
156#else
157    canvas->translate(200, 0);
158#endif
159
160    ctx.save();
161    ctx.lineWidth = 1;
162    ctx.beginPath();
163    ctx.moveTo(10, 100);
164    ctx.lineTo(150, 100);
165    ctx.lineTo(150, 15);
166    ctx.lineTo(10, 15);
167    ctx.closePath();
168
169    ctx.moveTo(175, 125);
170
171    ctx.stroke();
172    ctx.restore();
173
174    ctx.fillText("As Expected - line width 1", 10, 10);
175}
176
177class Poly2PolyGM : public skiagm::GM {
178public:
179    Poly2PolyGM() {}
180
181protected:
182
183    SkString onShortName() override {
184        return SkString("poly2poly");
185    }
186
187    SkISize onISize() override {
188        return SkISize::Make(835, 840);
189    }
190
191    static void doDraw(SkCanvas* canvas, SkPaint* paint, const int isrc[],
192                       const int idst[], int count) {
193        SkMatrix matrix;
194        SkPoint src[4], dst[4];
195
196        for (int i = 0; i < count; i++) {
197            src[i].set(SkIntToScalar(isrc[2*i+0]), SkIntToScalar(isrc[2*i+1]));
198            dst[i].set(SkIntToScalar(idst[2*i+0]), SkIntToScalar(idst[2*i+1]));
199        }
200
201        canvas->save();
202        matrix.setPolyToPoly(src, dst, count);
203        canvas->concat(matrix);
204
205        paint->setColor(SK_ColorGRAY);
206        paint->setStyle(SkPaint::kStroke_Style);
207        const SkScalar D = SkIntToScalar(64);
208        canvas->drawRectCoords(0, 0, D, D, *paint);
209        canvas->drawLine(0, 0, D, D, *paint);
210        canvas->drawLine(0, D, D, 0, *paint);
211
212        SkPaint::FontMetrics fm;
213        paint->getFontMetrics(&fm);
214        paint->setColor(SK_ColorRED);
215        paint->setStyle(SkPaint::kFill_Style);
216        SkScalar x = D/2;
217        SkScalar y = D/2 - (fm.fAscent + fm.fDescent)/2;
218        SkString str;
219        str.appendS32(count);
220        canvas->drawText(str.c_str(), str.size(), x, y, *paint);
221
222        canvas->restore();
223    }
224
225    void onDraw(SkCanvas* canvas) override {
226        if (false) { test_stroke(canvas); return; }
227
228        SkPaint paint;
229        paint.setAntiAlias(true);
230        sk_tool_utils::set_portable_typeface(&paint);
231        paint.setStrokeWidth(SkIntToScalar(4));
232        paint.setTextSize(SkIntToScalar(40));
233        paint.setTextAlign(SkPaint::kCenter_Align);
234
235        canvas->save();
236        canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
237        // translate (1 point)
238        const int src1[] = { 0, 0 };
239        const int dst1[] = { 5, 5 };
240        doDraw(canvas, &paint, src1, dst1, 1);
241        canvas->restore();
242
243        canvas->save();
244        canvas->translate(SkIntToScalar(160), SkIntToScalar(10));
245        // rotate/uniform-scale (2 points)
246        const int src2[] = { 32, 32, 64, 32 };
247        const int dst2[] = { 32, 32, 64, 48 };
248        doDraw(canvas, &paint, src2, dst2, 2);
249        canvas->restore();
250
251        canvas->save();
252        canvas->translate(SkIntToScalar(10), SkIntToScalar(110));
253        // rotate/skew (3 points)
254        const int src3[] = { 0, 0, 64, 0, 0, 64 };
255        const int dst3[] = { 0, 0, 96, 0, 24, 64 };
256        doDraw(canvas, &paint, src3, dst3, 3);
257        canvas->restore();
258
259        canvas->save();
260        canvas->translate(SkIntToScalar(160), SkIntToScalar(110));
261        // perspective (4 points)
262        const int src4[] = { 0, 0, 64, 0, 64, 64, 0, 64 };
263        const int dst4[] = { 0, 0, 96, 0, 64, 96, 0, 64 };
264        doDraw(canvas, &paint, src4, dst4, 4);
265        canvas->restore();
266    }
267
268private:
269    typedef skiagm::GM INHERITED;
270};
271
272//////////////////////////////////////////////////////////////////////////////
273
274DEF_GM( return new Poly2PolyGM; )
275