188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark/*
288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark * Copyright 2012 Google Inc.
388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark *
488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark * Use of this source code is governed by a BSD-style license that can be
588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark * found in the LICENSE file.
688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark */
788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark#include "sk_tool_utils.h"
988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark#include "SampleCode.h"
1088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark#include "SkView.h"
1188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark#include "SkCanvas.h"
12b6474dd1a530a543ae799c3822e8bc60180761c0caryclark#include "SkGeometry.h"
1388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark#include "SkPathMeasure.h"
14df429f3beac1c191289ba1e3bd918bf84df57bf5Cary Clark#include "SkPointPriv.h"
1588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark#include "SkRandom.h"
1688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark#include "SkRRect.h"
1788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark#include "SkColorPriv.h"
1888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark#include "SkStrokerPriv.h"
1988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark#include "SkSurface.h"
2088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
2188c748aeea1cedfc8280d7f3da3d949ed01be177caryclarkstatic bool hittest(const SkPoint& target, SkScalar x, SkScalar y) {
2288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    const SkScalar TOL = 7;
2388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    return SkPoint::Distance(target, SkPoint::Make(x, y)) <= TOL;
2488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark}
2588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
2688c748aeea1cedfc8280d7f3da3d949ed01be177caryclarkstatic int getOnCurvePoints(const SkPath& path, SkPoint storage[]) {
2788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkPath::RawIter iter(path);
2888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkPoint pts[4];
2988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkPath::Verb verb;
3088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
3188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    int count = 0;
3288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
3388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        switch (verb) {
3488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            case SkPath::kMove_Verb:
3588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            case SkPath::kLine_Verb:
3688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            case SkPath::kQuad_Verb:
3788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            case SkPath::kConic_Verb:
3888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            case SkPath::kCubic_Verb:
3988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                storage[count++] = pts[0];
4088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                break;
4188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            default:
4288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                break;
4388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
4488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
4588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    return count;
4688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark}
4788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
4888c748aeea1cedfc8280d7f3da3d949ed01be177caryclarkstatic void getContourCounts(const SkPath& path, SkTArray<int>* contourCounts) {
4988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkPath::RawIter iter(path);
5088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkPoint pts[4];
5188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkPath::Verb verb;
5288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
5388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    int count = 0;
5488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
5588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        switch (verb) {
5688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            case SkPath::kMove_Verb:
5788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            case SkPath::kLine_Verb:
5888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                count += 1;
5988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                break;
6088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            case SkPath::kQuad_Verb:
6188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            case SkPath::kConic_Verb:
6288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                count += 2;
6388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                break;
6488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            case SkPath::kCubic_Verb:
6588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                count += 3;
6688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                break;
6788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            case SkPath::kClose_Verb:
6888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                contourCounts->push_back(count);
6988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                count = 0;
7088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                break;
7188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            default:
7288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                break;
7388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
7488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
7588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    if (count > 0) {
7688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        contourCounts->push_back(count);
7788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
7888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark}
7988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
80e8f3062a36d3682f4019309a32b5b84dc9eddf8creedstatic void erase(const sk_sp<SkSurface>& surface) {
8188651aeb551fb02003a7600679e8e7df8a589e7fcaryclark    SkCanvas* canvas = surface->getCanvas();
8288651aeb551fb02003a7600679e8e7df8a589e7fcaryclark    if (canvas) {
8388651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        canvas->clear(SK_ColorTRANSPARENT);
8488651aeb551fb02003a7600679e8e7df8a589e7fcaryclark    }
8588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark}
8688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
8788c748aeea1cedfc8280d7f3da3d949ed01be177caryclarkstruct StrokeTypeButton {
8888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkRect fBounds;
8988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    char fLabel;
9088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    bool fEnabled;
9188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark};
9288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
9304e4d08556750ff6be4576a4cd4925964c63376fcaryclarkstruct CircleTypeButton : public StrokeTypeButton {
9404e4d08556750ff6be4576a4cd4925964c63376fcaryclark    bool fFill;
9504e4d08556750ff6be4576a4cd4925964c63376fcaryclark};
9604e4d08556750ff6be4576a4cd4925964c63376fcaryclark
9788c748aeea1cedfc8280d7f3da3d949ed01be177caryclarkclass QuadStrokerView : public SampleView {
9888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    enum {
9988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SKELETON_COLOR = 0xFF0000FF,
10088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        WIREFRAME_COLOR = 0x80FF0000
10188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    };
10288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
10388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    enum {
10488651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        kCount = 18
10588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    };
10688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkPoint fPts[kCount];
10704e4d08556750ff6be4576a4cd4925964c63376fcaryclark    SkRect fWeightControl;
10888651aeb551fb02003a7600679e8e7df8a589e7fcaryclark    SkRect fRadiusControl;
10988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkRect fErrorControl;
11088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkRect fWidthControl;
11188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkRect fBounds;
11288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkMatrix fMatrix, fInverse;
1138a21c9fe7f5fef9e87115defef27bd7218419f28reed    sk_sp<SkShader> fShader;
114e8f3062a36d3682f4019309a32b5b84dc9eddf8creed    sk_sp<SkSurface> fMinSurface;
115e8f3062a36d3682f4019309a32b5b84dc9eddf8creed    sk_sp<SkSurface> fMaxSurface;
11688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    StrokeTypeButton fCubicButton;
11704e4d08556750ff6be4576a4cd4925964c63376fcaryclark    StrokeTypeButton fConicButton;
11888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    StrokeTypeButton fQuadButton;
11988651aeb551fb02003a7600679e8e7df8a589e7fcaryclark    StrokeTypeButton fArcButton;
12088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    StrokeTypeButton fRRectButton;
12104e4d08556750ff6be4576a4cd4925964c63376fcaryclark    CircleTypeButton fCircleButton;
12288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    StrokeTypeButton fTextButton;
12388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkString fText;
12488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkScalar fTextSize;
12504e4d08556750ff6be4576a4cd4925964c63376fcaryclark    SkScalar fWeight;
12688651aeb551fb02003a7600679e8e7df8a589e7fcaryclark    SkScalar fRadius;
12788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkScalar fWidth, fDWidth;
12888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    SkScalar fWidthScale;
12988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    int fW, fH, fZoom;
13088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    bool fAnimate;
13188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    bool fDrawRibs;
13288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    bool fDrawTangents;
133b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    bool fDrawTDivs;
134a76b7a3b04bc0e937921a1eb38d713c619e60e4ecaryclark#ifdef SK_DEBUG
13588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    #define kStrokerErrorMin 0.001f
13688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    #define kStrokerErrorMax 5
13788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark#endif
13888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    #define kWidthMin 1
13988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    #define kWidthMax 100
14088c748aeea1cedfc8280d7f3da3d949ed01be177caryclarkpublic:
14188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    QuadStrokerView() {
14288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        this->setBGColor(SK_ColorLTGRAY);
14388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
14404e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fPts[0].set(50, 200);  // cubic
14588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fPts[1].set(50, 100);
14688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fPts[2].set(150, 50);
14788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fPts[3].set(300, 50);
14888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
14904e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fPts[4].set(350, 200);  // conic
15088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fPts[5].set(350, 100);
15188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fPts[6].set(450, 50);
15288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
15304e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fPts[7].set(150, 300);  // quad
15404e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fPts[8].set(150, 200);
15504e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fPts[9].set(250, 150);
15604e4d08556750ff6be4576a4cd4925964c63376fcaryclark
15788651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fPts[10].set(250, 200);  // arc
15888651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fPts[11].set(250, 300);
15988651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fPts[12].set(150, 350);
16088651aeb551fb02003a7600679e8e7df8a589e7fcaryclark
16188651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fPts[13].set(200, 200); // rrect
16288651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fPts[14].set(400, 400);
16304e4d08556750ff6be4576a4cd4925964c63376fcaryclark
16488651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fPts[15].set(250, 250);  // oval
16588651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fPts[16].set(450, 450);
16688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
16788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fText = "a";
16888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fTextSize = 12;
16988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fWidth = 50;
17088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fDWidth = 0.25f;
17104e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fWeight = 1;
17288651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fRadius = 150;
17388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
17488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fCubicButton.fLabel = 'C';
17588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fCubicButton.fEnabled = false;
17604e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fConicButton.fLabel = 'K';
17788651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fConicButton.fEnabled = false;
17888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fQuadButton.fLabel = 'Q';
17988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fQuadButton.fEnabled = false;
18088651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fArcButton.fLabel = 'A';
18188651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fArcButton.fEnabled = true;
18288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fRRectButton.fLabel = 'R';
18388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fRRectButton.fEnabled = false;
18404e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fCircleButton.fLabel = 'O';
18588651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fCircleButton.fEnabled = true;
18688651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fCircleButton.fFill = true;
18788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fTextButton.fLabel = 'T';
18804e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fTextButton.fEnabled = false;
18988651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fAnimate = false;
19088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        setAsNeeded();
19188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
19288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
19388c748aeea1cedfc8280d7f3da3d949ed01be177caryclarkprotected:
19436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onQuery(SkEvent* evt) override {
19588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (SampleCode::TitleQ(*evt)) {
19688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            SampleCode::TitleR(evt, "QuadStroker");
19788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            return true;
19888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
19988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkUnichar uni;
20088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (fTextButton.fEnabled && SampleCode::CharQ(*evt, &uni)) {
20188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            switch (uni) {
20288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                case ' ':
20388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                    fText = "";
20488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                    break;
20588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                case '-':
20688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                    fTextSize = SkTMax(1.0f, fTextSize - 1);
20788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                    break;
20888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                case '+':
20988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                case '=':
21088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                    fTextSize += 1;
21188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                    break;
21288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                default:
21388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                    fText.appendUnichar(uni);
21488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            }
21588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            return true;
21688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
21788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        return this->INHERITED::onQuery(evt);
21888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
21988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
22036352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onSizeChange() override {
22188651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fRadiusControl.setXYWH(this->width() - 200, 30, 30, 400);
22204e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fWeightControl.setXYWH(this->width() - 150, 30, 30, 400);
22388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fErrorControl.setXYWH(this->width() - 100, 30, 30, 400);
22488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fWidthControl.setXYWH(this->width() -  50, 30, 30, 400);
22504e4d08556750ff6be4576a4cd4925964c63376fcaryclark        int buttonOffset = 450;
22604e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fCubicButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30);
22704e4d08556750ff6be4576a4cd4925964c63376fcaryclark        buttonOffset += 50;
22804e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fConicButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30);
22904e4d08556750ff6be4576a4cd4925964c63376fcaryclark        buttonOffset += 50;
23004e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fQuadButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30);
23104e4d08556750ff6be4576a4cd4925964c63376fcaryclark        buttonOffset += 50;
23288651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        fArcButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30);
23388651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        buttonOffset += 50;
23404e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fRRectButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30);
23504e4d08556750ff6be4576a4cd4925964c63376fcaryclark        buttonOffset += 50;
23604e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fCircleButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30);
23704e4d08556750ff6be4576a4cd4925964c63376fcaryclark        buttonOffset += 50;
23804e4d08556750ff6be4576a4cd4925964c63376fcaryclark        fTextButton.fBounds.setXYWH(this->width() - 50, SkIntToScalar(buttonOffset), 30, 30);
23988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        this->INHERITED::onSizeChange();
24088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
24188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
24288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark     void copyMinToMax() {
24388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        erase(fMaxSurface);
24488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkCanvas* canvas = fMaxSurface->getCanvas();
24588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        canvas->save();
24688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        canvas->concat(fMatrix);
24796fcdcc219d2a0d3579719b84b28bede76efba64halcanary        fMinSurface->draw(canvas, 0, 0, nullptr);
24888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        canvas->restore();
24988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
25088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkPaint paint;
251374772bd61951f01bf84fe17bf53d8867681c9aereed        paint.setBlendMode(SkBlendMode::kClear);
25288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        for (int iy = 1; iy < fH; ++iy) {
25388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            SkScalar y = SkIntToScalar(iy * fZoom);
25488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            canvas->drawLine(0, y - SK_ScalarHalf, 999, y - SK_ScalarHalf, paint);
25588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
25688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        for (int ix = 1; ix < fW; ++ix) {
25788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            SkScalar x = SkIntToScalar(ix * fZoom);
25888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            canvas->drawLine(x - SK_ScalarHalf, 0, x - SK_ScalarHalf, 999, paint);
25988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
26088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
26188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
26288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark   void setWHZ(int width, int height, int zoom) {
26388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fZoom = zoom;
26488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fBounds.set(0, 0, SkIntToScalar(width * zoom), SkIntToScalar(height * zoom));
26588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fMatrix.setScale(SkIntToScalar(zoom), SkIntToScalar(zoom));
26688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fInverse.setScale(SK_Scalar1 / zoom, SK_Scalar1 / zoom);
2678a21c9fe7f5fef9e87115defef27bd7218419f28reed        fShader = sk_tool_utils::create_checkerboard_shader(0xFFCCCCCC, 0xFFFFFFFF, zoom);
26888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
26988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
270e8f3062a36d3682f4019309a32b5b84dc9eddf8creed        fMinSurface = SkSurface::MakeRaster(info);
27188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        info = info.makeWH(width * zoom, height * zoom);
272e8f3062a36d3682f4019309a32b5b84dc9eddf8creed        fMaxSurface = SkSurface::MakeRaster(info);
27388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
27488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
27588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    void draw_points(SkCanvas* canvas, const SkPath& path, SkColor color,
27688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                     bool show_lines) {
27788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkPaint paint;
27888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setColor(color);
27988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setAlpha(0x80);
28088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setAntiAlias(true);
28188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        int n = path.countPoints();
28288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkAutoSTArray<32, SkPoint> pts(n);
28388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (show_lines && fDrawTangents) {
28488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            SkTArray<int> contourCounts;
28588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            getContourCounts(path, &contourCounts);
28688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            SkPoint* ptPtr = pts.get();
28788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            for (int i = 0; i < contourCounts.count(); ++i) {
28888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                int count = contourCounts[i];
28988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                path.getPoints(ptPtr, count);
29088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                canvas->drawPoints(SkCanvas::kPolygon_PointMode, count, ptPtr, paint);
29188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                ptPtr += count;
29288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            }
29388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        } else {
29488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            n = getOnCurvePoints(path, pts.get());
29588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
29688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setStrokeWidth(5);
29788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        canvas->drawPoints(SkCanvas::kPoints_PointMode, n, pts.get(), paint);
29888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
29988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
30088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    void draw_ribs(SkCanvas* canvas, const SkPath& path, SkScalar width,
30188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                   SkColor color) {
30288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        const SkScalar radius = width / 2;
30388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
30488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkPathMeasure meas(path, false);
30588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkScalar total = meas.getLength();
30688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
30788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkScalar delta = 8;
308b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        SkPaint paint, labelP;
30988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setColor(color);
310b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        labelP.setColor(color & 0xff5f9f5f);
31188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkPoint pos, tan;
312b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        int index = 0;
31388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        for (SkScalar dist = 0; dist <= total; dist += delta) {
31488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            if (meas.getPosTan(dist, &pos, &tan)) {
31588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                tan.scale(radius);
316df429f3beac1c191289ba1e3bd918bf84df57bf5Cary Clark                SkPointPriv::RotateCCW(&tan);
31788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                canvas->drawLine(pos.x() + tan.x(), pos.y() + tan.y(),
31888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                                 pos.x() - tan.x(), pos.y() - tan.y(), paint);
319b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                if (0 == index % 10) {
320b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    SkString label;
321b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    label.appendS32(index);
322b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    SkRect dot = SkRect::MakeXYWH(pos.x() - 2, pos.y() - 2, 4, 4);
323b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    canvas->drawRect(dot, labelP);
3242a475eae622adc1e8fa29206be1eaf862c23548eCary Clark                    canvas->drawString(label,
325b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                        pos.x() - tan.x() * 1.25f, pos.y() - tan.y() * 1.25f, labelP);
326b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                }
327b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            }
328b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            ++index;
329b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        }
330b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    }
331b6474dd1a530a543ae799c3822e8bc60180761c0caryclark
332b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    void draw_t_divs(SkCanvas* canvas, const SkPath& path, SkScalar width, SkColor color) {
333b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        const SkScalar radius = width / 2;
334b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        SkPaint paint;
335b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        paint.setColor(color);
336b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        SkPathMeasure meas(path, false);
337b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        SkScalar total = meas.getLength();
338b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        SkScalar delta = 8;
339b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        int ribs = 0;
340b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        for (SkScalar dist = 0; dist <= total; dist += delta) {
341b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            ++ribs;
342b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        }
343b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        SkPath::RawIter iter(path);
344b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        SkPoint pts[4];
345b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        if (SkPath::kMove_Verb != iter.next(pts)) {
346b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            SkASSERT(0);
347b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            return;
348b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        }
349b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        SkPath::Verb verb = iter.next(pts);
350b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        SkASSERT(SkPath::kLine_Verb <= verb && verb <= SkPath::kCubic_Verb);
351b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        SkPoint pos, tan;
352b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        for (int index = 0; index < ribs; ++index) {
353b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            SkScalar t = (SkScalar) index / ribs;
354b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            switch (verb) {
355b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                case SkPath::kLine_Verb:
356b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    tan = pts[1] - pts[0];
357b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    pos = pts[0];
358b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    pos.fX += tan.fX * t;
359b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    pos.fY += tan.fY * t;
360b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    break;
361b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                case SkPath::kQuad_Verb:
362b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    pos = SkEvalQuadAt(pts, t);
363b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    tan = SkEvalQuadTangentAt(pts, t);
364b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    break;
365b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                case SkPath::kConic_Verb: {
366b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    SkConic conic(pts, iter.conicWeight());
367b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    pos = conic.evalAt(t);
368b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    tan = conic.evalTangentAt(t);
369b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    } break;
370b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                case SkPath::kCubic_Verb:
371b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    SkEvalCubicAt(pts, t, &pos, &tan, nullptr);
372b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    break;
373b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                default:
374b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    SkASSERT(0);
375b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    return;
376b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            }
377b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            tan.setLength(radius);
378df429f3beac1c191289ba1e3bd918bf84df57bf5Cary Clark            SkPointPriv::RotateCCW(&tan);
379b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            canvas->drawLine(pos.x() + tan.x(), pos.y() + tan.y(),
380b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                                pos.x() - tan.x(), pos.y() - tan.y(), paint);
381b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            if (0 == index % 10) {
382b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                SkString label;
383b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                label.appendS32(index);
3842a475eae622adc1e8fa29206be1eaf862c23548eCary Clark                canvas->drawString(label,
385b6474dd1a530a543ae799c3822e8bc60180761c0caryclark                    pos.x() + tan.x() * 1.25f, pos.y() + tan.y() * 1.25f, paint);
38688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            }
38788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
38888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
38988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
39004e4d08556750ff6be4576a4cd4925964c63376fcaryclark    void draw_stroke(SkCanvas* canvas, const SkPath& path, SkScalar width, SkScalar scale,
39104e4d08556750ff6be4576a4cd4925964c63376fcaryclark            bool drawText) {
392612f70d5fa2d4bf7a393c791966bbce933407017caryclark        if (path.isEmpty()) {
39388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            return;
39488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
395612f70d5fa2d4bf7a393c791966bbce933407017caryclark        SkRect bounds = path.getBounds();
3969d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary        this->setWHZ(SkScalarCeilToInt(bounds.right()), drawText
39704e4d08556750ff6be4576a4cd4925964c63376fcaryclark                ? SkScalarRoundToInt(scale * 3 / 2) : SkScalarRoundToInt(scale),
39804e4d08556750ff6be4576a4cd4925964c63376fcaryclark                SkScalarRoundToInt(950.0f / scale));
39988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        erase(fMinSurface);
40088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkPaint paint;
40188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setColor(0x1f1f0f0f);
40288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setStyle(SkPaint::kStroke_Style);
40304e4d08556750ff6be4576a4cd4925964c63376fcaryclark        paint.setStrokeWidth(width * scale * scale);
40488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setColor(0x3f0f1f3f);
40504e4d08556750ff6be4576a4cd4925964c63376fcaryclark        if (drawText) {
40604e4d08556750ff6be4576a4cd4925964c63376fcaryclark            fMinSurface->getCanvas()->drawPath(path, paint);
40704e4d08556750ff6be4576a4cd4925964c63376fcaryclark            this->copyMinToMax();
40896fcdcc219d2a0d3579719b84b28bede76efba64halcanary            fMaxSurface->draw(canvas, 0, 0, nullptr);
40904e4d08556750ff6be4576a4cd4925964c63376fcaryclark        }
41088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setAntiAlias(true);
41188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setStyle(SkPaint::kStroke_Style);
41288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setStrokeWidth(1);
41388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
41488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setColor(SKELETON_COLOR);
41588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkPath scaled;
41688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkMatrix matrix;
41788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        matrix.reset();
41804e4d08556750ff6be4576a4cd4925964c63376fcaryclark        matrix.setScale(950 / scale, 950 / scale);
41988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (drawText) {
42088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            path.transform(matrix, &scaled);
42188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        } else {
42288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            scaled = path;
42388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
42488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        canvas->drawPath(scaled, paint);
42588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        draw_points(canvas, scaled, SKELETON_COLOR, true);
42688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
42788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (fDrawRibs) {
42888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            draw_ribs(canvas, scaled, width, 0xFF00FF00);
42988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
43088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
431b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        if (fDrawTDivs) {
432b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            draw_t_divs(canvas, scaled, width, 0xFF3F3F00);
433b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        }
434b6474dd1a530a543ae799c3822e8bc60180761c0caryclark
43588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkPath fill;
43688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
43788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkPaint p;
43888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        p.setStyle(SkPaint::kStroke_Style);
43904e4d08556750ff6be4576a4cd4925964c63376fcaryclark        if (drawText) {
44004e4d08556750ff6be4576a4cd4925964c63376fcaryclark            p.setStrokeWidth(width * scale * scale);
44104e4d08556750ff6be4576a4cd4925964c63376fcaryclark        } else {
44204e4d08556750ff6be4576a4cd4925964c63376fcaryclark            p.setStrokeWidth(width);
44304e4d08556750ff6be4576a4cd4925964c63376fcaryclark        }
44488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        p.getFillPath(path, &fill);
44588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkPath scaledFill;
44688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (drawText) {
44788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            fill.transform(matrix, &scaledFill);
44888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        } else {
44988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            scaledFill = fill;
45088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
45188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setColor(WIREFRAME_COLOR);
45288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        canvas->drawPath(scaledFill, paint);
45388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        draw_points(canvas, scaledFill, WIREFRAME_COLOR, false);
45488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
45588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
45604e4d08556750ff6be4576a4cd4925964c63376fcaryclark    void draw_fill(SkCanvas* canvas, const SkRect& rect, SkScalar width) {
45704e4d08556750ff6be4576a4cd4925964c63376fcaryclark        if (rect.isEmpty()) {
45804e4d08556750ff6be4576a4cd4925964c63376fcaryclark            return;
45904e4d08556750ff6be4576a4cd4925964c63376fcaryclark        }
46004e4d08556750ff6be4576a4cd4925964c63376fcaryclark        SkPaint paint;
46104e4d08556750ff6be4576a4cd4925964c63376fcaryclark        paint.setColor(0x1f1f0f0f);
46204e4d08556750ff6be4576a4cd4925964c63376fcaryclark        paint.setStyle(SkPaint::kStroke_Style);
46304e4d08556750ff6be4576a4cd4925964c63376fcaryclark        paint.setStrokeWidth(width);
46404e4d08556750ff6be4576a4cd4925964c63376fcaryclark        SkPath path;
46504e4d08556750ff6be4576a4cd4925964c63376fcaryclark        SkScalar maxSide = SkTMax(rect.width(), rect.height()) / 2;
46604e4d08556750ff6be4576a4cd4925964c63376fcaryclark        SkPoint center = { rect.fLeft + maxSide, rect.fTop + maxSide };
46704e4d08556750ff6be4576a4cd4925964c63376fcaryclark        path.addCircle(center.fX, center.fY, maxSide);
46804e4d08556750ff6be4576a4cd4925964c63376fcaryclark        canvas->drawPath(path, paint);
46904e4d08556750ff6be4576a4cd4925964c63376fcaryclark        paint.setStyle(SkPaint::kFill_Style);
47004e4d08556750ff6be4576a4cd4925964c63376fcaryclark        path.reset();
47104e4d08556750ff6be4576a4cd4925964c63376fcaryclark        path.addCircle(center.fX, center.fY, maxSide - width / 2);
47204e4d08556750ff6be4576a4cd4925964c63376fcaryclark        paint.setColor(0x3f0f1f3f);
47304e4d08556750ff6be4576a4cd4925964c63376fcaryclark        canvas->drawPath(path, paint);
47404e4d08556750ff6be4576a4cd4925964c63376fcaryclark        path.reset();
47504e4d08556750ff6be4576a4cd4925964c63376fcaryclark        path.setFillType(SkPath::kEvenOdd_FillType);
47604e4d08556750ff6be4576a4cd4925964c63376fcaryclark        path.addCircle(center.fX, center.fY, maxSide + width / 2);
4779d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary        SkRect outside = SkRect::MakeXYWH(center.fX - maxSide - width, center.fY - maxSide - width,
47804e4d08556750ff6be4576a4cd4925964c63376fcaryclark                (maxSide + width) * 2, (maxSide + width) * 2);
47904e4d08556750ff6be4576a4cd4925964c63376fcaryclark        path.addRect(outside);
48004e4d08556750ff6be4576a4cd4925964c63376fcaryclark        canvas->drawPath(path, paint);
48104e4d08556750ff6be4576a4cd4925964c63376fcaryclark    }
48204e4d08556750ff6be4576a4cd4925964c63376fcaryclark
48388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    void draw_button(SkCanvas* canvas, const StrokeTypeButton& button) {
48488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkPaint paint;
48588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setAntiAlias(true);
48688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setStyle(SkPaint::kStroke_Style);
48788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setColor(button.fEnabled ? 0xFF3F0000 : 0x6F3F0000);
48888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        canvas->drawRect(button.fBounds, paint);
48988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setTextSize(25.0f);
49088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setColor(button.fEnabled ? 0xFF3F0000 : 0x6F3F0000);
49188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setTextAlign(SkPaint::kCenter_Align);
49288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setStyle(SkPaint::kFill_Style);
49388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        canvas->drawText(&button.fLabel, 1, button.fBounds.centerX(), button.fBounds.fBottom - 5,
49488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                paint);
49588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
49688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
49788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    void draw_control(SkCanvas* canvas, const SkRect& bounds, SkScalar value,
49888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            SkScalar min, SkScalar max, const char* name) {
49988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkPaint paint;
50088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setAntiAlias(true);
50188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setStyle(SkPaint::kStroke_Style);
50288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        canvas->drawRect(bounds, paint);
50388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkScalar scale = max - min;
50488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkScalar yPos = bounds.fTop + (value - min) * bounds.height() / scale;
50588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setColor(0xFFFF0000);
50688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        canvas->drawLine(bounds.fLeft - 5, yPos, bounds.fRight + 5, yPos, paint);
50788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkString label;
50888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        label.printf("%0.3g", value);
50988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setColor(0xFF000000);
51088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setTextSize(11.0f);
51188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setStyle(SkPaint::kFill_Style);
5122a475eae622adc1e8fa29206be1eaf862c23548eCary Clark        canvas->drawString(label, bounds.fLeft + 5, yPos - 5, paint);
51388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        paint.setTextSize(13.0f);
5142a475eae622adc1e8fa29206be1eaf862c23548eCary Clark        canvas->drawString(name, bounds.fLeft, bounds.bottom() + 11, paint);
51588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
51688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
51788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    void setForGeometry() {
51888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fDrawRibs = true;
51988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fDrawTangents = true;
520b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        fDrawTDivs = false;
52188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fWidthScale = 1;
52288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
52388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
52488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    void setForText() {
525b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        fDrawRibs = fDrawTangents = fDrawTDivs = false;
52688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        fWidthScale = 0.002f;
52788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
52888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
529b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    void setForSingles() {
530b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        setForGeometry();
531b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        fDrawTDivs = true;
532b6474dd1a530a543ae799c3822e8bc60180761c0caryclark    }
533b6474dd1a530a543ae799c3822e8bc60180761c0caryclark
53488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    void setAsNeeded() {
535b6474dd1a530a543ae799c3822e8bc60180761c0caryclark        if (fConicButton.fEnabled || fCubicButton.fEnabled || fQuadButton.fEnabled) {
536b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            setForSingles();
53788651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        } else if (fRRectButton.fEnabled || fCircleButton.fEnabled || fArcButton.fEnabled) {
53888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            setForGeometry();
53988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        } else {
54088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            setForText();
54188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
54288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
54388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
54488651aeb551fb02003a7600679e8e7df8a589e7fcaryclark    bool arcCenter(SkPoint* center) {
54588651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        SkPath path;
54688651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        path.moveTo(fPts[10]);
54788651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        path.arcTo(fPts[11], fPts[12], fRadius);
54888651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        SkPath::Iter iter(path, false);
54988651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        SkPoint pts[4];
55088651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        iter.next(pts);
55188651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        if (SkPath::kLine_Verb == iter.next(pts)) {
55288651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            iter.next(pts);
55388651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        }
55488651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        SkVector before = pts[0] - pts[1];
55588651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        SkVector after = pts[1] - pts[2];
55688651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        before.setLength(fRadius);
55788651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        after.setLength(fRadius);
55888651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        SkVector beforeCCW, afterCCW;
559df429f3beac1c191289ba1e3bd918bf84df57bf5Cary Clark        SkPointPriv::RotateCCW(before, &beforeCCW);
560df429f3beac1c191289ba1e3bd918bf84df57bf5Cary Clark        SkPointPriv::RotateCCW(after, &afterCCW);
56188651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        beforeCCW += pts[0];
56288651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        afterCCW += pts[2];
56388651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        *center = beforeCCW;
56488651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        if (SkScalarNearlyEqual(beforeCCW.fX, afterCCW.fX)
56588651aeb551fb02003a7600679e8e7df8a589e7fcaryclark                && SkScalarNearlyEqual(beforeCCW.fY, afterCCW.fY)) {
56688651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            return true;
56788651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        }
56888651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        SkVector beforeCW, afterCW;
569df429f3beac1c191289ba1e3bd918bf84df57bf5Cary Clark        SkPointPriv::RotateCW(before, &beforeCW);
570df429f3beac1c191289ba1e3bd918bf84df57bf5Cary Clark        SkPointPriv::RotateCW(after, &afterCW);
57188651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        beforeCW += pts[0];
57288651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        afterCW += pts[2];
57388651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        *center = beforeCW;
57488651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        return SkScalarNearlyEqual(beforeCW.fX, afterCW.fX)
57588651aeb551fb02003a7600679e8e7df8a589e7fcaryclark                && SkScalarNearlyEqual(beforeCCW.fY, afterCW.fY);
57688651aeb551fb02003a7600679e8e7df8a589e7fcaryclark    }
57788651aeb551fb02003a7600679e8e7df8a589e7fcaryclark
57836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onDrawContent(SkCanvas* canvas) override {
57988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkPath path;
58088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        SkScalar width = fWidth;
58188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
58288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (fCubicButton.fEnabled) {
58388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            path.moveTo(fPts[0]);
58488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            path.cubicTo(fPts[1], fPts[2], fPts[3]);
585b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            setForSingles();
58604e4d08556750ff6be4576a4cd4925964c63376fcaryclark            draw_stroke(canvas, path, width, 950, false);
58704e4d08556750ff6be4576a4cd4925964c63376fcaryclark        }
58804e4d08556750ff6be4576a4cd4925964c63376fcaryclark
58904e4d08556750ff6be4576a4cd4925964c63376fcaryclark        if (fConicButton.fEnabled) {
590b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            path.reset();
59104e4d08556750ff6be4576a4cd4925964c63376fcaryclark            path.moveTo(fPts[4]);
59204e4d08556750ff6be4576a4cd4925964c63376fcaryclark            path.conicTo(fPts[5], fPts[6], fWeight);
593b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            setForSingles();
59404e4d08556750ff6be4576a4cd4925964c63376fcaryclark            draw_stroke(canvas, path, width, 950, false);
59588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
59688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
59788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (fQuadButton.fEnabled) {
59888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            path.reset();
59904e4d08556750ff6be4576a4cd4925964c63376fcaryclark            path.moveTo(fPts[7]);
60004e4d08556750ff6be4576a4cd4925964c63376fcaryclark            path.quadTo(fPts[8], fPts[9]);
601b6474dd1a530a543ae799c3822e8bc60180761c0caryclark            setForSingles();
60204e4d08556750ff6be4576a4cd4925964c63376fcaryclark            draw_stroke(canvas, path, width, 950, false);
60388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
60488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
60588651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        if (fArcButton.fEnabled) {
60688651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            path.reset();
60788651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            path.moveTo(fPts[10]);
60888651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            path.arcTo(fPts[11], fPts[12], fRadius);
60988651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            setForGeometry();
61088651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            draw_stroke(canvas, path, width, 950, false);
61188651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            SkPath pathPts;
61288651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            pathPts.moveTo(fPts[10]);
61388651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            pathPts.lineTo(fPts[11]);
61488651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            pathPts.lineTo(fPts[12]);
61588651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            draw_points(canvas, pathPts, SK_ColorDKGRAY, true);
61688651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        }
61788651aeb551fb02003a7600679e8e7df8a589e7fcaryclark
61888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (fRRectButton.fEnabled) {
61988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            SkScalar rad = 32;
62088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            SkRect r;
62188651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            r.set(&fPts[13], 2);
62288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            path.reset();
62388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            SkRRect rr;
62488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            rr.setRectXY(r, rad, rad);
62588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            path.addRRect(rr);
62688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            setForGeometry();
62704e4d08556750ff6be4576a4cd4925964c63376fcaryclark            draw_stroke(canvas, path, width, 950, false);
62888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
62988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            path.reset();
63088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            SkRRect rr2;
63188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            rr.inset(width/2, width/2, &rr2);
63288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            path.addRRect(rr2, SkPath::kCCW_Direction);
63388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            rr.inset(-width/2, -width/2, &rr2);
63488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            path.addRRect(rr2, SkPath::kCW_Direction);
63588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            SkPaint paint;
63688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            paint.setAntiAlias(true);
63788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            paint.setColor(0x40FF8844);
63888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            canvas->drawPath(path, paint);
63988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
64088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
64104e4d08556750ff6be4576a4cd4925964c63376fcaryclark        if (fCircleButton.fEnabled) {
64204e4d08556750ff6be4576a4cd4925964c63376fcaryclark            path.reset();
64304e4d08556750ff6be4576a4cd4925964c63376fcaryclark            SkRect r;
64488651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            r.set(&fPts[15], 2);
64504e4d08556750ff6be4576a4cd4925964c63376fcaryclark            path.addOval(r);
64604e4d08556750ff6be4576a4cd4925964c63376fcaryclark            setForGeometry();
64704e4d08556750ff6be4576a4cd4925964c63376fcaryclark            if (fCircleButton.fFill) {
64888651aeb551fb02003a7600679e8e7df8a589e7fcaryclark                if (fArcButton.fEnabled) {
64988651aeb551fb02003a7600679e8e7df8a589e7fcaryclark                    SkPoint center;
65088651aeb551fb02003a7600679e8e7df8a589e7fcaryclark                    if (arcCenter(&center)) {
6519d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary                        r.set(center.fX - fRadius, center.fY - fRadius, center.fX + fRadius,
65288651aeb551fb02003a7600679e8e7df8a589e7fcaryclark                                center.fY + fRadius);
65388651aeb551fb02003a7600679e8e7df8a589e7fcaryclark                    }
65488651aeb551fb02003a7600679e8e7df8a589e7fcaryclark                }
65504e4d08556750ff6be4576a4cd4925964c63376fcaryclark                draw_fill(canvas, r, width);
65604e4d08556750ff6be4576a4cd4925964c63376fcaryclark            } else {
65704e4d08556750ff6be4576a4cd4925964c63376fcaryclark                draw_stroke(canvas, path, width, 950, false);
65804e4d08556750ff6be4576a4cd4925964c63376fcaryclark            }
65904e4d08556750ff6be4576a4cd4925964c63376fcaryclark        }
66004e4d08556750ff6be4576a4cd4925964c63376fcaryclark
66188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (fTextButton.fEnabled) {
66288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            path.reset();
66388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            SkPaint paint;
66488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            paint.setAntiAlias(true);
66588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            paint.setTextSize(fTextSize);
66688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            paint.getTextPath(fText.c_str(), fText.size(), 0, fTextSize, &path);
66788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            setForText();
66804e4d08556750ff6be4576a4cd4925964c63376fcaryclark            draw_stroke(canvas, path, width * fWidthScale / fTextSize, fTextSize, true);
66988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
67088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
67188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (fAnimate) {
67288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            fWidth += fDWidth;
67388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            if (fDWidth > 0 && fWidth > kWidthMax) {
67488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                fDWidth = -fDWidth;
67588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            } else if (fDWidth < 0 && fWidth < kWidthMin) {
67688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                fDWidth = -fDWidth;
67788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            }
67888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
67988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        setAsNeeded();
68004e4d08556750ff6be4576a4cd4925964c63376fcaryclark        if (fConicButton.fEnabled) {
68104e4d08556750ff6be4576a4cd4925964c63376fcaryclark            draw_control(canvas, fWeightControl, fWeight, 0, 5, "weight");
68204e4d08556750ff6be4576a4cd4925964c63376fcaryclark        }
68388651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        if (fArcButton.fEnabled) {
68488651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            draw_control(canvas, fRadiusControl, fRadius, 0, 500, "radius");
68588651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        }
686a76b7a3b04bc0e937921a1eb38d713c619e60e4ecaryclark#ifdef SK_DEBUG
68788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        draw_control(canvas, fErrorControl, gDebugStrokerError, kStrokerErrorMin, kStrokerErrorMax,
68888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                "error");
68988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark#endif
69088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        draw_control(canvas, fWidthControl, fWidth * fWidthScale, kWidthMin * fWidthScale,
69188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                kWidthMax * fWidthScale, "width");
69288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        draw_button(canvas, fQuadButton);
69388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        draw_button(canvas, fCubicButton);
69404e4d08556750ff6be4576a4cd4925964c63376fcaryclark        draw_button(canvas, fConicButton);
69588651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        draw_button(canvas, fArcButton);
69688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        draw_button(canvas, fRRectButton);
69704e4d08556750ff6be4576a4cd4925964c63376fcaryclark        draw_button(canvas, fCircleButton);
69888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        draw_button(canvas, fTextButton);
69988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
70088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
70188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    class MyClick : public Click {
70288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    public:
70388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        int fIndex;
70488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        MyClick(SkView* target, int index) : Click(target), fIndex(index) {}
70588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    };
70688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
70788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y,
70836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein                                              unsigned modi) override {
70988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); ++i) {
71088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            if (hittest(fPts[i], x, y)) {
71188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                return new MyClick(this, (int)i);
71288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            }
71388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
71488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        const SkRect& rectPt = SkRect::MakeXYWH(x, y, 1, 1);
71504e4d08556750ff6be4576a4cd4925964c63376fcaryclark        if (fWeightControl.contains(rectPt)) {
71604e4d08556750ff6be4576a4cd4925964c63376fcaryclark            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 1);
71704e4d08556750ff6be4576a4cd4925964c63376fcaryclark        }
71888651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        if (fRadiusControl.contains(rectPt)) {
71988651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 2);
72088651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        }
721a76b7a3b04bc0e937921a1eb38d713c619e60e4ecaryclark#ifdef SK_DEBUG
72288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (fErrorControl.contains(rectPt)) {
72388651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 3);
72488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
72588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark#endif
72688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (fWidthControl.contains(rectPt)) {
72788651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 4);
72888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
72988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (fCubicButton.fBounds.contains(rectPt)) {
73088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            fCubicButton.fEnabled ^= true;
73188651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 5);
73288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
73304e4d08556750ff6be4576a4cd4925964c63376fcaryclark        if (fConicButton.fBounds.contains(rectPt)) {
73404e4d08556750ff6be4576a4cd4925964c63376fcaryclark            fConicButton.fEnabled ^= true;
73588651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 6);
73604e4d08556750ff6be4576a4cd4925964c63376fcaryclark        }
73788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (fQuadButton.fBounds.contains(rectPt)) {
73888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            fQuadButton.fEnabled ^= true;
73988651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 7);
74088651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        }
74188651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        if (fArcButton.fBounds.contains(rectPt)) {
74288651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            fArcButton.fEnabled ^= true;
74388651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 8);
74488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
74588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (fRRectButton.fBounds.contains(rectPt)) {
74688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            fRRectButton.fEnabled ^= true;
74788651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 9);
74804e4d08556750ff6be4576a4cd4925964c63376fcaryclark        }
74904e4d08556750ff6be4576a4cd4925964c63376fcaryclark        if (fCircleButton.fBounds.contains(rectPt)) {
75004e4d08556750ff6be4576a4cd4925964c63376fcaryclark            bool wasEnabled = fCircleButton.fEnabled;
75104e4d08556750ff6be4576a4cd4925964c63376fcaryclark            fCircleButton.fEnabled = !fCircleButton.fFill;
75204e4d08556750ff6be4576a4cd4925964c63376fcaryclark            fCircleButton.fFill = wasEnabled && !fCircleButton.fFill;
75388651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 10);
75488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
75588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (fTextButton.fBounds.contains(rectPt)) {
75688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            fTextButton.fEnabled ^= true;
75788651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 11);
75888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
75988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        return this->INHERITED::onFindClickHandler(x, y, modi);
76088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
76188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
76288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    static SkScalar MapScreenYtoValue(int y, const SkRect& control, SkScalar min,
76388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            SkScalar max) {
76488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        return (SkIntToScalar(y) - control.fTop) / control.height() * (max - min) + min;
76588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
76688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
76736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onClick(Click* click) override {
76888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        int index = ((MyClick*)click)->fIndex;
76988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        if (index < (int) SK_ARRAY_COUNT(fPts)) {
77088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            fPts[index].offset(SkIntToScalar(click->fICurr.fX - click->fIPrev.fX),
77188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                               SkIntToScalar(click->fICurr.fY - click->fIPrev.fY));
77204e4d08556750ff6be4576a4cd4925964c63376fcaryclark        } else if (index == (int) SK_ARRAY_COUNT(fPts) + 1) {
77304e4d08556750ff6be4576a4cd4925964c63376fcaryclark            fWeight = MapScreenYtoValue(click->fICurr.fY, fWeightControl, 0, 5);
77488651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        } else if (index == (int) SK_ARRAY_COUNT(fPts) + 2) {
77588651aeb551fb02003a7600679e8e7df8a589e7fcaryclark            fRadius = MapScreenYtoValue(click->fICurr.fY, fRadiusControl, 0, 500);
77688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
777a76b7a3b04bc0e937921a1eb38d713c619e60e4ecaryclark#ifdef SK_DEBUG
77888651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        else if (index == (int) SK_ARRAY_COUNT(fPts) + 3) {
77988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            gDebugStrokerError = SkTMax(FLT_EPSILON, MapScreenYtoValue(click->fICurr.fY,
78088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                    fErrorControl, kStrokerErrorMin, kStrokerErrorMax));
78188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            gDebugStrokerErrorSet = true;
78288c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
78388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark#endif
78488651aeb551fb02003a7600679e8e7df8a589e7fcaryclark        else if (index == (int) SK_ARRAY_COUNT(fPts) + 4) {
78588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            fWidth = SkTMax(FLT_EPSILON, MapScreenYtoValue(click->fICurr.fY, fWidthControl,
78688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark                    kWidthMin, kWidthMax));
78788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark            fAnimate = fWidth <= kWidthMin;
78888c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        }
78988c748aeea1cedfc8280d7f3da3d949ed01be177caryclark        return true;
79088c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    }
79188c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
79288c748aeea1cedfc8280d7f3da3d949ed01be177caryclarkprivate:
79388c748aeea1cedfc8280d7f3da3d949ed01be177caryclark    typedef SkView INHERITED;
79488c748aeea1cedfc8280d7f3da3d949ed01be177caryclark};
79588c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
79688c748aeea1cedfc8280d7f3da3d949ed01be177caryclark///////////////////////////////////////////////////////////////////////////////
79788c748aeea1cedfc8280d7f3da3d949ed01be177caryclark
79888c748aeea1cedfc8280d7f3da3d949ed01be177caryclarkstatic SkView* F2() { return new QuadStrokerView; }
79988c748aeea1cedfc8280d7f3da3d949ed01be177caryclarkstatic SkViewRegister gR2(F2);
800