172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Use of this source code is governed by a BSD-style license that can be 372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// found in the LICENSE file. 472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/infobars/infobar_view.h" 672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/message_loop.h" 872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/utf_string_conversions.h" 9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/tab_contents/infobar_delegate.h" 1072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/infobars/infobar_background.h" 11dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/views/infobars/infobar_button_border.h" 1272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "grit/generated_resources.h" 1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "grit/theme_resources.h" 1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "third_party/skia/include/effects/SkGradientShader.h" 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/base/accessibility/accessible_view_state.h" 1672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/animation/slide_animation.h" 1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h" 1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas_skia_paint.h" 2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "views/controls/button/image_button.h" 21dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "views/controls/button/menu_button.h" 22dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "views/controls/button/text_button.h" 2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "views/controls/image_view.h" 2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "views/controls/label.h" 25dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "views/controls/link.h" 2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "views/focus/external_focus_tracker.h" 2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "views/widget/widget.h" 28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "views/window/non_client_view.h" 2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(OS_WIN) 31dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include <shellapi.h> 32dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 33dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/win/win_util.h" 34dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/win/windows_version.h" 3572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/win/hwnd_util.h" 36dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "ui/gfx/icon_util.h" 3772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif 3872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static 40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int InfoBar::kSeparatorLineHeight = 41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen views::NonClientFrameView::kClientEdgeThickness; 42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int InfoBar::kDefaultArrowTargetHeight = 9; 43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int InfoBar::kMaximumArrowTargetHeight = 24; 44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int InfoBar::kDefaultArrowTargetHalfWidth = kDefaultArrowTargetHeight; 45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int InfoBar::kMaximumArrowTargetHalfWidth = 14; 46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int InfoBar::kDefaultBarTargetHeight = 36; 47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 4872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst int InfoBarView::kButtonButtonSpacing = 10; 4972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenconst int InfoBarView::kEndOfLabelSpacing = 16; 50dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenconst int InfoBarView::kHorizontalPadding = 6; 5172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 5272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenInfoBarView::InfoBarView(InfoBarDelegate* delegate) 5372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen : InfoBar(delegate), 54dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen icon_(NULL), 55dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen close_button_(NULL), 5672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ALLOW_THIS_IN_INITIALIZER_LIST(delete_factory_(this)), 57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen fill_path_(new SkPath), 58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen stroke_path_(new SkPath) { 5972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen set_parent_owned(false); // InfoBar deletes itself at the appropriate time. 60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen set_background(new InfoBarBackground(delegate->GetInfoBarType())); 6172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 6272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 6372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenInfoBarView::~InfoBarView() { 6472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 6572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 66dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static 67dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenviews::Label* InfoBarView::CreateLabel(const string16& text) { 68dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen views::Label* label = new views::Label(UTF16ToWideHack(text), 69dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont)); 70dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen label->SetColor(SK_ColorBLACK); 71dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 72dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return label; 73dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 74dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 75dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static 76dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenviews::Link* InfoBarView::CreateLink(const string16& text, 77dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen views::LinkController* controller, 78dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const SkColor& background_color) { 79dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen views::Link* link = new views::Link; 80dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen link->SetText(UTF16ToWideHack(text)); 81dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen link->SetFont( 82dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont)); 83dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen link->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 84dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen link->SetController(controller); 85dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen link->MakeReadableOverBackgroundColor(background_color); 86dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return link; 87dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 88dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 89dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static 90dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenviews::MenuButton* InfoBarView::CreateMenuButton( 91dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const string16& text, 92dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool normal_has_border, 93dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen views::ViewMenuDelegate* menu_delegate) { 94dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen views::MenuButton* menu_button = 95dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen new views::MenuButton(NULL, UTF16ToWideHack(text), menu_delegate, true); 96dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen menu_button->set_border(new InfoBarButtonBorder); 97dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 98dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen menu_button->set_menu_marker( 99dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen rb.GetBitmapNamed(IDR_INFOBARBUTTON_MENU_DROPARROW)); 100dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (normal_has_border) { 101dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen menu_button->SetNormalHasBorder(true); 102dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen menu_button->SetAnimationDuration(0); 103dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 104dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen menu_button->SetEnabledColor(SK_ColorBLACK); 105dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen menu_button->SetHighlightColor(SK_ColorBLACK); 106dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen menu_button->SetHoverColor(SK_ColorBLACK); 107dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen menu_button->SetFont(rb.GetFont(ResourceBundle::MediumFont)); 108dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return menu_button; 109dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 110dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 111dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static 112dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenviews::TextButton* InfoBarView::CreateTextButton( 113dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen views::ButtonListener* listener, 114dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const string16& text, 115dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool needs_elevation) { 116dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen views::TextButton* text_button = 117dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen new views::TextButton(listener, UTF16ToWideHack(text)); 118dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen text_button->set_border(new InfoBarButtonBorder); 119dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen text_button->SetNormalHasBorder(true); 120dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen text_button->SetAnimationDuration(0); 121dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen text_button->SetEnabledColor(SK_ColorBLACK); 122dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen text_button->SetHighlightColor(SK_ColorBLACK); 123dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen text_button->SetHoverColor(SK_ColorBLACK); 124dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 125dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen text_button->SetFont(rb.GetFont(ResourceBundle::MediumFont)); 126dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(OS_WIN) 127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (needs_elevation && 128dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen (base::win::GetVersion() >= base::win::VERSION_VISTA) && 129dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen base::win::UserAccountControlIsEnabled()) { 130dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen SHSTOCKICONINFO icon_info = { sizeof SHSTOCKICONINFO }; 131dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Even with the runtime guard above, we have to use GetProcAddress() here, 132dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // because otherwise the loader will try to resolve the function address on 133dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // startup, which will break on XP. 134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen typedef HRESULT (STDAPICALLTYPE *GetStockIconInfo)(SHSTOCKICONID, UINT, 135dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen SHSTOCKICONINFO*); 136dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen GetStockIconInfo func = reinterpret_cast<GetStockIconInfo>( 137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen GetProcAddress(GetModuleHandle(L"shell32.dll"), "SHGetStockIconInfo")); 138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen (*func)(SIID_SHIELD, SHGSI_ICON | SHGSI_SMALLICON, &icon_info); 139dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen text_button->SetIcon(*IconUtil::CreateSkBitmapFromHICON(icon_info.hIcon, 140dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen gfx::Size(GetSystemMetrics(SM_CXSMICON), 141dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen GetSystemMetrics(SM_CYSMICON)))); 142dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif 144dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return text_button; 145dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 14772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid InfoBarView::Layout() { 148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Calculate the fill and stroke paths. We do this here, rather than in 149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // PlatformSpecificRecalculateHeight(), because this is also reached when our 150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // width is changed, which affects both paths. 151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen stroke_path_->rewind(); 152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen fill_path_->rewind(); 153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const InfoBarContainer::Delegate* delegate = container_delegate(); 154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (delegate) { 155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen static_cast<InfoBarBackground*>(background())->set_separator_color( 156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate->GetInfoBarSeparatorColor()); 157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int arrow_x; 158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen SkScalar arrow_fill_height = 159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen SkIntToScalar(std::max(arrow_height() - kSeparatorLineHeight, 0)); 160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen SkScalar arrow_fill_half_width = SkIntToScalar(arrow_half_width()); 161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen SkScalar separator_height = SkIntToScalar(kSeparatorLineHeight); 162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (delegate->DrawInfoBarArrows(&arrow_x) && arrow_fill_height) { 163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Skia pixel centers are at the half-values, so the arrow is horizontally 164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // centered at |arrow_x| + 0.5. Vertically, the stroke path is the center 165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // of the separator, while the fill path is a closed path that extends up 166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // through the entire height of the separator and down to the bottom of 167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // the arrow where it joins the bar. 168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen stroke_path_->moveTo( 169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen SkIntToScalar(arrow_x) + SK_ScalarHalf - arrow_fill_half_width, 170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen SkIntToScalar(arrow_height()) - (separator_height * SK_ScalarHalf)); 171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen stroke_path_->rLineTo(arrow_fill_half_width, -arrow_fill_height); 172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen stroke_path_->rLineTo(arrow_fill_half_width, arrow_fill_height); 173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *fill_path_ = *stroke_path_; 175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Move the top of the fill path up to the top of the separator and then 176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // extend it down all the way through. 177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen fill_path_->offset(0, -separator_height * SK_ScalarHalf); 178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // This 0.01 hack prevents the fill from filling more pixels on the right 179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // edge of the arrow than on the left. 180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const SkScalar epsilon = 0.01f; 181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen fill_path_->rLineTo(-epsilon, 0); 182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen fill_path_->rLineTo(0, separator_height); 183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen fill_path_->rLineTo(epsilon - (arrow_fill_half_width * 2), 0); 184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen fill_path_->close(); 185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (bar_height()) { 188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen fill_path_->addRect(0.0, SkIntToScalar(arrow_height()), 189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen SkIntToScalar(width()), SkIntToScalar(height() - kSeparatorLineHeight)); 190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 192dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int start_x = kHorizontalPadding; 193dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (icon_ != NULL) { 194dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen gfx::Size icon_size = icon_->GetPreferredSize(); 195dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen icon_->SetBounds(start_x, OffsetY(icon_size), icon_size.width(), 196dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen icon_size.height()); 197dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 198dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 19972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen gfx::Size button_size = close_button_->GetPreferredSize(); 200dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen close_button_->SetBounds(std::max(start_x + ContentMinimumWidth(), 201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen width() - kHorizontalPadding - button_size.width()), OffsetY(button_size), 202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen button_size.width(), button_size.height()); 20372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 20472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 20572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid InfoBarView::ViewHierarchyChanged(bool is_add, View* parent, View* child) { 20672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen View::ViewHierarchyChanged(is_add, parent, child); 20772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 20872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (child == this) { 20972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (is_add) { 21072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#if defined(OS_WIN) 21172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // When we're added to a view hierarchy within a widget, we create an 21272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // external focus tracker to track what was focused in case we obtain 21372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // focus so that we can restore focus when we're removed. 21472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen views::Widget* widget = GetWidget(); 21572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (widget) { 21672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen focus_tracker_.reset( 21772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen new views::ExternalFocusTracker(this, GetFocusManager())); 21872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 21972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#endif 22072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (GetFocusManager()) 22172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen GetFocusManager()->AddFocusChangeListener(this); 222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (GetWidget()) { 223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen GetWidget()->NotifyAccessibilityEvent( 224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this, ui::AccessibilityTypes::EVENT_ALERT, true); 225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 226dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 227dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (close_button_ == NULL) { 228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen SkBitmap* image = delegate()->GetIcon(); 229dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (image) { 230dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen icon_ = new views::ImageView; 231dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen icon_->SetImage(image); 232dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen AddChildView(icon_); 233dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 234dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 235dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen close_button_ = new views::ImageButton(this); 236dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 237dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen close_button_->SetImage(views::CustomButton::BS_NORMAL, 238dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen rb.GetBitmapNamed(IDR_CLOSE_BAR)); 239dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen close_button_->SetImage(views::CustomButton::BS_HOT, 240dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen rb.GetBitmapNamed(IDR_CLOSE_BAR_H)); 241dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen close_button_->SetImage(views::CustomButton::BS_PUSHED, 242dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen rb.GetBitmapNamed(IDR_CLOSE_BAR_P)); 243dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen close_button_->SetAccessibleName( 244dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE)); 245dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen close_button_->SetFocusable(true); 246dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen AddChildView(close_button_); 247dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 24872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else { 24972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DestroyFocusTracker(false); 250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen animation()->Stop(); 25172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Finally, clean ourselves up when we're removed from the view hierarchy 25272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // since no-one refers to us now. 25372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen MessageLoop::current()->PostTask(FROM_HERE, 25472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen delete_factory_.NewRunnableMethod(&InfoBarView::DeleteSelf)); 25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (GetFocusManager()) 25672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen GetFocusManager()->RemoveFocusChangeListener(this); 25772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 25872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 26072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // For accessibility, ensure the close button is the last child view. 261dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if ((close_button_ != NULL) && (parent == this) && (child != close_button_) && 26272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (close_button_->parent() == this) && 26372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen (GetChildViewAt(child_count() - 1) != close_button_)) { 26472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen RemoveChildView(close_button_); 26572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen AddChildView(close_button_); 26672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 26772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 26872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid InfoBarView::PaintChildren(gfx::Canvas* canvas) { 270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen canvas->Save(); 271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // TODO(scr): This really should be the |fill_path_|, but the clipPath seems 273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // broken on non-Windows platforms (crbug.com/75154). For now, just clip to 274ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // the bar bounds. 275ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // 276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // gfx::CanvasSkia* canvas_skia = canvas->AsCanvasSkia(); 277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // canvas_skia->clipPath(*fill_path_); 278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK_EQ(total_height(), height()) 279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen << "Infobar piecewise heights do not match overall height"; 280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen canvas->ClipRectInt(0, arrow_height(), width(), bar_height()); 281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen views::View::PaintChildren(canvas); 282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen canvas->Restore(); 283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 284ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 28572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid InfoBarView::ButtonPressed(views::Button* sender, 28672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const views::Event& event) { 28772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (sender == close_button_) { 288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (delegate()) 289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen delegate()->InfoBarDismissed(); 29072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen RemoveInfoBar(); 29172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 29272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 29372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 294dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenint InfoBarView::ContentMinimumWidth() const { 295dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return 0; 29672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 29772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 298dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenint InfoBarView::StartX() const { 299dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Ensure we don't return a value greater than EndX(), so children can safely 300dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // set something's width to "EndX() - StartX()" without risking that being 301dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // negative. 302dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return std::min(EndX(), 303dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ((icon_ != NULL) ? icon_->bounds().right() : 0) + kHorizontalPadding); 304dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 305dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 306dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenint InfoBarView::EndX() const { 307dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const int kCloseButtonSpacing = 12; 308dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return close_button_->x() - kCloseButtonSpacing; 309dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 310dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst InfoBarContainer::Delegate* InfoBarView::container_delegate() const { 312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const InfoBarContainer* infobar_container = container(); 313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return infobar_container ? infobar_container->delegate() : NULL; 314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid InfoBarView::PlatformSpecificHide(bool animate) { 317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!animate) 318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool restore_focus = true; 321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN) 322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Do not restore focus (and active state with it) on Windows if some other 323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // top-level window became active. 324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (GetWidget() && 325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen !ui::DoesWindowBelongToActiveWindow(GetWidget()->GetNativeView())) 326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen restore_focus = false; 327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif // defined(OS_WIN) 328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DestroyFocusTracker(restore_focus); 32972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 33072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid InfoBarView::PlatformSpecificOnHeightsRecalculated() { 332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Ensure that notifying our container of our size change will result in a 333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // re-layout. 334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen InvalidateLayout(); 33572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 33672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 337ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid InfoBarView::GetAccessibleState(ui::AccessibleViewState* state) { 338ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (delegate()) { 339ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen state->name = l10n_util::GetStringUTF16( 340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (delegate()->GetInfoBarType() == InfoBarDelegate::WARNING_TYPE) ? 341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen IDS_ACCNAME_INFOBAR_WARNING : IDS_ACCNAME_INFOBAR_PAGE_ACTION); 342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen state->role = ui::AccessibilityTypes::ROLE_ALERT; 34472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 34572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 34672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsengfx::Size InfoBarView::GetPreferredSize() { 347ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return gfx::Size(0, total_height()); 34872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 34972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 35072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid InfoBarView::FocusWillChange(View* focused_before, View* focused_now) { 35172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // This will trigger some screen readers to read the entire contents of this 35272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // infobar. 35372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (focused_before && focused_now && !this->Contains(focused_before) && 354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this->Contains(focused_now) && GetWidget()) { 355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen GetWidget()->NotifyAccessibilityEvent( 356ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen this, ui::AccessibilityTypes::EVENT_ALERT, true); 357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 35872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 35972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 36072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid InfoBarView::DestroyFocusTracker(bool restore_focus) { 36172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (focus_tracker_ != NULL) { 36272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (restore_focus) 36372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen focus_tracker_->FocusLastFocusedExternalView(); 36472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen focus_tracker_->SetFocusManager(NULL); 36572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen focus_tracker_.reset(); 36672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 36772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 36872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 36972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid InfoBarView::DeleteSelf() { 37072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen delete this; 37172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 372