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