19bd4c693020bb440464ae12ae05e8e8f97568ee0hstern/*
29bd4c693020bb440464ae12ae05e8e8f97568ee0hstern * Copyright 2016 Google Inc.
39bd4c693020bb440464ae12ae05e8e8f97568ee0hstern *
49bd4c693020bb440464ae12ae05e8e8f97568ee0hstern * Use of this source code is governed by a BSD-style license that can be
59bd4c693020bb440464ae12ae05e8e8f97568ee0hstern * found in the LICENSE file.
69bd4c693020bb440464ae12ae05e8e8f97568ee0hstern */
79bd4c693020bb440464ae12ae05e8e8f97568ee0hstern#include "SampleCode.h"
89bd4c693020bb440464ae12ae05e8e8f97568ee0hstern#include "SkView.h"
99bd4c693020bb440464ae12ae05e8e8f97568ee0hstern#include "SkCanvas.h"
109bd4c693020bb440464ae12ae05e8e8f97568ee0hstern#include "SkPath.h"
119bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
12e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern#include <iostream>
139bd4c693020bb440464ae12ae05e8e8f97568ee0hstern#include <cmath>
149bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
159bd4c693020bb440464ae12ae05e8e8f97568ee0hstern#define PI SK_ScalarPI
169bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
179bd4c693020bb440464ae12ae05e8e8f97568ee0hstern#define LIN_SEGMENTS 10
189bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
199bd4c693020bb440464ae12ae05e8e8f97568ee0hsternclass OverstrokeView : public SampleView {
209bd4c693020bb440464ae12ae05e8e8f97568ee0hstern   public:
219bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    SkScalar fStroke;
229bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    int fPathType;  // super lazy enum
239bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    bool fClosePath;
249bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    bool fDrawFillPath;
25e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern    bool fDumpHex;
269bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    OverstrokeView() {
279bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        fStroke = 5;
289bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        fPathType = 0;
299bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        fClosePath = false;
309bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        fDrawFillPath = false;
31e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        fDumpHex = false;
329bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        this->setBGColor(0xFFFFFFFF);
339bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    }
349bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
359bd4c693020bb440464ae12ae05e8e8f97568ee0hstern   protected:
369bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    bool onQuery(SkEvent* evt) override {
379bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        if (SampleCode::TitleQ(*evt)) {
389bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            SampleCode::TitleR(evt, "PathOverstroke");
399bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            return true;
409bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        }
419bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        SkUnichar uni;
429bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        if (SampleCode::CharQ(*evt, &uni)) {
439bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            switch (uni) {
449bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                case ',':
459bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    fStroke += 1.0;
469bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    this->inval(nullptr);
479bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    return true;
489bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                case '.':
499bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    fStroke -= 1.0;
509bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    this->inval(nullptr);
519bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    return true;
529bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                case 'x':
53e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern                    fPathType = (fPathType + 1) % 4;
549bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    this->inval(nullptr);
559bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    return true;
569bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                case 'c':
579bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    fClosePath = !fClosePath;
589bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    this->inval(nullptr);
599bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    return true;
609bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                case 'f':
619bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    fDrawFillPath = !fDrawFillPath;
629bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    this->inval(nullptr);
639bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    return true;
64e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern                case 'D':
65e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern                    fDumpHex = !fDumpHex;
66e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern                    this->inval(nullptr);
67e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern                    return true;
689bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                default:
699bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                    break;
709bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            }
719bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        }
729bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        return this->INHERITED::onQuery(evt);
739bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    }
749bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
759bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    SkPath quadPath(SkPoint p1, SkPoint p2) {
769bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        SkASSERT(p1.y() == p2.y());
779bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
789bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        SkPath path;
799bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        path.moveTo(p1);
809bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        path.lineTo(p2);
819bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
829bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 2.0f, p1.y() * 0.7f);
839bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
849bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        path.quadTo(p3, p1);
859bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
869bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        return path;
879bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    }
889bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
89e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern    SkPath cubicPath(SkPoint p1, SkPoint p2) {
90e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        SkASSERT(p1.y() == p2.y());
91e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern
92e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        SkPath path;
93e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        path.moveTo(p1);
94e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern
95e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 3.0f, p1.y() * 0.7f);
96e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        SkPoint p4 = SkPoint::Make(2.0f*(p1.x() + p2.x()) / 3.0f, p1.y() * 1.5f);
97e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern
98e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        path.cubicTo(p3, p4, p2);
99e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern
100e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        return path;
101e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern    }
102e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern
1039bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    SkPath linSemicirclePath(SkPoint p1, SkPoint p2) {
1049bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        SkASSERT(p1.y() == p2.y());
1059bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
1069bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        SkPath path;
1079bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        path.moveTo(p1);
1089bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        path.lineTo(p2);
1099bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
1109bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        SkPoint pt;
1119bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
1129bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        for (int i = 0; i < LIN_SEGMENTS; i++) {
1139bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            float theta = i * PI / (LIN_SEGMENTS);
1149bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            SkScalar x = 65 + 15 * cos(theta);
1159bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            SkScalar y = 50 - 15 * sin(theta);
1169bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            pt = SkPoint::Make(x, y);
1179bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            path.lineTo(pt);
1189bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        }
1199bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        path.lineTo(p1);
1209bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
1219bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        return path;
1229bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    }
1239bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
1249bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    SkPath rectPath(SkPoint p1) {
1259bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        SkRect r = SkRect::MakeXYWH(p1.fX, p1.fY, 20, 20);
1269bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        SkPath path;
1279bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        path.addRect(r);
1289bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
1299bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        return path;
1309bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    }
1319bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
1329bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    void onDrawContent(SkCanvas* canvas) override {
1339bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        const float SCALE = 1;
1349bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
1359bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        canvas->translate(30, 40);
1369bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        canvas->scale(SCALE, SCALE);
1379bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
1389bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        SkPoint p1 = SkPoint::Make(50, 50);
1399bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        SkPoint p2 = SkPoint::Make(80, 50);
1409bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
1419bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        SkPath path;
1429bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        switch (fPathType) {
1439bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            case 0:
1449bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                path = quadPath(p1, p2);
1459bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                break;
1469bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            case 1:
147e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern                path = cubicPath(p1, p2);
1489bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                break;
1499bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            case 2:
1509bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                path = rectPath(p1);
1519bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                break;
152e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern            case 3:
153e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern                path = linSemicirclePath(p1, p2);
154e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern                break;
1559bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            default:
1569bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                path = quadPath(p1, p2);
1579bd4c693020bb440464ae12ae05e8e8f97568ee0hstern                break;
1589bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        }
1599bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
1609bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        if (fClosePath) {
1619bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            path.close();
1629bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        }
1639bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
1649bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        SkPaint p;
1659bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        p.setColor(SK_ColorRED);
1669bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        p.setAntiAlias(true);
1679bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        p.setStyle(SkPaint::kStroke_Style);
1689bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        p.setStrokeWidth(fStroke);
1699bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
1709bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        canvas->drawPath(path, p);
1719bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
172e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        if (fDumpHex) {
173e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern            std::cerr << "path dumpHex" << std::endl;
174e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern            path.dumpHex();
175e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        }
176e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern
177e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        SkPaint hairp;
178e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        hairp.setColor(SK_ColorBLACK);
179e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        hairp.setAntiAlias(true);
180e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        hairp.setStyle(SkPaint::kStroke_Style);
181e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern
1829bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        if (fDrawFillPath) {
1839bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            SkPath fillpath;
1849bd4c693020bb440464ae12ae05e8e8f97568ee0hstern            p.getFillPath(path, &fillpath);
1859bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
186e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern            canvas->drawPath(fillpath, hairp);
1879bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
188e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern            if (fDumpHex) {
189e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern                std::cerr << "fillpath dumpHex" << std::endl;
190e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern                fillpath.dumpHex();
191e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern            }
1929bd4c693020bb440464ae12ae05e8e8f97568ee0hstern        }
193e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern
194e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        if (fDumpHex) {
195e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern            std::cerr << std::endl;
196e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern
197e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern            fDumpHex = false;
198e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        }
199e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern
200e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        // draw original path with green hairline
201e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        hairp.setColor(SK_ColorGREEN);
202e2463ed91ede5e6b38cf3f93205a59f8bc3f3b44hstern        canvas->drawPath(path, hairp);
2039bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    }
2049bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
2059bd4c693020bb440464ae12ae05e8e8f97568ee0hstern   private:
2069bd4c693020bb440464ae12ae05e8e8f97568ee0hstern    typedef SampleView INHERITED;
2079bd4c693020bb440464ae12ae05e8e8f97568ee0hstern};
2089bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
2099bd4c693020bb440464ae12ae05e8e8f97568ee0hstern///////////////////////////////////////////////////////////////////////////////
2109bd4c693020bb440464ae12ae05e8e8f97568ee0hstern
2119bd4c693020bb440464ae12ae05e8e8f97568ee0hsternstatic SkView* MyFactory() { return new OverstrokeView; }
2129bd4c693020bb440464ae12ae05e8e8f97568ee0hsternstatic SkViewRegister reg(MyFactory);
213