Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / samplecode / SamplePathClip.cpp
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 "include/core/SkCanvas.h"
9 #include "include/core/SkColorFilter.h"
10 #include "include/core/SkColorPriv.h"
11 #include "include/core/SkGraphics.h"
12 #include "include/core/SkPath.h"
13 #include "include/core/SkRegion.h"
14 #include "include/core/SkShader.h"
15 #include "include/core/SkTime.h"
16 #include "include/core/SkTypeface.h"
17 #include "include/effects/SkGradientShader.h"
18 #include "include/private/SkTo.h"
19 #include "samplecode/Sample.h"
20 #include "src/utils/SkUTF.h"
21
22 #include <utility>
23
24 class PathClipView : public Sample {
25 public:
26     SkRect fOval;
27     SkPoint fCenter;
28
29     PathClipView() : fOval(SkRect::MakeWH(200, 50)), fCenter(SkPoint::Make(250, 250)) {}
30
31 protected:
32     SkString name() override { return SkString("PathClip"); }
33
34     void onDrawContent(SkCanvas* canvas) override {
35         const SkRect oval = fOval.makeOffset(fCenter.fX - fOval.centerX(),
36                                              fCenter.fY - fOval.centerY());
37
38         SkPaint p;
39         p.setAntiAlias(true);
40
41         p.setStyle(SkPaint::kStroke_Style);
42         canvas->drawOval(oval, p);
43
44         const SkRect r = SkRect::MakeLTRB(200, 200, 300, 300);
45         canvas->clipRect(r);
46
47         p.setStyle(SkPaint::kFill_Style);
48         p.setColor(SK_ColorRED);
49         canvas->drawRect(r, p);
50
51         p.setColor(0x800000FF);
52         canvas->drawOval(oval, p);
53     }
54
55     Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override {
56         return new Click([&](Click* c) {
57             fCenter = c->fCurr;
58             return false;
59         });
60     }
61
62 private:
63     using INHERITED = Sample;
64 };
65 DEF_SAMPLE( return new PathClipView; )
66
67 //////////////////////////////////////////////////////////////////////////////
68
69 static int clip_line(const SkRect& bounds, SkPoint p0, SkPoint p1, SkPoint edges[]) {
70     SkPoint* edgesStart = edges;
71
72     if (p0.fY == p1.fY) {
73         return 0;
74     }
75
76     if (p0.fY > p1.fY) {
77         using std::swap;
78         swap(p0, p1);
79     }
80     // now we're monotonic in Y: p0 <= p1
81     if (p1.fY <= bounds.top() || p0.fY >= bounds.bottom()) {
82         return 0;
83     }
84
85     double dxdy = (double)(p1.fX - p0.fX) / (p1.fY - p0.fY);
86     if (p0.fY < bounds.top()) {
87         p0.fX = SkDoubleToScalar(p0.fX + dxdy * (bounds.top() - p0.fY));
88         p0.fY = bounds.top();
89     }
90     if (p1.fY > bounds.bottom()) {
91         p1.fX = SkDoubleToScalar(p1.fX + dxdy * (bounds.bottom() - p1.fY));
92         p1.fY = bounds.bottom();
93     }
94
95     // Now p0...p1 is strictly inside bounds vertically, so we just need to clip horizontally
96
97     if (p0.fX > p1.fX) {
98         using std::swap;
99         swap(p0, p1);
100     }
101     // now we're left-to-right: p0 .. p1
102
103     if (p1.fX <= bounds.left()) {   // entirely to the left
104         p0.fX = p1.fX = bounds.left();
105         *edges++ = p0;
106         *edges++ = p1;
107         return 2;
108     }
109     if (p0.fX >= bounds.right()) {  // entirely to the right
110         p0.fX = p1.fX = bounds.right();
111         *edges++ = p0;
112         *edges++ = p1;
113         return 2;
114     }
115
116     if (p0.fX < bounds.left()) {
117         float y = SkDoubleToScalar(p0.fY + (bounds.left() - p0.fX) / dxdy);
118         *edges++ = SkPoint::Make(bounds.left(), p0.fY);
119         *edges++ = SkPoint::Make(bounds.left(), y);
120         p0.set(bounds.left(), y);
121     }
122     if (p1.fX > bounds.right()) {
123         float y = SkDoubleToScalar(p0.fY + (bounds.right() - p0.fX) / dxdy);
124         *edges++ = p0;
125         *edges++ = SkPoint::Make(bounds.right(), y);
126         *edges++ = SkPoint::Make(bounds.right(), p1.fY);
127     } else {
128         *edges++ = p0;
129         *edges++ = p1;
130     }
131     return SkToInt(edges - edgesStart);
132 }
133
134 static void draw_clipped_line(SkCanvas* canvas, const SkRect& bounds,
135                               SkPoint p0, SkPoint p1, const SkPaint& paint) {
136     SkPoint verts[6];
137     int count = clip_line(bounds, p0, p1, verts);
138
139     SkPath path;
140     path.addPoly(verts, count, false);
141     canvas->drawPath(path, paint);
142 }
143
144 // Demonstrate edge-clipping that is used in the scan converter
145 //
146 class EdgeClipView : public Sample {
147     enum {
148         N = 3
149     };
150 public:
151     SkPoint fPoly[N];
152     SkRect  fClip;
153     SkColor fEdgeColor[N];
154
155     EdgeClipView() : fClip(SkRect::MakeLTRB(150, 150, 550, 450)) {
156         fPoly[0].set(300, 40);
157         fPoly[1].set(550, 250);
158         fPoly[2].set(40, 450);
159
160         fEdgeColor[0] = 0xFFFF0000;
161         fEdgeColor[1] = 0xFF00FF00;
162         fEdgeColor[2] = 0xFF0000FF;
163     }
164
165 protected:
166     SkString name() override { return SkString("EdgeClip"); }
167
168     static SkScalar snap(SkScalar x) {
169         return SkScalarRoundToScalar(x * 0.5f) * 2;
170     }
171     static SkPoint snap(const SkPoint& pt) {
172         return SkPoint::Make(snap(pt.x()), snap(pt.y()));
173     }
174     static void snap(SkPoint dst[], const SkPoint src[], int count) {
175         for (int i = 0; i < count; ++i) {
176             dst[i] = snap(src[i]);
177         }
178     }
179
180     void onDrawContent(SkCanvas* canvas) override {
181         SkPath path;
182         path.addPoly(fPoly, N, true);
183
184         // Draw the full triangle, stroked and filled
185         SkPaint p;
186         p.setAntiAlias(true);
187         p.setColor(0xFFE0E0E0);
188         canvas->drawPath(path, p);
189         p.setStyle(SkPaint::kStroke_Style);
190         p.setStrokeWidth(2);
191         for (int i = 0; i < N; ++i) {
192             const int j = (i + 1) % N;
193             p.setColor(fEdgeColor[i]);
194             p.setAlpha(0x88);
195             canvas->drawLine(fPoly[i], fPoly[j], p);
196         }
197         p.setStyle(SkPaint::kFill_Style);
198
199         // Draw the clip itself
200         p.setColor(0xFF8888CC);
201         canvas->drawRect(fClip, p);
202
203         // Draw the filled triangle through the clip
204         p.setColor(0xFF88CC88);
205         canvas->save();
206         canvas->clipRect(fClip);
207         canvas->drawPath(path, p);
208         canvas->restore();
209
210         p.setStyle(SkPaint::kStroke_Style);
211         p.setStrokeWidth(6);
212
213         // Draw each of the "Edges" that survived the clipping
214         // We use a layer, so we can PLUS the different edge-colors, showing where two edges
215         // canceled each other out.
216         canvas->saveLayer(nullptr, nullptr);
217         p.setBlendMode(SkBlendMode::kPlus);
218         for (int i = 0; i < N; ++i) {
219             const int j = (i + 1) % N;
220             p.setColor(fEdgeColor[i]);
221             draw_clipped_line(canvas, fClip, fPoly[i], fPoly[j], p);
222         }
223         canvas->restore();
224     }
225
226     class MyClick : public Click {
227     public:
228         MyClick() {}
229         virtual void handleMove() = 0;
230     };
231
232     class VertClick : public MyClick {
233         SkPoint* fPt;
234     public:
235         VertClick(SkPoint* pt) : fPt(pt) {}
236         void handleMove() override { *fPt = snap(fCurr); }
237     };
238
239     class DragRectClick : public MyClick {
240         SkRect* fRect;
241     public:
242         DragRectClick(SkRect* rect) : fRect(rect) {}
243         void handleMove() override { fRect->offset(fCurr.x() - fPrev.x(), fCurr.y() - fPrev.y()); }
244     };
245
246     class DragPolyClick : public MyClick {
247         SkPoint fSrc[100];
248         SkPoint* fPoly;
249         int fCount;
250     public:
251         DragPolyClick(SkPoint poly[], int count) : fPoly(poly), fCount(count)
252         {
253             SkASSERT((size_t)count <= SK_ARRAY_COUNT(fSrc));
254             memcpy(fSrc, poly, count * sizeof(SkPoint));
255         }
256         void handleMove() override {
257             const SkScalar dx = fCurr.x() - fOrig.x();
258             const SkScalar dy = fCurr.y() - fOrig.y();
259             for (int i = 0; i < fCount; ++i) {
260                 fPoly[i].set(snap(fSrc[i].x() + dx), snap(fSrc[i].y() + dy));
261             }
262         }
263     };
264
265     class DoNothingClick : public MyClick {
266     public:
267         DoNothingClick() {}
268         void handleMove() override {}
269     };
270
271     static bool hit_test(const SkPoint& pt, SkScalar x, SkScalar y) {
272         const SkScalar rad = 8;
273         const SkScalar dx = pt.x() - x;
274         const SkScalar dy = pt.y() - y;
275         return dx*dx + dy*dy <= rad*rad;
276     }
277
278     Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override {
279         for (int i = 0; i < N; ++i) {
280             if (hit_test(fPoly[i], x, y)) {
281                 return new VertClick(&fPoly[i]);
282             }
283         }
284
285         SkPath path;
286         path.addPoly(fPoly, N, true);
287         if (path.contains(x, y)) {
288             return new DragPolyClick(fPoly, N);
289         }
290
291         if (fClip.intersects(SkRect::MakeLTRB(x - 1, y - 1, x + 1, y + 1))) {
292             return new DragRectClick(&fClip);
293         }
294         return new DoNothingClick();
295     }
296
297     bool onClick(Click* click) override {
298         ((MyClick*)click)->handleMove();
299         return true;
300     }
301
302 private:
303     using INHERITED = Sample;
304 };
305
306 DEF_SAMPLE( return new EdgeClipView; )