1/* 2 * Copyright 2017 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 8#include "include/core/SkTypes.h" 9 10#if SK_SUPPORT_GPU 11 12#include "include/core/SkCanvas.h" 13#include "include/core/SkFont.h" 14#include "include/core/SkPaint.h" 15#include "include/core/SkPath.h" 16#include "samplecode/Sample.h" 17#include "src/core/SkGeometry.h" 18 19enum class VerbType { 20 kTriangles, 21 kQuadratics, 22 kCubics, 23 kConics 24}; 25 26static const char* verb_type_name(VerbType verbType) { 27 switch (verbType) { 28 case VerbType::kTriangles: return "kTriangles"; 29 case VerbType::kQuadratics: return "kQuadratics"; 30 case VerbType::kCubics: return "kCubics"; 31 case VerbType::kConics: return "kConics"; 32 } 33 SkUNREACHABLE; 34}; 35 36/** 37 * This sample visualizes simple strokes. 38 */ 39class StrokeVerbView : public Sample { 40 void onOnceBeforeDraw() override { this->updatePath(); } 41 void onDrawContent(SkCanvas*) override; 42 43 Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override; 44 bool onClick(Sample::Click*) override; 45 bool onChar(SkUnichar) override; 46 SkString name() override { return SkString("StrokeVerb"); } 47 48 class Click; 49 50 void updateAndInval() { this->updatePath(); } 51 52 void updatePath(); 53 54 VerbType fVerbType = VerbType::kCubics; 55 56 SkPoint fPoints[4] = { 57 {100.05f, 100.05f}, {400.75f, 100.05f}, {400.75f, 300.95f}, {100.05f, 300.95f}}; 58 59 float fConicWeight = .5; 60 float fStrokeWidth = 40; 61 SkPaint::Join fStrokeJoin = SkPaint::kMiter_Join; 62 SkPaint::Cap fStrokeCap = SkPaint::kButt_Cap; 63 64 SkPath fPath; 65}; 66 67void StrokeVerbView::onDrawContent(SkCanvas* canvas) { 68 canvas->clear(SK_ColorBLACK); 69 70 SkPaint outlinePaint; 71 outlinePaint.setColor(0xff808080); 72 outlinePaint.setStyle(SkPaint::kStroke_Style); 73 outlinePaint.setStrokeWidth(fStrokeWidth); 74 outlinePaint.setStrokeJoin(fStrokeJoin); 75 outlinePaint.setStrokeCap(fStrokeCap); 76 outlinePaint.setAntiAlias(true); 77 canvas->drawPath(fPath, outlinePaint); 78 79 SkString caption; 80 caption.appendf("VerbType_%s", verb_type_name(fVerbType)); 81 if (VerbType::kCubics == fVerbType) { 82 caption.appendf(" (%s)", SkCubicTypeName(SkClassifyCubic(fPoints))); 83 } else if (VerbType::kConics == fVerbType) { 84 caption.appendf(" (w=%f)", fConicWeight); 85 } 86 87 caption.appendf(" (stroke_width=%f)", fStrokeWidth); 88 89 SkPaint pointsPaint; 90 pointsPaint.setColor(SK_ColorBLUE); 91 pointsPaint.setStrokeWidth(8); 92 pointsPaint.setAntiAlias(true); 93 94 if (VerbType::kCubics == fVerbType) { 95 canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, fPoints, pointsPaint); 96 } else { 97 canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, fPoints, pointsPaint); 98 canvas->drawPoints(SkCanvas::kPoints_PointMode, 1, fPoints + 3, pointsPaint); 99 } 100 101 SkFont font(nullptr, 20); 102 SkPaint captionPaint; 103 captionPaint.setColor(SK_ColorWHITE); 104 canvas->drawString(caption, 10, 30, font, captionPaint); 105} 106 107void StrokeVerbView::updatePath() { 108 fPath.reset(); 109 fPath.moveTo(fPoints[0]); 110 switch (fVerbType) { 111 case VerbType::kCubics: 112 fPath.cubicTo(fPoints[1], fPoints[2], fPoints[3]); 113 break; 114 case VerbType::kQuadratics: 115 fPath.quadTo(fPoints[1], fPoints[3]); 116 break; 117 case VerbType::kConics: 118 fPath.conicTo(fPoints[1], fPoints[3], fConicWeight); 119 break; 120 case VerbType::kTriangles: 121 fPath.lineTo(fPoints[1]); 122 fPath.lineTo(fPoints[3]); 123 fPath.close(); 124 break; 125 } 126} 127 128class StrokeVerbView::Click : public Sample::Click { 129public: 130 Click(int ptIdx) : fPtIdx(ptIdx) {} 131 132 void doClick(SkPoint points[]) { 133 if (fPtIdx >= 0) { 134 points[fPtIdx] += fCurr - fPrev; 135 } else { 136 for (int i = 0; i < 4; ++i) { 137 points[i] += fCurr - fPrev; 138 } 139 } 140 } 141 142private: 143 int fPtIdx; 144}; 145 146Sample::Click* StrokeVerbView::onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) { 147 for (int i = 0; i < 4; ++i) { 148 if (VerbType::kCubics != fVerbType && 2 == i) { 149 continue; 150 } 151 if (fabs(x - fPoints[i].x()) < 20 && fabsf(y - fPoints[i].y()) < 20) { 152 return new Click(i); 153 } 154 } 155 return new Click(-1); 156} 157 158bool StrokeVerbView::onClick(Sample::Click* click) { 159 Click* myClick = (Click*)click; 160 myClick->doClick(fPoints); 161 this->updateAndInval(); 162 return true; 163} 164 165bool StrokeVerbView::onChar(SkUnichar unichar) { 166 if (unichar >= '1' && unichar <= '4') { 167 fVerbType = VerbType(unichar - '1'); 168 this->updateAndInval(); 169 return true; 170 } 171 float* valueToScale = nullptr; 172 if (VerbType::kConics == fVerbType) { 173 valueToScale = &fConicWeight; 174 } else { 175 valueToScale = &fStrokeWidth; 176 } 177 if (valueToScale) { 178 if (unichar == '+') { 179 *valueToScale *= 2; 180 this->updateAndInval(); 181 return true; 182 } 183 if (unichar == '+' || unichar == '=') { 184 *valueToScale *= 5/4.f; 185 this->updateAndInval(); 186 return true; 187 } 188 if (unichar == '-') { 189 *valueToScale *= 4/5.f; 190 this->updateAndInval(); 191 return true; 192 } 193 if (unichar == '_') { 194 *valueToScale *= .5f; 195 this->updateAndInval(); 196 return true; 197 } 198 } 199 if (unichar == 'D') { 200 SkDebugf(" SkPoint fPoints[4] = {\n"); 201 SkDebugf(" {%ff, %ff},\n", fPoints[0].x(), fPoints[0].y()); 202 SkDebugf(" {%ff, %ff},\n", fPoints[1].x(), fPoints[1].y()); 203 SkDebugf(" {%ff, %ff},\n", fPoints[2].x(), fPoints[2].y()); 204 SkDebugf(" {%ff, %ff}\n", fPoints[3].x(), fPoints[3].y()); 205 SkDebugf(" };\n"); 206 return true; 207 } 208 if (unichar == 'J') { 209 fStrokeJoin = (SkPaint::Join)((fStrokeJoin + 1) % 3); 210 this->updateAndInval(); 211 return true; 212 } 213 if (unichar == 'C') { 214 fStrokeCap = (SkPaint::Cap)((fStrokeCap + 1) % 3); 215 this->updateAndInval(); 216 return true; 217 } 218 return false; 219} 220 221DEF_SAMPLE(return new StrokeVerbView;) 222 223#endif // SK_SUPPORT_GPU 224