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