1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/libgtk2ui/gtk2_border.h"
9 #include "chrome/browser/ui/libgtk2ui/gtk2_ui.h"
10 #include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
11 #include "chrome/browser/ui/libgtk2ui/native_theme_gtk2.h"
12 #include "third_party/skia/include/effects/SkLerpXfermode.h"
13 #include "ui/base/theme_provider.h"
14 #include "ui/gfx/animation/animation.h"
15 #include "ui/gfx/canvas.h"
16 #include "ui/gfx/geometry/rect.h"
17 #include "ui/gfx/image/image_skia_source.h"
18 #include "ui/gfx/skia_util.h"
19 #include "ui/views/controls/button/blue_button.h"
20 #include "ui/views/controls/button/label_button.h"
21 #include "ui/views/controls/button/label_button_border.h"
22 #include "ui/views/native_theme_delegate.h"
25 using views::NativeThemeDelegate
;
31 const int kNumberOfFocusedStates
= 2;
33 class ButtonImageSkiaSource
: public gfx::ImageSkiaSource
{
35 ButtonImageSkiaSource(const Gtk2UI
* gtk2_ui
,
36 const GtkStateType state
,
38 const bool call_to_action
,
39 const gfx::Size
& size
)
43 call_to_action_(call_to_action
),
47 ~ButtonImageSkiaSource() override
{}
49 gfx::ImageSkiaRep
GetImageForScale(float scale
) override
{
50 int w
= size_
.width() * scale
;
51 int h
= size_
.height() * scale
;
52 return gfx::ImageSkiaRep(
53 gtk2_ui_
->DrawGtkButtonBorder(state_
, focused_
, call_to_action_
, w
, h
),
58 const Gtk2UI
* gtk2_ui_
;
59 const GtkStateType state_
;
61 const bool call_to_action_
;
62 const gfx::Size size_
;
64 DISALLOW_COPY_AND_ASSIGN(ButtonImageSkiaSource
);
69 Gtk2Border::Gtk2Border(Gtk2UI
* gtk2_ui
,
70 views::LabelButton
* owning_button
,
71 scoped_ptr
<views::LabelButtonBorder
> border
)
73 owning_button_(owning_button
),
74 border_(border
.Pass()),
75 observer_manager_(this) {
76 observer_manager_
.Add(NativeThemeGtk2::instance());
79 Gtk2Border::~Gtk2Border() {
82 void Gtk2Border::Paint(const views::View
& view
, gfx::Canvas
* canvas
) {
83 DCHECK_EQ(&view
, owning_button_
);
84 const NativeThemeDelegate
* native_theme_delegate
= owning_button_
;
85 gfx::Rect
rect(native_theme_delegate
->GetThemePaintRect());
86 ui::NativeTheme::ExtraParams extra
;
87 ui::NativeTheme::State state
= native_theme_delegate
->GetThemeState(&extra
);
89 const gfx::Animation
* animation
= native_theme_delegate
->GetThemeAnimation();
90 if (animation
&& animation
->is_animating()) {
91 // Linearly interpolate background and foreground painters during animation.
92 const SkRect sk_rect
= gfx::RectToSkRect(rect
);
93 canvas
->sk_canvas()->saveLayer(&sk_rect
, NULL
);
94 state
= native_theme_delegate
->GetBackgroundThemeState(&extra
);
95 PaintState(state
, extra
, rect
, canvas
);
98 skia::RefPtr
<SkXfermode
> sk_lerp_xfer
=
99 skia::AdoptRef(SkLerpXfermode::Create(animation
->GetCurrentValue()));
100 paint
.setXfermode(sk_lerp_xfer
.get());
101 canvas
->sk_canvas()->saveLayer(&sk_rect
, &paint
);
102 state
= native_theme_delegate
->GetForegroundThemeState(&extra
);
103 PaintState(state
, extra
, rect
, canvas
);
104 canvas
->sk_canvas()->restore();
106 canvas
->sk_canvas()->restore();
108 PaintState(state
, extra
, rect
, canvas
);
112 gfx::Insets
Gtk2Border::GetInsets() const {
113 return border_
->GetInsets();
116 gfx::Size
Gtk2Border::GetMinimumSize() const {
117 return border_
->GetMinimumSize();
120 void Gtk2Border::OnNativeThemeUpdated(ui::NativeTheme
* observed_theme
) {
121 DCHECK_EQ(observed_theme
, NativeThemeGtk2::instance());
122 for (int i
= 0; i
< kNumberOfFocusedStates
; ++i
) {
123 for (int j
= 0; j
< views::Button::STATE_COUNT
; ++j
) {
124 button_images_
[i
][j
] = gfx::ImageSkia();
128 // Our owning view must have its layout invalidated because the insets could
130 owning_button_
->InvalidateLayout();
133 void Gtk2Border::PaintState(const ui::NativeTheme::State state
,
134 const ui::NativeTheme::ExtraParams
& extra
,
135 const gfx::Rect
& rect
,
136 gfx::Canvas
* canvas
) {
137 bool focused
= extra
.button
.is_focused
;
138 Button::ButtonState views_state
= Button::GetButtonStateFrom(state
);
140 if (border_
->PaintsButtonState(focused
, views_state
)) {
141 gfx::ImageSkia
* image
= &button_images_
[focused
][views_state
];
143 if (image
->isNull() || image
->size() != rect
.size()) {
144 bool call_to_action
= owning_button_
->GetClassName() ==
145 views::BlueButton::kViewClassName
;
146 GtkStateType gtk_state
= GetGtkState(state
);
147 *image
= gfx::ImageSkia(
148 new ButtonImageSkiaSource(gtk2_ui_
,
155 canvas
->DrawImageInt(*image
, rect
.x(), rect
.y());
159 } // namespace libgtk2ui