Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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 {
34 const SkRect oval = fOval.makeOffset(fCenter.fX - fOval.centerX(),
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:
239 DragRectClick(SkRect* rect) : fRect(rect) {}
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
int count
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
static std::unique_ptr< SkEncoder > Make(SkWStream *dst, const SkPixmap *src, const SkYUVAPixmaps *srcYUVA, const SkColorSpace *srcYUVAColorSpace, const SkJpegEncoder::Options &options)
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 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:500
void drawRect(const SkRect &rect, const SkPaint &paint)
void drawOval(const SkRect &oval, const SkPaint &paint)
void clipRect(const SkRect &rect, SkClipOp op, bool doAntiAlias)
void restore()
Definition SkCanvas.cpp:465
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
int save()
Definition SkCanvas.cpp:451
void drawPath(const SkPath &path, const SkPaint &paint)
@ kStroke_Style
set to stroke geometry
Definition SkPaint.h:194
@ kFill_Style
set to fill geometry
Definition SkPaint.h:193
SkString fName
Definition Slide.h:54
const Paint & paint
float SkScalar
Definition extension.cpp:12
double y
double x
ModifierKey
Definition ModifierKey.h:9
float fX
x-axis value
static constexpr SkPoint Make(float x, float y)
void set(float x, float y)
float fY
y-axis value
constexpr float y() const
constexpr float x() const
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