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