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