Flutter Engine
The Flutter Engine
PathClipSlide.cpp
Go to the documentation of this file.
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
12#include "include/core/SkPath.h"
18#include "src/base/SkTime.h"
19#include "src/base/SkUTF.h"
21
22#include <utility>
23
25public:
28
29 PathClipSlide() : fOval(SkRect::MakeWH(200, 50)), fCenter(SkPoint::Make(250, 250)) {
30 fName = "PathClip";
31 }
32
33 void draw(SkCanvas* canvas) override {
36
37 SkPaint p;
38 p.setAntiAlias(true);
39
40 p.setStyle(SkPaint::kStroke_Style);
41 canvas->drawOval(oval, p);
42
43 const SkRect r = SkRect::MakeLTRB(200, 200, 300, 300);
44 canvas->clipRect(r);
45
46 p.setStyle(SkPaint::kFill_Style);
47 p.setColor(SK_ColorRED);
48 canvas->drawRect(r, p);
49
50 p.setColor(0x800000FF);
51 canvas->drawOval(oval, p);
52 }
53
54protected:
56 return new Click([&](Click* c) {
57 fCenter = c->fCurr;
58 return false;
59 });
60 }
61
62 bool onClick(ClickHandlerSlide::Click *) override { return false; }
63};
64DEF_SLIDE( return new PathClipSlide; )
65
66//////////////////////////////////////////////////////////////////////////////
67
68static int clip_line(const SkRect& bounds, SkPoint p0, SkPoint p1, SkPoint edges[]) {
69 SkPoint* edgesStart = edges;
70
71 if (p0.fY == p1.fY) {
72 return 0;
73 }
74
75 if (p0.fY > p1.fY) {
76 using std::swap;
77 swap(p0, p1);
78 }
79 // now we're monotonic in Y: p0 <= p1
80 if (p1.fY <= bounds.top() || p0.fY >= bounds.bottom()) {
81 return 0;
82 }
83
84 double dxdy = (double)(p1.fX - p0.fX) / (p1.fY - p0.fY);
85 if (p0.fY < bounds.top()) {
86 p0.fX = SkDoubleToScalar(p0.fX + dxdy * (bounds.top() - p0.fY));
87 p0.fY = bounds.top();
88 }
89 if (p1.fY > bounds.bottom()) {
90 p1.fX = SkDoubleToScalar(p1.fX + dxdy * (bounds.bottom() - p1.fY));
91 p1.fY = bounds.bottom();
92 }
93
94 // Now p0...p1 is strictly inside bounds vertically, so we just need to clip horizontally
95
96 if (p0.fX > p1.fX) {
97 using std::swap;
98 swap(p0, p1);
99 }
100 // now we're left-to-right: p0 .. p1
101
102 if (p1.fX <= bounds.left()) { // entirely to the left
103 p0.fX = p1.fX = bounds.left();
104 *edges++ = p0;
105 *edges++ = p1;
106 return 2;
107 }
108 if (p0.fX >= bounds.right()) { // entirely to the right
109 p0.fX = p1.fX = bounds.right();
110 *edges++ = p0;
111 *edges++ = p1;
112 return 2;
113 }
114
115 if (p0.fX < bounds.left()) {
116 float y = SkDoubleToScalar(p0.fY + (bounds.left() - p0.fX) / dxdy);
117 *edges++ = SkPoint::Make(bounds.left(), p0.fY);
118 *edges++ = SkPoint::Make(bounds.left(), y);
119 p0.set(bounds.left(), y);
120 }
121 if (p1.fX > bounds.right()) {
122 float y = SkDoubleToScalar(p0.fY + (bounds.right() - p0.fX) / dxdy);
123 *edges++ = p0;
124 *edges++ = SkPoint::Make(bounds.right(), y);
125 *edges++ = SkPoint::Make(bounds.right(), p1.fY);
126 } else {
127 *edges++ = p0;
128 *edges++ = p1;
129 }
130 return SkToInt(edges - edgesStart);
131}
132
133static void draw_clipped_line(SkCanvas* canvas, const SkRect& bounds,
134 SkPoint p0, SkPoint p1, const SkPaint& paint) {
135 SkPoint verts[6];
136 int count = clip_line(bounds, p0, p1, verts);
137
138 SkPath path;
139 path.addPoly(verts, count, false);
140 canvas->drawPath(path, paint);
141}
142
143// Demonstrate edge-clipping that is used in the scan converter
144//
146 enum {
147 N = 3
148 };
149 SkPoint fPoly[N];
150 SkRect fClip;
151 SkColor fEdgeColor[N];
152
153public:
154 EdgeClipSlide() : fClip(SkRect::MakeLTRB(150, 150, 550, 450)) {
155 fPoly[0].set(300, 40);
156 fPoly[1].set(550, 250);
157 fPoly[2].set(40, 450);
158
159 fEdgeColor[0] = 0xFFFF0000;
160 fEdgeColor[1] = 0xFF00FF00;
161 fEdgeColor[2] = 0xFF0000FF;
162 fName = "EdgeClip";
163 }
164
166 return SkScalarRoundToScalar(x * 0.5f) * 2;
167 }
168 static SkPoint snap(const SkPoint& pt) {
169 return SkPoint::Make(snap(pt.x()), snap(pt.y()));
170 }
171 static void snap(SkPoint dst[], const SkPoint src[], int count) {
172 for (int i = 0; i < count; ++i) {
173 dst[i] = snap(src[i]);
174 }
175 }
176
177 void draw(SkCanvas* canvas) override {
178 SkPath path;
179 path.addPoly(fPoly, N, true);
180
181 // Draw the full triangle, stroked and filled
182 SkPaint p;
183 p.setAntiAlias(true);
184 p.setColor(0xFFE0E0E0);
185 canvas->drawPath(path, p);
186 p.setStyle(SkPaint::kStroke_Style);
187 p.setStrokeWidth(2);
188 for (int i = 0; i < N; ++i) {
189 const int j = (i + 1) % N;
190 p.setColor(fEdgeColor[i]);
191 p.setAlpha(0x88);
192 canvas->drawLine(fPoly[i], fPoly[j], p);
193 }
194 p.setStyle(SkPaint::kFill_Style);
195
196 // Draw the clip itself
197 p.setColor(0xFF8888CC);
198 canvas->drawRect(fClip, p);
199
200 // Draw the filled triangle through the clip
201 p.setColor(0xFF88CC88);
202 canvas->save();
203 canvas->clipRect(fClip);
204 canvas->drawPath(path, p);
205 canvas->restore();
206
207 p.setStyle(SkPaint::kStroke_Style);
208 p.setStrokeWidth(6);
209
210 // Draw each of the "Edges" that survived the clipping
211 // We use a layer, so we can PLUS the different edge-colors, showing where two edges
212 // canceled each other out.
213 canvas->saveLayer(nullptr, nullptr);
214 p.setBlendMode(SkBlendMode::kPlus);
215 for (int i = 0; i < N; ++i) {
216 const int j = (i + 1) % N;
217 p.setColor(fEdgeColor[i]);
218 draw_clipped_line(canvas, fClip, fPoly[i], fPoly[j], p);
219 }
220 canvas->restore();
221 }
222
223 class MyClick : public Click {
224 public:
226 virtual void handleMove() = 0;
227 };
228
229 class VertClick : public MyClick {
230 SkPoint* fPt;
231 public:
232 VertClick(SkPoint* pt) : fPt(pt) {}
233 void handleMove() override { *fPt = snap(fCurr); }
234 };
235
236 class DragRectClick : public MyClick {
237 SkRect* fRect;
238 public:
240 void handleMove() override { fRect->offset(fCurr.x() - fPrev.x(), fCurr.y() - fPrev.y()); }
241 };
242
243 class DragPolyClick : public MyClick {
244 SkPoint fSrc[100];
245 SkPoint* fPoly;
246 int fCount;
247 public:
248 DragPolyClick(SkPoint poly[], int count) : fPoly(poly), fCount(count)
249 {
250 SkASSERT((size_t)count <= std::size(fSrc));
251 memcpy(fSrc, poly, count * sizeof(SkPoint));
252 }
253 void handleMove() override {
254 const SkScalar dx = fCurr.x() - fOrig.x();
255 const SkScalar dy = fCurr.y() - fOrig.y();
256 for (int i = 0; i < fCount; ++i) {
257 fPoly[i].set(snap(fSrc[i].x() + dx), snap(fSrc[i].y() + dy));
258 }
259 }
260 };
261
262 class DoNothingClick : public MyClick {
263 public:
265 void handleMove() override {}
266 };
267
268 static bool hit_test(const SkPoint& pt, SkScalar x, SkScalar y) {
269 const SkScalar rad = 8;
270 const SkScalar dx = pt.x() - x;
271 const SkScalar dy = pt.y() - y;
272 return dx*dx + dy*dy <= rad*rad;
273 }
274
275protected:
277 for (int i = 0; i < N; ++i) {
278 if (hit_test(fPoly[i], x, y)) {
279 return new VertClick(&fPoly[i]);
280 }
281 }
282
283 SkPath path;
284 path.addPoly(fPoly, N, true);
285 if (path.contains(x, y)) {
286 return new DragPolyClick(fPoly, N);
287 }
288
289 if (fClip.intersects(SkRect::MakeLTRB(x - 1, y - 1, x + 1, y + 1))) {
290 return new DragRectClick(&fClip);
291 }
292 return new DoNothingClick();
293 }
294
295 bool onClick(Click* click) override {
296 ((MyClick*)click)->handleMove();
297 return true;
298 }
299};
300
301DEF_SLIDE( return new EdgeClipSlide; )
SkRect fRect
Definition: FillRRectOp.cpp:73
int count
Definition: FontMgrTest.cpp:50
static void draw_clipped_line(SkCanvas *canvas, const SkRect &bounds, SkPoint p0, SkPoint p1, const SkPaint &paint)
static int clip_line(const SkRect &bounds, SkPoint p0, SkPoint p1, SkPoint edges[])
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kPlus
r = min(s + d, 1)
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
#define SkDoubleToScalar(x)
Definition: SkScalar.h:64
#define SkScalarRoundToScalar(x)
Definition: SkScalar.h:32
constexpr int SkToInt(S x)
Definition: SkTo.h:29
#define DEF_SLIDE(code)
Definition: Slide.h:25
#define N
Definition: beziers.cpp:19
DragPolyClick(SkPoint poly[], int count)
virtual void handleMove()=0
void handleMove() override
void draw(SkCanvas *canvas) override
static void snap(SkPoint dst[], const SkPoint src[], int count)
Click * onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override
static SkPoint snap(const SkPoint &pt)
static bool hit_test(const SkPoint &pt, SkScalar x, SkScalar y)
bool onClick(Click *click) override
static SkScalar snap(SkScalar x)
bool onClick(ClickHandlerSlide::Click *) override
void draw(SkCanvas *canvas) override
Click * onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override
int saveLayer(const SkRect *bounds, const SkPaint *paint)
Definition: SkCanvas.cpp:496
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void drawOval(const SkRect &oval, const SkPaint &paint)
Definition: SkCanvas.cpp:1698
void clipRect(const SkRect &rect, SkClipOp op, bool doAntiAlias)
Definition: SkCanvas.cpp:1361
void restore()
Definition: SkCanvas.cpp:461
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
Definition: SkCanvas.cpp:2700
int save()
Definition: SkCanvas.cpp:447
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
@ kFill_Style
set to fill geometry
Definition: SkPaint.h:193
Definition: SkPath.h:59
SkString fName
Definition: Slide.h:54
const Paint & paint
Definition: color_source.cc:38
float SkScalar
Definition: extension.cpp:12
double y
double x
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
Optional< SkRect > bounds
Definition: SkRecords.h:189
SkRect oval
Definition: SkRecords.h:249
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition: SkRecords.h:208
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
dst
Definition: cp.py:12
ModifierKey
Definition: ModifierKey.h:9
float fX
x-axis value
Definition: SkPoint_impl.h:164
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
void set(float x, float y)
Definition: SkPoint_impl.h:200
float fY
y-axis value
Definition: SkPoint_impl.h:165
constexpr float y() const
Definition: SkPoint_impl.h:187
constexpr float x() const
Definition: SkPoint_impl.h:181
constexpr SkRect makeOffset(float dx, float dy) const
Definition: SkRect.h:965
constexpr float centerX() const
Definition: SkRect.h:776
void offset(float dx, float dy)
Definition: SkRect.h:1016
constexpr float centerY() const
Definition: SkRect.h:785
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646