1 /* 2 * Copyright 2016 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 "gm.h" 9 #include "sk_tool_utils.h" 10 #include "SkBlurMaskFilter.h" 11 #include "SkRRect.h" 12 13 static SkRect offset_center_to(const SkIRect& src, SkScalar x, SkScalar y) { 14 SkScalar halfW = 0.5f * src.width(); 15 SkScalar halfH = 0.5f * src.height(); 16 17 return SkRect::MakeLTRB(x - halfW, y - halfH, x + halfW, y + halfH); 18 } 19 20 static void draw_rrect(SkCanvas* canvas, const SkRRect& rr, const SkRRect& occRR) { 21 const SkScalar kBlurSigma = 5.0f; 22 23 SkRect occRect; 24 SkColor strokeColor; 25 26 { 27 SkRect occRect1 = sk_tool_utils::compute_central_occluder(occRR); 28 SkRect occRect2 = sk_tool_utils::compute_widest_occluder(occRR); 29 SkRect occRect3 = sk_tool_utils::compute_tallest_occluder(occRR); 30 31 SkScalar area1 = occRect1.width() * occRect1.height(); 32 SkScalar area2 = occRect2.width() * occRect2.height(); 33 SkScalar area3 = occRect3.width() * occRect3.height(); 34 35 if (area1 >= area2 && area1 >= area3) { 36 strokeColor = SK_ColorRED; 37 occRect = occRect1; 38 } else if (area2 > area3) { 39 strokeColor = SK_ColorYELLOW; 40 occRect = occRect2; 41 } else { 42 strokeColor = SK_ColorCYAN; 43 occRect = occRect3; 44 } 45 } 46 47 // draw the blur 48 SkPaint paint; 49 paint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle, kBlurSigma, occRect)); 50 canvas->drawRRect(rr, paint); 51 52 // draw the stroked geometry of the full occluder 53 SkPaint stroke; 54 stroke.setStyle(SkPaint::kStroke_Style); 55 stroke.setColor(SK_ColorBLUE); 56 canvas->drawRRect(occRR, stroke); 57 58 // draw the geometry of the occluding rect 59 stroke.setColor(strokeColor); 60 canvas->drawRect(occRect, stroke); 61 } 62 63 static void draw_45(SkCanvas* canvas, SkRRect::Corner corner, 64 SkScalar dist, const SkPoint& center) { 65 SkRRect::Corner left = SkRRect::kUpperLeft_Corner, right = SkRRect::kUpperLeft_Corner; 66 SkVector dir = { 0, 0 }; 67 68 constexpr SkScalar kSize = 64.0f / SK_ScalarSqrt2; 69 70 switch (corner) { 71 case SkRRect::kUpperLeft_Corner: 72 left = SkRRect::kUpperRight_Corner; 73 right = SkRRect::kLowerLeft_Corner; 74 75 dir.set(-SK_ScalarRoot2Over2, -SK_ScalarRoot2Over2); 76 break; 77 case SkRRect::kUpperRight_Corner: 78 left = SkRRect::kUpperLeft_Corner; 79 right = SkRRect::kLowerRight_Corner; 80 dir.set(SK_ScalarRoot2Over2, -SK_ScalarRoot2Over2); 81 break; 82 case SkRRect::kLowerRight_Corner: 83 left = SkRRect::kLowerLeft_Corner; 84 right = SkRRect::kUpperRight_Corner; 85 dir.set(SK_ScalarRoot2Over2, SK_ScalarRoot2Over2); 86 break; 87 case SkRRect::kLowerLeft_Corner: 88 left = SkRRect::kLowerRight_Corner; 89 right = SkRRect::kUpperLeft_Corner; 90 dir.set(-SK_ScalarRoot2Over2, SK_ScalarRoot2Over2); 91 break; 92 default: 93 SK_ABORT("Invalid shape."); 94 } 95 96 SkRect r = SkRect::MakeWH(kSize, kSize); 97 // UL, UR, LR, LL 98 SkVector radii[4] = { { 0.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 0.0f } }; 99 radii[left] = SkVector::Make(kSize, kSize); 100 radii[right] = SkVector::Make(kSize, kSize); 101 SkRRect rr; 102 rr.setRectRadii( 103 offset_center_to(r.roundOut(), center.fX + dist*dir.fX, center.fY + dist*dir.fY), 104 radii); 105 106 SkRRect occRR; 107 dist -= 10.0f; 108 occRR.setRectRadii( 109 offset_center_to(r.roundOut(), center.fX + dist*dir.fX, center.fY + dist*dir.fY), 110 radii); 111 112 draw_rrect(canvas, rr, occRR); 113 } 114 115 static void draw_45_simple(SkCanvas* canvas, const SkVector& v, 116 SkScalar dist, const SkPoint& center) { 117 SkIRect r = SkIRect::MakeWH(64, 64); 118 SkRRect rr = SkRRect::MakeRectXY( 119 offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY), 120 8, 8); 121 122 dist -= 10.0f; 123 SkRRect occRR = SkRRect::MakeRectXY( 124 offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY), 125 8, 8); 126 127 draw_rrect(canvas, rr, occRR); 128 } 129 130 static void draw_90(SkCanvas* canvas, const SkVector& v, SkScalar dist, const SkPoint& center) { 131 constexpr int kWidth = 25; 132 133 SkIRect r; 134 if (fabs(v.fX) < fabs(v.fY)) { 135 r = SkIRect::MakeWH(kWidth, 64); 136 } else { 137 r = SkIRect::MakeWH(64, kWidth); 138 } 139 SkRRect rr = SkRRect::MakeOval( 140 offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY)); 141 142 dist -= 10.0f; 143 SkRRect occRR = SkRRect::MakeOval( 144 offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY)); 145 146 draw_rrect(canvas, rr, occRR); 147 } 148 149 static void draw_90_simple(SkCanvas* canvas, const SkVector& v, 150 SkScalar dist, const SkPoint& center) { 151 constexpr int kLength = 128; 152 // The width needs to be larger than 2*3*blurRadii+2*cornerRadius for the analytic 153 // RRect blur to kick in 154 constexpr int kWidth = 47; 155 156 SkIRect r; 157 if (fabs(v.fX) < fabs(v.fY)) { 158 r = SkIRect::MakeWH(kLength, kWidth); 159 } else { 160 r = SkIRect::MakeWH(kWidth, kLength); 161 } 162 SkRRect rr = SkRRect::MakeRectXY( 163 offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY), 164 8, 8); 165 166 dist -= 10.0f; 167 SkRRect occRR = SkRRect::MakeRectXY( 168 offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY), 169 8, 8); 170 171 draw_rrect(canvas, rr, occRR); 172 } 173 174 static void draw_30_60(SkCanvas* canvas, SkRRect::Corner corner, const SkVector& v, 175 SkScalar dist, const SkPoint& center) { 176 SkRRect::Corner left = SkRRect::kUpperLeft_Corner, right = SkRRect::kUpperLeft_Corner; 177 178 constexpr int kLength = 64; 179 constexpr int kWidth = 30; 180 181 switch (corner) { 182 case SkRRect::kUpperLeft_Corner: 183 left = SkRRect::kUpperRight_Corner; 184 right = SkRRect::kLowerLeft_Corner; 185 break; 186 case SkRRect::kUpperRight_Corner: 187 left = SkRRect::kUpperLeft_Corner; 188 right = SkRRect::kLowerRight_Corner; 189 break; 190 case SkRRect::kLowerRight_Corner: 191 left = SkRRect::kLowerLeft_Corner; 192 right = SkRRect::kUpperRight_Corner; 193 break; 194 case SkRRect::kLowerLeft_Corner: 195 left = SkRRect::kLowerRight_Corner; 196 right = SkRRect::kUpperLeft_Corner; 197 break; 198 default: 199 SK_ABORT("Invalid shape."); 200 } 201 202 SkIRect r; 203 if (fabs(v.fX) < fabs(v.fY)) { 204 r = SkIRect::MakeWH(kLength, kWidth); 205 } else { 206 r = SkIRect::MakeWH(kWidth, kLength); 207 } 208 // UL, UR, LR, LL 209 SkVector radii[4] = { { 0.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 0.0f } }; 210 radii[left] = SkVector::Make(SkIntToScalar(kWidth), SkIntToScalar(kWidth)); 211 radii[right] = SkVector::Make(SkIntToScalar(kWidth), SkIntToScalar(kWidth)); 212 SkRRect rr; 213 rr.setRectRadii(offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY), radii); 214 215 dist -= 10.0f; 216 SkRRect occRR; 217 occRR.setRectRadii(offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY), radii); 218 draw_rrect(canvas, rr, occRR); 219 } 220 221 namespace skiagm { 222 223 class OccludedRRectBlurGM : public GM { 224 public: 225 OccludedRRectBlurGM() { 226 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC)); 227 } 228 229 protected: 230 231 SkString onShortName() override { 232 return SkString("occludedrrectblur"); 233 } 234 235 SkISize onISize() override { 236 return SkISize::Make(kWidth, kHeight); 237 } 238 239 void onDraw(SkCanvas* canvas) override { 240 const SkPoint center = SkPoint::Make(kWidth/2, kHeight/2); 241 242 // outer-most big RR 243 { 244 SkIRect r = SkIRect::MakeWH(420, 420); 245 SkRRect rr = SkRRect::MakeRectXY(offset_center_to(r, center.fX, center.fY), 64, 64); 246 draw_rrect(canvas, rr, rr); 247 248 #if 1 249 // TODO: remove this. Until we actually start skipping the middle draw we need this 250 // to provide contrast 251 SkPaint temp; 252 temp.setColor(sk_tool_utils::color_to_565(0xFFCCCCCC)); 253 r.inset(32, 32); 254 canvas->drawRect(offset_center_to(r, center.fX, center.fY), temp); 255 #endif 256 } 257 258 // center circle 259 { 260 SkIRect r = SkIRect::MakeWH(32, 32); 261 SkRRect rr = SkRRect::MakeOval(offset_center_to(r, center.fX, center.fY)); 262 draw_rrect(canvas, rr, rr); 263 } 264 265 draw_45(canvas, SkRRect::kUpperLeft_Corner, 64, center); 266 draw_45(canvas, SkRRect::kUpperRight_Corner, 64, center); 267 draw_45(canvas, SkRRect::kLowerRight_Corner, 64, center); 268 draw_45(canvas, SkRRect::kLowerLeft_Corner, 64, center); 269 270 draw_90(canvas, SkVector::Make(-1.0f, 0.0f), 64, center); 271 draw_90(canvas, SkVector::Make(0.0f, -1.0f), 64, center); 272 draw_90(canvas, SkVector::Make(1.0f, 0.0f), 64, center); 273 draw_90(canvas, SkVector::Make(0.0f, 1.0f), 64, center); 274 275 constexpr SkScalar kRoot3Over2 = 0.8660254037844386f; 276 277 draw_30_60(canvas, SkRRect::kLowerLeft_Corner, 278 SkVector::Make(0.5f, kRoot3Over2), 120, center); 279 draw_30_60(canvas, SkRRect::kUpperRight_Corner, 280 SkVector::Make(kRoot3Over2, 0.5f), 120, center); 281 282 draw_30_60(canvas, SkRRect::kUpperLeft_Corner, 283 SkVector::Make(-0.5f, kRoot3Over2), 120, center); 284 draw_30_60(canvas, SkRRect::kLowerRight_Corner, 285 SkVector::Make(-kRoot3Over2, 0.5f), 120, center); 286 287 draw_30_60(canvas, SkRRect::kLowerLeft_Corner, 288 SkVector::Make(-0.5f, -kRoot3Over2), 120, center); 289 draw_30_60(canvas, SkRRect::kUpperRight_Corner, 290 SkVector::Make(-kRoot3Over2, -0.5f), 120, center); 291 292 draw_30_60(canvas, SkRRect::kUpperLeft_Corner, 293 SkVector::Make(0.5f, -kRoot3Over2), 120, center); 294 draw_30_60(canvas, SkRRect::kLowerRight_Corner, 295 SkVector::Make(kRoot3Over2, -0.5f), 120, center); 296 297 draw_45_simple(canvas, SkVector::Make(-SK_ScalarRoot2Over2, -SK_ScalarRoot2Over2), 298 210, center); 299 draw_45_simple(canvas, SkVector::Make(SK_ScalarRoot2Over2, -SK_ScalarRoot2Over2), 300 210, center); 301 draw_45_simple(canvas, SkVector::Make(SK_ScalarRoot2Over2, SK_ScalarRoot2Over2), 302 210, center); 303 draw_45_simple(canvas, SkVector::Make(-SK_ScalarRoot2Over2, SK_ScalarRoot2Over2), 304 210, center); 305 306 draw_90_simple(canvas, SkVector::Make(-1.0f, 0.0f), 160, center); 307 draw_90_simple(canvas, SkVector::Make(0.0f, -1.0f), 160, center); 308 draw_90_simple(canvas, SkVector::Make(1.0f, 0.0f), 160, center); 309 draw_90_simple(canvas, SkVector::Make(0.0f, 1.0f), 160, center); 310 } 311 312 private: 313 static constexpr int kWidth = 440; 314 static constexpr int kHeight = 440; 315 316 typedef GM INHERITED; 317 }; 318 319 ////////////////////////////////////////////////////////////////////////////// 320 321 DEF_GM(return new OccludedRRectBlurGM;) 322 } 323