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