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 24enum 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] 37static const float kMin = 100.5f; 38static const float kMid = 200.0f; 39static 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) 43static const float kXlate = 100.0f; 44 45SkRect create_rect(const SkPoint& offset) { 46 SkRect r = SkRect::MakeLTRB(kMin, kMin, kMax, kMax); 47 r.offset(offset); 48 return r; 49} 50 51SkRRect create_rrect(const SkPoint& offset) { 52 SkRRect rrect; 53 rrect.setRectXY(create_rect(offset), 10, 10); 54 return rrect; 55} 56 57SkRRect create_circle(const SkPoint& offset) { 58 SkRRect circle; 59 circle.setOval(create_rect(offset)); 60 return circle; 61} 62 63SkPath 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 73SkPath 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 89static 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 117class ClipDrawMatchView : public SampleView { 118public: 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, SkTime::GetMSecs() + 1000, values); 125 values[1] = 1; 126 fTrans.setKeyFrame(1, SkTime::GetMSecs() + 2000, values); 127 values[0] = values[1] = 1; 128 fTrans.setKeyFrame(2, SkTime::GetMSecs() + 3000, values); 129 values[1] = 0; 130 fTrans.setKeyFrame(3, SkTime::GetMSecs() + 4000, values); 131 values[0] = 0; 132 fTrans.setKeyFrame(4, SkTime::GetMSecs() + 5000, values); 133 } 134 135protected: 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; this->inval(nullptr); return true; 145 case '2': fGeom = kRRect_Geometry; this->inval(nullptr); return true; 146 case '3': fGeom = kCircle_Geometry; this->inval(nullptr); return true; 147 case '4': fGeom = kConvexPath_Geometry; this->inval(nullptr); return true; 148 case '5': fGeom = kConcavePath_Geometry; this->inval(nullptr); return true; 149 case '6': fGeom = kRectAndRect_Geometry; this->inval(nullptr); return true; 150 case '7': fGeom = kRectAndRRect_Geometry; this->inval(nullptr); return true; 151 case '8': fGeom = kRectAndConvex_Geometry; this->inval(nullptr); return true; 152 case '9': fGeom = kRectAndConcave_Geometry; this->inval(nullptr); return true; 153 case 'f': fSign = -fSign; this->inval(nullptr); return true; 154 case 't': fClipFirst = !fClipFirst; this->inval(nullptr); return true; 155 default: break; 156 } 157 } 158 return this->INHERITED::onQuery(evt); 159 } 160 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), SkRegion::kReplace_Op, useAA); 168 break; 169 case kRRect_Geometry: 170 canvas->clipRRect(create_rrect(offset), SkRegion::kReplace_Op, useAA); 171 break; 172 case kCircle_Geometry: 173 canvas->clipRRect(create_circle(offset), SkRegion::kReplace_Op, useAA); 174 break; 175 case kConvexPath_Geometry: 176 canvas->clipPath(create_convex_path(offset), SkRegion::kReplace_Op, useAA); 177 break; 178 case kConcavePath_Geometry: 179 canvas->clipPath(create_concave_path(offset), SkRegion::kReplace_Op, useAA); 180 break; 181 case kRectAndRect_Geometry: { 182 SkRect r = create_rect(offset); 183 r.offset(fSign * kXlate, fSign * kXlate); 184 canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips 185 canvas->clipRect(create_rect(offset), SkRegion::kIntersect_Op, useAA); 186 } break; 187 case kRectAndRRect_Geometry: { 188 SkRect r = create_rect(offset); 189 r.offset(fSign * kXlate, fSign * kXlate); 190 canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips 191 canvas->clipRRect(create_rrect(offset), SkRegion::kIntersect_Op, useAA); 192 } break; 193 case kRectAndConvex_Geometry: { 194 SkRect r = create_rect(offset); 195 r.offset(fSign * kXlate, fSign * kXlate); 196 canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips 197 canvas->clipPath(create_convex_path(offset), SkRegion::kIntersect_Op, useAA); 198 } break; 199 case kRectAndConcave_Geometry: { 200 SkRect r = create_rect(offset); 201 r.offset(fSign * kXlate, fSign * kXlate); 202 canvas->clipRect(r, SkRegion::kReplace_Op, true); // AA here forces shader clips 203 canvas->clipPath(create_concave_path(offset), SkRegion::kIntersect_Op, useAA); 204 } break; 205 } 206 207 SkISize size = canvas->getDeviceSize(); 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. 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 232 void onDrawContent(SkCanvas* canvas) override { 233 SkScalar trans[2]; 234 fTrans.timeToValues(SkTime::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 this->inval(nullptr); 244 } 245 246private: 247 SkInterpolator fTrans; 248 Geometry fGeom; 249 bool fClipFirst; 250 int fSign; 251 252 typedef SampleView INHERITED; 253}; 254 255////////////////////////////////////////////////////////////////////////////// 256 257static SkView* MyFactory() { return new ClipDrawMatchView; } 258static SkViewRegister reg(MyFactory); 259