0dbe2b1405ea9da2d9101edee6770827da1071bc
[platform/upstream/libSkiaSharp.git] / samplecode / SampleClipDrawMatch.cpp
1 /*
2  * Copyright 2015 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 "SampleCode.h"
9 #include "SkCanvas.h"
10 #include "SkInterpolator.h"
11 #include "SkTime.h"
12
13 // This slide tests out the match up between BW clipping and rendering. It can
14 // draw a large rect through some clip geometry and draw the same geometry
15 // normally. Which one is drawn first can be toggled. The pair of objects is translated
16 // fractionally (via an animator) to expose snapping bugs. The key bindings are:
17 //      1-9: the different geometries
18 //      t:   toggle which is drawn first the clip or the normal geometry
19 //      f:   flip-flops which corner the bottom AA clip rect occupies in the complex clip cases
20
21 // The possible geometric combinations to test
22 enum Geometry {
23     kRect_Geometry,
24     kRRect_Geometry,
25     kCircle_Geometry,
26     kConvexPath_Geometry,
27     kConcavePath_Geometry,
28     kRectAndRect_Geometry,
29     kRectAndRRect_Geometry,
30     kRectAndConvex_Geometry,
31     kRectAndConcave_Geometry
32 };
33
34 // The basic rect used is [kMin,kMin]..[kMax,kMax]
35 static const float kMin = 100.5f;
36 static const float kMid = 200.0f;
37 static const float kMax = 299.5f;
38
39 // The translation applied to the base AA rect in the combination cases
40 // (i.e., kRectAndRect through kRectAndConcave)
41 static const float kXlate = 100.0f;
42
43 SkRect create_rect(const SkPoint& offset) {
44     SkRect r = SkRect::MakeLTRB(kMin, kMin, kMax, kMax);
45     r.offset(offset);
46     return r;
47 }
48
49 SkRRect create_rrect(const SkPoint& offset) {
50     SkRRect rrect;
51     rrect.setRectXY(create_rect(offset), 10, 10);
52     return rrect;
53 }
54
55 SkRRect create_circle(const SkPoint& offset) {
56     SkRRect circle;
57     circle.setOval(create_rect(offset));
58     return circle;
59 }
60
61 SkPath create_convex_path(const SkPoint& offset) {
62     SkPath convexPath;
63     convexPath.moveTo(kMin, kMin);
64     convexPath.lineTo(kMax, kMax);
65     convexPath.lineTo(kMin, kMax);
66     convexPath.close();
67     convexPath.offset(offset.fX, offset.fY);
68     return convexPath;
69 }
70
71 SkPath create_concave_path(const SkPoint& offset) {
72     SkPath concavePath;
73     concavePath.moveTo(kMin, kMin);
74     concavePath.lineTo(kMid, 105.0f);
75     concavePath.lineTo(kMax, kMin);
76     concavePath.lineTo(295.0f, kMid);
77     concavePath.lineTo(kMax, kMax);
78     concavePath.lineTo(kMid, 295.0f);
79     concavePath.lineTo(kMin, kMax);
80     concavePath.lineTo(105.0f, kMid);
81     concavePath.close();
82
83     concavePath.offset(offset.fX, offset.fY);
84     return concavePath;
85 }
86
87 static void draw_normal_geom(SkCanvas* canvas, const SkPoint& offset, int geom, bool useAA) {
88     SkPaint p;
89     p.setAntiAlias(useAA);
90     p.setColor(SK_ColorBLACK);
91
92     switch (geom) {
93     case kRect_Geometry:                // fall thru
94     case kRectAndRect_Geometry:
95         canvas->drawRect(create_rect(offset), p);
96         break;
97     case kRRect_Geometry:               // fall thru
98     case kRectAndRRect_Geometry:
99         canvas->drawRRect(create_rrect(offset), p);
100         break;
101     case kCircle_Geometry:
102         canvas->drawRRect(create_circle(offset), p);
103         break;
104     case kConvexPath_Geometry:          // fall thru
105     case kRectAndConvex_Geometry:
106         canvas->drawPath(create_convex_path(offset), p);
107         break;
108     case kConcavePath_Geometry:         // fall thru
109     case kRectAndConcave_Geometry:
110         canvas->drawPath(create_concave_path(offset), p);
111         break;
112     } 
113 }
114
115 class ClipDrawMatchView : public SampleView {
116 public:
117     ClipDrawMatchView() : fTrans(2, 5), fGeom(kRect_Geometry), fClipFirst(true), fSign(1) {
118         SkScalar values[2];
119
120         fTrans.setRepeatCount(999);
121         values[0] = values[1] = 0;
122         fTrans.setKeyFrame(0, SkTime::GetMSecs() + 1000, values);
123         values[1] = 1;
124         fTrans.setKeyFrame(1, SkTime::GetMSecs() + 2000, values);
125         values[0] = values[1] = 1;
126         fTrans.setKeyFrame(2, SkTime::GetMSecs() + 3000, values);
127         values[1] = 0;
128         fTrans.setKeyFrame(3, SkTime::GetMSecs() + 4000, values);
129         values[0] = 0;
130         fTrans.setKeyFrame(4, SkTime::GetMSecs() + 5000, values);
131     }
132
133 protected:
134     bool onQuery(SkEvent* evt) SK_OVERRIDE {
135         if (SampleCode::TitleQ(*evt)) {
136             SampleCode::TitleR(evt, "ClipDrawMatch");
137             return true;
138         }
139         SkUnichar uni;
140         if (SampleCode::CharQ(*evt, &uni)) {
141             switch (uni) {
142                 case '1': fGeom = kRect_Geometry; this->inval(NULL); return true;
143                 case '2': fGeom = kRRect_Geometry; this->inval(NULL); return true;
144                 case '3': fGeom = kCircle_Geometry; this->inval(NULL); return true;
145                 case '4': fGeom = kConvexPath_Geometry; this->inval(NULL); return true;
146                 case '5': fGeom = kConcavePath_Geometry; this->inval(NULL); return true;
147                 case '6': fGeom = kRectAndRect_Geometry; this->inval(NULL); return true;
148                 case '7': fGeom = kRectAndRRect_Geometry; this->inval(NULL); return true;
149                 case '8': fGeom = kRectAndConvex_Geometry; this->inval(NULL); return true;
150                 case '9': fGeom = kRectAndConcave_Geometry; this->inval(NULL); return true;
151                 case 'f': fSign = -fSign; this->inval(NULL); return true;
152                 case 't': fClipFirst = !fClipFirst; this->inval(NULL); return true;
153                 default: break;
154             }
155         }
156         return this->INHERITED::onQuery(evt);
157     }
158
159     void drawClippedGeom(SkCanvas* canvas, const SkPoint& offset, bool useAA) {
160
161         int count = canvas->save();
162
163         switch (fGeom) {
164         case kRect_Geometry:
165             canvas->clipRect(create_rect(offset), SkRegion::kReplace_Op, useAA);
166             break;
167         case kRRect_Geometry:
168             canvas->clipRRect(create_rrect(offset), SkRegion::kReplace_Op, useAA);
169             break;
170         case kCircle_Geometry:
171             canvas->clipRRect(create_circle(offset), SkRegion::kReplace_Op, useAA);
172             break;
173         case kConvexPath_Geometry:
174             canvas->clipPath(create_convex_path(offset), SkRegion::kReplace_Op, useAA);
175             break;
176         case kConcavePath_Geometry:
177             canvas->clipPath(create_concave_path(offset), SkRegion::kReplace_Op, useAA);
178             break;
179         case kRectAndRect_Geometry: {
180             SkRect r = create_rect(offset);
181             r.offset(fSign * kXlate, fSign * kXlate);
182             canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips
183             canvas->clipRect(create_rect(offset), SkRegion::kIntersect_Op, useAA);
184             } break;
185         case kRectAndRRect_Geometry: {
186             SkRect r = create_rect(offset);
187             r.offset(fSign * kXlate, fSign * kXlate);
188             canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips
189             canvas->clipRRect(create_rrect(offset), SkRegion::kIntersect_Op, useAA);
190             } break;
191         case kRectAndConvex_Geometry: {
192             SkRect r = create_rect(offset);
193             r.offset(fSign * kXlate, fSign * kXlate);
194             canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips
195             canvas->clipPath(create_convex_path(offset), SkRegion::kIntersect_Op, useAA);
196             } break;
197         case kRectAndConcave_Geometry: {
198             SkRect r = create_rect(offset);
199             r.offset(fSign * kXlate, fSign * kXlate);
200             canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips
201             canvas->clipPath(create_concave_path(offset), SkRegion::kIntersect_Op, useAA);
202             } break;
203         } 
204
205         SkISize size = canvas->getDeviceSize();
206         SkRect bigR = SkRect::MakeWH(SkIntToScalar(size.width()), SkIntToScalar(size.height()));
207
208         SkPaint p;
209         p.setColor(SK_ColorRED);
210
211         canvas->drawRect(bigR, p);
212         canvas->restoreToCount(count);
213     }
214
215     // Draw a big red rect through some clip geometry and also draw that same
216     // geometry in black. The order in which they are drawn can be swapped.
217     // This tests whether the clip and normally drawn geometry match up.
218     void drawGeometry(SkCanvas* canvas, const SkPoint& offset, bool useAA) {
219         if (fClipFirst) {
220             this->drawClippedGeom(canvas, offset, useAA);
221         }
222
223         draw_normal_geom(canvas, offset, fGeom, useAA);
224
225         if (!fClipFirst) {
226             this->drawClippedGeom(canvas, offset, useAA);
227         }
228     }
229
230     void onDrawContent(SkCanvas* canvas) SK_OVERRIDE {
231         SkScalar trans[2];
232         fTrans.timeToValues(SkTime::GetMSecs(), trans);
233
234         SkPoint offset;
235         offset.set(trans[0], trans[1]);
236
237         int saveCount = canvas->save();
238         this->drawGeometry(canvas, offset, false);
239         canvas->restoreToCount(saveCount);
240
241         this->inval(NULL);
242     }
243
244 private:
245     SkInterpolator  fTrans;
246     Geometry        fGeom;
247     bool            fClipFirst;
248     int             fSign;
249
250     typedef SampleView INHERITED;
251 };
252
253 //////////////////////////////////////////////////////////////////////////////
254
255 static SkView* MyFactory() { return new ClipDrawMatchView; }
256 static SkViewRegister reg(MyFactory);