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    virtual uint32_t onGetFlags() const SK_OVERRIDE {
183        return kSkipTiled_Flag;
184    }
185
186    virtual SkString onShortName() SK_OVERRIDE {
187        return SkString("poly2poly");
188    }
189
190    virtual SkISize onISize() SK_OVERRIDE {
191        return SkISize::Make(835, 840);
192    }
193
194    static void doDraw(SkCanvas* canvas, SkPaint* paint, const int isrc[],
195                       const int idst[], int count) {
196        SkMatrix matrix;
197        SkPoint src[4], dst[4];
198
199        for (int i = 0; i < count; i++) {
200            src[i].set(SkIntToScalar(isrc[2*i+0]), SkIntToScalar(isrc[2*i+1]));
201            dst[i].set(SkIntToScalar(idst[2*i+0]), SkIntToScalar(idst[2*i+1]));
202        }
203
204        canvas->save();
205        matrix.setPolyToPoly(src, dst, count);
206        canvas->concat(matrix);
207
208        paint->setColor(SK_ColorGRAY);
209        paint->setStyle(SkPaint::kStroke_Style);
210        const SkScalar D = SkIntToScalar(64);
211        canvas->drawRectCoords(0, 0, D, D, *paint);
212        canvas->drawLine(0, 0, D, D, *paint);
213        canvas->drawLine(0, D, D, 0, *paint);
214
215        SkPaint::FontMetrics fm;
216        paint->getFontMetrics(&fm);
217        paint->setColor(SK_ColorRED);
218        paint->setStyle(SkPaint::kFill_Style);
219        SkScalar x = D/2;
220        SkScalar y = D/2 - (fm.fAscent + fm.fDescent)/2;
221        SkString str;
222        str.appendS32(count);
223        canvas->drawText(str.c_str(), str.size(), x, y, *paint);
224
225        canvas->restore();
226    }
227
228    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
229        if (false) { test_stroke(canvas); return; }
230
231        SkPaint paint;
232        paint.setAntiAlias(true);
233        sk_tool_utils::set_portable_typeface(&paint);
234        paint.setStrokeWidth(SkIntToScalar(4));
235        paint.setTextSize(SkIntToScalar(40));
236        paint.setTextAlign(SkPaint::kCenter_Align);
237
238        canvas->save();
239        canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
240        // translate (1 point)
241        const int src1[] = { 0, 0 };
242        const int dst1[] = { 5, 5 };
243        doDraw(canvas, &paint, src1, dst1, 1);
244        canvas->restore();
245
246        canvas->save();
247        canvas->translate(SkIntToScalar(160), SkIntToScalar(10));
248        // rotate/uniform-scale (2 points)
249        const int src2[] = { 32, 32, 64, 32 };
250        const int dst2[] = { 32, 32, 64, 48 };
251        doDraw(canvas, &paint, src2, dst2, 2);
252        canvas->restore();
253
254        canvas->save();
255        canvas->translate(SkIntToScalar(10), SkIntToScalar(110));
256        // rotate/skew (3 points)
257        const int src3[] = { 0, 0, 64, 0, 0, 64 };
258        const int dst3[] = { 0, 0, 96, 0, 24, 64 };
259        doDraw(canvas, &paint, src3, dst3, 3);
260        canvas->restore();
261
262        canvas->save();
263        canvas->translate(SkIntToScalar(160), SkIntToScalar(110));
264        // perspective (4 points)
265        const int src4[] = { 0, 0, 64, 0, 64, 64, 0, 64 };
266        const int dst4[] = { 0, 0, 96, 0, 64, 96, 0, 64 };
267        doDraw(canvas, &paint, src4, dst4, 4);
268        canvas->restore();
269    }
270
271private:
272    typedef skiagm::GM INHERITED;
273};
274
275//////////////////////////////////////////////////////////////////////////////
276
277DEF_GM( return new Poly2PolyGM; )
278