Home | History | Annotate | Download | only in samplecode
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 #include "SampleCode.h"
      8 #include "SkView.h"
      9 #include "SkCanvas.h"
     10 #include "SkPath.h"
     11 
     12 #include <iostream>
     13 #include <cmath>
     14 
     15 #define PI SK_ScalarPI
     16 
     17 #define LIN_SEGMENTS 10
     18 
     19 class OverstrokeView : public SampleView {
     20    public:
     21     SkScalar fStroke;
     22     int fPathType;  // super lazy enum
     23     bool fClosePath;
     24     bool fDrawFillPath;
     25     bool fDumpHex;
     26     OverstrokeView() {
     27         fStroke = 5;
     28         fPathType = 0;
     29         fClosePath = false;
     30         fDrawFillPath = false;
     31         fDumpHex = false;
     32         this->setBGColor(0xFFFFFFFF);
     33     }
     34 
     35    protected:
     36     bool onQuery(SkEvent* evt) override {
     37         if (SampleCode::TitleQ(*evt)) {
     38             SampleCode::TitleR(evt, "PathOverstroke");
     39             return true;
     40         }
     41         SkUnichar uni;
     42         if (SampleCode::CharQ(*evt, &uni)) {
     43             switch (uni) {
     44                 case ',':
     45                     fStroke += 1.0;
     46                     this->inval(nullptr);
     47                     return true;
     48                 case '.':
     49                     fStroke -= 1.0;
     50                     this->inval(nullptr);
     51                     return true;
     52                 case 'x':
     53                     fPathType = (fPathType + 1) % 4;
     54                     this->inval(nullptr);
     55                     return true;
     56                 case 'c':
     57                     fClosePath = !fClosePath;
     58                     this->inval(nullptr);
     59                     return true;
     60                 case 'f':
     61                     fDrawFillPath = !fDrawFillPath;
     62                     this->inval(nullptr);
     63                     return true;
     64                 case 'D':
     65                     fDumpHex = !fDumpHex;
     66                     this->inval(nullptr);
     67                     return true;
     68                 default:
     69                     break;
     70             }
     71         }
     72         return this->INHERITED::onQuery(evt);
     73     }
     74 
     75     SkPath quadPath(SkPoint p1, SkPoint p2) {
     76         SkASSERT(p1.y() == p2.y());
     77 
     78         SkPath path;
     79         path.moveTo(p1);
     80         path.lineTo(p2);
     81 
     82         SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 2.0f, p1.y() * 0.7f);
     83 
     84         path.quadTo(p3, p1);
     85 
     86         return path;
     87     }
     88 
     89     SkPath cubicPath(SkPoint p1, SkPoint p2) {
     90         SkASSERT(p1.y() == p2.y());
     91 
     92         SkPath path;
     93         path.moveTo(p1);
     94 
     95         SkPoint p3 = SkPoint::Make((p1.x() + p2.x()) / 3.0f, p1.y() * 0.7f);
     96         SkPoint p4 = SkPoint::Make(2.0f*(p1.x() + p2.x()) / 3.0f, p1.y() * 1.5f);
     97 
     98         path.cubicTo(p3, p4, p2);
     99 
    100         return path;
    101     }
    102 
    103     SkPath linSemicirclePath(SkPoint p1, SkPoint p2) {
    104         SkASSERT(p1.y() == p2.y());
    105 
    106         SkPath path;
    107         path.moveTo(p1);
    108         path.lineTo(p2);
    109 
    110         SkPoint pt;
    111 
    112         for (int i = 0; i < LIN_SEGMENTS; i++) {
    113             float theta = i * PI / (LIN_SEGMENTS);
    114             SkScalar x = 65 + 15 * cos(theta);
    115             SkScalar y = 50 - 15 * sin(theta);
    116             pt = SkPoint::Make(x, y);
    117             path.lineTo(pt);
    118         }
    119         path.lineTo(p1);
    120 
    121         return path;
    122     }
    123 
    124     SkPath rectPath(SkPoint p1) {
    125         SkRect r = SkRect::MakeXYWH(p1.fX, p1.fY, 20, 20);
    126         SkPath path;
    127         path.addRect(r);
    128 
    129         return path;
    130     }
    131 
    132     void onDrawContent(SkCanvas* canvas) override {
    133         const float SCALE = 1;
    134 
    135         canvas->translate(30, 40);
    136         canvas->scale(SCALE, SCALE);
    137 
    138         SkPoint p1 = SkPoint::Make(50, 50);
    139         SkPoint p2 = SkPoint::Make(80, 50);
    140 
    141         SkPath path;
    142         switch (fPathType) {
    143             case 0:
    144                 path = quadPath(p1, p2);
    145                 break;
    146             case 1:
    147                 path = cubicPath(p1, p2);
    148                 break;
    149             case 2:
    150                 path = rectPath(p1);
    151                 break;
    152             case 3:
    153                 path = linSemicirclePath(p1, p2);
    154                 break;
    155             default:
    156                 path = quadPath(p1, p2);
    157                 break;
    158         }
    159 
    160         if (fClosePath) {
    161             path.close();
    162         }
    163 
    164         SkPaint p;
    165         p.setColor(SK_ColorRED);
    166         p.setAntiAlias(true);
    167         p.setStyle(SkPaint::kStroke_Style);
    168         p.setStrokeWidth(fStroke);
    169 
    170         canvas->drawPath(path, p);
    171 
    172         if (fDumpHex) {
    173             std::cerr << "path dumpHex" << std::endl;
    174             path.dumpHex();
    175         }
    176 
    177         SkPaint hairp;
    178         hairp.setColor(SK_ColorBLACK);
    179         hairp.setAntiAlias(true);
    180         hairp.setStyle(SkPaint::kStroke_Style);
    181 
    182         if (fDrawFillPath) {
    183             SkPath fillpath;
    184             p.getFillPath(path, &fillpath);
    185 
    186             canvas->drawPath(fillpath, hairp);
    187 
    188             if (fDumpHex) {
    189                 std::cerr << "fillpath dumpHex" << std::endl;
    190                 fillpath.dumpHex();
    191             }
    192         }
    193 
    194         if (fDumpHex) {
    195             std::cerr << std::endl;
    196 
    197             fDumpHex = false;
    198         }
    199 
    200         // draw original path with green hairline
    201         hairp.setColor(SK_ColorGREEN);
    202         canvas->drawPath(path, hairp);
    203     }
    204 
    205    private:
    206     typedef SampleView INHERITED;
    207 };
    208 
    209 ///////////////////////////////////////////////////////////////////////////////
    210 
    211 static SkView* MyFactory() { return new OverstrokeView; }
    212 static SkViewRegister reg(MyFactory);
    213