/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "include/core/SkTypes.h" #if SK_SUPPORT_GPU #include "include/core/SkCanvas.h" #include "include/core/SkFont.h" #include "include/core/SkPaint.h" #include "include/core/SkPath.h" #include "samplecode/Sample.h" #include "src/core/SkGeometry.h" enum class VerbType { kTriangles, kQuadratics, kCubics, kConics }; static const char* verb_type_name(VerbType verbType) { switch (verbType) { case VerbType::kTriangles: return "kTriangles"; case VerbType::kQuadratics: return "kQuadratics"; case VerbType::kCubics: return "kCubics"; case VerbType::kConics: return "kConics"; } SkUNREACHABLE; }; /** * This sample visualizes simple strokes. */ class CCPRGeometryView : public Sample { void onOnceBeforeDraw() override { this->updatePath(); } void onDrawContent(SkCanvas*) override; Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override; bool onClick(Sample::Click*) override; bool onChar(SkUnichar) override; SkString name() override { return SkString("StrokeVerb"); } class Click; void updateAndInval() { this->updatePath(); } void updatePath(); VerbType fVerbType = VerbType::kCubics; SkPoint fPoints[4] = { {100.05f, 100.05f}, {400.75f, 100.05f}, {400.75f, 300.95f}, {100.05f, 300.95f}}; float fConicWeight = .5; float fStrokeWidth = 40; SkPaint::Join fStrokeJoin = SkPaint::kMiter_Join; SkPaint::Cap fStrokeCap = SkPaint::kButt_Cap; SkPath fPath; }; void CCPRGeometryView::onDrawContent(SkCanvas* canvas) { canvas->clear(SK_ColorBLACK); SkPaint outlinePaint; outlinePaint.setColor(0xff808080); outlinePaint.setStyle(SkPaint::kStroke_Style); outlinePaint.setStrokeWidth(fStrokeWidth); outlinePaint.setStrokeJoin(fStrokeJoin); outlinePaint.setStrokeCap(fStrokeCap); outlinePaint.setAntiAlias(true); canvas->drawPath(fPath, outlinePaint); SkString caption; caption.appendf("VerbType_%s", verb_type_name(fVerbType)); if (VerbType::kCubics == fVerbType) { caption.appendf(" (%s)", SkCubicTypeName(SkClassifyCubic(fPoints))); } else if (VerbType::kConics == fVerbType) { caption.appendf(" (w=%f)", fConicWeight); } caption.appendf(" (stroke_width=%f)", fStrokeWidth); SkPaint pointsPaint; pointsPaint.setColor(SK_ColorBLUE); pointsPaint.setStrokeWidth(8); pointsPaint.setAntiAlias(true); if (VerbType::kCubics == fVerbType) { canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, fPoints, pointsPaint); } else { canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, fPoints, pointsPaint); canvas->drawPoints(SkCanvas::kPoints_PointMode, 1, fPoints + 3, pointsPaint); } SkFont font(nullptr, 20); SkPaint captionPaint; captionPaint.setColor(SK_ColorWHITE); canvas->drawString(caption, 10, 30, font, captionPaint); } void CCPRGeometryView::updatePath() { fPath.reset(); fPath.moveTo(fPoints[0]); switch (fVerbType) { case VerbType::kCubics: fPath.cubicTo(fPoints[1], fPoints[2], fPoints[3]); break; case VerbType::kQuadratics: fPath.quadTo(fPoints[1], fPoints[3]); break; case VerbType::kConics: fPath.conicTo(fPoints[1], fPoints[3], fConicWeight); break; case VerbType::kTriangles: fPath.lineTo(fPoints[1]); fPath.lineTo(fPoints[3]); fPath.close(); break; } } class CCPRGeometryView::Click : public Sample::Click { public: Click(int ptIdx) : fPtIdx(ptIdx) {} void doClick(SkPoint points[]) { if (fPtIdx >= 0) { points[fPtIdx] += fCurr - fPrev; } else { for (int i = 0; i < 4; ++i) { points[i] += fCurr - fPrev; } } } private: int fPtIdx; }; Sample::Click* CCPRGeometryView::onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) { for (int i = 0; i < 4; ++i) { if (VerbType::kCubics != fVerbType && 2 == i) { continue; } if (fabs(x - fPoints[i].x()) < 20 && fabsf(y - fPoints[i].y()) < 20) { return new Click(i); } } return new Click(-1); } bool CCPRGeometryView::onClick(Sample::Click* click) { Click* myClick = (Click*)click; myClick->doClick(fPoints); this->updateAndInval(); return true; } bool CCPRGeometryView::onChar(SkUnichar unichar) { if (unichar >= '1' && unichar <= '4') { fVerbType = VerbType(unichar - '1'); this->updateAndInval(); return true; } float* valueToScale = nullptr; if (VerbType::kConics == fVerbType) { valueToScale = &fConicWeight; } else { valueToScale = &fStrokeWidth; } if (valueToScale) { if (unichar == '+') { *valueToScale *= 2; this->updateAndInval(); return true; } if (unichar == '+' || unichar == '=') { *valueToScale *= 5/4.f; this->updateAndInval(); return true; } if (unichar == '-') { *valueToScale *= 4/5.f; this->updateAndInval(); return true; } if (unichar == '_') { *valueToScale *= .5f; this->updateAndInval(); return true; } } if (unichar == 'D') { SkDebugf(" SkPoint fPoints[4] = {\n"); SkDebugf(" {%ff, %ff},\n", fPoints[0].x(), fPoints[0].y()); SkDebugf(" {%ff, %ff},\n", fPoints[1].x(), fPoints[1].y()); SkDebugf(" {%ff, %ff},\n", fPoints[2].x(), fPoints[2].y()); SkDebugf(" {%ff, %ff}\n", fPoints[3].x(), fPoints[3].y()); SkDebugf(" };\n"); return true; } if (unichar == 'J') { fStrokeJoin = (SkPaint::Join)((fStrokeJoin + 1) % 3); this->updateAndInval(); return true; } if (unichar == 'C') { fStrokeCap = (SkPaint::Cap)((fStrokeCap + 1) % 3); this->updateAndInval(); return true; } return false; } DEF_SAMPLE(return new CCPRGeometryView;) #endif // SK_SUPPORT_GPU