1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2012 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/SkBlendMode.h" 9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 10cb93a386Sopenharmony_ci#include "include/core/SkColor.h" 11cb93a386Sopenharmony_ci#include "include/core/SkFont.h" 12cb93a386Sopenharmony_ci#include "include/core/SkImageInfo.h" 13cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h" 14cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 15cb93a386Sopenharmony_ci#include "include/core/SkPath.h" 16cb93a386Sopenharmony_ci#include "include/core/SkPathMeasure.h" 17cb93a386Sopenharmony_ci#include "include/core/SkPoint.h" 18cb93a386Sopenharmony_ci#include "include/core/SkRRect.h" 19cb93a386Sopenharmony_ci#include "include/core/SkRect.h" 20cb93a386Sopenharmony_ci#include "include/core/SkRefCnt.h" 21cb93a386Sopenharmony_ci#include "include/core/SkScalar.h" 22cb93a386Sopenharmony_ci#include "include/core/SkShader.h" 23cb93a386Sopenharmony_ci#include "include/core/SkString.h" 24cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 25cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 26cb93a386Sopenharmony_ci#include "include/private/SkTArray.h" 27cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 28cb93a386Sopenharmony_ci#include "include/utils/SkTextUtils.h" 29cb93a386Sopenharmony_ci#include "samplecode/Sample.h" 30cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h" 31cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h" 32cb93a386Sopenharmony_ci#include "src/core/SkPointPriv.h" 33cb93a386Sopenharmony_ci#include "src/core/SkStroke.h" 34cb93a386Sopenharmony_ci#include "tools/ToolUtils.h" 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_ci#include <cfloat> 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ciclass SkEvent; 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_cistatic bool hittest(const SkPoint& target, SkScalar x, SkScalar y) { 41cb93a386Sopenharmony_ci const SkScalar TOL = 7; 42cb93a386Sopenharmony_ci return SkPoint::Distance(target, SkPoint::Make(x, y)) <= TOL; 43cb93a386Sopenharmony_ci} 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_cistatic int getOnCurvePoints(const SkPath& path, SkPoint storage[]) { 46cb93a386Sopenharmony_ci int count = 0; 47cb93a386Sopenharmony_ci for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) { 48cb93a386Sopenharmony_ci switch (verb) { 49cb93a386Sopenharmony_ci case SkPathVerb::kMove: 50cb93a386Sopenharmony_ci case SkPathVerb::kLine: 51cb93a386Sopenharmony_ci case SkPathVerb::kQuad: 52cb93a386Sopenharmony_ci case SkPathVerb::kConic: 53cb93a386Sopenharmony_ci case SkPathVerb::kCubic: 54cb93a386Sopenharmony_ci storage[count++] = pts[0]; 55cb93a386Sopenharmony_ci break; 56cb93a386Sopenharmony_ci default: 57cb93a386Sopenharmony_ci break; 58cb93a386Sopenharmony_ci } 59cb93a386Sopenharmony_ci } 60cb93a386Sopenharmony_ci return count; 61cb93a386Sopenharmony_ci} 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_cistatic void getContourCounts(const SkPath& path, SkTArray<int>* contourCounts) { 64cb93a386Sopenharmony_ci int count = 0; 65cb93a386Sopenharmony_ci for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) { 66cb93a386Sopenharmony_ci switch (verb) { 67cb93a386Sopenharmony_ci case SkPathVerb::kMove: 68cb93a386Sopenharmony_ci case SkPathVerb::kLine: 69cb93a386Sopenharmony_ci count += 1; 70cb93a386Sopenharmony_ci break; 71cb93a386Sopenharmony_ci case SkPathVerb::kQuad: 72cb93a386Sopenharmony_ci case SkPathVerb::kConic: 73cb93a386Sopenharmony_ci count += 2; 74cb93a386Sopenharmony_ci break; 75cb93a386Sopenharmony_ci case SkPathVerb::kCubic: 76cb93a386Sopenharmony_ci count += 3; 77cb93a386Sopenharmony_ci break; 78cb93a386Sopenharmony_ci case SkPathVerb::kClose: 79cb93a386Sopenharmony_ci contourCounts->push_back(count); 80cb93a386Sopenharmony_ci count = 0; 81cb93a386Sopenharmony_ci break; 82cb93a386Sopenharmony_ci default: 83cb93a386Sopenharmony_ci break; 84cb93a386Sopenharmony_ci } 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci if (count > 0) { 87cb93a386Sopenharmony_ci contourCounts->push_back(count); 88cb93a386Sopenharmony_ci } 89cb93a386Sopenharmony_ci} 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_cistatic void erase(const sk_sp<SkSurface>& surface) { 92cb93a386Sopenharmony_ci SkCanvas* canvas = surface->getCanvas(); 93cb93a386Sopenharmony_ci if (canvas) { 94cb93a386Sopenharmony_ci canvas->clear(SK_ColorTRANSPARENT); 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci} 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_cistruct StrokeTypeButton { 99cb93a386Sopenharmony_ci SkRect fBounds; 100cb93a386Sopenharmony_ci char fLabel; 101cb93a386Sopenharmony_ci bool fEnabled; 102cb93a386Sopenharmony_ci}; 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_cistruct CircleTypeButton : public StrokeTypeButton { 105cb93a386Sopenharmony_ci bool fFill; 106cb93a386Sopenharmony_ci}; 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ciclass QuadStrokerView : public Sample { 109cb93a386Sopenharmony_ci enum { 110cb93a386Sopenharmony_ci SKELETON_COLOR = 0xFF0000FF, 111cb93a386Sopenharmony_ci WIREFRAME_COLOR = 0x80FF0000 112cb93a386Sopenharmony_ci }; 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci enum { 115cb93a386Sopenharmony_ci kCount = 18 116cb93a386Sopenharmony_ci }; 117cb93a386Sopenharmony_ci SkPoint fPts[kCount]; 118cb93a386Sopenharmony_ci SkRect fWeightControl; 119cb93a386Sopenharmony_ci SkRect fRadiusControl; 120cb93a386Sopenharmony_ci SkRect fErrorControl; 121cb93a386Sopenharmony_ci SkRect fWidthControl; 122cb93a386Sopenharmony_ci SkRect fBounds; 123cb93a386Sopenharmony_ci SkMatrix fMatrix, fInverse; 124cb93a386Sopenharmony_ci sk_sp<SkShader> fShader; 125cb93a386Sopenharmony_ci sk_sp<SkSurface> fMinSurface; 126cb93a386Sopenharmony_ci sk_sp<SkSurface> fMaxSurface; 127cb93a386Sopenharmony_ci StrokeTypeButton fCubicButton; 128cb93a386Sopenharmony_ci StrokeTypeButton fConicButton; 129cb93a386Sopenharmony_ci StrokeTypeButton fQuadButton; 130cb93a386Sopenharmony_ci StrokeTypeButton fArcButton; 131cb93a386Sopenharmony_ci StrokeTypeButton fRRectButton; 132cb93a386Sopenharmony_ci CircleTypeButton fCircleButton; 133cb93a386Sopenharmony_ci StrokeTypeButton fTextButton; 134cb93a386Sopenharmony_ci SkString fText; 135cb93a386Sopenharmony_ci SkScalar fTextSize; 136cb93a386Sopenharmony_ci SkScalar fWeight; 137cb93a386Sopenharmony_ci SkScalar fRadius; 138cb93a386Sopenharmony_ci SkScalar fWidth, fDWidth; 139cb93a386Sopenharmony_ci SkScalar fWidthScale; 140cb93a386Sopenharmony_ci int fW, fH, fZoom; 141cb93a386Sopenharmony_ci bool fAnimate; 142cb93a386Sopenharmony_ci bool fDrawRibs; 143cb93a386Sopenharmony_ci bool fDrawTangents; 144cb93a386Sopenharmony_ci bool fDrawTDivs; 145cb93a386Sopenharmony_ci#ifdef SK_DEBUG 146cb93a386Sopenharmony_ci #define kStrokerErrorMin 0.001f 147cb93a386Sopenharmony_ci #define kStrokerErrorMax 5 148cb93a386Sopenharmony_ci#endif 149cb93a386Sopenharmony_ci #define kWidthMin 1 150cb93a386Sopenharmony_ci #define kWidthMax 100 151cb93a386Sopenharmony_cipublic: 152cb93a386Sopenharmony_ci QuadStrokerView() { 153cb93a386Sopenharmony_ci this->setBGColor(SK_ColorLTGRAY); 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci fPts[0].set(50, 200); // cubic 156cb93a386Sopenharmony_ci fPts[1].set(50, 100); 157cb93a386Sopenharmony_ci fPts[2].set(150, 50); 158cb93a386Sopenharmony_ci fPts[3].set(300, 50); 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci fPts[4].set(350, 200); // conic 161cb93a386Sopenharmony_ci fPts[5].set(350, 100); 162cb93a386Sopenharmony_ci fPts[6].set(450, 50); 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ci fPts[7].set(150, 300); // quad 165cb93a386Sopenharmony_ci fPts[8].set(150, 200); 166cb93a386Sopenharmony_ci fPts[9].set(250, 150); 167cb93a386Sopenharmony_ci 168cb93a386Sopenharmony_ci fPts[10].set(250, 200); // arc 169cb93a386Sopenharmony_ci fPts[11].set(250, 300); 170cb93a386Sopenharmony_ci fPts[12].set(150, 350); 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_ci fPts[13].set(200, 200); // rrect 173cb93a386Sopenharmony_ci fPts[14].set(400, 400); 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_ci fPts[15].set(250, 250); // oval 176cb93a386Sopenharmony_ci fPts[16].set(450, 450); 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci fText = "a"; 179cb93a386Sopenharmony_ci fTextSize = 12; 180cb93a386Sopenharmony_ci fWidth = 50; 181cb93a386Sopenharmony_ci fDWidth = 0.25f; 182cb93a386Sopenharmony_ci fWeight = 1; 183cb93a386Sopenharmony_ci fRadius = 150; 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci fCubicButton.fLabel = 'C'; 186cb93a386Sopenharmony_ci fCubicButton.fEnabled = false; 187cb93a386Sopenharmony_ci fConicButton.fLabel = 'K'; 188cb93a386Sopenharmony_ci fConicButton.fEnabled = false; 189cb93a386Sopenharmony_ci fQuadButton.fLabel = 'Q'; 190cb93a386Sopenharmony_ci fQuadButton.fEnabled = false; 191cb93a386Sopenharmony_ci fArcButton.fLabel = 'A'; 192cb93a386Sopenharmony_ci fArcButton.fEnabled = true; 193cb93a386Sopenharmony_ci fRRectButton.fLabel = 'R'; 194cb93a386Sopenharmony_ci fRRectButton.fEnabled = false; 195cb93a386Sopenharmony_ci fCircleButton.fLabel = 'O'; 196cb93a386Sopenharmony_ci fCircleButton.fEnabled = true; 197cb93a386Sopenharmony_ci fCircleButton.fFill = true; 198cb93a386Sopenharmony_ci fTextButton.fLabel = 'T'; 199cb93a386Sopenharmony_ci fTextButton.fEnabled = false; 200cb93a386Sopenharmony_ci fAnimate = false; 201cb93a386Sopenharmony_ci setAsNeeded(); 202cb93a386Sopenharmony_ci } 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_ciprotected: 205cb93a386Sopenharmony_ci SkString name() override { return SkString("QuadStroker"); } 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_ci bool onChar(SkUnichar uni) override { 208cb93a386Sopenharmony_ci if (fTextButton.fEnabled) { 209cb93a386Sopenharmony_ci switch (uni) { 210cb93a386Sopenharmony_ci case ' ': 211cb93a386Sopenharmony_ci fText = ""; 212cb93a386Sopenharmony_ci break; 213cb93a386Sopenharmony_ci case '-': 214cb93a386Sopenharmony_ci fTextSize = std::max(1.0f, fTextSize - 1); 215cb93a386Sopenharmony_ci break; 216cb93a386Sopenharmony_ci case '+': 217cb93a386Sopenharmony_ci case '=': 218cb93a386Sopenharmony_ci fTextSize += 1; 219cb93a386Sopenharmony_ci break; 220cb93a386Sopenharmony_ci default: 221cb93a386Sopenharmony_ci fText.appendUnichar(uni); 222cb93a386Sopenharmony_ci } 223cb93a386Sopenharmony_ci return true; 224cb93a386Sopenharmony_ci } 225cb93a386Sopenharmony_ci return false; 226cb93a386Sopenharmony_ci } 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci void onSizeChange() override { 229cb93a386Sopenharmony_ci fRadiusControl.setXYWH(this->width() - 200, 30, 30, 400); 230cb93a386Sopenharmony_ci fWeightControl.setXYWH(this->width() - 150, 30, 30, 400); 231cb93a386Sopenharmony_ci fErrorControl.setXYWH(this->width() - 100, 30, 30, 400); 232cb93a386Sopenharmony_ci fWidthControl.setXYWH(this->width() - 50, 30, 30, 400); 233cb93a386Sopenharmony_ci int buttonOffset = 450; 234cb93a386Sopenharmony_ci fCubicButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30); 235cb93a386Sopenharmony_ci buttonOffset += 50; 236cb93a386Sopenharmony_ci fConicButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30); 237cb93a386Sopenharmony_ci buttonOffset += 50; 238cb93a386Sopenharmony_ci fQuadButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30); 239cb93a386Sopenharmony_ci buttonOffset += 50; 240cb93a386Sopenharmony_ci fArcButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30); 241cb93a386Sopenharmony_ci buttonOffset += 50; 242cb93a386Sopenharmony_ci fRRectButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30); 243cb93a386Sopenharmony_ci buttonOffset += 50; 244cb93a386Sopenharmony_ci fCircleButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30); 245cb93a386Sopenharmony_ci buttonOffset += 50; 246cb93a386Sopenharmony_ci fTextButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30); 247cb93a386Sopenharmony_ci this->INHERITED::onSizeChange(); 248cb93a386Sopenharmony_ci } 249cb93a386Sopenharmony_ci 250cb93a386Sopenharmony_ci void copyMinToMax() { 251cb93a386Sopenharmony_ci erase(fMaxSurface); 252cb93a386Sopenharmony_ci SkCanvas* canvas = fMaxSurface->getCanvas(); 253cb93a386Sopenharmony_ci canvas->save(); 254cb93a386Sopenharmony_ci canvas->concat(fMatrix); 255cb93a386Sopenharmony_ci fMinSurface->draw(canvas, 0, 0); 256cb93a386Sopenharmony_ci canvas->restore(); 257cb93a386Sopenharmony_ci 258cb93a386Sopenharmony_ci SkPaint paint; 259cb93a386Sopenharmony_ci paint.setBlendMode(SkBlendMode::kClear); 260cb93a386Sopenharmony_ci for (int iy = 1; iy < fH; ++iy) { 261cb93a386Sopenharmony_ci SkScalar y = SkIntToScalar(iy * fZoom); 262cb93a386Sopenharmony_ci canvas->drawLine(0, y - SK_ScalarHalf, 999, y - SK_ScalarHalf, paint); 263cb93a386Sopenharmony_ci } 264cb93a386Sopenharmony_ci for (int ix = 1; ix < fW; ++ix) { 265cb93a386Sopenharmony_ci SkScalar x = SkIntToScalar(ix * fZoom); 266cb93a386Sopenharmony_ci canvas->drawLine(x - SK_ScalarHalf, 0, x - SK_ScalarHalf, 999, paint); 267cb93a386Sopenharmony_ci } 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci 270cb93a386Sopenharmony_ci void setWHZ(int width, int height, int zoom) { 271cb93a386Sopenharmony_ci fZoom = zoom; 272cb93a386Sopenharmony_ci fBounds.setIWH(width * zoom, height * zoom); 273cb93a386Sopenharmony_ci fMatrix.setScale(SkIntToScalar(zoom), SkIntToScalar(zoom)); 274cb93a386Sopenharmony_ci fInverse.setScale(SK_Scalar1 / zoom, SK_Scalar1 / zoom); 275cb93a386Sopenharmony_ci fShader = ToolUtils::create_checkerboard_shader(0xFFCCCCCC, 0xFFFFFFFF, zoom); 276cb93a386Sopenharmony_ci 277cb93a386Sopenharmony_ci SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); 278cb93a386Sopenharmony_ci fMinSurface = SkSurface::MakeRaster(info); 279cb93a386Sopenharmony_ci info = info.makeWH(width * zoom, height * zoom); 280cb93a386Sopenharmony_ci fMaxSurface = SkSurface::MakeRaster(info); 281cb93a386Sopenharmony_ci } 282cb93a386Sopenharmony_ci 283cb93a386Sopenharmony_ci void draw_points(SkCanvas* canvas, const SkPath& path, SkColor color, 284cb93a386Sopenharmony_ci bool show_lines) { 285cb93a386Sopenharmony_ci SkPaint paint; 286cb93a386Sopenharmony_ci paint.setColor(color); 287cb93a386Sopenharmony_ci paint.setAlpha(0x80); 288cb93a386Sopenharmony_ci paint.setAntiAlias(true); 289cb93a386Sopenharmony_ci int n = path.countPoints(); 290cb93a386Sopenharmony_ci SkAutoSTArray<32, SkPoint> pts(n); 291cb93a386Sopenharmony_ci if (show_lines && fDrawTangents) { 292cb93a386Sopenharmony_ci SkTArray<int> contourCounts; 293cb93a386Sopenharmony_ci getContourCounts(path, &contourCounts); 294cb93a386Sopenharmony_ci SkPoint* ptPtr = pts.get(); 295cb93a386Sopenharmony_ci for (int i = 0; i < contourCounts.count(); ++i) { 296cb93a386Sopenharmony_ci int count = contourCounts[i]; 297cb93a386Sopenharmony_ci path.getPoints(ptPtr, count); 298cb93a386Sopenharmony_ci canvas->drawPoints(SkCanvas::kPolygon_PointMode, count, ptPtr, paint); 299cb93a386Sopenharmony_ci ptPtr += count; 300cb93a386Sopenharmony_ci } 301cb93a386Sopenharmony_ci } else { 302cb93a386Sopenharmony_ci n = getOnCurvePoints(path, pts.get()); 303cb93a386Sopenharmony_ci } 304cb93a386Sopenharmony_ci paint.setStrokeWidth(5); 305cb93a386Sopenharmony_ci canvas->drawPoints(SkCanvas::kPoints_PointMode, n, pts.get(), paint); 306cb93a386Sopenharmony_ci } 307cb93a386Sopenharmony_ci 308cb93a386Sopenharmony_ci void draw_ribs(SkCanvas* canvas, const SkPath& path, SkScalar width, 309cb93a386Sopenharmony_ci SkColor color) { 310cb93a386Sopenharmony_ci const SkScalar radius = width / 2; 311cb93a386Sopenharmony_ci 312cb93a386Sopenharmony_ci SkPathMeasure meas(path, false); 313cb93a386Sopenharmony_ci SkScalar total = meas.getLength(); 314cb93a386Sopenharmony_ci 315cb93a386Sopenharmony_ci SkScalar delta = 8; 316cb93a386Sopenharmony_ci SkPaint paint, labelP; 317cb93a386Sopenharmony_ci paint.setColor(color); 318cb93a386Sopenharmony_ci labelP.setColor(color & 0xff5f9f5f); 319cb93a386Sopenharmony_ci SkFont font; 320cb93a386Sopenharmony_ci SkPoint pos, tan; 321cb93a386Sopenharmony_ci int index = 0; 322cb93a386Sopenharmony_ci for (SkScalar dist = 0; dist <= total; dist += delta) { 323cb93a386Sopenharmony_ci if (meas.getPosTan(dist, &pos, &tan)) { 324cb93a386Sopenharmony_ci tan.scale(radius); 325cb93a386Sopenharmony_ci SkPointPriv::RotateCCW(&tan); 326cb93a386Sopenharmony_ci canvas->drawLine(pos.x() + tan.x(), pos.y() + tan.y(), 327cb93a386Sopenharmony_ci pos.x() - tan.x(), pos.y() - tan.y(), paint); 328cb93a386Sopenharmony_ci if (0 == index % 10) { 329cb93a386Sopenharmony_ci SkString label; 330cb93a386Sopenharmony_ci label.appendS32(index); 331cb93a386Sopenharmony_ci SkRect dot = SkRect::MakeXYWH(pos.x() - 2, pos.y() - 2, 4, 4); 332cb93a386Sopenharmony_ci canvas->drawRect(dot, labelP); 333cb93a386Sopenharmony_ci canvas->drawString(label, 334cb93a386Sopenharmony_ci pos.x() - tan.x() * 1.25f, pos.y() - tan.y() * 1.25f, font, labelP); 335cb93a386Sopenharmony_ci } 336cb93a386Sopenharmony_ci } 337cb93a386Sopenharmony_ci ++index; 338cb93a386Sopenharmony_ci } 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci 341cb93a386Sopenharmony_ci void draw_t_divs(SkCanvas* canvas, const SkPath& path, SkScalar width, SkColor color) { 342cb93a386Sopenharmony_ci const SkScalar radius = width / 2; 343cb93a386Sopenharmony_ci SkPaint paint; 344cb93a386Sopenharmony_ci paint.setColor(color); 345cb93a386Sopenharmony_ci SkPathMeasure meas(path, false); 346cb93a386Sopenharmony_ci SkScalar total = meas.getLength(); 347cb93a386Sopenharmony_ci SkScalar delta = 8; 348cb93a386Sopenharmony_ci int ribs = 0; 349cb93a386Sopenharmony_ci for (SkScalar dist = 0; dist <= total; dist += delta) { 350cb93a386Sopenharmony_ci ++ribs; 351cb93a386Sopenharmony_ci } 352cb93a386Sopenharmony_ci const uint8_t* verbs = SkPathPriv::VerbData(path); 353cb93a386Sopenharmony_ci if (path.countVerbs() < 2 || SkPath::kMove_Verb != verbs[0]) { 354cb93a386Sopenharmony_ci SkASSERT(0); 355cb93a386Sopenharmony_ci return; 356cb93a386Sopenharmony_ci } 357cb93a386Sopenharmony_ci auto verb = static_cast<SkPath::Verb>(verbs[1]); 358cb93a386Sopenharmony_ci SkASSERT(SkPath::kLine_Verb <= verb && verb <= SkPath::kCubic_Verb); 359cb93a386Sopenharmony_ci const SkPoint* pts = SkPathPriv::PointData(path); 360cb93a386Sopenharmony_ci SkPoint pos, tan; 361cb93a386Sopenharmony_ci for (int index = 0; index < ribs; ++index) { 362cb93a386Sopenharmony_ci SkScalar t = (SkScalar) index / ribs; 363cb93a386Sopenharmony_ci switch (verb) { 364cb93a386Sopenharmony_ci case SkPath::kLine_Verb: 365cb93a386Sopenharmony_ci tan = pts[1] - pts[0]; 366cb93a386Sopenharmony_ci pos = pts[0]; 367cb93a386Sopenharmony_ci pos.fX += tan.fX * t; 368cb93a386Sopenharmony_ci pos.fY += tan.fY * t; 369cb93a386Sopenharmony_ci break; 370cb93a386Sopenharmony_ci case SkPath::kQuad_Verb: 371cb93a386Sopenharmony_ci pos = SkEvalQuadAt(pts, t); 372cb93a386Sopenharmony_ci tan = SkEvalQuadTangentAt(pts, t); 373cb93a386Sopenharmony_ci break; 374cb93a386Sopenharmony_ci case SkPath::kConic_Verb: { 375cb93a386Sopenharmony_ci SkConic conic(pts, SkPathPriv::ConicWeightData(path)[0]); 376cb93a386Sopenharmony_ci pos = conic.evalAt(t); 377cb93a386Sopenharmony_ci tan = conic.evalTangentAt(t); 378cb93a386Sopenharmony_ci } break; 379cb93a386Sopenharmony_ci case SkPath::kCubic_Verb: 380cb93a386Sopenharmony_ci SkEvalCubicAt(pts, t, &pos, &tan, nullptr); 381cb93a386Sopenharmony_ci break; 382cb93a386Sopenharmony_ci default: 383cb93a386Sopenharmony_ci SkASSERT(0); 384cb93a386Sopenharmony_ci return; 385cb93a386Sopenharmony_ci } 386cb93a386Sopenharmony_ci tan.setLength(radius); 387cb93a386Sopenharmony_ci SkPointPriv::RotateCCW(&tan); 388cb93a386Sopenharmony_ci canvas->drawLine(pos.x() + tan.x(), pos.y() + tan.y(), 389cb93a386Sopenharmony_ci pos.x() - tan.x(), pos.y() - tan.y(), paint); 390cb93a386Sopenharmony_ci if (0 == index % 10) { 391cb93a386Sopenharmony_ci SkString label; 392cb93a386Sopenharmony_ci label.appendS32(index); 393cb93a386Sopenharmony_ci canvas->drawString(label, 394cb93a386Sopenharmony_ci pos.x() + tan.x() * 1.25f, pos.y() + tan.y() * 1.25f, SkFont(), paint); 395cb93a386Sopenharmony_ci } 396cb93a386Sopenharmony_ci } 397cb93a386Sopenharmony_ci } 398cb93a386Sopenharmony_ci 399cb93a386Sopenharmony_ci void draw_stroke(SkCanvas* canvas, const SkPath& path, SkScalar width, SkScalar scale, 400cb93a386Sopenharmony_ci bool drawText) { 401cb93a386Sopenharmony_ci if (path.isEmpty()) { 402cb93a386Sopenharmony_ci return; 403cb93a386Sopenharmony_ci } 404cb93a386Sopenharmony_ci SkRect bounds = path.getBounds(); 405cb93a386Sopenharmony_ci this->setWHZ(SkScalarCeilToInt(bounds.right()), drawText 406cb93a386Sopenharmony_ci ? SkScalarRoundToInt(scale * 3 / 2) : SkScalarRoundToInt(scale), 407cb93a386Sopenharmony_ci SkScalarRoundToInt(950.0f / scale)); 408cb93a386Sopenharmony_ci erase(fMinSurface); 409cb93a386Sopenharmony_ci SkPaint paint; 410cb93a386Sopenharmony_ci paint.setColor(0x1f1f0f0f); 411cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kStroke_Style); 412cb93a386Sopenharmony_ci paint.setStrokeWidth(width * scale * scale); 413cb93a386Sopenharmony_ci paint.setColor(0x3f0f1f3f); 414cb93a386Sopenharmony_ci if (drawText) { 415cb93a386Sopenharmony_ci fMinSurface->getCanvas()->drawPath(path, paint); 416cb93a386Sopenharmony_ci this->copyMinToMax(); 417cb93a386Sopenharmony_ci fMaxSurface->draw(canvas, 0, 0); 418cb93a386Sopenharmony_ci } 419cb93a386Sopenharmony_ci paint.setAntiAlias(true); 420cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kStroke_Style); 421cb93a386Sopenharmony_ci paint.setStrokeWidth(1); 422cb93a386Sopenharmony_ci 423cb93a386Sopenharmony_ci paint.setColor(SKELETON_COLOR); 424cb93a386Sopenharmony_ci SkPath scaled; 425cb93a386Sopenharmony_ci SkMatrix matrix; 426cb93a386Sopenharmony_ci matrix.reset(); 427cb93a386Sopenharmony_ci matrix.setScale(950 / scale, 950 / scale); 428cb93a386Sopenharmony_ci if (drawText) { 429cb93a386Sopenharmony_ci path.transform(matrix, &scaled); 430cb93a386Sopenharmony_ci } else { 431cb93a386Sopenharmony_ci scaled = path; 432cb93a386Sopenharmony_ci } 433cb93a386Sopenharmony_ci canvas->drawPath(scaled, paint); 434cb93a386Sopenharmony_ci draw_points(canvas, scaled, SKELETON_COLOR, true); 435cb93a386Sopenharmony_ci 436cb93a386Sopenharmony_ci if (fDrawRibs) { 437cb93a386Sopenharmony_ci draw_ribs(canvas, scaled, width, 0xFF00FF00); 438cb93a386Sopenharmony_ci } 439cb93a386Sopenharmony_ci 440cb93a386Sopenharmony_ci if (fDrawTDivs) { 441cb93a386Sopenharmony_ci draw_t_divs(canvas, scaled, width, 0xFF3F3F00); 442cb93a386Sopenharmony_ci } 443cb93a386Sopenharmony_ci 444cb93a386Sopenharmony_ci SkPath fill; 445cb93a386Sopenharmony_ci 446cb93a386Sopenharmony_ci SkPaint p; 447cb93a386Sopenharmony_ci p.setStyle(SkPaint::kStroke_Style); 448cb93a386Sopenharmony_ci if (drawText) { 449cb93a386Sopenharmony_ci p.setStrokeWidth(width * scale * scale); 450cb93a386Sopenharmony_ci } else { 451cb93a386Sopenharmony_ci p.setStrokeWidth(width); 452cb93a386Sopenharmony_ci } 453cb93a386Sopenharmony_ci p.getFillPath(path, &fill); 454cb93a386Sopenharmony_ci SkPath scaledFill; 455cb93a386Sopenharmony_ci if (drawText) { 456cb93a386Sopenharmony_ci fill.transform(matrix, &scaledFill); 457cb93a386Sopenharmony_ci } else { 458cb93a386Sopenharmony_ci scaledFill = fill; 459cb93a386Sopenharmony_ci } 460cb93a386Sopenharmony_ci paint.setColor(WIREFRAME_COLOR); 461cb93a386Sopenharmony_ci canvas->drawPath(scaledFill, paint); 462cb93a386Sopenharmony_ci draw_points(canvas, scaledFill, WIREFRAME_COLOR, false); 463cb93a386Sopenharmony_ci } 464cb93a386Sopenharmony_ci 465cb93a386Sopenharmony_ci void draw_fill(SkCanvas* canvas, const SkRect& rect, SkScalar width) { 466cb93a386Sopenharmony_ci if (rect.isEmpty()) { 467cb93a386Sopenharmony_ci return; 468cb93a386Sopenharmony_ci } 469cb93a386Sopenharmony_ci SkPaint paint; 470cb93a386Sopenharmony_ci paint.setColor(0x1f1f0f0f); 471cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kStroke_Style); 472cb93a386Sopenharmony_ci paint.setStrokeWidth(width); 473cb93a386Sopenharmony_ci SkPath path; 474cb93a386Sopenharmony_ci SkScalar maxSide = std::max(rect.width(), rect.height()) / 2; 475cb93a386Sopenharmony_ci SkPoint center = { rect.fLeft + maxSide, rect.fTop + maxSide }; 476cb93a386Sopenharmony_ci path.addCircle(center.fX, center.fY, maxSide); 477cb93a386Sopenharmony_ci canvas->drawPath(path, paint); 478cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kFill_Style); 479cb93a386Sopenharmony_ci path.reset(); 480cb93a386Sopenharmony_ci path.addCircle(center.fX, center.fY, maxSide - width / 2); 481cb93a386Sopenharmony_ci paint.setColor(0x3f0f1f3f); 482cb93a386Sopenharmony_ci canvas->drawPath(path, paint); 483cb93a386Sopenharmony_ci path.reset(); 484cb93a386Sopenharmony_ci path.setFillType(SkPathFillType::kEvenOdd); 485cb93a386Sopenharmony_ci path.addCircle(center.fX, center.fY, maxSide + width / 2); 486cb93a386Sopenharmony_ci SkRect outside = SkRect::MakeXYWH(center.fX - maxSide - width, center.fY - maxSide - width, 487cb93a386Sopenharmony_ci (maxSide + width) * 2, (maxSide + width) * 2); 488cb93a386Sopenharmony_ci path.addRect(outside); 489cb93a386Sopenharmony_ci canvas->drawPath(path, paint); 490cb93a386Sopenharmony_ci } 491cb93a386Sopenharmony_ci 492cb93a386Sopenharmony_ci void draw_button(SkCanvas* canvas, const StrokeTypeButton& button) { 493cb93a386Sopenharmony_ci SkPaint paint; 494cb93a386Sopenharmony_ci paint.setAntiAlias(true); 495cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kStroke_Style); 496cb93a386Sopenharmony_ci paint.setColor(button.fEnabled ? 0xFF3F0000 : 0x6F3F0000); 497cb93a386Sopenharmony_ci canvas->drawRect(button.fBounds, paint); 498cb93a386Sopenharmony_ci paint.setColor(button.fEnabled ? 0xFF3F0000 : 0x6F3F0000); 499cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kFill_Style); 500cb93a386Sopenharmony_ci SkFont font; 501cb93a386Sopenharmony_ci font.setSize(25.0f); 502cb93a386Sopenharmony_ci SkTextUtils::Draw(canvas, &button.fLabel, 1, SkTextEncoding::kUTF8, 503cb93a386Sopenharmony_ci button.fBounds.centerX(), button.fBounds.fBottom - 5, 504cb93a386Sopenharmony_ci font, paint, SkTextUtils::kCenter_Align); 505cb93a386Sopenharmony_ci } 506cb93a386Sopenharmony_ci 507cb93a386Sopenharmony_ci void draw_control(SkCanvas* canvas, const SkRect& bounds, SkScalar value, 508cb93a386Sopenharmony_ci SkScalar min, SkScalar max, const char* name) { 509cb93a386Sopenharmony_ci SkPaint paint; 510cb93a386Sopenharmony_ci paint.setAntiAlias(true); 511cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kStroke_Style); 512cb93a386Sopenharmony_ci canvas->drawRect(bounds, paint); 513cb93a386Sopenharmony_ci SkScalar scale = max - min; 514cb93a386Sopenharmony_ci SkScalar yPos = bounds.fTop + (value - min) * bounds.height() / scale; 515cb93a386Sopenharmony_ci paint.setColor(0xFFFF0000); 516cb93a386Sopenharmony_ci canvas->drawLine(bounds.fLeft - 5, yPos, bounds.fRight + 5, yPos, paint); 517cb93a386Sopenharmony_ci SkString label; 518cb93a386Sopenharmony_ci label.printf("%0.3g", value); 519cb93a386Sopenharmony_ci paint.setColor(0xFF000000); 520cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kFill_Style); 521cb93a386Sopenharmony_ci SkFont font(nullptr, 11.0f); 522cb93a386Sopenharmony_ci canvas->drawString(label, bounds.fLeft + 5, yPos - 5, font, paint); 523cb93a386Sopenharmony_ci font.setSize(13.0f); 524cb93a386Sopenharmony_ci canvas->drawString(name, bounds.fLeft, bounds.bottom() + 11, font, paint); 525cb93a386Sopenharmony_ci } 526cb93a386Sopenharmony_ci 527cb93a386Sopenharmony_ci void setForGeometry() { 528cb93a386Sopenharmony_ci fDrawRibs = true; 529cb93a386Sopenharmony_ci fDrawTangents = true; 530cb93a386Sopenharmony_ci fDrawTDivs = false; 531cb93a386Sopenharmony_ci fWidthScale = 1; 532cb93a386Sopenharmony_ci } 533cb93a386Sopenharmony_ci 534cb93a386Sopenharmony_ci void setForText() { 535cb93a386Sopenharmony_ci fDrawRibs = fDrawTangents = fDrawTDivs = false; 536cb93a386Sopenharmony_ci fWidthScale = 0.002f; 537cb93a386Sopenharmony_ci } 538cb93a386Sopenharmony_ci 539cb93a386Sopenharmony_ci void setForSingles() { 540cb93a386Sopenharmony_ci setForGeometry(); 541cb93a386Sopenharmony_ci fDrawTDivs = true; 542cb93a386Sopenharmony_ci } 543cb93a386Sopenharmony_ci 544cb93a386Sopenharmony_ci void setAsNeeded() { 545cb93a386Sopenharmony_ci if (fConicButton.fEnabled || fCubicButton.fEnabled || fQuadButton.fEnabled) { 546cb93a386Sopenharmony_ci setForSingles(); 547cb93a386Sopenharmony_ci } else if (fRRectButton.fEnabled || fCircleButton.fEnabled || fArcButton.fEnabled) { 548cb93a386Sopenharmony_ci setForGeometry(); 549cb93a386Sopenharmony_ci } else { 550cb93a386Sopenharmony_ci setForText(); 551cb93a386Sopenharmony_ci } 552cb93a386Sopenharmony_ci } 553cb93a386Sopenharmony_ci 554cb93a386Sopenharmony_ci bool arcCenter(SkPoint* center) { 555cb93a386Sopenharmony_ci SkPath path; 556cb93a386Sopenharmony_ci path.moveTo(fPts[10]); 557cb93a386Sopenharmony_ci path.arcTo(fPts[11], fPts[12], fRadius); 558cb93a386Sopenharmony_ci SkPath::Iter iter(path, false); 559cb93a386Sopenharmony_ci SkPoint pts[4]; 560cb93a386Sopenharmony_ci iter.next(pts); 561cb93a386Sopenharmony_ci if (SkPath::kLine_Verb == iter.next(pts)) { 562cb93a386Sopenharmony_ci iter.next(pts); 563cb93a386Sopenharmony_ci } 564cb93a386Sopenharmony_ci SkVector before = pts[0] - pts[1]; 565cb93a386Sopenharmony_ci SkVector after = pts[1] - pts[2]; 566cb93a386Sopenharmony_ci before.setLength(fRadius); 567cb93a386Sopenharmony_ci after.setLength(fRadius); 568cb93a386Sopenharmony_ci SkVector beforeCCW, afterCCW; 569cb93a386Sopenharmony_ci SkPointPriv::RotateCCW(before, &beforeCCW); 570cb93a386Sopenharmony_ci SkPointPriv::RotateCCW(after, &afterCCW); 571cb93a386Sopenharmony_ci beforeCCW += pts[0]; 572cb93a386Sopenharmony_ci afterCCW += pts[2]; 573cb93a386Sopenharmony_ci *center = beforeCCW; 574cb93a386Sopenharmony_ci if (SkScalarNearlyEqual(beforeCCW.fX, afterCCW.fX) 575cb93a386Sopenharmony_ci && SkScalarNearlyEqual(beforeCCW.fY, afterCCW.fY)) { 576cb93a386Sopenharmony_ci return true; 577cb93a386Sopenharmony_ci } 578cb93a386Sopenharmony_ci SkVector beforeCW, afterCW; 579cb93a386Sopenharmony_ci SkPointPriv::RotateCW(before, &beforeCW); 580cb93a386Sopenharmony_ci SkPointPriv::RotateCW(after, &afterCW); 581cb93a386Sopenharmony_ci beforeCW += pts[0]; 582cb93a386Sopenharmony_ci afterCW += pts[2]; 583cb93a386Sopenharmony_ci *center = beforeCW; 584cb93a386Sopenharmony_ci return SkScalarNearlyEqual(beforeCW.fX, afterCW.fX) 585cb93a386Sopenharmony_ci && SkScalarNearlyEqual(beforeCCW.fY, afterCW.fY); 586cb93a386Sopenharmony_ci } 587cb93a386Sopenharmony_ci 588cb93a386Sopenharmony_ci void onDrawContent(SkCanvas* canvas) override { 589cb93a386Sopenharmony_ci SkPath path; 590cb93a386Sopenharmony_ci SkScalar width = fWidth; 591cb93a386Sopenharmony_ci 592cb93a386Sopenharmony_ci if (fCubicButton.fEnabled) { 593cb93a386Sopenharmony_ci path.moveTo(fPts[0]); 594cb93a386Sopenharmony_ci path.cubicTo(fPts[1], fPts[2], fPts[3]); 595cb93a386Sopenharmony_ci setForSingles(); 596cb93a386Sopenharmony_ci draw_stroke(canvas, path, width, 950, false); 597cb93a386Sopenharmony_ci } 598cb93a386Sopenharmony_ci 599cb93a386Sopenharmony_ci if (fConicButton.fEnabled) { 600cb93a386Sopenharmony_ci path.reset(); 601cb93a386Sopenharmony_ci path.moveTo(fPts[4]); 602cb93a386Sopenharmony_ci path.conicTo(fPts[5], fPts[6], fWeight); 603cb93a386Sopenharmony_ci setForSingles(); 604cb93a386Sopenharmony_ci draw_stroke(canvas, path, width, 950, false); 605cb93a386Sopenharmony_ci } 606cb93a386Sopenharmony_ci 607cb93a386Sopenharmony_ci if (fQuadButton.fEnabled) { 608cb93a386Sopenharmony_ci path.reset(); 609cb93a386Sopenharmony_ci path.moveTo(fPts[7]); 610cb93a386Sopenharmony_ci path.quadTo(fPts[8], fPts[9]); 611cb93a386Sopenharmony_ci setForSingles(); 612cb93a386Sopenharmony_ci draw_stroke(canvas, path, width, 950, false); 613cb93a386Sopenharmony_ci } 614cb93a386Sopenharmony_ci 615cb93a386Sopenharmony_ci if (fArcButton.fEnabled) { 616cb93a386Sopenharmony_ci path.reset(); 617cb93a386Sopenharmony_ci path.moveTo(fPts[10]); 618cb93a386Sopenharmony_ci path.arcTo(fPts[11], fPts[12], fRadius); 619cb93a386Sopenharmony_ci setForGeometry(); 620cb93a386Sopenharmony_ci draw_stroke(canvas, path, width, 950, false); 621cb93a386Sopenharmony_ci SkPath pathPts; 622cb93a386Sopenharmony_ci pathPts.moveTo(fPts[10]); 623cb93a386Sopenharmony_ci pathPts.lineTo(fPts[11]); 624cb93a386Sopenharmony_ci pathPts.lineTo(fPts[12]); 625cb93a386Sopenharmony_ci draw_points(canvas, pathPts, SK_ColorDKGRAY, true); 626cb93a386Sopenharmony_ci } 627cb93a386Sopenharmony_ci 628cb93a386Sopenharmony_ci if (fRRectButton.fEnabled) { 629cb93a386Sopenharmony_ci SkScalar rad = 32; 630cb93a386Sopenharmony_ci SkRect r; 631cb93a386Sopenharmony_ci r.setBounds(&fPts[13], 2); 632cb93a386Sopenharmony_ci path.reset(); 633cb93a386Sopenharmony_ci SkRRect rr; 634cb93a386Sopenharmony_ci rr.setRectXY(r, rad, rad); 635cb93a386Sopenharmony_ci path.addRRect(rr); 636cb93a386Sopenharmony_ci setForGeometry(); 637cb93a386Sopenharmony_ci draw_stroke(canvas, path, width, 950, false); 638cb93a386Sopenharmony_ci 639cb93a386Sopenharmony_ci path.reset(); 640cb93a386Sopenharmony_ci SkRRect rr2; 641cb93a386Sopenharmony_ci rr.inset(width/2, width/2, &rr2); 642cb93a386Sopenharmony_ci path.addRRect(rr2, SkPathDirection::kCCW); 643cb93a386Sopenharmony_ci rr.inset(-width/2, -width/2, &rr2); 644cb93a386Sopenharmony_ci path.addRRect(rr2, SkPathDirection::kCW); 645cb93a386Sopenharmony_ci SkPaint paint; 646cb93a386Sopenharmony_ci paint.setAntiAlias(true); 647cb93a386Sopenharmony_ci paint.setColor(0x40FF8844); 648cb93a386Sopenharmony_ci canvas->drawPath(path, paint); 649cb93a386Sopenharmony_ci } 650cb93a386Sopenharmony_ci 651cb93a386Sopenharmony_ci if (fCircleButton.fEnabled) { 652cb93a386Sopenharmony_ci path.reset(); 653cb93a386Sopenharmony_ci SkRect r; 654cb93a386Sopenharmony_ci r.setBounds(&fPts[15], 2); 655cb93a386Sopenharmony_ci path.addOval(r); 656cb93a386Sopenharmony_ci setForGeometry(); 657cb93a386Sopenharmony_ci if (fCircleButton.fFill) { 658cb93a386Sopenharmony_ci if (fArcButton.fEnabled) { 659cb93a386Sopenharmony_ci SkPoint center; 660cb93a386Sopenharmony_ci if (arcCenter(¢er)) { 661cb93a386Sopenharmony_ci r.setLTRB(center.fX - fRadius, center.fY - fRadius, 662cb93a386Sopenharmony_ci center.fX + fRadius, center.fY + fRadius); 663cb93a386Sopenharmony_ci } 664cb93a386Sopenharmony_ci } 665cb93a386Sopenharmony_ci draw_fill(canvas, r, width); 666cb93a386Sopenharmony_ci } else { 667cb93a386Sopenharmony_ci draw_stroke(canvas, path, width, 950, false); 668cb93a386Sopenharmony_ci } 669cb93a386Sopenharmony_ci } 670cb93a386Sopenharmony_ci 671cb93a386Sopenharmony_ci if (fTextButton.fEnabled) { 672cb93a386Sopenharmony_ci path.reset(); 673cb93a386Sopenharmony_ci SkFont font; 674cb93a386Sopenharmony_ci font.setSize(fTextSize); 675cb93a386Sopenharmony_ci SkTextUtils::GetPath(fText.c_str(), fText.size(), SkTextEncoding::kUTF8, 676cb93a386Sopenharmony_ci 0, fTextSize, font, &path); 677cb93a386Sopenharmony_ci setForText(); 678cb93a386Sopenharmony_ci draw_stroke(canvas, path, width * fWidthScale / fTextSize, fTextSize, true); 679cb93a386Sopenharmony_ci } 680cb93a386Sopenharmony_ci 681cb93a386Sopenharmony_ci if (fAnimate) { 682cb93a386Sopenharmony_ci fWidth += fDWidth; 683cb93a386Sopenharmony_ci if (fDWidth > 0 && fWidth > kWidthMax) { 684cb93a386Sopenharmony_ci fDWidth = -fDWidth; 685cb93a386Sopenharmony_ci } else if (fDWidth < 0 && fWidth < kWidthMin) { 686cb93a386Sopenharmony_ci fDWidth = -fDWidth; 687cb93a386Sopenharmony_ci } 688cb93a386Sopenharmony_ci } 689cb93a386Sopenharmony_ci setAsNeeded(); 690cb93a386Sopenharmony_ci if (fConicButton.fEnabled) { 691cb93a386Sopenharmony_ci draw_control(canvas, fWeightControl, fWeight, 0, 5, "weight"); 692cb93a386Sopenharmony_ci } 693cb93a386Sopenharmony_ci if (fArcButton.fEnabled) { 694cb93a386Sopenharmony_ci draw_control(canvas, fRadiusControl, fRadius, 0, 500, "radius"); 695cb93a386Sopenharmony_ci } 696cb93a386Sopenharmony_ci#ifdef SK_DEBUG 697cb93a386Sopenharmony_ci draw_control(canvas, fErrorControl, gDebugStrokerError, kStrokerErrorMin, kStrokerErrorMax, 698cb93a386Sopenharmony_ci "error"); 699cb93a386Sopenharmony_ci#endif 700cb93a386Sopenharmony_ci draw_control(canvas, fWidthControl, fWidth * fWidthScale, kWidthMin * fWidthScale, 701cb93a386Sopenharmony_ci kWidthMax * fWidthScale, "width"); 702cb93a386Sopenharmony_ci draw_button(canvas, fQuadButton); 703cb93a386Sopenharmony_ci draw_button(canvas, fCubicButton); 704cb93a386Sopenharmony_ci draw_button(canvas, fConicButton); 705cb93a386Sopenharmony_ci draw_button(canvas, fArcButton); 706cb93a386Sopenharmony_ci draw_button(canvas, fRRectButton); 707cb93a386Sopenharmony_ci draw_button(canvas, fCircleButton); 708cb93a386Sopenharmony_ci draw_button(canvas, fTextButton); 709cb93a386Sopenharmony_ci } 710cb93a386Sopenharmony_ci 711cb93a386Sopenharmony_ci class MyClick : public Click { 712cb93a386Sopenharmony_ci public: 713cb93a386Sopenharmony_ci int fIndex; 714cb93a386Sopenharmony_ci MyClick(int index) : fIndex(index) {} 715cb93a386Sopenharmony_ci }; 716cb93a386Sopenharmony_ci 717cb93a386Sopenharmony_ci Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override { 718cb93a386Sopenharmony_ci for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); ++i) { 719cb93a386Sopenharmony_ci if (hittest(fPts[i], x, y)) { 720cb93a386Sopenharmony_ci return new MyClick((int)i); 721cb93a386Sopenharmony_ci } 722cb93a386Sopenharmony_ci } 723cb93a386Sopenharmony_ci const SkRect& rectPt = SkRect::MakeXYWH(x, y, 1, 1); 724cb93a386Sopenharmony_ci if (fWeightControl.contains(rectPt)) { 725cb93a386Sopenharmony_ci return new MyClick((int) SK_ARRAY_COUNT(fPts) + 1); 726cb93a386Sopenharmony_ci } 727cb93a386Sopenharmony_ci if (fRadiusControl.contains(rectPt)) { 728cb93a386Sopenharmony_ci return new MyClick((int) SK_ARRAY_COUNT(fPts) + 2); 729cb93a386Sopenharmony_ci } 730cb93a386Sopenharmony_ci#ifdef SK_DEBUG 731cb93a386Sopenharmony_ci if (fErrorControl.contains(rectPt)) { 732cb93a386Sopenharmony_ci return new MyClick((int) SK_ARRAY_COUNT(fPts) + 3); 733cb93a386Sopenharmony_ci } 734cb93a386Sopenharmony_ci#endif 735cb93a386Sopenharmony_ci if (fWidthControl.contains(rectPt)) { 736cb93a386Sopenharmony_ci return new MyClick((int) SK_ARRAY_COUNT(fPts) + 4); 737cb93a386Sopenharmony_ci } 738cb93a386Sopenharmony_ci if (fCubicButton.fBounds.contains(rectPt)) { 739cb93a386Sopenharmony_ci fCubicButton.fEnabled ^= true; 740cb93a386Sopenharmony_ci return new MyClick((int) SK_ARRAY_COUNT(fPts) + 5); 741cb93a386Sopenharmony_ci } 742cb93a386Sopenharmony_ci if (fConicButton.fBounds.contains(rectPt)) { 743cb93a386Sopenharmony_ci fConicButton.fEnabled ^= true; 744cb93a386Sopenharmony_ci return new MyClick((int) SK_ARRAY_COUNT(fPts) + 6); 745cb93a386Sopenharmony_ci } 746cb93a386Sopenharmony_ci if (fQuadButton.fBounds.contains(rectPt)) { 747cb93a386Sopenharmony_ci fQuadButton.fEnabled ^= true; 748cb93a386Sopenharmony_ci return new MyClick((int) SK_ARRAY_COUNT(fPts) + 7); 749cb93a386Sopenharmony_ci } 750cb93a386Sopenharmony_ci if (fArcButton.fBounds.contains(rectPt)) { 751cb93a386Sopenharmony_ci fArcButton.fEnabled ^= true; 752cb93a386Sopenharmony_ci return new MyClick((int) SK_ARRAY_COUNT(fPts) + 8); 753cb93a386Sopenharmony_ci } 754cb93a386Sopenharmony_ci if (fRRectButton.fBounds.contains(rectPt)) { 755cb93a386Sopenharmony_ci fRRectButton.fEnabled ^= true; 756cb93a386Sopenharmony_ci return new MyClick((int) SK_ARRAY_COUNT(fPts) + 9); 757cb93a386Sopenharmony_ci } 758cb93a386Sopenharmony_ci if (fCircleButton.fBounds.contains(rectPt)) { 759cb93a386Sopenharmony_ci bool wasEnabled = fCircleButton.fEnabled; 760cb93a386Sopenharmony_ci fCircleButton.fEnabled = !fCircleButton.fFill; 761cb93a386Sopenharmony_ci fCircleButton.fFill = wasEnabled && !fCircleButton.fFill; 762cb93a386Sopenharmony_ci return new MyClick((int) SK_ARRAY_COUNT(fPts) + 10); 763cb93a386Sopenharmony_ci } 764cb93a386Sopenharmony_ci if (fTextButton.fBounds.contains(rectPt)) { 765cb93a386Sopenharmony_ci fTextButton.fEnabled ^= true; 766cb93a386Sopenharmony_ci return new MyClick((int) SK_ARRAY_COUNT(fPts) + 11); 767cb93a386Sopenharmony_ci } 768cb93a386Sopenharmony_ci return nullptr; 769cb93a386Sopenharmony_ci } 770cb93a386Sopenharmony_ci 771cb93a386Sopenharmony_ci static SkScalar MapScreenYtoValue(SkScalar y, const SkRect& control, SkScalar min, 772cb93a386Sopenharmony_ci SkScalar max) { 773cb93a386Sopenharmony_ci return (y - control.fTop) / control.height() * (max - min) + min; 774cb93a386Sopenharmony_ci } 775cb93a386Sopenharmony_ci 776cb93a386Sopenharmony_ci bool onClick(Click* click) override { 777cb93a386Sopenharmony_ci int index = ((MyClick*)click)->fIndex; 778cb93a386Sopenharmony_ci if (index < (int) SK_ARRAY_COUNT(fPts)) { 779cb93a386Sopenharmony_ci fPts[index].offset(click->fCurr.fX - click->fPrev.fX, 780cb93a386Sopenharmony_ci click->fCurr.fY - click->fPrev.fY); 781cb93a386Sopenharmony_ci } else if (index == (int) SK_ARRAY_COUNT(fPts) + 1) { 782cb93a386Sopenharmony_ci fWeight = MapScreenYtoValue(click->fCurr.fY, fWeightControl, 0, 5); 783cb93a386Sopenharmony_ci } else if (index == (int) SK_ARRAY_COUNT(fPts) + 2) { 784cb93a386Sopenharmony_ci fRadius = MapScreenYtoValue(click->fCurr.fY, fRadiusControl, 0, 500); 785cb93a386Sopenharmony_ci } 786cb93a386Sopenharmony_ci#ifdef SK_DEBUG 787cb93a386Sopenharmony_ci else if (index == (int) SK_ARRAY_COUNT(fPts) + 3) { 788cb93a386Sopenharmony_ci gDebugStrokerError = std::max(FLT_EPSILON, MapScreenYtoValue(click->fCurr.fY, 789cb93a386Sopenharmony_ci fErrorControl, kStrokerErrorMin, kStrokerErrorMax)); 790cb93a386Sopenharmony_ci gDebugStrokerErrorSet = true; 791cb93a386Sopenharmony_ci } 792cb93a386Sopenharmony_ci#endif 793cb93a386Sopenharmony_ci else if (index == (int) SK_ARRAY_COUNT(fPts) + 4) { 794cb93a386Sopenharmony_ci fWidth = std::max(FLT_EPSILON, MapScreenYtoValue(click->fCurr.fY, fWidthControl, 795cb93a386Sopenharmony_ci kWidthMin, kWidthMax)); 796cb93a386Sopenharmony_ci fAnimate = fWidth <= kWidthMin; 797cb93a386Sopenharmony_ci } 798cb93a386Sopenharmony_ci return true; 799cb93a386Sopenharmony_ci } 800cb93a386Sopenharmony_ci 801cb93a386Sopenharmony_ciprivate: 802cb93a386Sopenharmony_ci using INHERITED = Sample; 803cb93a386Sopenharmony_ci}; 804cb93a386Sopenharmony_ci 805cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 806cb93a386Sopenharmony_ci 807cb93a386Sopenharmony_ciDEF_SAMPLE( return new QuadStrokerView(); ) 808