1 
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 #include "SampleCode.h"
10 #include "SkAnimTimer.h"
11 #include "SkView.h"
12 #include "SkCanvas.h"
13 #include "SkGradientShader.h"
14 #include "SkGraphics.h"
15 #include "SkImageDecoder.h"
16 #include "SkPath.h"
17 #include "SkRegion.h"
18 #include "SkShader.h"
19 #include "SkUtils.h"
20 #include "SkXfermode.h"
21 #include "SkColorPriv.h"
22 #include "SkColorFilter.h"
23 #include "SkParsePath.h"
24 #include "SkTime.h"
25 #include "SkTypeface.h"
26 
27 #include "SkGeometry.h"
28 
29 #include <stdlib.h>
30 
31 // http://code.google.com/p/skia/issues/detail?id=32
test_cubic()32 static void test_cubic() {
33     SkPoint src[4] = {
34         { 556.25000f, 523.03003f },
35         { 556.23999f, 522.96002f },
36         { 556.21997f, 522.89001f },
37         { 556.21997f, 522.82001f }
38     };
39     SkPoint dst[11];
40     dst[10].set(42, -42);   // one past the end, that we don't clobber these
41     SkScalar tval[] = { 0.33333334f, 0.99999994f };
42 
43     SkChopCubicAt(src, dst, tval, 2);
44 
45 #if 0
46     for (int i = 0; i < 11; i++) {
47         SkDebugf("--- %d [%g %g]\n", i, dst[i].fX, dst[i].fY);
48     }
49 #endif
50 }
51 
test_cubic2()52 static void test_cubic2() {
53     const char* str = "M2242 -590088L-377758 9.94099e+07L-377758 9.94099e+07L2242 -590088Z";
54     SkPath path;
55     SkParsePath::FromSVGString(str, &path);
56 
57     {
58 #ifdef SK_BUILD_FOR_WIN
59         // windows doesn't have strtof
60         float x = (float)strtod("9.94099e+07", nullptr);
61 #else
62         float x = strtof("9.94099e+07", nullptr);
63 #endif
64         int ix = (int)x;
65         int fx = (int)(x * 65536);
66         int ffx = SkScalarToFixed(x);
67         SkDebugf("%g %x %x %x\n", x, ix, fx, ffx);
68 
69         SkRect r = path.getBounds();
70         SkIRect ir;
71         r.round(&ir);
72         SkDebugf("[%g %g %g %g] [%x %x %x %x]\n",
73                 SkScalarToDouble(r.fLeft), SkScalarToDouble(r.fTop),
74                 SkScalarToDouble(r.fRight), SkScalarToDouble(r.fBottom),
75                 ir.fLeft, ir.fTop, ir.fRight, ir.fBottom);
76     }
77 
78     SkBitmap bitmap;
79     bitmap.allocN32Pixels(300, 200);
80 
81     SkCanvas canvas(bitmap);
82     SkPaint paint;
83     paint.setAntiAlias(true);
84     canvas.drawPath(path, paint);
85 }
86 
87 class PathView : public SampleView {
88     SkScalar fPrevSecs;
89 public:
90     SkScalar fDStroke, fStroke, fMinStroke, fMaxStroke;
91     SkPath fPath[6];
92     bool fShowHairline;
93     bool fOnce;
94 
PathView()95     PathView() {
96         fPrevSecs = 0;
97         fOnce = false;
98     }
99 
init()100     void init() {
101         if (fOnce) {
102             return;
103         }
104         fOnce = true;
105 
106         test_cubic();
107         test_cubic2();
108 
109         fShowHairline = false;
110 
111         fDStroke = 1;
112         fStroke = 10;
113         fMinStroke = 10;
114         fMaxStroke = 180;
115 
116         const SkScalar V = 85;
117 
118         fPath[0].moveTo(40, 70);
119         fPath[0].lineTo(70, 70 + SK_ScalarHalf);
120         fPath[0].lineTo(110, 70);
121 
122         fPath[1].moveTo(40, 70);
123         fPath[1].lineTo(70, 70 - SK_ScalarHalf);
124         fPath[1].lineTo(110, 70);
125 
126         fPath[2].moveTo(V, V);
127         fPath[2].lineTo(50, V);
128         fPath[2].lineTo(50, 50);
129 
130         fPath[3].moveTo(50, 50);
131         fPath[3].lineTo(50, V);
132         fPath[3].lineTo(V, V);
133 
134         fPath[4].moveTo(50, 50);
135         fPath[4].lineTo(50, V);
136         fPath[4].lineTo(52, 50);
137 
138         fPath[5].moveTo(52, 50);
139         fPath[5].lineTo(50, V);
140         fPath[5].lineTo(50, 50);
141 
142         this->setBGColor(0xFFDDDDDD);
143     }
144 
145 protected:
146     // overrides from SkEventSink
onQuery(SkEvent * evt)147     bool onQuery(SkEvent* evt) override {
148         if (SampleCode::TitleQ(*evt)) {
149             SampleCode::TitleR(evt, "Paths");
150             return true;
151         }
152         return this->INHERITED::onQuery(evt);
153     }
154 
drawPath(SkCanvas * canvas,const SkPath & path,SkPaint::Join j)155     void drawPath(SkCanvas* canvas, const SkPath& path, SkPaint::Join j) {
156         SkPaint paint;
157 
158         paint.setAntiAlias(true);
159         paint.setStyle(SkPaint::kStroke_Style);
160         paint.setStrokeJoin(j);
161         paint.setStrokeWidth(fStroke);
162 
163         if (fShowHairline) {
164             SkPath  fill;
165 
166             paint.getFillPath(path, &fill);
167             paint.setStrokeWidth(0);
168             canvas->drawPath(fill, paint);
169         } else {
170             canvas->drawPath(path, paint);
171         }
172 
173         paint.setColor(SK_ColorRED);
174         paint.setStrokeWidth(0);
175         canvas->drawPath(path, paint);
176     }
177 
onDrawContent(SkCanvas * canvas)178     void onDrawContent(SkCanvas* canvas) override {
179         this->init();
180         canvas->translate(50, 50);
181 
182         static const SkPaint::Join gJoins[] = {
183             SkPaint::kBevel_Join,
184             SkPaint::kMiter_Join,
185             SkPaint::kRound_Join
186         };
187 
188         for (size_t i = 0; i < SK_ARRAY_COUNT(gJoins); i++) {
189             canvas->save();
190             for (size_t j = 0; j < SK_ARRAY_COUNT(fPath); j++) {
191                 this->drawPath(canvas, fPath[j], gJoins[i]);
192                 canvas->translate(200, 0);
193             }
194             canvas->restore();
195 
196             canvas->translate(0, 200);
197         }
198     }
199 
onAnimate(const SkAnimTimer & timer)200     bool onAnimate(const SkAnimTimer& timer) override {
201         SkScalar currSecs = timer.scaled(100);
202         SkScalar delta = currSecs - fPrevSecs;
203         fPrevSecs = currSecs;
204 
205         fStroke += fDStroke * delta;
206         if (fStroke > fMaxStroke || fStroke < fMinStroke) {
207             fDStroke = -fDStroke;
208         }
209         return true;
210     }
211 
onFindClickHandler(SkScalar x,SkScalar y,unsigned modi)212     SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
213         fShowHairline = !fShowHairline;
214         this->inval(nullptr);
215         return this->INHERITED::onFindClickHandler(x, y, modi);
216     }
217 
218 private:
219     typedef SampleView INHERITED;
220 };
221 DEF_SAMPLE( return new PathView; )
222 
223 //////////////////////////////////////////////////////////////////////////////
224 
225 #include "SkArcToPathEffect.h"
226 #include "SkCornerPathEffect.h"
227 #include "SkRandom.h"
228 
229 class ArcToView : public SampleView {
230     bool fDoFrame, fDoArcTo, fDoCorner, fDoConic;
231     SkPaint fPtsPaint, fArcToPaint, fSkeletonPaint, fCornerPaint;
232 public:
233     enum {
234         N = 4
235     };
236     SkPoint fPts[N];
237 
ArcToView()238     ArcToView()
239         : fDoFrame(false), fDoArcTo(false), fDoCorner(false), fDoConic(false)
240     {
241         SkRandom rand;
242         for (int i = 0; i < N; ++i) {
243             fPts[i].fX = 20 + rand.nextUScalar1() * 640;
244             fPts[i].fY = 20 + rand.nextUScalar1() * 480;
245         }
246 
247         const SkScalar rad = 50;
248 
249         fPtsPaint.setAntiAlias(true);
250         fPtsPaint.setStrokeWidth(15);
251         fPtsPaint.setStrokeCap(SkPaint::kRound_Cap);
252 
253         fArcToPaint.setAntiAlias(true);
254         fArcToPaint.setStyle(SkPaint::kStroke_Style);
255         fArcToPaint.setStrokeWidth(9);
256         fArcToPaint.setColor(0x800000FF);
257         fArcToPaint.setPathEffect(SkArcToPathEffect::Create(rad))->unref();
258 
259         fCornerPaint.setAntiAlias(true);
260         fCornerPaint.setStyle(SkPaint::kStroke_Style);
261         fCornerPaint.setStrokeWidth(13);
262         fCornerPaint.setColor(SK_ColorGREEN);
263         fCornerPaint.setPathEffect(SkCornerPathEffect::Create(rad*2))->unref();
264 
265         fSkeletonPaint.setAntiAlias(true);
266         fSkeletonPaint.setStyle(SkPaint::kStroke_Style);
267         fSkeletonPaint.setColor(SK_ColorRED);
268     }
269 
toggle(bool & value)270     void toggle(bool& value) {
271         value = !value;
272         this->inval(nullptr);
273     }
274 
275 protected:
276     // overrides from SkEventSink
onQuery(SkEvent * evt)277     bool onQuery(SkEvent* evt) override {
278         if (SampleCode::TitleQ(*evt)) {
279             SampleCode::TitleR(evt, "ArcTo");
280             return true;
281         }
282         SkUnichar uni;
283         if (SampleCode::CharQ(*evt, &uni)) {
284             switch (uni) {
285                 case '1': this->toggle(fDoFrame); return true;
286                 case '2': this->toggle(fDoArcTo); return true;
287                 case '3': this->toggle(fDoCorner); return true;
288                 case '4': this->toggle(fDoConic); return true;
289                 default: break;
290             }
291         }
292         return this->INHERITED::onQuery(evt);
293     }
294 
makePath(SkPath * path)295     void makePath(SkPath* path) {
296         path->moveTo(fPts[0]);
297         for (int i = 1; i < N; ++i) {
298             path->lineTo(fPts[i]);
299         }
300         if (!fDoFrame) {
301             path->close();
302         }
303     }
304 
onDrawContent(SkCanvas * canvas)305     void onDrawContent(SkCanvas* canvas) override {
306         canvas->drawPoints(SkCanvas::kPoints_PointMode, N, fPts, fPtsPaint);
307 
308         SkPath path;
309         this->makePath(&path);
310 
311         if (fDoCorner) {
312             canvas->drawPath(path, fCornerPaint);
313         }
314         if (fDoArcTo) {
315             canvas->drawPath(path, fArcToPaint);
316         }
317 
318         canvas->drawPath(path, fSkeletonPaint);
319     }
320 
onClick(Click * click)321     bool onClick(Click* click) override {
322         int32_t index;
323         if (click->fMeta.findS32("index", &index)) {
324             SkASSERT((unsigned)index < N);
325             fPts[index] = click->fCurr;
326             this->inval(nullptr);
327             return true;
328         }
329         return false;
330     }
331 
onFindClickHandler(SkScalar x,SkScalar y,unsigned modi)332     SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
333         const SkScalar tol = 4;
334         const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
335         for (int i = 0; i < N; ++i) {
336             if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
337                 Click* click = new Click(this);
338                 click->fMeta.setS32("index", i);
339                 return click;
340             }
341         }
342         return this->INHERITED::onFindClickHandler(x, y, modi);
343     }
344 
345 private:
346     typedef SampleView INHERITED;
347 };
348 DEF_SAMPLE( return new ArcToView; )
349 
350