Home | History | Annotate | Download | only in gm
      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         SkFAIL("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         SkFAIL("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