| /* | |
| * Copyright 2017 Google LLC | |
| * | |
| * 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 defined(SK_GANESH) | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkFont.h" | |
| #include "include/core/SkPaint.h" | |
| #include "include/core/SkPath.h" | |
| #include "include/core/SkPathBuilder.h" | |
| #include "src/core/SkGeometry.h" | |
| #include "tools/fonts/FontToolUtils.h" | |
| #include "tools/viewer/ClickHandlerSlide.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 StrokeVerbSlide : public ClickHandlerSlide { | |
| public: | |
| StrokeVerbSlide() { fName = "StrokeVerb"; } | |
| void load(SkScalar w, SkScalar h) override { this->updatePath(); } | |
| void draw(SkCanvas*) override; | |
| bool onChar(SkUnichar) override; | |
| protected: | |
| class Click; | |
| ClickHandlerSlide::Click* onFindClickHandler(SkScalar x, SkScalar y, | |
| skui::ModifierKey) override; | |
| bool onClick(ClickHandlerSlide::Click*) override; | |
| private: | |
| 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 StrokeVerbSlide::draw(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, {fPoints, 4}, pointsPaint); | |
| } else { | |
| canvas->drawPoints(SkCanvas::kPoints_PointMode, {fPoints, 2}, pointsPaint); | |
| canvas->drawPoints(SkCanvas::kPoints_PointMode, {fPoints + 3, 1}, pointsPaint); | |
| } | |
| SkFont font(ToolUtils::DefaultTypeface(), 20); | |
| SkPaint captionPaint; | |
| captionPaint.setColor(SK_ColorWHITE); | |
| canvas->drawString(caption, 10, 30, font, captionPaint); | |
| } | |
| void StrokeVerbSlide::updatePath() { | |
| SkPathBuilder builder; | |
| builder.moveTo(fPoints[0]); | |
| switch (fVerbType) { | |
| case VerbType::kCubics: | |
| builder.cubicTo(fPoints[1], fPoints[2], fPoints[3]); | |
| break; | |
| case VerbType::kQuadratics: | |
| builder.quadTo(fPoints[1], fPoints[3]); | |
| break; | |
| case VerbType::kConics: | |
| builder.conicTo(fPoints[1], fPoints[3], fConicWeight); | |
| break; | |
| case VerbType::kTriangles: | |
| builder.lineTo(fPoints[1]); | |
| builder.lineTo(fPoints[3]); | |
| builder.close(); | |
| break; | |
| } | |
| fPath = builder.detach(); | |
| } | |
| class StrokeVerbSlide::Click : public ClickHandlerSlide::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; | |
| }; | |
| ClickHandlerSlide::Click* StrokeVerbSlide::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 StrokeVerbSlide::onClick(ClickHandlerSlide::Click* click) { | |
| Click* myClick = (Click*)click; | |
| myClick->doClick(fPoints); | |
| this->updateAndInval(); | |
| return true; | |
| } | |
| bool StrokeVerbSlide::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 == '=') { | |
| *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_SLIDE(return new StrokeVerbSlide;) | |
| #endif // defined(SK_GANESH) |