1/* 2 * Copyright 2011 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 "gm/gm.h" 9#include "include/core/SkCanvas.h" 10#include "include/core/SkColor.h" 11#include "include/core/SkFont.h" 12#include "include/core/SkPaint.h" 13#include "include/core/SkPathBuilder.h" 14#include "include/core/SkPoint.h" 15#include "include/core/SkRect.h" 16#include "include/core/SkScalar.h" 17#include "include/core/SkSize.h" 18#include "include/core/SkString.h" 19#include "include/core/SkTypeface.h" 20#include "include/core/SkTypes.h" 21#include "include/utils/SkRandom.h" 22#include "tools/ToolUtils.h" 23 24namespace skiagm { 25 26class EmptyPathGM : public GM { 27 SkString onShortName() override { return SkString("emptypath"); } 28 29 SkISize onISize() override { return {600, 280}; } 30 31 void drawEmpty(SkCanvas* canvas, 32 SkColor color, 33 const SkRect& clip, 34 SkPaint::Style style, 35 SkPathFillType fill) { 36 SkPath path; 37 path.setFillType(fill); 38 SkPaint paint; 39 paint.setColor(color); 40 paint.setStyle(style); 41 canvas->save(); 42 canvas->clipRect(clip); 43 canvas->drawPath(path, paint); 44 canvas->restore(); 45 } 46 47 void onDraw(SkCanvas* canvas) override { 48 struct FillAndName { 49 SkPathFillType fFill; 50 const char* fName; 51 }; 52 constexpr FillAndName gFills[] = { 53 {SkPathFillType::kWinding, "Winding"}, 54 {SkPathFillType::kEvenOdd, "Even / Odd"}, 55 {SkPathFillType::kInverseWinding, "Inverse Winding"}, 56 {SkPathFillType::kInverseEvenOdd, "Inverse Even / Odd"}, 57 }; 58 struct StyleAndName { 59 SkPaint::Style fStyle; 60 const char* fName; 61 }; 62 constexpr StyleAndName gStyles[] = { 63 {SkPaint::kFill_Style, "Fill"}, 64 {SkPaint::kStroke_Style, "Stroke"}, 65 {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, 66 }; 67 68 SkFont font(ToolUtils::create_portable_typeface(), 15); 69 const char title[] = "Empty Paths Drawn Into Rectangle Clips With " 70 "Indicated Style and Fill"; 71 canvas->drawString(title, 20.0f, 20.0f, font, SkPaint()); 72 73 SkRandom rand; 74 SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); 75 int i = 0; 76 canvas->save(); 77 canvas->translate(10 * SK_Scalar1, 0); 78 canvas->save(); 79 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { 80 for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { 81 if (0 == i % 4) { 82 canvas->restore(); 83 canvas->translate(0, rect.height() + 40 * SK_Scalar1); 84 canvas->save(); 85 } else { 86 canvas->translate(rect.width() + 40 * SK_Scalar1, 0); 87 } 88 ++i; 89 90 91 SkColor color = rand.nextU(); 92 color = 0xff000000 | color; // force solid 93 color = ToolUtils::color_to_565(color); 94 this->drawEmpty(canvas, color, rect, 95 gStyles[style].fStyle, gFills[fill].fFill); 96 97 SkPaint rectPaint; 98 rectPaint.setColor(SK_ColorBLACK); 99 rectPaint.setStyle(SkPaint::kStroke_Style); 100 rectPaint.setStrokeWidth(-1); 101 rectPaint.setAntiAlias(true); 102 canvas->drawRect(rect, rectPaint); 103 104 SkPaint labelPaint; 105 labelPaint.setColor(color); 106 SkFont labelFont(ToolUtils::create_portable_typeface(), 12); 107 canvas->drawString(gStyles[style].fName, 0, rect.height() + 15.0f, 108 labelFont, labelPaint); 109 canvas->drawString(gFills[fill].fName, 0, rect.height() + 28.0f, 110 labelFont, labelPaint); 111 } 112 } 113 canvas->restore(); 114 canvas->restore(); 115 } 116}; 117DEF_GM( return new EmptyPathGM; ) 118 119////////////////////////////////////////////////////////////////////////////// 120 121static constexpr int kPtsCount = 3; 122static constexpr SkPoint kPts[kPtsCount] = { 123 {40, 40}, 124 {80, 40}, 125 {120, 40}, 126}; 127 128static SkPath make_path_move() { 129 SkPathBuilder builder; 130 for (SkPoint p : kPts) { 131 builder.moveTo(p); 132 } 133 return builder.detach(); 134} 135 136static SkPath make_path_move_close() { 137 SkPathBuilder builder; 138 for (SkPoint p : kPts) { 139 builder.moveTo(p).close(); 140 } 141 return builder.detach(); 142} 143 144static SkPath make_path_move_line() { 145 SkPathBuilder builder; 146 for (SkPoint p : kPts) { 147 builder.moveTo(p).lineTo(p); 148 } 149 return builder.detach(); 150} 151 152static SkPath make_path_move_mix() { 153 return SkPathBuilder().moveTo(kPts[0]) 154 .moveTo(kPts[1]).close() 155 .moveTo(kPts[2]).lineTo(kPts[2]) 156 .detach(); 157} 158 159class EmptyStrokeGM : public GM { 160 SkString onShortName() override { return SkString("emptystroke"); } 161 162 SkISize onISize() override { return {200, 240}; } 163 164 void onDraw(SkCanvas* canvas) override { 165 static constexpr SkPath (*kProcs[])() = { 166 make_path_move, // expect red red red 167 make_path_move_close, // expect black black black 168 make_path_move_line, // expect black black black 169 make_path_move_mix, // expect red black black, 170 }; 171 172 SkPaint strokePaint; 173 strokePaint.setStyle(SkPaint::kStroke_Style); 174 strokePaint.setStrokeWidth(21); 175 strokePaint.setStrokeCap(SkPaint::kSquare_Cap); 176 177 SkPaint dotPaint; 178 dotPaint.setColor(SK_ColorRED); 179 strokePaint.setStyle(SkPaint::kStroke_Style); 180 dotPaint.setStrokeWidth(7); 181 182 for (auto proc : kProcs) { 183 canvas->drawPoints(SkCanvas::kPoints_PointMode, kPtsCount, kPts, dotPaint); 184 canvas->drawPath(proc(), strokePaint); 185 canvas->translate(0, 40); 186 } 187 } 188}; 189DEF_GM( return new EmptyStrokeGM; ) 190 191} // namespace skiagm 192