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