blob: 4493d397d5f8032bcf7dae001013cf44b1e3682c [file] [log] [blame]
reed@android.comf2b98d62010-12-20 18:26:13 +00001
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002/*
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
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SampleCode.h"
reed339cdbf2015-02-05 22:02:37 -080010#include "SkAnimTimer.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#include "SkView.h"
12#include "SkCanvas.h"
13#include "SkGradientShader.h"
14#include "SkGraphics.h"
15#include "SkImageDecoder.h"
16#include "SkPath.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#include "SkRegion.h"
18#include "SkShader.h"
19#include "SkUtils.h"
20#include "SkXfermode.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000021#include "SkColorPriv.h"
22#include "SkColorFilter.h"
reed@android.comd0d0e652009-10-13 13:31:27 +000023#include "SkParsePath.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000024#include "SkTime.h"
25#include "SkTypeface.h"
26
reed@android.coma9640282009-08-28 20:06:54 +000027#include "SkGeometry.h"
28
29// http://code.google.com/p/skia/issues/detail?id=32
30static void test_cubic() {
31 SkPoint src[4] = {
reed@google.com261b8e22011-04-14 17:53:24 +000032 { 556.25000f, 523.03003f },
33 { 556.23999f, 522.96002f },
34 { 556.21997f, 522.89001f },
35 { 556.21997f, 522.82001f }
reed@android.coma9640282009-08-28 20:06:54 +000036 };
37 SkPoint dst[11];
38 dst[10].set(42, -42); // one past the end, that we don't clobber these
39 SkScalar tval[] = { 0.33333334f, 0.99999994f };
40
41 SkChopCubicAt(src, dst, tval, 2);
42
43#if 0
44 for (int i = 0; i < 11; i++) {
45 SkDebugf("--- %d [%g %g]\n", i, dst[i].fX, dst[i].fY);
46 }
47#endif
48}
49
reed@android.comd0d0e652009-10-13 13:31:27 +000050static void test_cubic2() {
51 const char* str = "M2242 -590088L-377758 9.94099e+07L-377758 9.94099e+07L2242 -590088Z";
52 SkPath path;
53 SkParsePath::FromSVGString(str, &path);
rmistry@google.comae933ce2012-08-23 18:19:56 +000054
reed@android.comd0d0e652009-10-13 13:31:27 +000055 {
reed@android.comf2b98d62010-12-20 18:26:13 +000056#ifdef SK_BUILD_FOR_WIN
57 // windows doesn't have strtof
58 float x = (float)strtod("9.94099e+07", NULL);
59#else
reed@android.comd0d0e652009-10-13 13:31:27 +000060 float x = strtof("9.94099e+07", NULL);
reed@android.comf2b98d62010-12-20 18:26:13 +000061#endif
reed@android.comd0d0e652009-10-13 13:31:27 +000062 int ix = (int)x;
63 int fx = (int)(x * 65536);
64 int ffx = SkScalarToFixed(x);
bungeman@google.comfab44db2013-10-11 18:50:45 +000065 SkDebugf("%g %x %x %x\n", x, ix, fx, ffx);
rmistry@google.comae933ce2012-08-23 18:19:56 +000066
reed@android.comd0d0e652009-10-13 13:31:27 +000067 SkRect r = path.getBounds();
68 SkIRect ir;
69 r.round(&ir);
bungeman@google.comfab44db2013-10-11 18:50:45 +000070 SkDebugf("[%g %g %g %g] [%x %x %x %x]\n",
71 SkScalarToDouble(r.fLeft), SkScalarToDouble(r.fTop),
72 SkScalarToDouble(r.fRight), SkScalarToDouble(r.fBottom),
73 ir.fLeft, ir.fTop, ir.fRight, ir.fBottom);
reed@android.comd0d0e652009-10-13 13:31:27 +000074 }
rmistry@google.comae933ce2012-08-23 18:19:56 +000075
reed@android.comd0d0e652009-10-13 13:31:27 +000076 SkBitmap bitmap;
commit-bot@chromium.orga8c18312014-02-17 02:55:57 +000077 bitmap.allocN32Pixels(300, 200);
reed@android.comd0d0e652009-10-13 13:31:27 +000078
79 SkCanvas canvas(bitmap);
80 SkPaint paint;
81 paint.setAntiAlias(true);
82 canvas.drawPath(path, paint);
83}
84
reed@google.com0faac1e2011-05-11 05:58:58 +000085class PathView : public SampleView {
reed339cdbf2015-02-05 22:02:37 -080086 SkScalar fPrevSecs;
reed@android.com8a1c16f2008-12-17 15:59:43 +000087public:
reed339cdbf2015-02-05 22:02:37 -080088 SkScalar fDStroke, fStroke, fMinStroke, fMaxStroke;
reed@android.com8a1c16f2008-12-17 15:59:43 +000089 SkPath fPath[6];
90 bool fShowHairline;
reed@google.comc9fa63c2012-03-12 21:14:09 +000091 bool fOnce;
rmistry@google.comae933ce2012-08-23 18:19:56 +000092
93 PathView() {
reed339cdbf2015-02-05 22:02:37 -080094 fPrevSecs = 0;
reed@google.comc9fa63c2012-03-12 21:14:09 +000095 fOnce = false;
96 }
rmistry@google.comae933ce2012-08-23 18:19:56 +000097
reed@google.comc9fa63c2012-03-12 21:14:09 +000098 void init() {
99 if (fOnce) {
100 return;
101 }
102 fOnce = true;
103
reed@android.coma9640282009-08-28 20:06:54 +0000104 test_cubic();
reed@android.comd0d0e652009-10-13 13:31:27 +0000105 test_cubic2();
reed@android.coma9640282009-08-28 20:06:54 +0000106
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107 fShowHairline = false;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000108
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109 fDStroke = 1;
110 fStroke = 10;
111 fMinStroke = 10;
112 fMaxStroke = 180;
113
reed339cdbf2015-02-05 22:02:37 -0800114 const SkScalar V = 85;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000115
reed339cdbf2015-02-05 22:02:37 -0800116 fPath[0].moveTo(40, 70);
117 fPath[0].lineTo(70, 70 + SK_ScalarHalf);
118 fPath[0].lineTo(110, 70);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000119
reed339cdbf2015-02-05 22:02:37 -0800120 fPath[1].moveTo(40, 70);
121 fPath[1].lineTo(70, 70 - SK_ScalarHalf);
122 fPath[1].lineTo(110, 70);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000123
reed339cdbf2015-02-05 22:02:37 -0800124 fPath[2].moveTo(V, V);
125 fPath[2].lineTo(50, V);
126 fPath[2].lineTo(50, 50);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000127
reed339cdbf2015-02-05 22:02:37 -0800128 fPath[3].moveTo(50, 50);
129 fPath[3].lineTo(50, V);
130 fPath[3].lineTo(V, V);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000131
reed339cdbf2015-02-05 22:02:37 -0800132 fPath[4].moveTo(50, 50);
133 fPath[4].lineTo(50, V);
134 fPath[4].lineTo(52, 50);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000135
reed339cdbf2015-02-05 22:02:37 -0800136 fPath[5].moveTo(52, 50);
137 fPath[5].lineTo(50, V);
138 fPath[5].lineTo(50, 50);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000139
reed@google.com0faac1e2011-05-11 05:58:58 +0000140 this->setBGColor(0xFFDDDDDD);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000142
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143protected:
144 // overrides from SkEventSink
reed@google.com0faac1e2011-05-11 05:58:58 +0000145 virtual bool onQuery(SkEvent* evt) {
146 if (SampleCode::TitleQ(*evt)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147 SampleCode::TitleR(evt, "Paths");
148 return true;
149 }
150 return this->INHERITED::onQuery(evt);
151 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000152
reed@google.com0faac1e2011-05-11 05:58:58 +0000153 void drawPath(SkCanvas* canvas, const SkPath& path, SkPaint::Join j) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 SkPaint paint;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000155
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156 paint.setAntiAlias(true);
157 paint.setStyle(SkPaint::kStroke_Style);
158 paint.setStrokeJoin(j);
reed339cdbf2015-02-05 22:02:37 -0800159 paint.setStrokeWidth(fStroke);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160
reed@google.com0faac1e2011-05-11 05:58:58 +0000161 if (fShowHairline) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162 SkPath fill;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000163
164 paint.getFillPath(path, &fill);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 paint.setStrokeWidth(0);
166 canvas->drawPath(fill, paint);
reed@google.com0faac1e2011-05-11 05:58:58 +0000167 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168 canvas->drawPath(path, paint);
reed@google.com0faac1e2011-05-11 05:58:58 +0000169 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000170
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171 paint.setColor(SK_ColorRED);
172 paint.setStrokeWidth(0);
173 canvas->drawPath(path, paint);
174 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000175
reed@google.comc9fa63c2012-03-12 21:14:09 +0000176 virtual void onDrawContent(SkCanvas* canvas) {
177 this->init();
reed339cdbf2015-02-05 22:02:37 -0800178 canvas->translate(50, 50);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179
180 static const SkPaint::Join gJoins[] = {
181 SkPaint::kBevel_Join,
182 SkPaint::kMiter_Join,
183 SkPaint::kRound_Join
184 };
185
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000186 for (size_t i = 0; i < SK_ARRAY_COUNT(gJoins); i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 canvas->save();
senorblanco@chromium.org64cc5792011-05-19 19:58:58 +0000188 for (size_t j = 0; j < SK_ARRAY_COUNT(fPath); j++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 this->drawPath(canvas, fPath[j], gJoins[i]);
reed339cdbf2015-02-05 22:02:37 -0800190 canvas->translate(200, 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191 }
192 canvas->restore();
rmistry@google.comae933ce2012-08-23 18:19:56 +0000193
reed339cdbf2015-02-05 22:02:37 -0800194 canvas->translate(0, 200);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195 }
reed339cdbf2015-02-05 22:02:37 -0800196 }
197
mtklein36352bf2015-03-25 18:17:31 -0700198 bool onAnimate(const SkAnimTimer& timer) override {
reed339cdbf2015-02-05 22:02:37 -0800199 SkScalar currSecs = timer.scaled(100);
200 SkScalar delta = currSecs - fPrevSecs;
201 fPrevSecs = currSecs;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000202
reed339cdbf2015-02-05 22:02:37 -0800203 fStroke += fDStroke * delta;
204 if (fStroke > fMaxStroke || fStroke < fMinStroke) {
205 fDStroke = -fDStroke;
206 }
207 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000209
mtklein36352bf2015-03-25 18:17:31 -0700210 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211 fShowHairline = !fShowHairline;
212 this->inval(NULL);
reed@google.com4d5c26d2013-01-08 16:17:50 +0000213 return this->INHERITED::onFindClickHandler(x, y, modi);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000215
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216private:
reed@google.com0faac1e2011-05-11 05:58:58 +0000217 typedef SampleView INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218};
reeda7a8b102014-12-16 08:07:43 -0800219DEF_SAMPLE( return new PathView; )
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220
221//////////////////////////////////////////////////////////////////////////////
222
reed8b575242014-12-17 01:47:32 -0800223#include "SkArcToPathEffect.h"
reeda7a8b102014-12-16 08:07:43 -0800224#include "SkCornerPathEffect.h"
225#include "SkRandom.h"
226
227class ArcToView : public SampleView {
reed8b575242014-12-17 01:47:32 -0800228 bool fDoFrame, fDoArcTo, fDoCorner, fDoConic;
229 SkPaint fPtsPaint, fArcToPaint, fSkeletonPaint, fCornerPaint;
reeda7a8b102014-12-16 08:07:43 -0800230public:
231 enum {
232 N = 4
233 };
234 SkPoint fPts[N];
reeda7a8b102014-12-16 08:07:43 -0800235
reed8b575242014-12-17 01:47:32 -0800236 ArcToView()
237 : fDoFrame(false), fDoArcTo(false), fDoCorner(false), fDoConic(false)
238 {
reeda7a8b102014-12-16 08:07:43 -0800239 SkRandom rand;
240 for (int i = 0; i < N; ++i) {
241 fPts[i].fX = 20 + rand.nextUScalar1() * 640;
242 fPts[i].fY = 20 + rand.nextUScalar1() * 480;
243 }
reed8b575242014-12-17 01:47:32 -0800244
245 const SkScalar rad = 50;
reeda7a8b102014-12-16 08:07:43 -0800246
247 fPtsPaint.setAntiAlias(true);
248 fPtsPaint.setStrokeWidth(15);
249 fPtsPaint.setStrokeCap(SkPaint::kRound_Cap);
250
reed8b575242014-12-17 01:47:32 -0800251 fArcToPaint.setAntiAlias(true);
252 fArcToPaint.setStyle(SkPaint::kStroke_Style);
253 fArcToPaint.setStrokeWidth(9);
254 fArcToPaint.setColor(0x800000FF);
255 fArcToPaint.setPathEffect(SkArcToPathEffect::Create(rad))->unref();
reeda7a8b102014-12-16 08:07:43 -0800256
257 fCornerPaint.setAntiAlias(true);
258 fCornerPaint.setStyle(SkPaint::kStroke_Style);
259 fCornerPaint.setStrokeWidth(13);
260 fCornerPaint.setColor(SK_ColorGREEN);
reed8b575242014-12-17 01:47:32 -0800261 fCornerPaint.setPathEffect(SkCornerPathEffect::Create(rad*2))->unref();
reeda7a8b102014-12-16 08:07:43 -0800262
263 fSkeletonPaint.setAntiAlias(true);
264 fSkeletonPaint.setStyle(SkPaint::kStroke_Style);
265 fSkeletonPaint.setColor(SK_ColorRED);
266 }
267
reed8b575242014-12-17 01:47:32 -0800268 void toggle(bool& value) {
269 value = !value;
270 this->inval(NULL);
271 }
272
reeda7a8b102014-12-16 08:07:43 -0800273protected:
274 // overrides from SkEventSink
mtklein36352bf2015-03-25 18:17:31 -0700275 bool onQuery(SkEvent* evt) override {
reeda7a8b102014-12-16 08:07:43 -0800276 if (SampleCode::TitleQ(*evt)) {
277 SampleCode::TitleR(evt, "ArcTo");
278 return true;
279 }
reed8b575242014-12-17 01:47:32 -0800280 SkUnichar uni;
281 if (SampleCode::CharQ(*evt, &uni)) {
282 switch (uni) {
283 case '1': this->toggle(fDoFrame); return true;
284 case '2': this->toggle(fDoArcTo); return true;
285 case '3': this->toggle(fDoCorner); return true;
286 case '4': this->toggle(fDoConic); return true;
287 default: break;
288 }
289 }
reeda7a8b102014-12-16 08:07:43 -0800290 return this->INHERITED::onQuery(evt);
291 }
reed8b575242014-12-17 01:47:32 -0800292
293 void makePath(SkPath* path) {
294 path->moveTo(fPts[0]);
295 for (int i = 1; i < N; ++i) {
296 path->lineTo(fPts[i]);
297 }
298 if (!fDoFrame) {
299 path->close();
300 }
301 }
reeda7a8b102014-12-16 08:07:43 -0800302
mtklein36352bf2015-03-25 18:17:31 -0700303 void onDrawContent(SkCanvas* canvas) override {
reeda7a8b102014-12-16 08:07:43 -0800304 canvas->drawPoints(SkCanvas::kPoints_PointMode, N, fPts, fPtsPaint);
305
306 SkPath path;
reed8b575242014-12-17 01:47:32 -0800307 this->makePath(&path);
reeda7a8b102014-12-16 08:07:43 -0800308
reed8b575242014-12-17 01:47:32 -0800309 if (fDoCorner) {
310 canvas->drawPath(path, fCornerPaint);
reeda7a8b102014-12-16 08:07:43 -0800311 }
reed8b575242014-12-17 01:47:32 -0800312 if (fDoArcTo) {
313 canvas->drawPath(path, fArcToPaint);
reeda7a8b102014-12-16 08:07:43 -0800314 }
reeda7a8b102014-12-16 08:07:43 -0800315
reed8b575242014-12-17 01:47:32 -0800316 canvas->drawPath(path, fSkeletonPaint);
reeda7a8b102014-12-16 08:07:43 -0800317 }
318
mtklein36352bf2015-03-25 18:17:31 -0700319 bool onClick(Click* click) override {
reeda7a8b102014-12-16 08:07:43 -0800320 int32_t index;
321 if (click->fMeta.findS32("index", &index)) {
322 SkASSERT((unsigned)index < N);
323 fPts[index] = click->fCurr;
324 this->inval(NULL);
325 return true;
326 }
327 return false;
328 }
329
mtklein36352bf2015-03-25 18:17:31 -0700330 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
reeda7a8b102014-12-16 08:07:43 -0800331 const SkScalar tol = 4;
332 const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
333 for (int i = 0; i < N; ++i) {
334 if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
335 Click* click = new Click(this);
336 click->fMeta.setS32("index", i);
337 return click;
338 }
339 }
340 return this->INHERITED::onFindClickHandler(x, y, modi);
341 }
342
343private:
344 typedef SampleView INHERITED;
345};
346DEF_SAMPLE( return new ArcToView; )
347