1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 10cb93a386Sopenharmony_ci#include "include/core/SkColorFilter.h" 11cb93a386Sopenharmony_ci#include "include/core/SkColorPriv.h" 12cb93a386Sopenharmony_ci#include "include/core/SkFont.h" 13cb93a386Sopenharmony_ci#include "include/core/SkGraphics.h" 14cb93a386Sopenharmony_ci#include "include/core/SkPathBuilder.h" 15cb93a386Sopenharmony_ci#include "include/core/SkRegion.h" 16cb93a386Sopenharmony_ci#include "include/core/SkShader.h" 17cb93a386Sopenharmony_ci#include "include/core/SkTime.h" 18cb93a386Sopenharmony_ci#include "include/core/SkTypeface.h" 19cb93a386Sopenharmony_ci#include "include/effects/SkGradientShader.h" 20cb93a386Sopenharmony_ci#include "include/utils/SkParsePath.h" 21cb93a386Sopenharmony_ci#include "samplecode/Sample.h" 22cb93a386Sopenharmony_ci#include "src/utils/SkUTF.h" 23cb93a386Sopenharmony_ci#include "tools/timer/TimeUtils.h" 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h" 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci#include <stdlib.h> 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ci// http://code.google.com/p/skia/issues/detail?id=32 30cb93a386Sopenharmony_cistatic void test_cubic() { 31cb93a386Sopenharmony_ci SkPoint src[4] = { 32cb93a386Sopenharmony_ci { 556.25000f, 523.03003f }, 33cb93a386Sopenharmony_ci { 556.23999f, 522.96002f }, 34cb93a386Sopenharmony_ci { 556.21997f, 522.89001f }, 35cb93a386Sopenharmony_ci { 556.21997f, 522.82001f } 36cb93a386Sopenharmony_ci }; 37cb93a386Sopenharmony_ci SkPoint dst[11]; 38cb93a386Sopenharmony_ci dst[10].set(42, -42); // one past the end, that we don't clobber these 39cb93a386Sopenharmony_ci SkScalar tval[] = { 0.33333334f, 0.99999994f }; 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci SkChopCubicAt(src, dst, tval, 2); 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci#if 0 44cb93a386Sopenharmony_ci for (int i = 0; i < 11; i++) { 45cb93a386Sopenharmony_ci SkDebugf("--- %d [%g %g]\n", i, dst[i].fX, dst[i].fY); 46cb93a386Sopenharmony_ci } 47cb93a386Sopenharmony_ci#endif 48cb93a386Sopenharmony_ci} 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_cistatic void test_cubic2() { 51cb93a386Sopenharmony_ci const char* str = "M2242 -590088L-377758 9.94099e+07L-377758 9.94099e+07L2242 -590088Z"; 52cb93a386Sopenharmony_ci SkPath path; 53cb93a386Sopenharmony_ci SkParsePath::FromSVGString(str, &path); 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_ci { 56cb93a386Sopenharmony_ci SkRect r = path.getBounds(); 57cb93a386Sopenharmony_ci SkIRect ir; 58cb93a386Sopenharmony_ci r.round(&ir); 59cb93a386Sopenharmony_ci SkDebugf("[%g %g %g %g] [%x %x %x %x]\n", 60cb93a386Sopenharmony_ci SkScalarToDouble(r.fLeft), SkScalarToDouble(r.fTop), 61cb93a386Sopenharmony_ci SkScalarToDouble(r.fRight), SkScalarToDouble(r.fBottom), 62cb93a386Sopenharmony_ci ir.fLeft, ir.fTop, ir.fRight, ir.fBottom); 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci SkBitmap bitmap; 66cb93a386Sopenharmony_ci bitmap.allocN32Pixels(300, 200); 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ci SkCanvas canvas(bitmap); 69cb93a386Sopenharmony_ci SkPaint paint; 70cb93a386Sopenharmony_ci paint.setAntiAlias(true); 71cb93a386Sopenharmony_ci canvas.drawPath(path, paint); 72cb93a386Sopenharmony_ci} 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ciclass PathView : public Sample { 75cb93a386Sopenharmony_ci SkScalar fPrevSecs; 76cb93a386Sopenharmony_cipublic: 77cb93a386Sopenharmony_ci SkScalar fDStroke, fStroke, fMinStroke, fMaxStroke; 78cb93a386Sopenharmony_ci SkPath fPath[6]; 79cb93a386Sopenharmony_ci bool fShowHairline; 80cb93a386Sopenharmony_ci bool fOnce; 81cb93a386Sopenharmony_ci 82cb93a386Sopenharmony_ci PathView() { 83cb93a386Sopenharmony_ci fPrevSecs = 0; 84cb93a386Sopenharmony_ci fOnce = false; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci void init() { 88cb93a386Sopenharmony_ci if (fOnce) { 89cb93a386Sopenharmony_ci return; 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci fOnce = true; 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci test_cubic(); 94cb93a386Sopenharmony_ci test_cubic2(); 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci fShowHairline = false; 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ci fDStroke = 1; 99cb93a386Sopenharmony_ci fStroke = 10; 100cb93a386Sopenharmony_ci fMinStroke = 10; 101cb93a386Sopenharmony_ci fMaxStroke = 180; 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ci const SkScalar V = 85; 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci fPath[0].moveTo(40, 70); 106cb93a386Sopenharmony_ci fPath[0].lineTo(70, 70 + SK_ScalarHalf); 107cb93a386Sopenharmony_ci fPath[0].lineTo(110, 70); 108cb93a386Sopenharmony_ci 109cb93a386Sopenharmony_ci fPath[1].moveTo(40, 70); 110cb93a386Sopenharmony_ci fPath[1].lineTo(70, 70 - SK_ScalarHalf); 111cb93a386Sopenharmony_ci fPath[1].lineTo(110, 70); 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci fPath[2].moveTo(V, V); 114cb93a386Sopenharmony_ci fPath[2].lineTo(50, V); 115cb93a386Sopenharmony_ci fPath[2].lineTo(50, 50); 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ci fPath[3].moveTo(50, 50); 118cb93a386Sopenharmony_ci fPath[3].lineTo(50, V); 119cb93a386Sopenharmony_ci fPath[3].lineTo(V, V); 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci fPath[4].moveTo(50, 50); 122cb93a386Sopenharmony_ci fPath[4].lineTo(50, V); 123cb93a386Sopenharmony_ci fPath[4].lineTo(52, 50); 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ci fPath[5].moveTo(52, 50); 126cb93a386Sopenharmony_ci fPath[5].lineTo(50, V); 127cb93a386Sopenharmony_ci fPath[5].lineTo(50, 50); 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci this->setBGColor(0xFFDDDDDD); 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ciprotected: 133cb93a386Sopenharmony_ci SkString name() override { return SkString("Paths"); } 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ci void drawPath(SkCanvas* canvas, const SkPath& path, SkPaint::Join j) { 136cb93a386Sopenharmony_ci SkPaint paint; 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_ci paint.setAntiAlias(true); 139cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kStroke_Style); 140cb93a386Sopenharmony_ci paint.setStrokeJoin(j); 141cb93a386Sopenharmony_ci paint.setStrokeWidth(fStroke); 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci if (fShowHairline) { 144cb93a386Sopenharmony_ci SkPath fill; 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci paint.getFillPath(path, &fill); 147cb93a386Sopenharmony_ci paint.setStrokeWidth(0); 148cb93a386Sopenharmony_ci canvas->drawPath(fill, paint); 149cb93a386Sopenharmony_ci } else { 150cb93a386Sopenharmony_ci canvas->drawPath(path, paint); 151cb93a386Sopenharmony_ci } 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci paint.setColor(SK_ColorRED); 154cb93a386Sopenharmony_ci paint.setStrokeWidth(0); 155cb93a386Sopenharmony_ci canvas->drawPath(path, paint); 156cb93a386Sopenharmony_ci } 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_ci void onDrawContent(SkCanvas* canvas) override { 159cb93a386Sopenharmony_ci this->init(); 160cb93a386Sopenharmony_ci canvas->translate(50, 50); 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_ci static const SkPaint::Join gJoins[] = { 163cb93a386Sopenharmony_ci SkPaint::kBevel_Join, 164cb93a386Sopenharmony_ci SkPaint::kMiter_Join, 165cb93a386Sopenharmony_ci SkPaint::kRound_Join 166cb93a386Sopenharmony_ci }; 167cb93a386Sopenharmony_ci 168cb93a386Sopenharmony_ci for (size_t i = 0; i < SK_ARRAY_COUNT(gJoins); i++) { 169cb93a386Sopenharmony_ci canvas->save(); 170cb93a386Sopenharmony_ci for (size_t j = 0; j < SK_ARRAY_COUNT(fPath); j++) { 171cb93a386Sopenharmony_ci this->drawPath(canvas, fPath[j], gJoins[i]); 172cb93a386Sopenharmony_ci canvas->translate(200, 0); 173cb93a386Sopenharmony_ci } 174cb93a386Sopenharmony_ci canvas->restore(); 175cb93a386Sopenharmony_ci 176cb93a386Sopenharmony_ci canvas->translate(0, 200); 177cb93a386Sopenharmony_ci } 178cb93a386Sopenharmony_ci } 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_ci bool onAnimate(double nanos) override { 181cb93a386Sopenharmony_ci SkScalar currSecs = TimeUtils::Scaled(1e-9 * nanos, 100); 182cb93a386Sopenharmony_ci SkScalar delta = currSecs - fPrevSecs; 183cb93a386Sopenharmony_ci fPrevSecs = currSecs; 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci fStroke += fDStroke * delta; 186cb93a386Sopenharmony_ci if (fStroke > fMaxStroke || fStroke < fMinStroke) { 187cb93a386Sopenharmony_ci fDStroke = -fDStroke; 188cb93a386Sopenharmony_ci } 189cb93a386Sopenharmony_ci return true; 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override { 193cb93a386Sopenharmony_ci fShowHairline = !fShowHairline; 194cb93a386Sopenharmony_ci return nullptr; 195cb93a386Sopenharmony_ci } 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_ciprivate: 198cb93a386Sopenharmony_ci using INHERITED = Sample; 199cb93a386Sopenharmony_ci}; 200cb93a386Sopenharmony_ciDEF_SAMPLE( return new PathView; ) 201cb93a386Sopenharmony_ci 202cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_ci#include "include/effects/SkCornerPathEffect.h" 205cb93a386Sopenharmony_ci#include "include/utils/SkRandom.h" 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_ciclass ArcToView : public Sample { 208cb93a386Sopenharmony_ci bool fDoFrame, fDoCorner, fDoConic; 209cb93a386Sopenharmony_ci SkPaint fPtsPaint, fSkeletonPaint, fCornerPaint; 210cb93a386Sopenharmony_cipublic: 211cb93a386Sopenharmony_ci enum { 212cb93a386Sopenharmony_ci N = 4 213cb93a386Sopenharmony_ci }; 214cb93a386Sopenharmony_ci SkPoint fPts[N]; 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci ArcToView() 217cb93a386Sopenharmony_ci : fDoFrame(false), fDoCorner(false), fDoConic(false) 218cb93a386Sopenharmony_ci { 219cb93a386Sopenharmony_ci SkRandom rand; 220cb93a386Sopenharmony_ci for (int i = 0; i < N; ++i) { 221cb93a386Sopenharmony_ci fPts[i].fX = 20 + rand.nextUScalar1() * 640; 222cb93a386Sopenharmony_ci fPts[i].fY = 20 + rand.nextUScalar1() * 480; 223cb93a386Sopenharmony_ci } 224cb93a386Sopenharmony_ci 225cb93a386Sopenharmony_ci const SkScalar rad = 50; 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci fPtsPaint.setAntiAlias(true); 228cb93a386Sopenharmony_ci fPtsPaint.setStrokeWidth(15); 229cb93a386Sopenharmony_ci fPtsPaint.setStrokeCap(SkPaint::kRound_Cap); 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_ci fCornerPaint.setAntiAlias(true); 232cb93a386Sopenharmony_ci fCornerPaint.setStyle(SkPaint::kStroke_Style); 233cb93a386Sopenharmony_ci fCornerPaint.setStrokeWidth(13); 234cb93a386Sopenharmony_ci fCornerPaint.setColor(SK_ColorGREEN); 235cb93a386Sopenharmony_ci fCornerPaint.setPathEffect(SkCornerPathEffect::Make(rad*2)); 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_ci fSkeletonPaint.setAntiAlias(true); 238cb93a386Sopenharmony_ci fSkeletonPaint.setStyle(SkPaint::kStroke_Style); 239cb93a386Sopenharmony_ci fSkeletonPaint.setColor(SK_ColorRED); 240cb93a386Sopenharmony_ci } 241cb93a386Sopenharmony_ci 242cb93a386Sopenharmony_ci void toggle(bool& value) { 243cb93a386Sopenharmony_ci value = !value; 244cb93a386Sopenharmony_ci } 245cb93a386Sopenharmony_ci 246cb93a386Sopenharmony_ciprotected: 247cb93a386Sopenharmony_ci SkString name() override { return SkString("ArcTo"); } 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci bool onChar(SkUnichar uni) override { 250cb93a386Sopenharmony_ci switch (uni) { 251cb93a386Sopenharmony_ci case '1': this->toggle(fDoFrame); return true; 252cb93a386Sopenharmony_ci case '2': this->toggle(fDoCorner); return true; 253cb93a386Sopenharmony_ci case '3': this->toggle(fDoConic); return true; 254cb93a386Sopenharmony_ci default: break; 255cb93a386Sopenharmony_ci } 256cb93a386Sopenharmony_ci return false; 257cb93a386Sopenharmony_ci } 258cb93a386Sopenharmony_ci 259cb93a386Sopenharmony_ci void makePath(SkPath* path) { 260cb93a386Sopenharmony_ci path->moveTo(fPts[0]); 261cb93a386Sopenharmony_ci for (int i = 1; i < N; ++i) { 262cb93a386Sopenharmony_ci path->lineTo(fPts[i]); 263cb93a386Sopenharmony_ci } 264cb93a386Sopenharmony_ci if (!fDoFrame) { 265cb93a386Sopenharmony_ci path->close(); 266cb93a386Sopenharmony_ci } 267cb93a386Sopenharmony_ci } 268cb93a386Sopenharmony_ci 269cb93a386Sopenharmony_ci void onDrawContent(SkCanvas* canvas) override { 270cb93a386Sopenharmony_ci canvas->drawPoints(SkCanvas::kPoints_PointMode, N, fPts, fPtsPaint); 271cb93a386Sopenharmony_ci 272cb93a386Sopenharmony_ci SkPath path; 273cb93a386Sopenharmony_ci this->makePath(&path); 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_ci if (fDoCorner) { 276cb93a386Sopenharmony_ci canvas->drawPath(path, fCornerPaint); 277cb93a386Sopenharmony_ci } 278cb93a386Sopenharmony_ci 279cb93a386Sopenharmony_ci canvas->drawPath(path, fSkeletonPaint); 280cb93a386Sopenharmony_ci } 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_ci Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override { 283cb93a386Sopenharmony_ci const SkScalar tol = 4; 284cb93a386Sopenharmony_ci const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2); 285cb93a386Sopenharmony_ci for (int i = 0; i < N; ++i) { 286cb93a386Sopenharmony_ci if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) { 287cb93a386Sopenharmony_ci return new Click([this, i](Click* c) { 288cb93a386Sopenharmony_ci fPts[i] = c->fCurr; 289cb93a386Sopenharmony_ci return true; 290cb93a386Sopenharmony_ci }); 291cb93a386Sopenharmony_ci } 292cb93a386Sopenharmony_ci } 293cb93a386Sopenharmony_ci return nullptr; 294cb93a386Sopenharmony_ci } 295cb93a386Sopenharmony_ci 296cb93a386Sopenharmony_ciprivate: 297cb93a386Sopenharmony_ci using INHERITED = Sample; 298cb93a386Sopenharmony_ci}; 299cb93a386Sopenharmony_ciDEF_SAMPLE( return new ArcToView; ) 300cb93a386Sopenharmony_ci 301cb93a386Sopenharmony_ci///////////// 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ciclass FatStroke : public Sample { 304cb93a386Sopenharmony_ci bool fClosed, fShowStroke, fShowHidden, fShowSkeleton, fAsCurves = false; 305cb93a386Sopenharmony_ci int fJoinType, fCapType; 306cb93a386Sopenharmony_ci float fWidth = 30; 307cb93a386Sopenharmony_ci SkPaint fPtsPaint, fHiddenPaint, fSkeletonPaint, fStrokePaint; 308cb93a386Sopenharmony_cipublic: 309cb93a386Sopenharmony_ci enum { 310cb93a386Sopenharmony_ci N = 4 311cb93a386Sopenharmony_ci }; 312cb93a386Sopenharmony_ci SkPoint fPts[N]; 313cb93a386Sopenharmony_ci 314cb93a386Sopenharmony_ci FatStroke() : fClosed(false), fShowStroke(true), fShowHidden(false), fShowSkeleton(true), 315cb93a386Sopenharmony_ci fJoinType(0), fCapType(0) 316cb93a386Sopenharmony_ci { 317cb93a386Sopenharmony_ci SkRandom rand; 318cb93a386Sopenharmony_ci for (int i = 0; i < N; ++i) { 319cb93a386Sopenharmony_ci fPts[i].fX = 20 + rand.nextUScalar1() * 640; 320cb93a386Sopenharmony_ci fPts[i].fY = 20 + rand.nextUScalar1() * 480; 321cb93a386Sopenharmony_ci } 322cb93a386Sopenharmony_ci 323cb93a386Sopenharmony_ci fPtsPaint.setAntiAlias(true); 324cb93a386Sopenharmony_ci fPtsPaint.setStrokeWidth(10); 325cb93a386Sopenharmony_ci fPtsPaint.setStrokeCap(SkPaint::kRound_Cap); 326cb93a386Sopenharmony_ci 327cb93a386Sopenharmony_ci fHiddenPaint.setAntiAlias(true); 328cb93a386Sopenharmony_ci fHiddenPaint.setStyle(SkPaint::kStroke_Style); 329cb93a386Sopenharmony_ci fHiddenPaint.setColor(0xFF0000FF); 330cb93a386Sopenharmony_ci 331cb93a386Sopenharmony_ci fStrokePaint.setAntiAlias(true); 332cb93a386Sopenharmony_ci fStrokePaint.setStyle(SkPaint::kStroke_Style); 333cb93a386Sopenharmony_ci fStrokePaint.setStrokeWidth(50); 334cb93a386Sopenharmony_ci fStrokePaint.setColor(0x8000FF00); 335cb93a386Sopenharmony_ci 336cb93a386Sopenharmony_ci fSkeletonPaint.setAntiAlias(true); 337cb93a386Sopenharmony_ci fSkeletonPaint.setStyle(SkPaint::kStroke_Style); 338cb93a386Sopenharmony_ci fSkeletonPaint.setColor(SK_ColorRED); 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci 341cb93a386Sopenharmony_ci void toggle(bool& value) { 342cb93a386Sopenharmony_ci value = !value; 343cb93a386Sopenharmony_ci } 344cb93a386Sopenharmony_ci 345cb93a386Sopenharmony_ci void toggle3(int& value) { 346cb93a386Sopenharmony_ci value = (value + 1) % 3; 347cb93a386Sopenharmony_ci } 348cb93a386Sopenharmony_ci 349cb93a386Sopenharmony_ciprotected: 350cb93a386Sopenharmony_ci SkString name() override { return SkString("FatStroke"); } 351cb93a386Sopenharmony_ci 352cb93a386Sopenharmony_ci bool onChar(SkUnichar uni) override { 353cb93a386Sopenharmony_ci switch (uni) { 354cb93a386Sopenharmony_ci case '1': this->toggle(fShowSkeleton); return true; 355cb93a386Sopenharmony_ci case '2': this->toggle(fShowStroke); return true; 356cb93a386Sopenharmony_ci case '3': this->toggle(fShowHidden); return true; 357cb93a386Sopenharmony_ci case '4': this->toggle3(fJoinType); return true; 358cb93a386Sopenharmony_ci case '5': this->toggle3(fCapType); return true; 359cb93a386Sopenharmony_ci case '6': this->toggle(fClosed); return true; 360cb93a386Sopenharmony_ci case 'c': this->toggle(fAsCurves); return true; 361cb93a386Sopenharmony_ci case '-': fWidth -= 5; return true; 362cb93a386Sopenharmony_ci case '=': fWidth += 5; return true; 363cb93a386Sopenharmony_ci default: break; 364cb93a386Sopenharmony_ci } 365cb93a386Sopenharmony_ci return false; 366cb93a386Sopenharmony_ci } 367cb93a386Sopenharmony_ci 368cb93a386Sopenharmony_ci void makePath(SkPath* path) { 369cb93a386Sopenharmony_ci path->moveTo(fPts[0]); 370cb93a386Sopenharmony_ci if (fAsCurves) { 371cb93a386Sopenharmony_ci for (int i = 1; i < N-2; ++i) { 372cb93a386Sopenharmony_ci path->quadTo(fPts[i], (fPts[i+1] + fPts[i]) * 0.5f); 373cb93a386Sopenharmony_ci } 374cb93a386Sopenharmony_ci path->quadTo(fPts[N-2], fPts[N-1]); 375cb93a386Sopenharmony_ci } else { 376cb93a386Sopenharmony_ci for (int i = 1; i < N; ++i) { 377cb93a386Sopenharmony_ci path->lineTo(fPts[i]); 378cb93a386Sopenharmony_ci } 379cb93a386Sopenharmony_ci } 380cb93a386Sopenharmony_ci if (fClosed) { 381cb93a386Sopenharmony_ci path->close(); 382cb93a386Sopenharmony_ci } 383cb93a386Sopenharmony_ci } 384cb93a386Sopenharmony_ci 385cb93a386Sopenharmony_ci void onDrawContent(SkCanvas* canvas) override { 386cb93a386Sopenharmony_ci canvas->drawColor(0xFFEEEEEE); 387cb93a386Sopenharmony_ci 388cb93a386Sopenharmony_ci SkPath path; 389cb93a386Sopenharmony_ci this->makePath(&path); 390cb93a386Sopenharmony_ci 391cb93a386Sopenharmony_ci fStrokePaint.setStrokeWidth(fWidth); 392cb93a386Sopenharmony_ci fStrokePaint.setStrokeJoin((SkPaint::Join)fJoinType); 393cb93a386Sopenharmony_ci fStrokePaint.setStrokeCap((SkPaint::Cap)fCapType); 394cb93a386Sopenharmony_ci 395cb93a386Sopenharmony_ci if (fShowStroke) { 396cb93a386Sopenharmony_ci canvas->drawPath(path, fStrokePaint); 397cb93a386Sopenharmony_ci } 398cb93a386Sopenharmony_ci if (fShowHidden) { 399cb93a386Sopenharmony_ci SkPath hidden; 400cb93a386Sopenharmony_ci fStrokePaint.getFillPath(path, &hidden); 401cb93a386Sopenharmony_ci canvas->drawPath(hidden, fHiddenPaint); 402cb93a386Sopenharmony_ci } 403cb93a386Sopenharmony_ci if (fShowSkeleton) { 404cb93a386Sopenharmony_ci canvas->drawPath(path, fSkeletonPaint); 405cb93a386Sopenharmony_ci } 406cb93a386Sopenharmony_ci canvas->drawPoints(SkCanvas::kPoints_PointMode, N, fPts, fPtsPaint); 407cb93a386Sopenharmony_ci } 408cb93a386Sopenharmony_ci 409cb93a386Sopenharmony_ci Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override { 410cb93a386Sopenharmony_ci const SkScalar tol = 4; 411cb93a386Sopenharmony_ci const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2); 412cb93a386Sopenharmony_ci for (int i = 0; i < N; ++i) { 413cb93a386Sopenharmony_ci if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) { 414cb93a386Sopenharmony_ci return new Click([this, i](Click* c) { 415cb93a386Sopenharmony_ci fPts[i] = c->fCurr; 416cb93a386Sopenharmony_ci return true; 417cb93a386Sopenharmony_ci }); 418cb93a386Sopenharmony_ci } 419cb93a386Sopenharmony_ci } 420cb93a386Sopenharmony_ci return nullptr; 421cb93a386Sopenharmony_ci } 422cb93a386Sopenharmony_ci 423cb93a386Sopenharmony_ciprivate: 424cb93a386Sopenharmony_ci using INHERITED = Sample; 425cb93a386Sopenharmony_ci}; 426cb93a386Sopenharmony_ciDEF_SAMPLE( return new FatStroke; ) 427cb93a386Sopenharmony_ci 428cb93a386Sopenharmony_cistatic int compute_parallel_to_base(const SkPoint pts[4], SkScalar t[2]) { 429cb93a386Sopenharmony_ci // F = At^3 + Bt^2 + Ct + D 430cb93a386Sopenharmony_ci SkVector A = pts[3] - pts[0] + (pts[1] - pts[2]) * 3.0f; 431cb93a386Sopenharmony_ci SkVector B = (pts[0] - pts[1] - pts[1] + pts[2]) * 3.0f; 432cb93a386Sopenharmony_ci SkVector C = (pts[1] - pts[0]) * 3.0f; 433cb93a386Sopenharmony_ci SkVector DA = pts[3] - pts[0]; 434cb93a386Sopenharmony_ci 435cb93a386Sopenharmony_ci // F' = 3At^2 + 2Bt + C 436cb93a386Sopenharmony_ci SkScalar a = 3 * A.cross(DA); 437cb93a386Sopenharmony_ci SkScalar b = 2 * B.cross(DA); 438cb93a386Sopenharmony_ci SkScalar c = C.cross(DA); 439cb93a386Sopenharmony_ci 440cb93a386Sopenharmony_ci int n = SkFindUnitQuadRoots(a, b, c, t); 441cb93a386Sopenharmony_ci SkString str; 442cb93a386Sopenharmony_ci for (int i = 0; i < n; ++i) { 443cb93a386Sopenharmony_ci str.appendf(" %g", t[i]); 444cb93a386Sopenharmony_ci } 445cb93a386Sopenharmony_ci SkDebugf("roots %s\n", str.c_str()); 446cb93a386Sopenharmony_ci return n; 447cb93a386Sopenharmony_ci} 448cb93a386Sopenharmony_ci 449cb93a386Sopenharmony_ciclass CubicCurve : public Sample { 450cb93a386Sopenharmony_cipublic: 451cb93a386Sopenharmony_ci enum { 452cb93a386Sopenharmony_ci N = 4 453cb93a386Sopenharmony_ci }; 454cb93a386Sopenharmony_ci SkPoint fPts[N]; 455cb93a386Sopenharmony_ci 456cb93a386Sopenharmony_ci CubicCurve() { 457cb93a386Sopenharmony_ci SkRandom rand; 458cb93a386Sopenharmony_ci for (int i = 0; i < N; ++i) { 459cb93a386Sopenharmony_ci fPts[i].fX = 20 + rand.nextUScalar1() * 640; 460cb93a386Sopenharmony_ci fPts[i].fY = 20 + rand.nextUScalar1() * 480; 461cb93a386Sopenharmony_ci } 462cb93a386Sopenharmony_ci } 463cb93a386Sopenharmony_ci 464cb93a386Sopenharmony_ciprotected: 465cb93a386Sopenharmony_ci SkString name() override { return SkString("CubicCurve"); } 466cb93a386Sopenharmony_ci 467cb93a386Sopenharmony_ci void onDrawContent(SkCanvas* canvas) override { 468cb93a386Sopenharmony_ci SkPaint paint; 469cb93a386Sopenharmony_ci paint.setAntiAlias(true); 470cb93a386Sopenharmony_ci 471cb93a386Sopenharmony_ci { 472cb93a386Sopenharmony_ci SkPath path; 473cb93a386Sopenharmony_ci path.moveTo(fPts[0]); 474cb93a386Sopenharmony_ci path.cubicTo(fPts[1], fPts[2], fPts[3]); 475cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kStroke_Style); 476cb93a386Sopenharmony_ci canvas->drawPath(path, paint); 477cb93a386Sopenharmony_ci } 478cb93a386Sopenharmony_ci 479cb93a386Sopenharmony_ci { 480cb93a386Sopenharmony_ci paint.setColor(SK_ColorRED); 481cb93a386Sopenharmony_ci SkScalar t[2]; 482cb93a386Sopenharmony_ci int n = compute_parallel_to_base(fPts, t); 483cb93a386Sopenharmony_ci SkPoint loc; 484cb93a386Sopenharmony_ci SkVector tan; 485cb93a386Sopenharmony_ci for (int i = 0; i < n; ++i) { 486cb93a386Sopenharmony_ci SkEvalCubicAt(fPts, t[i], &loc, &tan, nullptr); 487cb93a386Sopenharmony_ci tan.setLength(30); 488cb93a386Sopenharmony_ci canvas->drawLine(loc - tan, loc + tan, paint); 489cb93a386Sopenharmony_ci } 490cb93a386Sopenharmony_ci paint.setStrokeWidth(0.5f); 491cb93a386Sopenharmony_ci canvas->drawLine(fPts[0], fPts[3], paint); 492cb93a386Sopenharmony_ci 493cb93a386Sopenharmony_ci paint.setColor(SK_ColorBLUE); 494cb93a386Sopenharmony_ci paint.setStrokeWidth(6); 495cb93a386Sopenharmony_ci SkEvalCubicAt(fPts, 0.5f, &loc, nullptr, nullptr); 496cb93a386Sopenharmony_ci canvas->drawPoint(loc, paint); 497cb93a386Sopenharmony_ci 498cb93a386Sopenharmony_ci paint.setColor(0xFF008800); 499cb93a386Sopenharmony_ci SkEvalCubicAt(fPts, 1.0f/3, &loc, nullptr, nullptr); 500cb93a386Sopenharmony_ci canvas->drawPoint(loc, paint); 501cb93a386Sopenharmony_ci SkEvalCubicAt(fPts, 2.0f/3, &loc, nullptr, nullptr); 502cb93a386Sopenharmony_ci canvas->drawPoint(loc, paint); 503cb93a386Sopenharmony_ci 504cb93a386Sopenharmony_ci // n = SkFindCubicInflections(fPts, t); 505cb93a386Sopenharmony_ci // printf("inflections %d %g %g\n", n, t[0], t[1]); 506cb93a386Sopenharmony_ci } 507cb93a386Sopenharmony_ci 508cb93a386Sopenharmony_ci { 509cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kFill_Style); 510cb93a386Sopenharmony_ci paint.setColor(SK_ColorRED); 511cb93a386Sopenharmony_ci for (SkPoint p : fPts) { 512cb93a386Sopenharmony_ci canvas->drawCircle(p.fX, p.fY, 8, paint); 513cb93a386Sopenharmony_ci } 514cb93a386Sopenharmony_ci } 515cb93a386Sopenharmony_ci } 516cb93a386Sopenharmony_ci 517cb93a386Sopenharmony_ci Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override { 518cb93a386Sopenharmony_ci const SkScalar tol = 8; 519cb93a386Sopenharmony_ci const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2); 520cb93a386Sopenharmony_ci for (int i = 0; i < N; ++i) { 521cb93a386Sopenharmony_ci if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) { 522cb93a386Sopenharmony_ci return new Click([this, i](Click* c) { 523cb93a386Sopenharmony_ci fPts[i] = c->fCurr; 524cb93a386Sopenharmony_ci return true; 525cb93a386Sopenharmony_ci }); 526cb93a386Sopenharmony_ci } 527cb93a386Sopenharmony_ci } 528cb93a386Sopenharmony_ci return this->INHERITED::onFindClickHandler(x, y, modi); 529cb93a386Sopenharmony_ci } 530cb93a386Sopenharmony_ci 531cb93a386Sopenharmony_ciprivate: 532cb93a386Sopenharmony_ci using INHERITED = Sample; 533cb93a386Sopenharmony_ci}; 534cb93a386Sopenharmony_ciDEF_SAMPLE( return new CubicCurve; ) 535cb93a386Sopenharmony_ci 536cb93a386Sopenharmony_cistatic SkPoint lerp(SkPoint a, SkPoint b, float t) { 537cb93a386Sopenharmony_ci return a * (1 - t) + b * t; 538cb93a386Sopenharmony_ci} 539cb93a386Sopenharmony_ci 540cb93a386Sopenharmony_cistatic int find_max_deviation_cubic(const SkPoint src[4], SkScalar ts[2]) { 541cb93a386Sopenharmony_ci // deviation = F' x (d - a) == 0, solve for t(s) 542cb93a386Sopenharmony_ci // F = At^3 + Bt^2 + Ct + D 543cb93a386Sopenharmony_ci // F' = 3At^2 + 2Bt + C 544cb93a386Sopenharmony_ci // Z = d - a 545cb93a386Sopenharmony_ci // F' x Z = 3(A x Z)t^2 + 2(B x Z)t + (C x Z) 546cb93a386Sopenharmony_ci // 547cb93a386Sopenharmony_ci SkVector A = src[3] + (src[1] - src[2]) * 3 - src[0]; 548cb93a386Sopenharmony_ci SkVector B = (src[2] - src[1] - src[1] + src[0]) * 3; 549cb93a386Sopenharmony_ci SkVector C = (src[1] - src[0]) * 3; 550cb93a386Sopenharmony_ci SkVector Z = src[3] - src[0]; 551cb93a386Sopenharmony_ci // now forumlate the quadratic coefficients we need to solve for t : F' x Z 552cb93a386Sopenharmony_ci return SkFindUnitQuadRoots(3 * A.cross(Z), 2 * B.cross(Z), C.cross(Z), ts); 553cb93a386Sopenharmony_ci} 554cb93a386Sopenharmony_ci 555cb93a386Sopenharmony_ciclass CubicCurve2 : public Sample { 556cb93a386Sopenharmony_cipublic: 557cb93a386Sopenharmony_ci enum { 558cb93a386Sopenharmony_ci N = 7 559cb93a386Sopenharmony_ci }; 560cb93a386Sopenharmony_ci SkPoint fPts[N]; 561cb93a386Sopenharmony_ci SkPoint* fQuad = fPts + 4; 562cb93a386Sopenharmony_ci SkScalar fT = 0.5f; 563cb93a386Sopenharmony_ci bool fShowSub = false; 564cb93a386Sopenharmony_ci bool fShowFlatness = false; 565cb93a386Sopenharmony_ci bool fShowInnerQuads = false; 566cb93a386Sopenharmony_ci SkScalar fScale = 0.75; 567cb93a386Sopenharmony_ci 568cb93a386Sopenharmony_ci CubicCurve2() { 569cb93a386Sopenharmony_ci fPts[0] = { 90, 300 }; 570cb93a386Sopenharmony_ci fPts[1] = { 30, 60 }; 571cb93a386Sopenharmony_ci fPts[2] = { 250, 30 }; 572cb93a386Sopenharmony_ci fPts[3] = { 350, 200 }; 573cb93a386Sopenharmony_ci 574cb93a386Sopenharmony_ci fQuad[0] = fPts[0] + SkVector{ 300, 0}; 575cb93a386Sopenharmony_ci fQuad[1] = fPts[1] + SkVector{ 300, 0}; 576cb93a386Sopenharmony_ci fQuad[2] = fPts[2] + SkVector{ 300, 0}; 577cb93a386Sopenharmony_ci } 578cb93a386Sopenharmony_ci 579cb93a386Sopenharmony_ciprotected: 580cb93a386Sopenharmony_ci SkString name() override { return SkString("CubicCurve2"); } 581cb93a386Sopenharmony_ci 582cb93a386Sopenharmony_ci bool onChar(SkUnichar uni) override { 583cb93a386Sopenharmony_ci switch (uni) { 584cb93a386Sopenharmony_ci case 's': fShowSub = !fShowSub; break; 585cb93a386Sopenharmony_ci case 'f': fShowFlatness = !fShowFlatness; break; 586cb93a386Sopenharmony_ci case '-': fT -= 1.0f / 32; break; 587cb93a386Sopenharmony_ci case '=': fT += 1.0f / 32; break; 588cb93a386Sopenharmony_ci case 'q': fShowInnerQuads = !fShowInnerQuads; break; 589cb93a386Sopenharmony_ci default: return false; 590cb93a386Sopenharmony_ci } 591cb93a386Sopenharmony_ci fT = std::min(1.0f, std::max(0.0f, fT)); 592cb93a386Sopenharmony_ci return true; 593cb93a386Sopenharmony_ci } 594cb93a386Sopenharmony_ci 595cb93a386Sopenharmony_ci static void Dot(SkCanvas* canvas, SkPoint p, SkScalar radius, SkColor c) { 596cb93a386Sopenharmony_ci SkPaint paint; 597cb93a386Sopenharmony_ci paint.setAntiAlias(true); 598cb93a386Sopenharmony_ci paint.setColor(c); 599cb93a386Sopenharmony_ci canvas->drawCircle(p.fX, p.fY, radius, paint); 600cb93a386Sopenharmony_ci } 601cb93a386Sopenharmony_ci 602cb93a386Sopenharmony_ci void showFrame(SkCanvas* canvas, const SkPoint pts[], int count, const SkPaint& p) { 603cb93a386Sopenharmony_ci SkPaint paint(p); 604cb93a386Sopenharmony_ci SkPoint storage[3 + 2 + 1]; 605cb93a386Sopenharmony_ci SkPoint* tmp = storage; 606cb93a386Sopenharmony_ci const SkPoint* prev = pts; 607cb93a386Sopenharmony_ci for (int n = count; n > 0; --n) { 608cb93a386Sopenharmony_ci for (int i = 0; i < n; ++i) { 609cb93a386Sopenharmony_ci canvas->drawLine(prev[i], prev[i+1], paint); 610cb93a386Sopenharmony_ci tmp[i] = lerp(prev[i], prev[i+1], fT); 611cb93a386Sopenharmony_ci } 612cb93a386Sopenharmony_ci prev = tmp; 613cb93a386Sopenharmony_ci tmp += n; 614cb93a386Sopenharmony_ci } 615cb93a386Sopenharmony_ci 616cb93a386Sopenharmony_ci paint.setColor(SK_ColorBLUE); 617cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kFill_Style); 618cb93a386Sopenharmony_ci int n = tmp - storage; 619cb93a386Sopenharmony_ci for (int i = 0; i < n; ++i) { 620cb93a386Sopenharmony_ci Dot(canvas, storage[i], 4, SK_ColorBLUE); 621cb93a386Sopenharmony_ci } 622cb93a386Sopenharmony_ci } 623cb93a386Sopenharmony_ci 624cb93a386Sopenharmony_ci void showFlattness(SkCanvas* canvas) { 625cb93a386Sopenharmony_ci SkPaint paint; 626cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kStroke_Style); 627cb93a386Sopenharmony_ci paint.setAntiAlias(true); 628cb93a386Sopenharmony_ci 629cb93a386Sopenharmony_ci SkPaint paint2(paint); 630cb93a386Sopenharmony_ci paint2.setColor(0xFF008800); 631cb93a386Sopenharmony_ci 632cb93a386Sopenharmony_ci paint.setColor(0xFF888888); 633cb93a386Sopenharmony_ci canvas->drawLine(fPts[0], fPts[3], paint); 634cb93a386Sopenharmony_ci canvas->drawLine(fQuad[0], fQuad[2], paint); 635cb93a386Sopenharmony_ci 636cb93a386Sopenharmony_ci paint.setColor(0xFF0000FF); 637cb93a386Sopenharmony_ci SkPoint pts[2]; 638cb93a386Sopenharmony_ci pts[0] = (fQuad[0] + fQuad[1] + fQuad[1] + fQuad[2])*0.25; 639cb93a386Sopenharmony_ci pts[1] = (fQuad[0] + fQuad[2]) * 0.5; 640cb93a386Sopenharmony_ci canvas->drawLine(pts[0], pts[1], paint); 641cb93a386Sopenharmony_ci 642cb93a386Sopenharmony_ci // cubic 643cb93a386Sopenharmony_ci 644cb93a386Sopenharmony_ci SkVector v0 = (fPts[0] - fPts[1] - fPts[1] + fPts[2]) * fScale; 645cb93a386Sopenharmony_ci SkVector v1 = (fPts[1] - fPts[2] - fPts[2] + fPts[3]) * fScale; 646cb93a386Sopenharmony_ci SkVector v = (v0 + v1) * 0.5f; 647cb93a386Sopenharmony_ci 648cb93a386Sopenharmony_ci SkPoint anchor; 649cb93a386Sopenharmony_ci SkScalar ts[2]; 650cb93a386Sopenharmony_ci int n = find_max_deviation_cubic(fPts, ts); 651cb93a386Sopenharmony_ci if (n > 0) { 652cb93a386Sopenharmony_ci SkEvalCubicAt(fPts, ts[0], &anchor, nullptr, nullptr); 653cb93a386Sopenharmony_ci canvas->drawLine(anchor, anchor + v, paint2); 654cb93a386Sopenharmony_ci canvas->drawLine(anchor, anchor + v0, paint); 655cb93a386Sopenharmony_ci if (n == 2) { 656cb93a386Sopenharmony_ci SkEvalCubicAt(fPts, ts[1], &anchor, nullptr, nullptr); 657cb93a386Sopenharmony_ci canvas->drawLine(anchor, anchor + v, paint2); 658cb93a386Sopenharmony_ci } 659cb93a386Sopenharmony_ci canvas->drawLine(anchor, anchor + v1, paint); 660cb93a386Sopenharmony_ci } 661cb93a386Sopenharmony_ci // not sure we can get here 662cb93a386Sopenharmony_ci } 663cb93a386Sopenharmony_ci 664cb93a386Sopenharmony_ci void showInnerQuads(SkCanvas* canvas) { 665cb93a386Sopenharmony_ci auto draw_quad = [canvas](SkPoint a, SkPoint b, SkPoint c, SkColor color) { 666cb93a386Sopenharmony_ci SkPaint paint; 667cb93a386Sopenharmony_ci paint.setAntiAlias(true); 668cb93a386Sopenharmony_ci paint.setStroke(true); 669cb93a386Sopenharmony_ci paint.setColor(color); 670cb93a386Sopenharmony_ci 671cb93a386Sopenharmony_ci canvas->drawPath(SkPathBuilder().moveTo(a).quadTo(b, c).detach(), paint); 672cb93a386Sopenharmony_ci }; 673cb93a386Sopenharmony_ci 674cb93a386Sopenharmony_ci SkPoint p0 = SkEvalQuadAt(&fPts[0], fT), 675cb93a386Sopenharmony_ci p1 = SkEvalQuadAt(&fPts[1], fT), 676cb93a386Sopenharmony_ci p2 = lerp(p0, p1, fT); 677cb93a386Sopenharmony_ci 678cb93a386Sopenharmony_ci draw_quad(fPts[0], fPts[1], fPts[2], SK_ColorRED); 679cb93a386Sopenharmony_ci Dot(canvas, p0, 4, SK_ColorRED); 680cb93a386Sopenharmony_ci 681cb93a386Sopenharmony_ci draw_quad(fPts[1], fPts[2], fPts[3], SK_ColorBLUE); 682cb93a386Sopenharmony_ci Dot(canvas, p1, 4, SK_ColorBLUE); 683cb93a386Sopenharmony_ci 684cb93a386Sopenharmony_ci SkPaint paint; 685cb93a386Sopenharmony_ci paint.setAntiAlias(true); 686cb93a386Sopenharmony_ci paint.setColor(0xFF008800); 687cb93a386Sopenharmony_ci canvas->drawLine(p0, p1, paint); 688cb93a386Sopenharmony_ci Dot(canvas, p2, 4, 0xFF00AA00); 689cb93a386Sopenharmony_ci } 690cb93a386Sopenharmony_ci 691cb93a386Sopenharmony_ci void onDrawContent(SkCanvas* canvas) override { 692cb93a386Sopenharmony_ci SkPaint paint; 693cb93a386Sopenharmony_ci paint.setAntiAlias(true); 694cb93a386Sopenharmony_ci 695cb93a386Sopenharmony_ci { 696cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kStroke_Style); 697cb93a386Sopenharmony_ci SkPath path; 698cb93a386Sopenharmony_ci path.moveTo(fPts[0]); 699cb93a386Sopenharmony_ci path.cubicTo(fPts[1], fPts[2], fPts[3]); 700cb93a386Sopenharmony_ci path.moveTo(fQuad[0]); 701cb93a386Sopenharmony_ci path.quadTo(fQuad[1], fQuad[2]); 702cb93a386Sopenharmony_ci canvas->drawPath(path, paint); 703cb93a386Sopenharmony_ci } 704cb93a386Sopenharmony_ci 705cb93a386Sopenharmony_ci if (fShowSub) { 706cb93a386Sopenharmony_ci paint.setColor(SK_ColorRED); 707cb93a386Sopenharmony_ci paint.setStrokeWidth(1.7f); 708cb93a386Sopenharmony_ci this->showFrame(canvas, fPts, 3, paint); 709cb93a386Sopenharmony_ci this->showFrame(canvas, fQuad, 2, paint); 710cb93a386Sopenharmony_ci 711cb93a386Sopenharmony_ci paint.setColor(SK_ColorBLACK); 712cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kFill_Style); 713cb93a386Sopenharmony_ci SkFont font(nullptr, 20); 714cb93a386Sopenharmony_ci canvas->drawString(SkStringPrintf("t = %g", fT), 20, 20, font, paint); 715cb93a386Sopenharmony_ci } 716cb93a386Sopenharmony_ci 717cb93a386Sopenharmony_ci if (fShowFlatness) { 718cb93a386Sopenharmony_ci this->showFlattness(canvas); 719cb93a386Sopenharmony_ci } 720cb93a386Sopenharmony_ci 721cb93a386Sopenharmony_ci if (fShowInnerQuads) { 722cb93a386Sopenharmony_ci this->showInnerQuads(canvas); 723cb93a386Sopenharmony_ci } 724cb93a386Sopenharmony_ci 725cb93a386Sopenharmony_ci paint.setColor(SK_ColorGRAY); 726cb93a386Sopenharmony_ci paint.setStroke(true); 727cb93a386Sopenharmony_ci canvas->drawPath(SkPathBuilder().addPolygon(fPts, 4, false).detach(), paint); 728cb93a386Sopenharmony_ci canvas->drawPath(SkPathBuilder().addPolygon(fQuad, 3, false).detach(), paint); 729cb93a386Sopenharmony_ci 730cb93a386Sopenharmony_ci for (SkPoint p : fPts) { 731cb93a386Sopenharmony_ci Dot(canvas, p, 7, SK_ColorBLACK); 732cb93a386Sopenharmony_ci } 733cb93a386Sopenharmony_ci 734cb93a386Sopenharmony_ci if (false) { 735cb93a386Sopenharmony_ci SkScalar ts[2]; 736cb93a386Sopenharmony_ci int n = SkFindCubicInflections(fPts, ts); 737cb93a386Sopenharmony_ci for (int i = 0; i < n; ++i) { 738cb93a386Sopenharmony_ci SkPoint p; 739cb93a386Sopenharmony_ci SkEvalCubicAt(fPts, ts[i], &p, nullptr, nullptr); 740cb93a386Sopenharmony_ci canvas->drawCircle(p.fX, p.fY, 3, paint); 741cb93a386Sopenharmony_ci } 742cb93a386Sopenharmony_ci } 743cb93a386Sopenharmony_ci 744cb93a386Sopenharmony_ci } 745cb93a386Sopenharmony_ci 746cb93a386Sopenharmony_ci Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override { 747cb93a386Sopenharmony_ci const SkScalar tol = 8; 748cb93a386Sopenharmony_ci const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2); 749cb93a386Sopenharmony_ci for (int i = 0; i < N; ++i) { 750cb93a386Sopenharmony_ci if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) { 751cb93a386Sopenharmony_ci return new Click([this, i](Click* c) { 752cb93a386Sopenharmony_ci fPts[i] = c->fCurr; 753cb93a386Sopenharmony_ci return true; 754cb93a386Sopenharmony_ci }); 755cb93a386Sopenharmony_ci } 756cb93a386Sopenharmony_ci } 757cb93a386Sopenharmony_ci return this->INHERITED::onFindClickHandler(x, y, modi); 758cb93a386Sopenharmony_ci } 759cb93a386Sopenharmony_ci 760cb93a386Sopenharmony_ciprivate: 761cb93a386Sopenharmony_ci using INHERITED = Sample; 762cb93a386Sopenharmony_ci}; 763cb93a386Sopenharmony_ciDEF_SAMPLE( return new CubicCurve2; ) 764cb93a386Sopenharmony_ci 765