robertphillips | 7defaa6 | 2015-01-27 06:17:22 -0800 | [diff] [blame] | 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" |
bungeman | d3ebb48 | 2015-08-05 13:57:49 -0700 | [diff] [blame] | 11 | #include "SkPath.h" |
| 12 | #include "SkRRect.h" |
robertphillips | 7defaa6 | 2015-01-27 06:17:22 -0800 | [diff] [blame] | 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 |
robertphillips | c89f6fb | 2015-02-09 07:47:17 -0800 | [diff] [blame] | 21 | // f: flip-flops which corner the bottom AA clip rect occupies in the complex clip cases |
robertphillips | 7defaa6 | 2015-01-27 06:17:22 -0800 | [diff] [blame] | 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 | |
robertphillips | c89f6fb | 2015-02-09 07:47:17 -0800 | [diff] [blame] | 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 | |
robertphillips | 7defaa6 | 2015-01-27 06:17:22 -0800 | [diff] [blame] | 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 | |
| 51 | SkRRect create_rrect(const SkPoint& offset) { |
| 52 | SkRRect rrect; |
| 53 | rrect.setRectXY(create_rect(offset), 10, 10); |
| 54 | return rrect; |
| 55 | } |
| 56 | |
| 57 | SkRRect create_circle(const SkPoint& offset) { |
| 58 | SkRRect circle; |
| 59 | circle.setOval(create_rect(offset)); |
| 60 | return circle; |
| 61 | } |
| 62 | |
| 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 | |
| 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 | |
robertphillips | 7defaa6 | 2015-01-27 06:17:22 -0800 | [diff] [blame] | 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: |
robertphillips | c89f6fb | 2015-02-09 07:47:17 -0800 | [diff] [blame] | 119 | ClipDrawMatchView() : fTrans(2, 5), fGeom(kRect_Geometry), fClipFirst(true), fSign(1) { |
robertphillips | 7defaa6 | 2015-01-27 06:17:22 -0800 | [diff] [blame] | 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 | |
| 135 | protected: |
mtklein | 36352bf | 2015-03-25 18:17:31 -0700 | [diff] [blame] | 136 | bool onQuery(SkEvent* evt) override { |
robertphillips | 7defaa6 | 2015-01-27 06:17:22 -0800 | [diff] [blame] | 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) { |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 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; |
robertphillips | 7defaa6 | 2015-01-27 06:17:22 -0800 | [diff] [blame] | 155 | default: break; |
| 156 | } |
| 157 | } |
| 158 | return this->INHERITED::onQuery(evt); |
| 159 | } |
| 160 | |
robertphillips | c89f6fb | 2015-02-09 07:47:17 -0800 | [diff] [blame] | 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 | |
robertphillips | 7defaa6 | 2015-01-27 06:17:22 -0800 | [diff] [blame] | 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) { |
robertphillips | c89f6fb | 2015-02-09 07:47:17 -0800 | [diff] [blame] | 222 | this->drawClippedGeom(canvas, offset, useAA); |
robertphillips | 7defaa6 | 2015-01-27 06:17:22 -0800 | [diff] [blame] | 223 | } |
| 224 | |
| 225 | draw_normal_geom(canvas, offset, fGeom, useAA); |
| 226 | |
| 227 | if (!fClipFirst) { |
robertphillips | c89f6fb | 2015-02-09 07:47:17 -0800 | [diff] [blame] | 228 | this->drawClippedGeom(canvas, offset, useAA); |
robertphillips | 7defaa6 | 2015-01-27 06:17:22 -0800 | [diff] [blame] | 229 | } |
| 230 | } |
| 231 | |
mtklein | 36352bf | 2015-03-25 18:17:31 -0700 | [diff] [blame] | 232 | void onDrawContent(SkCanvas* canvas) override { |
robertphillips | 7defaa6 | 2015-01-27 06:17:22 -0800 | [diff] [blame] | 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 | |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 243 | this->inval(nullptr); |
robertphillips | 7defaa6 | 2015-01-27 06:17:22 -0800 | [diff] [blame] | 244 | } |
| 245 | |
| 246 | private: |
| 247 | SkInterpolator fTrans; |
| 248 | Geometry fGeom; |
| 249 | bool fClipFirst; |
robertphillips | c89f6fb | 2015-02-09 07:47:17 -0800 | [diff] [blame] | 250 | int fSign; |
robertphillips | 7defaa6 | 2015-01-27 06:17:22 -0800 | [diff] [blame] | 251 | |
| 252 | typedef SampleView INHERITED; |
| 253 | }; |
| 254 | |
| 255 | ////////////////////////////////////////////////////////////////////////////// |
| 256 | |
| 257 | static SkView* MyFactory() { return new ClipDrawMatchView; } |
| 258 | static SkViewRegister reg(MyFactory); |