Flutter Engine
The Flutter Engine
trickycubicstrokes.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 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"
13#include "include/core/SkPath.h"
15#include "include/core/SkRect.h"
16#include "include/core/SkSize.h"
21#include "src/base/SkRandom.h"
22#include "src/core/SkGeometry.h"
27
28static constexpr float kStrokeWidth = 30;
29static constexpr int kCellSize = 200;
30static constexpr int kNumCols = 5;
31static constexpr int kNumRows = 5;
32static constexpr int kTestWidth = kNumCols * kCellSize;
33static constexpr int kTestHeight = kNumRows * kCellSize;
34
35enum class CellFillMode {
37 kCenter
38};
39
44 float fScale = 1;
45};
46
47// This is a compilation of cubics that have given strokers grief. Feel free to add more.
48static const TrickyCubic kTrickyCubics[] = {
49 {{{122, 737}, {348, 553}, {403, 761}, {400, 760}}, 4, CellFillMode::kStretch},
50 {{{244, 520}, {244, 518}, {1141, 634}, {394, 688}}, 4, CellFillMode::kStretch},
51 {{{550, 194}, {138, 130}, {1035, 246}, {288, 300}}, 4, CellFillMode::kStretch},
52 {{{226, 733}, {556, 779}, {-43, 471}, {348, 683}}, 4, CellFillMode::kStretch},
53 {{{268, 204}, {492, 304}, {352, 23}, {433, 412}}, 4, CellFillMode::kStretch},
54 {{{172, 480}, {396, 580}, {256, 299}, {338, 677}}, 4, CellFillMode::kStretch},
55 {{{731, 340}, {318, 252}, {1026, -64}, {367, 265}}, 4, CellFillMode::kStretch},
56 {{{475, 708}, {62, 620}, {770, 304}, {220, 659}}, 4, CellFillMode::kStretch},
57 {{{0, 0}, {128, 128}, {128, 0}, {0, 128}}, 4, CellFillMode::kCenter}, // Perfect cusp
58 {{{0,.01f}, {128,127.999f}, {128,.01f}, {0,127.99f}}, 4, CellFillMode::kCenter}, // Near-cusp
59 {{{0,-.01f}, {128,128.001f}, {128,-.01f}, {0,128.001f}}, 4, CellFillMode::kCenter}, // Near-cusp
60 {{{0,0}, {0,-10}, {0,-10}, {0,10}}, 4, CellFillMode::kCenter, 1.098283f}, // Flat line with 180
61 {{{10,0}, {0,0}, {20,0}, {10,0}}, 4, CellFillMode::kStretch}, // Flat line with 2 180s
62 {{{39,-39}, {40,-40}, {40,-40}, {0,0}}, 4, CellFillMode::kStretch}, // Flat diagonal with 180
63 {{{39,-39}, {40,-40}, {37,-39}, {0,0}}, 4, CellFillMode::kStretch}, // Near-flat diagonal
64 {{{40, 40}, {0, 0}, {200, 200}, {0, 0}}, 4, CellFillMode::kStretch}, // Diag w/ an internal 180
65 {{{0,0}, {1e-2f,0}, {-1e-2f,0}, {0,0}}, 4, CellFillMode::kCenter}, // Circle
66 {{{400.75f,100.05f}, {400.75f,100.05f}, {100.05f,300.95f}, {100.05f,300.95f}}, 4,
67 CellFillMode::kStretch}, // Flat line with no turns
68 {{{0.5f,0}, {0,0}, {20,0}, {10,0}}, 4, CellFillMode::kStretch}, // Flat line with 2 180s
69 {{{10,0}, {0,0}, {10,0}, {10,0}}, 4, CellFillMode::kStretch}, // Flat line with a 180
70 {{{1,1}, {2,1}, {1,1}, {1, std::numeric_limits<float>::quiet_NaN()}}, 3,
71 CellFillMode::kStretch}, // Flat QUAD with a cusp
72 {{{1,1}, {100,1}, {25,1}, {.3f, std::numeric_limits<float>::quiet_NaN()}}, 3,
73 CellFillMode::kStretch}, // Flat CONIC with a cusp
74 {{{1,1}, {100,1}, {25,1}, {1.5f, std::numeric_limits<float>::quiet_NaN()}}, 3,
75 CellFillMode::kStretch}, // Flat CONIC with a cusp
76};
77
78static SkRect calc_tight_cubic_bounds(const SkPoint P[4], int depth=5) {
79 if (0 == depth) {
81 bounds.fLeft = std::min(std::min(P[0].x(), P[1].x()), std::min(P[2].x(), P[3].x()));
82 bounds.fTop = std::min(std::min(P[0].y(), P[1].y()), std::min(P[2].y(), P[3].y()));
83 bounds.fRight = std::max(std::max(P[0].x(), P[1].x()), std::max(P[2].x(), P[3].x()));
84 bounds.fBottom = std::max(std::max(P[0].y(), P[1].y()), std::max(P[2].y(), P[3].y()));
85 return bounds;
86 }
87
88 SkPoint chopped[7];
89 SkChopCubicAt(P, chopped, .5f);
90 SkRect bounds = calc_tight_cubic_bounds(chopped, depth - 1);
91 bounds.join(calc_tight_cubic_bounds(chopped+3, depth - 1));
92 return bounds;
93}
94
95static SkPoint lerp(const SkPoint& a, const SkPoint& b, float T) {
96 SkASSERT(1 != T); // The below does not guarantee lerp(a, b, 1) === b.
97 return (b - a) * T + a;
98}
99
100enum class FillMode {
101 kCenter,
102 kScale
103};
104
106 SkRandom rand;
107
108 canvas->clear(SK_ColorBLACK);
109
110 SkPaint strokePaint;
111 strokePaint.setAntiAlias(true);
112 strokePaint.setStrokeWidth(kStrokeWidth);
113 strokePaint.setStyle(SkPaint::kStroke_Style);
114 strokePaint.setStrokeCap(cap);
115 strokePaint.setStrokeJoin(join);
116
117 for (size_t i = 0; i < std::size(kTrickyCubics); ++i) {
118 auto [originalPts, numPts, fillMode, scale] = kTrickyCubics[i];
119
120 SkASSERT(numPts <= 4);
121 SkPoint p[4];
122 memcpy(p, originalPts, sizeof(SkPoint) * numPts);
123 for (int j = 0; j < numPts; ++j) {
124 p[j] *= scale;
125 }
126 float w = originalPts[3].fX;
127
128 auto cellRect = SkRect::MakeXYWH((i % kNumCols) * kCellSize, (i / kNumCols) * kCellSize,
130
131 SkRect strokeBounds;
132 if (numPts == 4) {
133 strokeBounds = calc_tight_cubic_bounds(p);
134 } else {
135 SkASSERT(numPts == 3);
136 SkPoint asCubic[4] = {p[0], lerp(p[0], p[1], 2/3.f), lerp(p[1], p[2], 1/3.f), p[2]};
137 strokeBounds = calc_tight_cubic_bounds(asCubic);
138 }
139 strokeBounds.outset(kStrokeWidth, kStrokeWidth);
140
142 if (fillMode == CellFillMode::kStretch) {
144 } else {
145 matrix.setTranslate(cellRect.x() + kStrokeWidth +
146 (cellRect.width() - strokeBounds.width()) / 2,
147 cellRect.y() + kStrokeWidth +
148 (cellRect.height() - strokeBounds.height()) / 2);
149 }
150
151 SkAutoCanvasRestore acr(canvas, true);
152 canvas->concat(matrix);
153 strokePaint.setStrokeWidth(kStrokeWidth / matrix.getMaxScale());
154 strokePaint.setColor(rand.nextU() | 0xff808080);
155 SkPath path = SkPath().moveTo(p[0]);
156 if (numPts == 4) {
157 path.cubicTo(p[1], p[2], p[3]);
158 } else if (w == 1) {
159 SkASSERT(numPts == 3);
160 path.quadTo(p[1], p[2]);
161 } else {
162 SkASSERT(numPts == 3);
163 path.conicTo(p[1], p[2], w);
164 }
165 canvas->drawPath(path, strokePaint);
166 }
167}
168
169DEF_SIMPLE_GM(trickycubicstrokes, canvas, kTestWidth, kTestHeight) {
171}
172
173DEF_SIMPLE_GM(trickycubicstrokes_roundcaps, canvas, kTestWidth, kTestHeight) {
175}
#define SkASSERT(cond)
Definition: SkAssert.h:116
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t)
Definition: SkGeometry.cpp:473
void clear(SkColor color)
Definition: SkCanvas.h:1199
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
void concat(const SkMatrix &matrix)
Definition: SkCanvas.cpp:1318
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
Definition: SkMatrix.h:157
@ kCenter_ScaleToFit
scales and aligns to center
Definition: SkMatrix.h:139
@ kRound_Cap
adds circle
Definition: SkPaint.h:335
@ kButt_Cap
no stroke extension
Definition: SkPaint.h:334
void setStyle(Style style)
Definition: SkPaint.cpp:105
void setColor(SkColor color)
Definition: SkPaint.cpp:119
void setAntiAlias(bool aa)
Definition: SkPaint.h:170
void setStrokeCap(Cap cap)
Definition: SkPaint.cpp:179
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
void setStrokeJoin(Join join)
Definition: SkPaint.cpp:189
@ kRound_Join
adds circle
Definition: SkPaint.h:360
@ kMiter_Join
extends to miter limit
Definition: SkPaint.h:359
void setStrokeWidth(SkScalar width)
Definition: SkPaint.cpp:159
Definition: SkPath.h:59
SkPath & moveTo(SkScalar x, SkScalar y)
Definition: SkPath.cpp:688
uint32_t nextU()
Definition: SkRandom.h:42
static bool b
struct MyStruct a[10]
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
double y
double x
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
Optional< SkRect > bounds
Definition: SkRecords.h:189
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SkScalar w
#define T
Definition: precompiler.cc:65
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741
const Scalar scale
void outset(float dx, float dy)
Definition: SkRect.h:1077
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
constexpr float height() const
Definition: SkRect.h:769
constexpr float width() const
Definition: SkRect.h:762
CellFillMode fFillMode
SkPoint fPoints[4]
static const TrickyCubic kTrickyCubics[]
static constexpr int kCellSize
static constexpr float kStrokeWidth
static SkRect calc_tight_cubic_bounds(const SkPoint P[4], int depth=5)
static constexpr int kTestHeight
DEF_SIMPLE_GM(trickycubicstrokes, canvas, kTestWidth, kTestHeight)
static constexpr int kNumCols
static constexpr int kNumRows
static void draw_test(SkCanvas *canvas, SkPaint::Cap cap, SkPaint::Join join)
static constexpr int kTestWidth
static SkPoint lerp(const SkPoint &a, const SkPoint &b, float T)