| OLD | NEW | 
|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "ui/views/style/mac/dialog_button_border_mac.h" | 5 #include "ui/views/style/mac/dialog_button_border_mac.h" | 
| 6 | 6 | 
| 7 #include "base/logging.h" | 7 #include "base/logging.h" | 
| 8 #include "skia/ext/refptr.h" | 8 #include "skia/ext/refptr.h" | 
| 9 #include "third_party/skia/include/core/SkCanvas.h" | 9 #include "third_party/skia/include/core/SkCanvas.h" | 
| 10 #include "third_party/skia/include/core/SkDrawLooper.h" | 10 #include "third_party/skia/include/core/SkDrawLooper.h" | 
| 11 #include "third_party/skia/include/core/SkPaint.h" | 11 #include "third_party/skia/include/core/SkPaint.h" | 
| 12 #include "third_party/skia/include/core/SkPath.h" | 12 #include "third_party/skia/include/core/SkPath.h" | 
| 13 #include "third_party/skia/include/effects/SkGradientShader.h" | 13 #include "third_party/skia/include/effects/SkGradientShader.h" | 
| 14 #include "ui/gfx/canvas.h" | 14 #include "ui/gfx/canvas.h" | 
|  | 15 #include "ui/native_theme/native_theme_mac.h" | 
| 15 #include "ui/views/border.h" | 16 #include "ui/views/border.h" | 
| 16 #include "ui/views/controls/button/custom_button.h" | 17 #include "ui/views/controls/button/custom_button.h" | 
|  | 18 #include "ui/views/controls/button/label_button.h" | 
|  | 19 | 
|  | 20 using ui::NativeThemeMac; | 
| 17 | 21 | 
| 18 namespace views { | 22 namespace views { | 
| 19 namespace { | 23 namespace { | 
| 20 | 24 | 
| 21 // Type to map button states to a corresponding SkColor. |  | 
| 22 typedef const SkColor ColorByState[Button::STATE_COUNT]; |  | 
| 23 |  | 
| 24 // If a state is added, ColorByState will silently fill with zeros, so assert. |  | 
| 25 static_assert(Button::STATE_COUNT == 4, |  | 
| 26               "DialogButtonBorderMac assumes 4 button states."); |  | 
| 27 |  | 
| 28 // Corner radius of rounded rectangles. | 25 // Corner radius of rounded rectangles. | 
| 29 const SkScalar kCornerRadius = 2; | 26 const SkScalar kCornerRadius = 2; | 
|  | 27 const SkScalar kFocusCornerRadius = 4; | 
|  | 28 const SkScalar kFocusRingThickness = 3; | 
| 30 | 29 | 
| 31 // Vertical offset of the drop shadow and the inner highlight shadow. | 30 const SkColor kDefaultBorderColor = SkColorSetARGB(0xF2, 0xBA, 0xBA, 0xBA); | 
| 32 const SkScalar kShadowOffsetY = 1; | 31 const SkColor kHighlightedBorderColor = SkColorSetARGB(0xFF, 0x52, 0x76, 0xFF); | 
| 33 | 32 const SkColor kFocusRingColor = SkColorSetARGB(0x80, 0x3B, 0x9A, 0xFC); | 
| 34 // Shadow blur radius of the inner highlight shadow. |  | 
| 35 const double kInnerShadowBlurRadius = 2.0; |  | 
| 36 | 33 | 
| 37 // Default border insets, to provide text padding. | 34 // Default border insets, to provide text padding. | 
| 38 const int kPaddingX = 14; | 35 const int kPaddingX = 19; | 
| 39 const int kPaddingY = 4; | 36 const int kPaddingY = 7; | 
| 40 | 37 | 
| 41 sk_sp<SkShader> CreateButtonGradient(int height, | 38 void DrawDialogButtonBackground(const SkRect& button_rect, | 
| 42                                      Button::ButtonState state) { | 39                                 SkCanvas* canvas, | 
| 43   ColorByState start = {0xFFF0F0F0, 0xFFF4F4F4, 0xFFEBEBEB, 0xFFEDEDED}; | 40                                 const CustomButton& button) { | 
| 44   ColorByState end = {0xFFE0E0E0, 0xFFE4E4E4, 0xFFDBDBDB, 0xFFDEDEDE}; |  | 
| 45 |  | 
| 46   SkPoint gradient_points[2]; |  | 
| 47   gradient_points[0].iset(0, 0); |  | 
| 48   gradient_points[1].iset(0, height); |  | 
| 49 |  | 
| 50   SkColor gradient_colors[] = {start[state], start[state], end[state]}; |  | 
| 51   SkScalar gradient_positions[] = {0.0, 0.38, 1.0}; |  | 
| 52 |  | 
| 53   return SkGradientShader::MakeLinear( |  | 
| 54           gradient_points, gradient_colors, gradient_positions, 3, |  | 
| 55           SkShader::kClamp_TileMode); |  | 
| 56 } |  | 
| 57 |  | 
| 58 void DrawConstrainedButtonBackground(const SkRect& button_rect, |  | 
| 59                                      SkCanvas* canvas, |  | 
| 60                                      Button::ButtonState button_state) { |  | 
| 61   // Extend the size of the SkRect so the border stroke is drawn over it on all | 41   // Extend the size of the SkRect so the border stroke is drawn over it on all | 
| 62   // sides. | 42   // sides. | 
| 63   SkRect rect(button_rect); | 43   SkRect rect(button_rect); | 
| 64   rect.fRight += 1; | 44   rect.fRight += 1; | 
| 65   rect.fBottom += 1; | 45   rect.fBottom += 1; | 
| 66 | 46 | 
| 67   SkPaint paint; | 47   NativeThemeMac::BackgroundType type = NativeThemeMac::BackgroundType::NORMAL; | 
| 68 | 48   if (!button.enabled() || button.state() == Button::STATE_DISABLED) | 
| 69   // Drop Shadow. | 49     type = NativeThemeMac::BackgroundType::DISABLED; | 
| 70   ColorByState shadow = {0x14000000, 0x1F000000, 0x00000000, 0x00000000}; | 50   else if (button.state() == Button::STATE_PRESSED) | 
| 71   const double blur = 0.0; | 51     type = NativeThemeMac::BackgroundType::PRESSED; | 
| 72   std::vector<gfx::ShadowValue> shadows( | 52   else if (DialogButtonBorderMac::ShowsDefault(button)) | 
| 73       1, gfx::ShadowValue(gfx::Vector2d(0, kShadowOffsetY), blur, | 53     type = NativeThemeMac::BackgroundType::HIGHLIGHTED; | 
| 74                           shadow[button_state])); |  | 
| 75   paint.setLooper(gfx::CreateShadowDrawLooper(shadows)); |  | 
| 76 | 54 | 
| 77   // Background. | 55   // Background. | 
| 78   paint.setShader(CreateButtonGradient(rect.height(), button_state)); | 56   SkPaint paint; | 
|  | 57   paint.setShader( | 
|  | 58       NativeThemeMac::GetButtonBackgroundShader(type, rect.height())); | 
| 79   paint.setStyle(SkPaint::kFill_Style); | 59   paint.setStyle(SkPaint::kFill_Style); | 
| 80   paint.setFlags(SkPaint::kAntiAlias_Flag); | 60   paint.setFlags(SkPaint::kAntiAlias_Flag); | 
| 81   canvas->drawRoundRect(rect, kCornerRadius, kCornerRadius, paint); | 61   canvas->drawRoundRect(rect, kCornerRadius, kCornerRadius, paint); | 
| 82 } | 62 } | 
| 83 | 63 | 
| 84 // Draws an inner box shadow inside a rounded rectangle of size |rect|. The | 64 }  // namespace | 
| 85 // technique: draw a black "ring" around the outside of the button cell. Then |  | 
| 86 // clip out everything except the shadow it casts. Works similar to Blink's |  | 
| 87 // GraphicsContext::drawInnerShadow(). |  | 
| 88 void DrawRoundRectInnerShadow(const SkRect& rect, |  | 
| 89                               SkCanvas* canvas, |  | 
| 90                               SkColor shadow_color) { |  | 
| 91   const gfx::Vector2d shadow_offset(0, kShadowOffsetY); |  | 
| 92   SkRect outer(rect); |  | 
| 93   outer.outset(abs(shadow_offset.x()) + kInnerShadowBlurRadius, |  | 
| 94                abs(shadow_offset.y()) + kInnerShadowBlurRadius); |  | 
| 95 | 65 | 
| 96   SkPath path; | 66 // static | 
| 97   path.addRect(outer); | 67 bool DialogButtonBorderMac::ShowsDefault(const CustomButton& button) { | 
| 98   path.setFillType(SkPath::kEvenOdd_FillType); | 68   const LabelButton* label_button = CustomButton::AsLabelButton(&button); | 
| 99   path.addRoundRect(rect, kCornerRadius, kCornerRadius);  // Poke a hole. | 69   if (!label_button || !label_button->is_default()) | 
|  | 70     return false; | 
| 100 | 71 | 
| 101   // Inset the clip to cater for the border stroke. | 72   // TODO(tapted): Check whether the Widget is active, and only return true here | 
| 102   SkPath clip; | 73   // if it is. Plumbing this requires default buttons to also observe Widget | 
| 103   clip.addRoundRect(rect.makeInset(0.5, 0.5), kCornerRadius, kCornerRadius); | 74   // activations to ensure text and background colors are properly invalidated. | 
| 104 | 75   return true; | 
| 105   SkPaint paint; |  | 
| 106   std::vector<gfx::ShadowValue> shadows( |  | 
| 107       1, gfx::ShadowValue(shadow_offset, kInnerShadowBlurRadius, shadow_color)); |  | 
| 108   paint.setLooper(gfx::CreateShadowDrawLooper(shadows)); |  | 
| 109   paint.setStyle(SkPaint::kFill_Style); |  | 
| 110   paint.setColor(SK_ColorBLACK);  // Note: Entirely clipped. |  | 
| 111 |  | 
| 112   canvas->save(); |  | 
| 113   canvas->clipPath(clip, SkRegion::kIntersect_Op, true /* antialias */); |  | 
| 114   canvas->drawPath(path, paint); |  | 
| 115   canvas->restore(); |  | 
| 116 } | 76 } | 
| 117 | 77 | 
| 118 }  // namespace |  | 
| 119 |  | 
| 120 DialogButtonBorderMac::DialogButtonBorderMac() { | 78 DialogButtonBorderMac::DialogButtonBorderMac() { | 
| 121   set_insets(gfx::Insets(kPaddingY, kPaddingX, kPaddingY, kPaddingX)); | 79   set_insets(gfx::Insets(kPaddingY, kPaddingX, kPaddingY, kPaddingX)); | 
| 122 } | 80 } | 
| 123 | 81 | 
| 124 DialogButtonBorderMac::~DialogButtonBorderMac() {} | 82 DialogButtonBorderMac::~DialogButtonBorderMac() {} | 
| 125 | 83 | 
| 126 void DialogButtonBorderMac::Paint(const View& view, gfx::Canvas* canvas) { | 84 void DialogButtonBorderMac::Paint(const View& view, gfx::Canvas* canvas) { | 
| 127   DCHECK(CustomButton::AsCustomButton(&view)); | 85   DCHECK(CustomButton::AsCustomButton(&view)); | 
| 128   const CustomButton& button = static_cast<const CustomButton&>(view); | 86   const CustomButton& button = static_cast<const CustomButton&>(view); | 
| 129   SkCanvas* canvas_skia = canvas->sk_canvas(); | 87   SkCanvas* canvas_skia = canvas->sk_canvas(); | 
| 130 | 88 | 
| 131   // Inset all sides for the rounded rectangle stroke. Inset again to make room | 89   // Inset all sides for the rounded rectangle stroke. Inset again to make room | 
| 132   // for the shadows (while keeping the text centered). | 90   // for the shadows and static focus ring (while keeping the text centered). | 
| 133   SkRect sk_rect = gfx::RectToSkRect(view.GetLocalBounds()); | 91   SkRect sk_rect = gfx::RectToSkRect(view.GetLocalBounds()); | 
| 134   sk_rect.inset(2.0, 2.0); | 92   sk_rect.inset(kFocusRingThickness, kFocusRingThickness); | 
| 135 | 93 | 
| 136   DrawConstrainedButtonBackground(sk_rect, canvas_skia, button.state()); | 94   DrawDialogButtonBackground(sk_rect, canvas_skia, button); | 
| 137 | 95 | 
| 138   // Offset so that strokes are contained within the pixel boundary. | 96   // Offset so that strokes are contained within the pixel boundary. | 
| 139   sk_rect.offset(0.5, 0.5); | 97   sk_rect.offset(0.5, 0.5); | 
| 140   ColorByState highlight = {0xBFFFFFFF, 0xF2FFFFFF, 0x24000000, 0x00000000}; |  | 
| 141   DrawRoundRectInnerShadow(sk_rect, canvas_skia, highlight[button.state()]); |  | 
| 142 | 98 | 
| 143   // Border or focus ring. | 99   // Border and focus ring. | 
|  | 100   SkColor border_color = kDefaultBorderColor; | 
|  | 101   if (button.state() == Button::STATE_PRESSED || ShowsDefault(button)) | 
|  | 102     border_color = kHighlightedBorderColor; | 
|  | 103 | 
| 144   SkPaint paint; | 104   SkPaint paint; | 
| 145   ColorByState border = {0x40000000, 0x4D000000, 0x4D000000, 0x1F000000}; |  | 
| 146   const SkColor focus_border = {0xFF5DA5FF}; |  | 
| 147   paint.setStrokeWidth(1); |  | 
| 148   paint.setStyle(SkPaint::kStroke_Style); | 105   paint.setStyle(SkPaint::kStroke_Style); | 
| 149   paint.setFlags(SkPaint::kAntiAlias_Flag); | 106   paint.setFlags(SkPaint::kAntiAlias_Flag); | 
| 150   if (button.HasFocus() && button.state() != Button::STATE_PRESSED) | 107   paint.setStrokeWidth(1); | 
| 151     paint.setColor(focus_border); | 108   paint.setColor(border_color); | 
| 152   else |  | 
| 153     paint.setColor(border[button.state()]); |  | 
| 154   canvas_skia->drawRoundRect(sk_rect, kCornerRadius, kCornerRadius, paint); | 109   canvas_skia->drawRoundRect(sk_rect, kCornerRadius, kCornerRadius, paint); | 
|  | 110 | 
|  | 111   if (button.HasFocus()) { | 
|  | 112     paint.setStrokeWidth(kFocusRingThickness); | 
|  | 113     paint.setColor(kFocusRingColor); | 
|  | 114     sk_rect.inset(-1, -1); | 
|  | 115     canvas_skia->drawRoundRect(sk_rect, kFocusCornerRadius, kFocusCornerRadius, | 
|  | 116                                paint); | 
|  | 117   } | 
| 155 } | 118 } | 
| 156 | 119 | 
| 157 gfx::Size DialogButtonBorderMac::GetMinimumSize() const { | 120 gfx::Size DialogButtonBorderMac::GetMinimumSize() const { | 
| 158   return gfx::Size(100, 30); | 121   return gfx::Size(28, 4); | 
| 159 } | 122 } | 
| 160 | 123 | 
| 161 }  // namespace views | 124 }  // namespace views | 
| OLD | NEW | 
|---|