| /* | |
| * Copyright 2011 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "gm/gm.h" | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkColor.h" | |
| #include "include/core/SkFont.h" | |
| #include "include/core/SkPaint.h" | |
| #include "include/core/SkPathBuilder.h" | |
| #include "include/core/SkPoint.h" | |
| #include "include/core/SkRect.h" | |
| #include "include/core/SkScalar.h" | |
| #include "include/core/SkSize.h" | |
| #include "include/core/SkString.h" | |
| #include "include/core/SkTypeface.h" | |
| #include "include/core/SkTypes.h" | |
| #include "src/core/SkRandom.h" | |
| #include "tools/ToolUtils.h" | |
| #include "tools/fonts/FontToolUtils.h" | |
| #include <array> | |
| namespace skiagm { | |
| class EmptyPathGM : public GM { | |
| SkString getName() const override { return SkString("emptypath"); } | |
| SkISize getISize() override { return {600, 280}; } | |
| void drawEmpty(SkCanvas* canvas, | |
| SkColor color, | |
| const SkRect& clip, | |
| SkPaint::Style style, | |
| SkPathFillType fill) { | |
| SkPath path; | |
| path.setFillType(fill); | |
| SkPaint paint; | |
| paint.setColor(color); | |
| paint.setStyle(style); | |
| canvas->save(); | |
| canvas->clipRect(clip); | |
| canvas->drawPath(path, paint); | |
| canvas->restore(); | |
| } | |
| void onDraw(SkCanvas* canvas) override { | |
| struct FillAndName { | |
| SkPathFillType fFill; | |
| const char* fName; | |
| }; | |
| static constexpr auto gFills = std::to_array<FillAndName>({ | |
| FillAndName{ SkPathFillType::kWinding, "Winding"}, | |
| FillAndName{ SkPathFillType::kEvenOdd, "Even / Odd"}, | |
| FillAndName{SkPathFillType::kInverseWinding, "Inverse Winding"}, | |
| FillAndName{SkPathFillType::kInverseEvenOdd, "Inverse Even / Odd"}, | |
| }); | |
| struct StyleAndName { | |
| SkPaint::Style fStyle; | |
| const char* fName; | |
| }; | |
| static constexpr auto gStyles = std::to_array<StyleAndName>({ | |
| StyleAndName{ SkPaint::kFill_Style, "Fill"}, | |
| StyleAndName{ SkPaint::kStroke_Style, "Stroke"}, | |
| StyleAndName{SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, | |
| }); | |
| SkFont font(ToolUtils::DefaultPortableTypeface(), 15); | |
| const char title[] = "Empty Paths Drawn Into Rectangle Clips With " | |
| "Indicated Style and Fill"; | |
| canvas->drawString(title, 20.0f, 20.0f, font, SkPaint()); | |
| SkRandom rand; | |
| SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); | |
| int i = 0; | |
| canvas->save(); | |
| canvas->translate(10 * SK_Scalar1, 0); | |
| canvas->save(); | |
| for (size_t style = 0; style < std::size(gStyles); ++style) { | |
| for (size_t fill = 0; fill < std::size(gFills); ++fill) { | |
| if (0 == i % 4) { | |
| canvas->restore(); | |
| canvas->translate(0, rect.height() + 40 * SK_Scalar1); | |
| canvas->save(); | |
| } else { | |
| canvas->translate(rect.width() + 40 * SK_Scalar1, 0); | |
| } | |
| ++i; | |
| SkColor color = rand.nextU(); | |
| color = 0xff000000 | color; // force solid | |
| color = ToolUtils::color_to_565(color); | |
| this->drawEmpty(canvas, color, rect, | |
| gStyles[style].fStyle, gFills[fill].fFill); | |
| SkPaint rectPaint; | |
| rectPaint.setColor(SK_ColorBLACK); | |
| rectPaint.setStyle(SkPaint::kStroke_Style); | |
| rectPaint.setStrokeWidth(-1); | |
| rectPaint.setAntiAlias(true); | |
| canvas->drawRect(rect, rectPaint); | |
| SkPaint labelPaint; | |
| labelPaint.setColor(color); | |
| SkFont labelFont(ToolUtils::DefaultPortableTypeface(), 12); | |
| canvas->drawString(gStyles[style].fName, 0, rect.height() + 15.0f, | |
| labelFont, labelPaint); | |
| canvas->drawString(gFills[fill].fName, 0, rect.height() + 28.0f, | |
| labelFont, labelPaint); | |
| } | |
| } | |
| canvas->restore(); | |
| canvas->restore(); | |
| } | |
| }; | |
| DEF_GM( return new EmptyPathGM; ) | |
| ////////////////////////////////////////////////////////////////////////////// | |
| static constexpr SkPoint kPts[] = { | |
| {40, 40}, | |
| {80, 40}, | |
| {120, 40}, | |
| }; | |
| static SkPath make_path_move() { | |
| SkPathBuilder builder; | |
| for (SkPoint p : kPts) { | |
| builder.moveTo(p); | |
| } | |
| return builder.detach(); | |
| } | |
| static SkPath make_path_move_close() { | |
| SkPathBuilder builder; | |
| for (SkPoint p : kPts) { | |
| builder.moveTo(p).close(); | |
| } | |
| return builder.detach(); | |
| } | |
| static SkPath make_path_move_line() { | |
| SkPathBuilder builder; | |
| for (SkPoint p : kPts) { | |
| builder.moveTo(p).lineTo(p); | |
| } | |
| return builder.detach(); | |
| } | |
| static SkPath make_path_move_mix() { | |
| return SkPathBuilder().moveTo(kPts[0]) | |
| .moveTo(kPts[1]).close() | |
| .moveTo(kPts[2]).lineTo(kPts[2]) | |
| .detach(); | |
| } | |
| class EmptyStrokeGM : public GM { | |
| SkString getName() const override { return SkString("emptystroke"); } | |
| SkISize getISize() override { return {200, 240}; } | |
| void onDraw(SkCanvas* canvas) override { | |
| static constexpr SkPath (*kProcs[])() = { | |
| make_path_move, // expect red red red | |
| make_path_move_close, // expect black black black | |
| make_path_move_line, // expect black black black | |
| make_path_move_mix, // expect red black black, | |
| }; | |
| SkPaint strokePaint; | |
| strokePaint.setStyle(SkPaint::kStroke_Style); | |
| strokePaint.setStrokeWidth(21); | |
| strokePaint.setStrokeCap(SkPaint::kSquare_Cap); | |
| SkPaint dotPaint; | |
| dotPaint.setColor(SK_ColorRED); | |
| strokePaint.setStyle(SkPaint::kStroke_Style); | |
| dotPaint.setStrokeWidth(7); | |
| for (auto proc : kProcs) { | |
| canvas->drawPoints(SkCanvas::kPoints_PointMode, kPts, dotPaint); | |
| canvas->drawPath(proc(), strokePaint); | |
| canvas->translate(0, 40); | |
| } | |
| } | |
| }; | |
| DEF_GM( return new EmptyStrokeGM; ) | |
| } // namespace skiagm |