| /* |
| * Copyright 2016 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "gm.h" |
| #include "SkBlurMaskFilter.h" |
| #include "SkRRect.h" |
| #include "sk_tool_utils.h" |
| |
| static SkRect offset_center_to(const SkIRect& src, SkScalar x, SkScalar y) { |
| SkScalar halfW = 0.5f * src.width(); |
| SkScalar halfH = 0.5f * src.height(); |
| |
| return SkRect::MakeLTRB(x - halfW, y - halfH, x + halfW, y + halfH); |
| } |
| |
| static void draw_rrect(SkCanvas* canvas, const SkRRect& rr, const SkRRect& occRR) { |
| const SkScalar kBlurSigma = 5.0f; |
| |
| SkRect occRect; |
| SkColor strokeColor; |
| |
| { |
| SkRect occRect1 = sk_tool_utils::compute_central_occluder(occRR); |
| SkRect occRect2 = sk_tool_utils::compute_widest_occluder(occRR); |
| SkRect occRect3 = sk_tool_utils::compute_tallest_occluder(occRR); |
| |
| SkScalar area1 = occRect1.width() * occRect1.height(); |
| SkScalar area2 = occRect2.width() * occRect2.height(); |
| SkScalar area3 = occRect3.width() * occRect3.height(); |
| |
| if (area1 >= area2 && area1 >= area3) { |
| strokeColor = SK_ColorRED; |
| occRect = occRect1; |
| } else if (area2 > area3) { |
| strokeColor = SK_ColorYELLOW; |
| occRect = occRect2; |
| } else { |
| strokeColor = SK_ColorCYAN; |
| occRect = occRect3; |
| } |
| } |
| |
| // draw the blur |
| SkPaint paint; |
| paint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle, kBlurSigma, occRect)); |
| canvas->drawRRect(rr, paint); |
| |
| // draw the stroked geometry of the full occluder |
| SkPaint stroke; |
| stroke.setStyle(SkPaint::kStroke_Style); |
| stroke.setColor(SK_ColorBLUE); |
| canvas->drawRRect(occRR, stroke); |
| |
| // draw the geometry of the occluding rect |
| stroke.setColor(strokeColor); |
| canvas->drawRect(occRect, stroke); |
| } |
| |
| static void draw_45(SkCanvas* canvas, SkRRect::Corner corner, |
| SkScalar dist, const SkPoint& center) { |
| SkRRect::Corner left = SkRRect::kUpperLeft_Corner, right = SkRRect::kUpperLeft_Corner; |
| SkVector dir = { 0, 0 }; |
| |
| static const SkScalar kSize = 64.0f / SK_ScalarSqrt2; |
| |
| switch (corner) { |
| case SkRRect::kUpperLeft_Corner: |
| left = SkRRect::kUpperRight_Corner; |
| right = SkRRect::kLowerLeft_Corner; |
| |
| dir.set(-SK_ScalarRoot2Over2, -SK_ScalarRoot2Over2); |
| break; |
| case SkRRect::kUpperRight_Corner: |
| left = SkRRect::kUpperLeft_Corner; |
| right = SkRRect::kLowerRight_Corner; |
| dir.set(SK_ScalarRoot2Over2, -SK_ScalarRoot2Over2); |
| break; |
| case SkRRect::kLowerRight_Corner: |
| left = SkRRect::kLowerLeft_Corner; |
| right = SkRRect::kUpperRight_Corner; |
| dir.set(SK_ScalarRoot2Over2, SK_ScalarRoot2Over2); |
| break; |
| case SkRRect::kLowerLeft_Corner: |
| left = SkRRect::kLowerRight_Corner; |
| right = SkRRect::kUpperLeft_Corner; |
| dir.set(-SK_ScalarRoot2Over2, SK_ScalarRoot2Over2); |
| break; |
| default: |
| SkFAIL("Invalid shape."); |
| } |
| |
| SkRect r = SkRect::MakeWH(kSize, kSize); |
| // UL, UR, LR, LL |
| SkVector radii[4] = { { 0.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 0.0f } }; |
| radii[left] = SkVector::Make(kSize, kSize); |
| radii[right] = SkVector::Make(kSize, kSize); |
| SkRRect rr; |
| rr.setRectRadii( |
| offset_center_to(r.roundOut(), center.fX + dist*dir.fX, center.fY + dist*dir.fY), |
| radii); |
| |
| SkRRect occRR; |
| dist -= 10.0f; |
| occRR.setRectRadii( |
| offset_center_to(r.roundOut(), center.fX + dist*dir.fX, center.fY + dist*dir.fY), |
| radii); |
| |
| draw_rrect(canvas, rr, occRR); |
| } |
| |
| static void draw_45_simple(SkCanvas* canvas, const SkVector& v, |
| SkScalar dist, const SkPoint& center) { |
| SkIRect r = SkIRect::MakeWH(64, 64); |
| SkRRect rr = SkRRect::MakeRectXY( |
| offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY), |
| 8, 8); |
| |
| dist -= 10.0f; |
| SkRRect occRR = SkRRect::MakeRectXY( |
| offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY), |
| 8, 8); |
| |
| draw_rrect(canvas, rr, occRR); |
| } |
| |
| static void draw_90(SkCanvas* canvas, const SkVector& v, SkScalar dist, const SkPoint& center) { |
| static const int kWidth = 25; |
| |
| SkIRect r; |
| if (fabs(v.fX) < fabs(v.fY)) { |
| r = SkIRect::MakeWH(kWidth, 64); |
| } else { |
| r = SkIRect::MakeWH(64, kWidth); |
| } |
| SkRRect rr = SkRRect::MakeOval( |
| offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY)); |
| |
| dist -= 10.0f; |
| SkRRect occRR = SkRRect::MakeOval( |
| offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY)); |
| |
| draw_rrect(canvas, rr, occRR); |
| } |
| |
| static void draw_90_simple(SkCanvas* canvas, const SkVector& v, |
| SkScalar dist, const SkPoint& center) { |
| static const int kLength = 128; |
| // The width needs to be larger than 2*3*blurRadii+2*cornerRadius for the analytic |
| // RRect blur to kick in |
| static const int kWidth = 47; |
| |
| SkIRect r; |
| if (fabs(v.fX) < fabs(v.fY)) { |
| r = SkIRect::MakeWH(kLength, kWidth); |
| } else { |
| r = SkIRect::MakeWH(kWidth, kLength); |
| } |
| SkRRect rr = SkRRect::MakeRectXY( |
| offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY), |
| 8, 8); |
| |
| dist -= 10.0f; |
| SkRRect occRR = SkRRect::MakeRectXY( |
| offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY), |
| 8, 8); |
| |
| draw_rrect(canvas, rr, occRR); |
| } |
| |
| static void draw_30_60(SkCanvas* canvas, SkRRect::Corner corner, const SkVector& v, |
| SkScalar dist, const SkPoint& center) { |
| SkRRect::Corner left = SkRRect::kUpperLeft_Corner, right = SkRRect::kUpperLeft_Corner; |
| |
| static const int kLength = 64; |
| static const int kWidth = 30; |
| |
| switch (corner) { |
| case SkRRect::kUpperLeft_Corner: |
| left = SkRRect::kUpperRight_Corner; |
| right = SkRRect::kLowerLeft_Corner; |
| break; |
| case SkRRect::kUpperRight_Corner: |
| left = SkRRect::kUpperLeft_Corner; |
| right = SkRRect::kLowerRight_Corner; |
| break; |
| case SkRRect::kLowerRight_Corner: |
| left = SkRRect::kLowerLeft_Corner; |
| right = SkRRect::kUpperRight_Corner; |
| break; |
| case SkRRect::kLowerLeft_Corner: |
| left = SkRRect::kLowerRight_Corner; |
| right = SkRRect::kUpperLeft_Corner; |
| break; |
| default: |
| SkFAIL("Invalid shape."); |
| } |
| |
| SkIRect r; |
| if (fabs(v.fX) < fabs(v.fY)) { |
| r = SkIRect::MakeWH(kLength, kWidth); |
| } else { |
| r = SkIRect::MakeWH(kWidth, kLength); |
| } |
| // UL, UR, LR, LL |
| SkVector radii[4] = { { 0.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 0.0f }, { 0.0f, 0.0f } }; |
| radii[left] = SkVector::Make(SkIntToScalar(kWidth), SkIntToScalar(kWidth)); |
| radii[right] = SkVector::Make(SkIntToScalar(kWidth), SkIntToScalar(kWidth)); |
| SkRRect rr; |
| rr.setRectRadii(offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY), radii); |
| |
| dist -= 10.0f; |
| SkRRect occRR; |
| occRR.setRectRadii(offset_center_to(r, center.fX + dist*v.fX, center.fY + dist*v.fY), radii); |
| draw_rrect(canvas, rr, occRR); |
| } |
| |
| namespace skiagm { |
| |
| class OccludedRRectBlurGM : public GM { |
| public: |
| OccludedRRectBlurGM() { |
| this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC)); |
| } |
| |
| protected: |
| |
| SkString onShortName() override { |
| return SkString("occludedrrectblur"); |
| } |
| |
| SkISize onISize() override { |
| return SkISize::Make(kWidth, kHeight); |
| } |
| |
| void onDraw(SkCanvas* canvas) override { |
| const SkPoint center = SkPoint::Make(kWidth/2, kHeight/2); |
| |
| // outer-most big RR |
| { |
| SkIRect r = SkIRect::MakeWH(420, 420); |
| SkRRect rr = SkRRect::MakeRectXY(offset_center_to(r, center.fX, center.fY), 64, 64); |
| draw_rrect(canvas, rr, rr); |
| |
| #if 1 |
| // TODO: remove this. Until we actually start skipping the middle draw we need this |
| // to provide contrast |
| SkPaint temp; |
| temp.setColor(sk_tool_utils::color_to_565(0xFFCCCCCC)); |
| r.inset(32, 32); |
| canvas->drawRect(offset_center_to(r, center.fX, center.fY), temp); |
| #endif |
| } |
| |
| // center circle |
| { |
| SkIRect r = SkIRect::MakeWH(32, 32); |
| SkRRect rr = SkRRect::MakeOval(offset_center_to(r, center.fX, center.fY)); |
| draw_rrect(canvas, rr, rr); |
| } |
| |
| draw_45(canvas, SkRRect::kUpperLeft_Corner, 64, center); |
| draw_45(canvas, SkRRect::kUpperRight_Corner, 64, center); |
| draw_45(canvas, SkRRect::kLowerRight_Corner, 64, center); |
| draw_45(canvas, SkRRect::kLowerLeft_Corner, 64, center); |
| |
| draw_90(canvas, SkVector::Make(-1.0f, 0.0f), 64, center); |
| draw_90(canvas, SkVector::Make(0.0f, -1.0f), 64, center); |
| draw_90(canvas, SkVector::Make(1.0f, 0.0f), 64, center); |
| draw_90(canvas, SkVector::Make(0.0f, 1.0f), 64, center); |
| |
| static const SkScalar kRoot3Over2 = 0.8660254037844386f; |
| |
| draw_30_60(canvas, SkRRect::kLowerLeft_Corner, |
| SkVector::Make(0.5f, kRoot3Over2), 120, center); |
| draw_30_60(canvas, SkRRect::kUpperRight_Corner, |
| SkVector::Make(kRoot3Over2, 0.5f), 120, center); |
| |
| draw_30_60(canvas, SkRRect::kUpperLeft_Corner, |
| SkVector::Make(-0.5f, kRoot3Over2), 120, center); |
| draw_30_60(canvas, SkRRect::kLowerRight_Corner, |
| SkVector::Make(-kRoot3Over2, 0.5f), 120, center); |
| |
| draw_30_60(canvas, SkRRect::kLowerLeft_Corner, |
| SkVector::Make(-0.5f, -kRoot3Over2), 120, center); |
| draw_30_60(canvas, SkRRect::kUpperRight_Corner, |
| SkVector::Make(-kRoot3Over2, -0.5f), 120, center); |
| |
| draw_30_60(canvas, SkRRect::kUpperLeft_Corner, |
| SkVector::Make(0.5f, -kRoot3Over2), 120, center); |
| draw_30_60(canvas, SkRRect::kLowerRight_Corner, |
| SkVector::Make(kRoot3Over2, -0.5f), 120, center); |
| |
| draw_45_simple(canvas, SkVector::Make(-SK_ScalarRoot2Over2, -SK_ScalarRoot2Over2), |
| 210, center); |
| draw_45_simple(canvas, SkVector::Make(SK_ScalarRoot2Over2, -SK_ScalarRoot2Over2), |
| 210, center); |
| draw_45_simple(canvas, SkVector::Make(SK_ScalarRoot2Over2, SK_ScalarRoot2Over2), |
| 210, center); |
| draw_45_simple(canvas, SkVector::Make(-SK_ScalarRoot2Over2, SK_ScalarRoot2Over2), |
| 210, center); |
| |
| draw_90_simple(canvas, SkVector::Make(-1.0f, 0.0f), 160, center); |
| draw_90_simple(canvas, SkVector::Make(0.0f, -1.0f), 160, center); |
| draw_90_simple(canvas, SkVector::Make(1.0f, 0.0f), 160, center); |
| draw_90_simple(canvas, SkVector::Make(0.0f, 1.0f), 160, center); |
| } |
| |
| private: |
| static const int kWidth = 440; |
| static const int kHeight = 440; |
| |
| typedef GM INHERITED; |
| }; |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| DEF_GM(return new OccludedRRectBlurGM;) |
| } |