Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / ui / views / profiles / new_avatar_button.cc
blob03b3fd6af1e1e3aa0703185b789b02d37d00f74f
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/views/profiles/new_avatar_button.h"
7 #include "base/win/windows_version.h"
8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/profiles/profile_manager.h"
10 #include "chrome/browser/profiles/profiles_state.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/browser/ui/views/profiles/profile_chooser_view.h"
13 #include "grit/theme_resources.h"
14 #include "ui/base/resource/resource_bundle.h"
15 #include "ui/gfx/canvas.h"
16 #include "ui/views/border.h"
17 #include "ui/views/controls/button/label_button_border.h"
18 #include "ui/views/painter.h"
20 namespace {
22 scoped_ptr<views::Border> CreateBorder(const int normal_image_set[],
23 const int hot_image_set[],
24 const int pushed_image_set[]) {
25 scoped_ptr<views::LabelButtonBorder> border(
26 new views::LabelButtonBorder(views::Button::STYLE_TEXTBUTTON));
27 border->SetPainter(false, views::Button::STATE_NORMAL,
28 views::Painter::CreateImageGridPainter(normal_image_set));
29 border->SetPainter(false, views::Button::STATE_HOVERED,
30 views::Painter::CreateImageGridPainter(hot_image_set));
31 border->SetPainter(false, views::Button::STATE_PRESSED,
32 views::Painter::CreateImageGridPainter(pushed_image_set));
34 const int kLeftRightInset = 8;
35 const int kTopInset = 2;
36 const int kBottomInset = 4;
37 border->set_insets(gfx::Insets(kTopInset, kLeftRightInset,
38 kBottomInset, kLeftRightInset));
40 return border.Pass();
43 } // namespace
45 NewAvatarButton::NewAvatarButton(views::ButtonListener* listener,
46 AvatarButtonStyle button_style,
47 Browser* browser)
48 : LabelButton(listener, base::string16()),
49 browser_(browser),
50 has_auth_error_(false),
51 suppress_mouse_released_action_(false) {
52 set_animate_on_state_change(false);
53 SetTextColor(views::Button::STATE_NORMAL, SK_ColorWHITE);
54 SetTextColor(views::Button::STATE_HOVERED, SK_ColorWHITE);
55 SetTextColor(views::Button::STATE_PRESSED, SK_ColorWHITE);
56 SetTextShadows(gfx::ShadowValues(10,
57 gfx::ShadowValue(gfx::Point(), 1.0f, SK_ColorDKGRAY)));
58 SetTextSubpixelRenderingEnabled(false);
59 SetHorizontalAlignment(gfx::ALIGN_CENTER);
61 // The largest text height that fits in the button. If the font list height
62 // is larger than this, it will be shrunk to match it.
63 // TODO(noms): Calculate this constant algorithmically.
64 const int kDisplayFontHeight = 15;
65 SetFontList(GetFontList().DeriveWithHeightUpperBound(kDisplayFontHeight));
67 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
68 if (button_style == THEMED_BUTTON) {
69 const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_NORMAL);
70 const int kHotImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_HOVER);
71 const int kPushedImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_PRESSED);
73 SetBorder(CreateBorder(kNormalImageSet, kHotImageSet, kPushedImageSet));
74 generic_avatar_ =
75 *rb->GetImageNamed(IDR_AVATAR_THEMED_BUTTON_AVATAR).ToImageSkia();
76 #if defined(OS_WIN)
77 } else if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
78 const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_METRO_BUTTON_NORMAL);
79 const int kHotImageSet[] = IMAGE_GRID(IDR_AVATAR_METRO_BUTTON_HOVER);
80 const int kPushedImageSet[] = IMAGE_GRID(IDR_AVATAR_METRO_BUTTON_PRESSED);
82 SetBorder(CreateBorder(kNormalImageSet, kHotImageSet, kPushedImageSet));
83 generic_avatar_ =
84 *rb->GetImageNamed(IDR_AVATAR_METRO_BUTTON_AVATAR).ToImageSkia();
85 #endif
86 } else {
87 const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_NORMAL);
88 const int kHotImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_HOVER);
89 const int kPushedImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_PRESSED);
91 SetBorder(CreateBorder(kNormalImageSet, kHotImageSet, kPushedImageSet));
92 generic_avatar_ =
93 *rb->GetImageNamed(IDR_AVATAR_GLASS_BUTTON_AVATAR).ToImageSkia();
96 g_browser_process->profile_manager()->GetProfileInfoCache().AddObserver(this);
98 // Subscribe to authentication error changes so that the avatar button can
99 // update itself. Note that guest mode profiles won't have a token service.
100 SigninErrorController* error =
101 profiles::GetSigninErrorController(browser_->profile());
102 if (error) {
103 error->AddObserver(this);
104 // This calls UpdateAvatarButtonAndRelayoutParent().
105 OnErrorChanged();
106 } else {
107 UpdateAvatarButtonAndRelayoutParent();
109 SchedulePaint();
112 NewAvatarButton::~NewAvatarButton() {
113 g_browser_process->profile_manager()->
114 GetProfileInfoCache().RemoveObserver(this);
115 SigninErrorController* error =
116 profiles::GetSigninErrorController(browser_->profile());
117 if (error)
118 error->RemoveObserver(this);
121 bool NewAvatarButton::OnMousePressed(const ui::MouseEvent& event) {
122 // Prevent the bubble from being re-shown if it's already showing.
123 suppress_mouse_released_action_ = ProfileChooserView::IsShowing();
124 return LabelButton::OnMousePressed(event);
127 void NewAvatarButton::OnMouseReleased(const ui::MouseEvent& event) {
128 if (suppress_mouse_released_action_)
129 suppress_mouse_released_action_ = false;
130 else
131 LabelButton::OnMouseReleased(event);
134 void NewAvatarButton::OnProfileAdded(const base::FilePath& profile_path) {
135 UpdateAvatarButtonAndRelayoutParent();
138 void NewAvatarButton::OnProfileWasRemoved(
139 const base::FilePath& profile_path,
140 const base::string16& profile_name) {
141 // If deleting the active profile, don't bother updating the avatar
142 // button, as the browser window is being closed anyway.
143 if (browser_->profile()->GetPath() != profile_path)
144 UpdateAvatarButtonAndRelayoutParent();
147 void NewAvatarButton::OnProfileNameChanged(
148 const base::FilePath& profile_path,
149 const base::string16& old_profile_name) {
150 if (browser_->profile()->GetPath() == profile_path)
151 UpdateAvatarButtonAndRelayoutParent();
154 void NewAvatarButton::OnProfileAvatarChanged(
155 const base::FilePath& profile_path) {
156 if (browser_->profile()->GetPath() == profile_path)
157 UpdateAvatarButtonAndRelayoutParent();
160 void NewAvatarButton::OnProfileSupervisedUserIdChanged(
161 const base::FilePath& profile_path) {
162 if (browser_->profile()->GetPath() == profile_path)
163 UpdateAvatarButtonAndRelayoutParent();
166 void NewAvatarButton::OnErrorChanged() {
167 // If there is an error, show an warning icon.
168 const SigninErrorController* error =
169 profiles::GetSigninErrorController(browser_->profile());
170 has_auth_error_ = error && error->HasError();
172 UpdateAvatarButtonAndRelayoutParent();
175 void NewAvatarButton::UpdateAvatarButtonAndRelayoutParent() {
176 const ProfileInfoCache& cache =
177 g_browser_process->profile_manager()->GetProfileInfoCache();
179 // If we have a single local profile, then use the generic avatar
180 // button instead of the profile name. Never use the generic button if
181 // the active profile is Guest.
182 bool use_generic_button = (!browser_->profile()->IsGuestSession() &&
183 cache.GetNumberOfProfiles() == 1 &&
184 cache.GetUserNameOfProfileAtIndex(0).empty());
186 SetText(use_generic_button ? base::string16() :
187 profiles::GetAvatarButtonTextForProfile(browser_->profile()));
188 // We want the button to resize if the new text is shorter.
189 SetMinSize(gfx::Size());
191 if (use_generic_button) {
192 SetImage(views::Button::STATE_NORMAL, generic_avatar_);
193 } else if (has_auth_error_) {
194 SetImage(views::Button::STATE_NORMAL,
195 *ui::ResourceBundle::GetSharedInstance().GetImageNamed(
196 IDR_ICON_PROFILES_AVATAR_BUTTON_ERROR).ToImageSkia());
197 } else {
198 SetImage(views::Button::STATE_NORMAL, gfx::ImageSkia());
201 // If we are not using the generic button, then reset the spacing between
202 // the text and the possible authentication error icon.
203 const int kDefaultImageTextSpacing = 5;
204 SetImageLabelSpacing(use_generic_button ? 0 : kDefaultImageTextSpacing);
206 InvalidateLayout();
208 // Because the width of the button might have changed, the parent browser
209 // frame needs to recalculate the button bounds and redraw it.
210 if (parent())
211 parent()->Layout();