| bsalomon | 71c5eee | 2016-08-19 10:53:13 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright 2016 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 |  | 
| Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 8 | #include "gm/gm.h" | 
|  | 9 | #include "include/core/SkCanvas.h" | 
| Ben Wagner | 7fde8e1 | 2019-05-01 17:28:53 -0400 | [diff] [blame] | 10 | #include "include/core/SkColor.h" | 
|  | 11 | #include "include/core/SkPaint.h" | 
| Mike Reed | 06d7c9d | 2020-08-26 12:56:51 -0400 | [diff] [blame] | 12 | #include "include/core/SkPathBuilder.h" | 
| Ben Wagner | 7fde8e1 | 2019-05-01 17:28:53 -0400 | [diff] [blame] | 13 | #include "include/core/SkPathEffect.h" | 
|  | 14 | #include "include/core/SkRect.h" | 
|  | 15 | #include "include/core/SkScalar.h" | 
|  | 16 | #include "include/core/SkTypes.h" | 
| Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 17 | #include "include/effects/SkDashPathEffect.h" | 
| Ben Wagner | 7fde8e1 | 2019-05-01 17:28:53 -0400 | [diff] [blame] | 18 | #include "include/private/SkFloatBits.h" | 
|  | 19 | #include "include/private/SkTArray.h" | 
|  | 20 |  | 
|  | 21 | #include <functional> | 
| bsalomon | 71c5eee | 2016-08-19 10:53:13 -0700 | [diff] [blame] | 22 |  | 
| Mike Reed | 9ded74e | 2020-05-20 17:01:56 -0400 | [diff] [blame] | 23 | #include "include/effects/SkStrokeAndFillPathEffect.h" | 
|  | 24 | static void set_strokeandfill(SkPaint* paint) { | 
|  | 25 | SkASSERT(paint->getPathEffect() == nullptr); | 
|  | 26 | paint->setPathEffect(SkStrokeAndFillPathEffect::Make()); | 
|  | 27 | paint->setStroke(true); | 
|  | 28 | } | 
|  | 29 |  | 
| mtklein | dbfd7ab | 2016-09-01 11:24:54 -0700 | [diff] [blame] | 30 | constexpr SkScalar kStarts[] = {0.f, 10.f, 30.f, 45.f, 90.f, 165.f, 180.f, 270.f}; | 
|  | 31 | constexpr SkScalar kSweeps[] = {1.f, 45.f, 90.f, 130.f, 180.f, 184.f, 300.f, 355.f}; | 
|  | 32 | constexpr SkScalar kDiameter = 40.f; | 
|  | 33 | constexpr SkRect kRect = {0.f, 0.f, kDiameter, kDiameter}; | 
|  | 34 | constexpr int kW = 1000; | 
|  | 35 | constexpr int kH = 1000; | 
|  | 36 | constexpr SkScalar kPad = 20.f; | 
| bsalomon | 71c5eee | 2016-08-19 10:53:13 -0700 | [diff] [blame] | 37 |  | 
|  | 38 | void draw_arcs(SkCanvas* canvas, std::function<void(SkPaint*)> configureStyle) { | 
|  | 39 | // Draws grid of arcs with different start/sweep angles in red and their complement arcs in | 
|  | 40 | // blue. | 
|  | 41 | auto drawGrid = [canvas, &configureStyle] (SkScalar x, SkScalar y, bool useCenter, bool aa) { | 
|  | 42 | SkPaint p0; | 
|  | 43 | p0.setColor(SK_ColorRED); | 
|  | 44 | p0.setAntiAlias(aa); | 
|  | 45 | // Set a reasonable stroke width that configureStyle can override. | 
|  | 46 | p0.setStrokeWidth(15.f); | 
| bsalomon | 71c5eee | 2016-08-19 10:53:13 -0700 | [diff] [blame] | 47 | SkPaint p1 = p0; | 
|  | 48 | p1.setColor(SK_ColorBLUE); | 
| bsalomon | 4c54788 | 2016-08-19 13:41:28 -0700 | [diff] [blame] | 49 | // Use alpha so we see magenta on overlap between arc and its complement. | 
|  | 50 | p0.setAlpha(100); | 
|  | 51 | p1.setAlpha(100); | 
| bsalomon | 71c5eee | 2016-08-19 10:53:13 -0700 | [diff] [blame] | 52 | configureStyle(&p0); | 
|  | 53 | configureStyle(&p1); | 
|  | 54 |  | 
|  | 55 | canvas->save(); | 
|  | 56 | canvas->translate(kPad + x, kPad + y); | 
|  | 57 | for (auto start : kStarts) { | 
|  | 58 | canvas->save(); | 
|  | 59 | for (auto sweep : kSweeps) { | 
|  | 60 | canvas->drawArc(kRect, start, sweep, useCenter, p0); | 
|  | 61 | canvas->drawArc(kRect, start, -(360.f - sweep), useCenter, p1); | 
|  | 62 | canvas->translate(kRect.width() + kPad, 0.f); | 
|  | 63 | } | 
|  | 64 | canvas->restore(); | 
|  | 65 | canvas->translate(0, kRect.height() + kPad); | 
|  | 66 | } | 
|  | 67 | canvas->restore(); | 
|  | 68 | }; | 
|  | 69 | // Draw a grids for combo of enabling/disabling aa and using center. | 
| mtklein | dbfd7ab | 2016-09-01 11:24:54 -0700 | [diff] [blame] | 70 | constexpr SkScalar kGridW = kW / 2.f; | 
|  | 71 | constexpr SkScalar kGridH = kH / 2.f; | 
| bsalomon | 71c5eee | 2016-08-19 10:53:13 -0700 | [diff] [blame] | 72 | drawGrid(0.f   , 0.f   , false, false); | 
|  | 73 | drawGrid(kGridW, 0.f   , true , false); | 
|  | 74 | drawGrid(0.f   , kGridH, false, true ); | 
|  | 75 | drawGrid(kGridW, kGridH, true , true ); | 
|  | 76 | // Draw separators between the grids. | 
|  | 77 | SkPaint linePaint; | 
|  | 78 | linePaint.setAntiAlias(true); | 
|  | 79 | linePaint.setColor(SK_ColorBLACK); | 
|  | 80 | canvas->drawLine(kGridW, 0.f   , kGridW,            SkIntToScalar(kH), linePaint); | 
|  | 81 | canvas->drawLine(0.f   , kGridH, SkIntToScalar(kW), kGridH,            linePaint); | 
|  | 82 | } | 
|  | 83 |  | 
|  | 84 | #define DEF_ARC_GM(name) DEF_SIMPLE_GM(circular_arcs_##name, canvas, kW, kH) | 
|  | 85 |  | 
| bsalomon | 4c54788 | 2016-08-19 13:41:28 -0700 | [diff] [blame] | 86 | DEF_ARC_GM(fill) { | 
| Mike Reed | 1963009 | 2020-05-18 21:25:44 -0400 | [diff] [blame] | 87 | auto setFill = [] (SkPaint*p) { p->setStroke(false); }; | 
| bsalomon | 71c5eee | 2016-08-19 10:53:13 -0700 | [diff] [blame] | 88 | draw_arcs(canvas, setFill); | 
|  | 89 | } | 
|  | 90 |  | 
|  | 91 | DEF_ARC_GM(hairline) { | 
|  | 92 | auto setHairline = [] (SkPaint* p) { | 
| Mike Reed | 1963009 | 2020-05-18 21:25:44 -0400 | [diff] [blame] | 93 | p->setStroke(true); | 
| bsalomon | 71c5eee | 2016-08-19 10:53:13 -0700 | [diff] [blame] | 94 | p->setStrokeWidth(0.f); | 
|  | 95 | }; | 
|  | 96 | draw_arcs(canvas, setHairline); | 
|  | 97 | } | 
|  | 98 |  | 
|  | 99 | DEF_ARC_GM(stroke_butt) { | 
|  | 100 | auto setStroke = [](SkPaint* p) { | 
| Mike Reed | 1963009 | 2020-05-18 21:25:44 -0400 | [diff] [blame] | 101 | p->setStroke(true); | 
| bsalomon | 71c5eee | 2016-08-19 10:53:13 -0700 | [diff] [blame] | 102 | p->setStrokeCap(SkPaint::kButt_Cap); | 
|  | 103 | }; | 
|  | 104 | draw_arcs(canvas, setStroke); | 
|  | 105 | } | 
|  | 106 |  | 
|  | 107 | DEF_ARC_GM(stroke_square) { | 
|  | 108 | auto setStroke = [] (SkPaint* p) { | 
| Mike Reed | 1963009 | 2020-05-18 21:25:44 -0400 | [diff] [blame] | 109 | p->setStroke(true); | 
| bsalomon | 71c5eee | 2016-08-19 10:53:13 -0700 | [diff] [blame] | 110 | p->setStrokeCap(SkPaint::kSquare_Cap); | 
|  | 111 | }; | 
|  | 112 | draw_arcs(canvas, setStroke); | 
|  | 113 | } | 
|  | 114 |  | 
|  | 115 | DEF_ARC_GM(stroke_round) { | 
|  | 116 | auto setStroke = [] (SkPaint* p) { | 
| Mike Reed | 1963009 | 2020-05-18 21:25:44 -0400 | [diff] [blame] | 117 | p->setStroke(true); | 
| bsalomon | 71c5eee | 2016-08-19 10:53:13 -0700 | [diff] [blame] | 118 | p->setStrokeCap(SkPaint::kRound_Cap); | 
|  | 119 | }; | 
|  | 120 | draw_arcs(canvas, setStroke); | 
|  | 121 | } | 
| bsalomon | ac1d0ab | 2016-08-22 10:00:14 -0700 | [diff] [blame] | 122 |  | 
| bsalomon | 4c261d0 | 2016-08-22 13:10:46 -0700 | [diff] [blame] | 123 | DEF_ARC_GM(stroke_and_fill_butt) { | 
|  | 124 | auto setStroke = [] (SkPaint* p) { | 
| Mike Reed | 9ded74e | 2020-05-20 17:01:56 -0400 | [diff] [blame] | 125 | set_strokeandfill(p); | 
| bsalomon | 4c261d0 | 2016-08-22 13:10:46 -0700 | [diff] [blame] | 126 | p->setStrokeCap(SkPaint::kButt_Cap); | 
|  | 127 | }; | 
|  | 128 | draw_arcs(canvas, setStroke); | 
|  | 129 | } | 
|  | 130 |  | 
|  | 131 | DEF_ARC_GM(stroke_and_fill_square) { | 
|  | 132 | auto setStroke = [] (SkPaint* p) { | 
| Mike Reed | 9ded74e | 2020-05-20 17:01:56 -0400 | [diff] [blame] | 133 | set_strokeandfill(p); | 
| bsalomon | 4c261d0 | 2016-08-22 13:10:46 -0700 | [diff] [blame] | 134 | p->setStrokeCap(SkPaint::kSquare_Cap); | 
|  | 135 | }; | 
|  | 136 | draw_arcs(canvas, setStroke); | 
|  | 137 | } | 
|  | 138 |  | 
|  | 139 | DEF_ARC_GM(stroke_and_fill_round) { | 
| bsalomon | ac1d0ab | 2016-08-22 10:00:14 -0700 | [diff] [blame] | 140 | auto setStroke = [] (SkPaint* p) { | 
| Mike Reed | 9ded74e | 2020-05-20 17:01:56 -0400 | [diff] [blame] | 141 | set_strokeandfill(p); | 
| bsalomon | ac1d0ab | 2016-08-22 10:00:14 -0700 | [diff] [blame] | 142 | p->setStrokeCap(SkPaint::kRound_Cap); | 
|  | 143 | }; | 
|  | 144 | draw_arcs(canvas, setStroke); | 
|  | 145 | } | 
| bsalomon | 21af9ca | 2016-08-25 12:29:23 -0700 | [diff] [blame] | 146 |  | 
|  | 147 | DEF_SIMPLE_GM(circular_arcs_weird, canvas, 1000, 400) { | 
| mtklein | dbfd7ab | 2016-09-01 11:24:54 -0700 | [diff] [blame] | 148 | constexpr SkScalar kS = 50; | 
| bsalomon | 21af9ca | 2016-08-25 12:29:23 -0700 | [diff] [blame] | 149 | struct Arc { | 
|  | 150 | SkRect   fOval; | 
|  | 151 | SkScalar fStart; | 
|  | 152 | SkScalar fSweep; | 
|  | 153 | }; | 
| mtklein | dbfd7ab | 2016-09-01 11:24:54 -0700 | [diff] [blame] | 154 | const Arc noDrawArcs[] = { | 
| bsalomon | 21af9ca | 2016-08-25 12:29:23 -0700 | [diff] [blame] | 155 | // no sweep | 
|  | 156 | {SkRect::MakeWH(kS, kS),  0,  0}, | 
|  | 157 | // empty rect in x | 
|  | 158 | {SkRect::MakeWH(-kS, kS), 0, 90}, | 
|  | 159 | // empty rect in y | 
|  | 160 | {SkRect::MakeWH(kS, -kS), 0, 90}, | 
|  | 161 | // empty rect in x and y | 
|  | 162 | {SkRect::MakeWH( 0,   0), 0, 90}, | 
|  | 163 | }; | 
| mtklein | dbfd7ab | 2016-09-01 11:24:54 -0700 | [diff] [blame] | 164 | const Arc arcs[] = { | 
| bsalomon | 21af9ca | 2016-08-25 12:29:23 -0700 | [diff] [blame] | 165 | // large start | 
|  | 166 | {SkRect::MakeWH(kS, kS),   810.f,   90.f}, | 
|  | 167 | // large negative start | 
|  | 168 | {SkRect::MakeWH(kS, kS),  -810.f,   90.f}, | 
|  | 169 | // exactly 360 sweep | 
|  | 170 | {SkRect::MakeWH(kS, kS),     0.f,  360.f}, | 
|  | 171 | // exactly -360 sweep | 
|  | 172 | {SkRect::MakeWH(kS, kS),     0.f, -360.f}, | 
|  | 173 | // exactly 540 sweep | 
|  | 174 | {SkRect::MakeWH(kS, kS),     0.f,  540.f}, | 
|  | 175 | // exactly -540 sweep | 
|  | 176 | {SkRect::MakeWH(kS, kS),     0.f, -540.f}, | 
|  | 177 | // generic large sweep and large start | 
|  | 178 | {SkRect::MakeWH(kS, kS),  1125.f,  990.f}, | 
|  | 179 | }; | 
|  | 180 | SkTArray<SkPaint> paints; | 
|  | 181 | // fill | 
|  | 182 | paints.push_back(); | 
|  | 183 | // stroke | 
| Mike Reed | 1963009 | 2020-05-18 21:25:44 -0400 | [diff] [blame] | 184 | paints.push_back().setStroke(true); | 
| bsalomon | 21af9ca | 2016-08-25 12:29:23 -0700 | [diff] [blame] | 185 | paints.back().setStrokeWidth(kS / 6.f); | 
|  | 186 | // hairline | 
| Mike Reed | 1963009 | 2020-05-18 21:25:44 -0400 | [diff] [blame] | 187 | paints.push_back().setStroke(true); | 
| bsalomon | 21af9ca | 2016-08-25 12:29:23 -0700 | [diff] [blame] | 188 | paints.back().setStrokeWidth(0.f); | 
|  | 189 | // stroke and fill | 
|  | 190 | paints.push_back().setStyle(SkPaint::kStrokeAndFill_Style); | 
|  | 191 | paints.back().setStrokeWidth(kS / 6.f); | 
|  | 192 | // dash effect | 
| Mike Reed | 1963009 | 2020-05-18 21:25:44 -0400 | [diff] [blame] | 193 | paints.push_back().setStroke(true); | 
| bsalomon | 21af9ca | 2016-08-25 12:29:23 -0700 | [diff] [blame] | 194 | paints.back().setStrokeWidth(kS / 6.f); | 
| mtklein | dbfd7ab | 2016-09-01 11:24:54 -0700 | [diff] [blame] | 195 | constexpr SkScalar kDashIntervals[] = {kS / 15, 2 * kS / 15}; | 
| bsalomon | 21af9ca | 2016-08-25 12:29:23 -0700 | [diff] [blame] | 196 | paints.back().setPathEffect(SkDashPathEffect::Make(kDashIntervals, 2, 0.f)); | 
|  | 197 |  | 
|  | 198 | canvas->translate(kPad, kPad); | 
|  | 199 | // This loop should draw nothing. | 
|  | 200 | for (auto arc : noDrawArcs) { | 
|  | 201 | for (auto paint : paints) { | 
|  | 202 | paint.setAntiAlias(true); | 
|  | 203 | canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, false, paint); | 
|  | 204 | canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, true, paint); | 
|  | 205 | } | 
|  | 206 | } | 
|  | 207 |  | 
|  | 208 | SkPaint linePaint; | 
|  | 209 | linePaint.setAntiAlias(true); | 
|  | 210 | linePaint.setColor(SK_ColorRED); | 
|  | 211 | SkScalar midX   = SK_ARRAY_COUNT(arcs) * (kS + kPad) - kPad/2.f; | 
|  | 212 | SkScalar height = paints.count() * (kS + kPad); | 
|  | 213 | canvas->drawLine(midX, -kPad, midX, height, linePaint); | 
|  | 214 |  | 
|  | 215 | for (auto paint : paints) { | 
|  | 216 | paint.setAntiAlias(true); | 
|  | 217 | canvas->save(); | 
|  | 218 | for (auto arc : arcs) { | 
|  | 219 | canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, false, paint); | 
|  | 220 | canvas->translate(kS + kPad, 0.f); | 
|  | 221 | } | 
|  | 222 | for (auto arc : arcs) { | 
|  | 223 | canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, true, paint); | 
|  | 224 | canvas->translate(kS + kPad, 0.f); | 
|  | 225 | } | 
|  | 226 | canvas->restore(); | 
|  | 227 | canvas->translate(0, kS + kPad); | 
|  | 228 | } | 
|  | 229 | } | 
| caryclark | f71ab8f | 2016-08-26 09:54:25 -0700 | [diff] [blame] | 230 |  | 
|  | 231 | DEF_SIMPLE_GM(onebadarc, canvas, 100, 100) { | 
| Mike Reed | 06d7c9d | 2020-08-26 12:56:51 -0400 | [diff] [blame] | 232 | SkPathBuilder path; | 
| caryclark | f71ab8f | 2016-08-26 09:54:25 -0700 | [diff] [blame] | 233 | path.moveTo(SkBits2Float(0x41a00000), SkBits2Float(0x41a00000));  // 20, 20 | 
|  | 234 | path.lineTo(SkBits2Float(0x4208918c), SkBits2Float(0x4208918c));  // 34.1421f, 34.1421f | 
|  | 235 | path.conicTo(SkBits2Float(0x41a00000), SkBits2Float(0x42412318),  // 20, 48.2843f | 
|  | 236 | SkBits2Float(0x40bb73a0), SkBits2Float(0x4208918c),       // 5.85786f, 34.1421f | 
|  | 237 | SkBits2Float(0x3f3504f3));                                // 0.707107f | 
|  | 238 | path.quadTo(SkBits2Float(0x40bb73a0), SkBits2Float(0x4208918c),   // 5.85786f, 34.1421f | 
|  | 239 | SkBits2Float(0x40bb73a2), SkBits2Float(0x4208918c));      // 5.85787f, 34.1421f | 
|  | 240 | path.lineTo(SkBits2Float(0x41a00000), SkBits2Float(0x41a00000));  // 20, 20 | 
|  | 241 | path.close(); | 
|  | 242 | SkPaint p0; | 
|  | 243 | p0.setColor(SK_ColorRED); | 
|  | 244 | p0.setStrokeWidth(15.f); | 
| Mike Reed | 1963009 | 2020-05-18 21:25:44 -0400 | [diff] [blame] | 245 | p0.setStroke(true); | 
| caryclark | f71ab8f | 2016-08-26 09:54:25 -0700 | [diff] [blame] | 246 | p0.setAlpha(100); | 
|  | 247 | canvas->translate(20, 0); | 
| Mike Reed | 06d7c9d | 2020-08-26 12:56:51 -0400 | [diff] [blame] | 248 | canvas->drawPath(path.detach(), p0); | 
| caryclark | f71ab8f | 2016-08-26 09:54:25 -0700 | [diff] [blame] | 249 |  | 
| John Stiles | a212b95 | 2021-08-02 13:26:38 -0400 | [diff] [blame] | 250 | canvas->drawArc(SkRect{60, 0, 100, 40}, 45, 90, true, p0); | 
| caryclark | f71ab8f | 2016-08-26 09:54:25 -0700 | [diff] [blame] | 251 | } | 
| Brian Osman | e3deee1 | 2018-11-20 11:10:15 -0500 | [diff] [blame] | 252 |  | 
|  | 253 | DEF_SIMPLE_GM(crbug_888453, canvas, 480, 150) { | 
|  | 254 | // Two GPU path renderers were using a too-large tolerance when chopping connics to quads. | 
|  | 255 | // This manifested as not-very-round circular arcs at certain radii. All the arcs being drawn | 
|  | 256 | // here should look like circles. | 
|  | 257 | SkPaint fill; | 
|  | 258 | fill.setAntiAlias(true); | 
|  | 259 | SkPaint hairline = fill; | 
| Mike Reed | 1963009 | 2020-05-18 21:25:44 -0400 | [diff] [blame] | 260 | hairline.setStroke(true); | 
| Brian Osman | e3deee1 | 2018-11-20 11:10:15 -0500 | [diff] [blame] | 261 | SkPaint stroke = hairline; | 
|  | 262 | stroke.setStrokeWidth(2.0f); | 
|  | 263 | int x = 4; | 
|  | 264 | int y0 = 25, y1 = 75, y2 = 125; | 
|  | 265 | for (int r = 2; r <= 20; ++r) { | 
|  | 266 | canvas->drawArc(SkRect::MakeXYWH(x - r, y0 - r, 2 * r, 2 * r), 0, 360, false, fill); | 
|  | 267 | canvas->drawArc(SkRect::MakeXYWH(x - r, y1 - r, 2 * r, 2 * r), 0, 360, false, hairline); | 
|  | 268 | canvas->drawArc(SkRect::MakeXYWH(x - r, y2 - r, 2 * r, 2 * r), 0, 360, false, stroke); | 
|  | 269 | x += 2 * r + 4; | 
|  | 270 | } | 
|  | 271 | } | 
| Brian Salomon | 3517aa7 | 2019-12-11 08:16:22 -0500 | [diff] [blame] | 272 |  | 
|  | 273 | DEF_SIMPLE_GM(circular_arc_stroke_matrix, canvas, 820, 1090) { | 
|  | 274 | static constexpr SkScalar kRadius = 40.f; | 
|  | 275 | static constexpr SkScalar kStrokeWidth = 5.f; | 
|  | 276 | static constexpr SkScalar kStart = 89.f; | 
|  | 277 | static constexpr SkScalar kSweep = 180.f/SK_ScalarPI; // one radian | 
|  | 278 |  | 
|  | 279 | SkTArray<SkMatrix> matrices; | 
|  | 280 | matrices.push_back().setRotate(kRadius, kRadius, 45.f); | 
|  | 281 | matrices.push_back(SkMatrix::I()); | 
|  | 282 | matrices.push_back().setAll(-1,  0,  2*kRadius, | 
|  | 283 | 0,  1,  0, | 
|  | 284 | 0,  0,  1); | 
|  | 285 | matrices.push_back().setAll( 1,  0,  0, | 
|  | 286 | 0, -1,  2*kRadius, | 
|  | 287 | 0,  0,  1); | 
|  | 288 | matrices.push_back().setAll( 1,  0,  0, | 
|  | 289 | 0, -1,  2*kRadius, | 
|  | 290 | 0,  0,  1); | 
|  | 291 | matrices.push_back().setAll( 0, -1,  2*kRadius, | 
|  | 292 | -1,  0,  2*kRadius, | 
|  | 293 | 0,  0,  1); | 
|  | 294 | matrices.push_back().setAll( 0, -1,  2*kRadius, | 
|  | 295 | 1,  0,  0, | 
|  | 296 | 0,  0,  1); | 
|  | 297 | matrices.push_back().setAll( 0,  1,  0, | 
|  | 298 | 1,  0,  0, | 
|  | 299 | 0,  0,  1); | 
|  | 300 | matrices.push_back().setAll( 0,  1,  0, | 
|  | 301 | -1,  0,  2*kRadius, | 
|  | 302 | 0,  0,  1); | 
|  | 303 | int baseMatrixCnt = matrices.count(); | 
|  | 304 |  | 
|  | 305 |  | 
|  | 306 | SkMatrix tinyCW; | 
|  | 307 | tinyCW.setRotate(0.001f, kRadius, kRadius); | 
|  | 308 | for (int i = 0; i < baseMatrixCnt; ++i) { | 
|  | 309 | matrices.push_back().setConcat(matrices[i], tinyCW); | 
|  | 310 | } | 
|  | 311 | SkMatrix tinyCCW; | 
|  | 312 | tinyCCW.setRotate(-0.001f, kRadius, kRadius); | 
|  | 313 | for (int i = 0; i < baseMatrixCnt; ++i) { | 
|  | 314 | matrices.push_back().setConcat(matrices[i], tinyCCW); | 
|  | 315 | } | 
|  | 316 | SkMatrix cw45; | 
|  | 317 | cw45.setRotate(45.f, kRadius, kRadius); | 
|  | 318 | for (int i = 0; i < baseMatrixCnt; ++i) { | 
|  | 319 | matrices.push_back().setConcat(matrices[i], cw45); | 
|  | 320 | } | 
|  | 321 |  | 
|  | 322 | int x = 0; | 
|  | 323 | int y = 0; | 
|  | 324 | static constexpr SkScalar kPad = 2*kStrokeWidth; | 
|  | 325 | canvas->translate(kPad, kPad); | 
|  | 326 | auto bounds = SkRect::MakeWH(2*kRadius, 2*kRadius); | 
|  | 327 | for (auto cap : {SkPaint::kRound_Cap, SkPaint::kButt_Cap, SkPaint::kSquare_Cap}) { | 
|  | 328 | for (const auto& m : matrices) { | 
|  | 329 | SkPaint paint; | 
|  | 330 | paint.setStrokeCap(cap); | 
|  | 331 | paint.setAntiAlias(true); | 
| Mike Reed | 1963009 | 2020-05-18 21:25:44 -0400 | [diff] [blame] | 332 | paint.setStroke(true); | 
| Brian Salomon | 3517aa7 | 2019-12-11 08:16:22 -0500 | [diff] [blame] | 333 | paint.setStrokeWidth(kStrokeWidth); | 
|  | 334 | canvas->save(); | 
|  | 335 | canvas->translate(x * (2*kRadius + kPad), y * (2*kRadius + kPad)); | 
|  | 336 | canvas->concat(m); | 
|  | 337 | paint.setColor(SK_ColorRED); | 
|  | 338 | paint.setAlpha(0x80); | 
|  | 339 | canvas->drawArc(bounds, kStart, kSweep, false, paint); | 
|  | 340 | paint.setColor(SK_ColorBLUE); | 
|  | 341 | paint.setAlpha(0x80); | 
|  | 342 | canvas->drawArc(bounds, kStart, kSweep - 360.f, false, paint); | 
|  | 343 | canvas->restore(); | 
|  | 344 | ++x; | 
|  | 345 | if (x == baseMatrixCnt) { | 
|  | 346 | x = 0; | 
|  | 347 | ++y; | 
|  | 348 | } | 
|  | 349 | } | 
|  | 350 | } | 
|  | 351 | } |