15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/location_bar/zoom_bubble_view.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/i18n/rtl.h"
8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/strings/stringprintf.h"
97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chrome_page_zoom.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser_finder.h"
13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/ui/browser_tabstrip.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/browser_window.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/views/frame/browser_view.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/views/location_bar/zoom_view.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/zoom/zoom_controller.h"
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/common/extensions/api/extension_action/action_info.h"
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/grit/generated_resources.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_source.h"
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/common/manifest_handlers/icons_handler.h"
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "grit/theme_resources.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/gfx/favicon_size.h"
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/views/controls/button/image_button.h"
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/controls/button/label_button.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/separator.h"
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ui/views/layout/grid_layout.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/layout/layout_constants.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The number of milliseconds the bubble should stay on the screen if it will
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// close automatically.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBubbleCloseDelay = 1500;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The bubble's padding from the screen edge, used in fullscreen.
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kFullscreenPaddingEnd = 20;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ZoomBubbleView* ZoomBubbleView::zoom_bubble_ = NULL;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ZoomBubbleView::ShowBubble(content::WebContents* web_contents,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                bool auto_close) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(browser && browser->window() && browser->fullscreen_controller());
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool is_fullscreen = browser_view->IsFullscreen();
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool anchor_to_view = !is_fullscreen ||
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      browser_view->immersive_mode_controller()->IsRevealed();
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  views::View* anchor_view = anchor_to_view ?
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      browser_view->GetLocationBarView()->zoom_view() : NULL;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Find the extension that initiated the zoom change, if any.
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ZoomController* zoom_controller =
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ZoomController::FromWebContents(web_contents);
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const extensions::Extension* extension = zoom_controller->last_extension();
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // If the bubble is already showing in this window and the zoom change was not
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // initiated by an extension, then the bubble can be reused and only the label
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // text needs to be updated.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (zoom_bubble_ &&
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      zoom_bubble_->GetAnchorView() == anchor_view &&
71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      !extension) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zoom_bubble_->Refresh();
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // If the bubble is already showing but in a different tab, the current
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // bubble must be closed and a new one created.
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CloseBubble();
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  zoom_bubble_ = new ZoomBubbleView(anchor_view,
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                    web_contents,
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                    auto_close,
83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                    browser_view->immersive_mode_controller(),
84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                    browser->fullscreen_controller());
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // If the zoom change was initiated by an extension, capture the relevent
87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // information from it.
88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (extension)
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    zoom_bubble_->SetExtensionInfo(extension);
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // If we do not have an anchor view, parent the bubble to the content area.
92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!anchor_to_view)
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    zoom_bubble_->set_parent_window(web_contents->GetTopLevelNativeWindow());
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  views::BubbleDelegateView::CreateBubble(zoom_bubble_);
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Adjust for fullscreen after creation as it relies on the content size.
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (is_fullscreen)
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    zoom_bubble_->AdjustForFullscreen(browser_view->GetBoundsInScreen());
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (auto_close)
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    zoom_bubble_->GetWidget()->ShowInactive();
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  else
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    zoom_bubble_->GetWidget()->Show();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ZoomBubbleView::CloseBubble() {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (zoom_bubble_)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zoom_bubble_->Close();
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ZoomBubbleView::IsShowing() {
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // The bubble may be in the process of closing.
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return zoom_bubble_ != NULL && zoom_bubble_->GetWidget()->IsVisible();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// static
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst ZoomBubbleView* ZoomBubbleView::GetZoomBubbleForTest() {
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return zoom_bubble_;
122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochZoomBubbleView::ZoomBubbleView(
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    views::View* anchor_view,
126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    content::WebContents* web_contents,
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    bool auto_close,
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ImmersiveModeController* immersive_mode_controller,
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    FullscreenController* fullscreen_controller)
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : BubbleDelegateView(anchor_view, anchor_view ?
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          views::BubbleBorder::TOP_RIGHT : views::BubbleBorder::NONE),
132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      image_button_(NULL),
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      label_(NULL),
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      web_contents_(web_contents),
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      auto_close_(auto_close),
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      immersive_mode_controller_(immersive_mode_controller) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Compensate for built-in vertical padding in the anchor view's image.
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  set_anchor_view_insets(gfx::Insets(5, 0, 5, 0));
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_notify_enter_exit_on_child(true);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Add observers to close the bubble if the fullscreen state or immersive
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // fullscreen revealed state changes.
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registrar_.Add(this,
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 chrome::NOTIFICATION_FULLSCREEN_CHANGED,
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 content::Source<FullscreenController>(fullscreen_controller));
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  immersive_mode_controller_->AddObserver(this);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ZoomBubbleView::~ZoomBubbleView() {
150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (immersive_mode_controller_)
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    immersive_mode_controller_->RemoveObserver(this);
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ZoomBubbleView::AdjustForFullscreen(const gfx::Rect& screen_bounds) {
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (GetAnchorView())
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(dbeam): should RTL logic be done in views::BubbleDelegateView?
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const size_t bubble_half_width = width() / 2;
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int x_pos = base::i18n::IsRTL() ?
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      screen_bounds.x() + bubble_half_width + kFullscreenPaddingEnd :
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      screen_bounds.right() - bubble_half_width - kFullscreenPaddingEnd;
163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  SetAnchorRect(gfx::Rect(x_pos, screen_bounds.y(), 0, 0));
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ZoomBubbleView::Refresh() {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ZoomController* zoom_controller =
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ZoomController::FromWebContents(web_contents_);
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int zoom_percent = zoom_controller->GetZoomPercent();
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  label_->SetText(
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      l10n_util::GetStringFUTF16Int(IDS_TOOLTIP_ZOOM, zoom_percent));
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartTimerIfNecessary();
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ZoomBubbleView::Close() {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetWidget()->Close();
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
179116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ZoomBubbleView::SetExtensionInfo(const extensions::Extension* extension) {
180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(extension);
181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  extension_info_.id = extension->id();
182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  extension_info_.name = extension->name();
183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const gfx::ImageSkia& default_extension_icon_image =
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      *rb.GetImageSkiaNamed(IDR_EXTENSIONS_FAVICON);
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int icon_size = gfx::kFaviconSize;
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // We give first preference to an icon from the extension's icon set that
190116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // matches the size of the default. But not all extensions will declare an
191116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // icon set, or may not have an icon of the default size (we don't want the
192116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // bubble to display, for example, a very large icon). In that case, if there
193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // is a browser-action icon (size-19) this is an acceptable alternative.
194116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const ExtensionIconSet& icons = extensions::IconsInfo::GetIcons(extension);
195116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool has_default_sized_icon =
196116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      !icons.Get(gfx::kFaviconSize, ExtensionIconSet::MATCH_EXACTLY).empty();
197116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (has_default_sized_icon) {
198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    extension_info_.icon_image.reset(
199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        new extensions::IconImage(web_contents_->GetBrowserContext(),
200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  extension,
201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  icons,
202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  icon_size,
203116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  default_extension_icon_image,
204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                  this));
205116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const extensions::ActionInfo* browser_action =
209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      extensions::ActionInfo::GetBrowserActionInfo(extension);
210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!browser_action || browser_action->default_icon.empty())
211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
213116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  icon_size = browser_action->default_icon.map().begin()->first;
214116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  extension_info_.icon_image.reset(
215116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new extensions::IconImage(web_contents_->GetBrowserContext(),
216116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                extension,
217116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                browser_action->default_icon,
218116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                icon_size,
219116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                default_extension_icon_image,
220116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                this));
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ZoomBubbleView::StartTimerIfNecessary() {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (auto_close_) {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (timer_.IsRunning()) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timer_.Reset();
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timer_.Start(
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeDelta::FromMilliseconds(kBubbleCloseDelay),
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this,
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          &ZoomBubbleView::Close);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ZoomBubbleView::StopTimer() {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Stop();
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid ZoomBubbleView::OnExtensionIconImageChanged(
242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    extensions::IconImage* /* image */) {
243116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  image_button_->SetImage(views::Button::STATE_NORMAL,
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                          &extension_info_.icon_image->image_skia());
245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  image_button_->SchedulePaint();
246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ZoomBubbleView::OnMouseEntered(const ui::MouseEvent& event) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopTimer();
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ZoomBubbleView::OnMouseExited(const ui::MouseEvent& event) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartTimerIfNecessary();
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ZoomBubbleView::OnGestureEvent(ui::GestureEvent* event) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!zoom_bubble_ || !zoom_bubble_->auto_close_ ||
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event->type() != ui::ET_GESTURE_TAP) {
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  auto_close_ = false;
2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  StopTimer();
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event->SetHandled();
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ZoomBubbleView::ButtonPressed(views::Button* sender,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const ui::Event& event) {
269116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (sender == image_button_) {
270116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DCHECK(extension_info_.icon_image) << "Invalid button press.";
271116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Browser* browser = chrome::FindBrowserWithWebContents(web_contents_);
272116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    chrome::AddSelectedTabWithURL(
273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        browser,
274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        GURL(base::StringPrintf("chrome://extensions?id=%s",
275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                extension_info_.id.c_str())),
2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ui::PAGE_TRANSITION_FROM_API);
277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {
278116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    chrome_page_zoom::Zoom(web_contents_, content::PAGE_ZOOM_RESET);
279116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ZoomBubbleView::Init() {
283116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Set up the layout of the zoom bubble. A grid layout is used because
284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // sometimes an extension icon is shown next to the zoom label.
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  views::GridLayout* grid_layout = new views::GridLayout(this);
286116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  SetLayoutManager(grid_layout);
287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  views::ColumnSet* columns = grid_layout->AddColumnSet(0);
288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // First row.
289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (extension_info_.icon_image) {
290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    columns->AddColumn(views::GridLayout::CENTER,views::GridLayout::CENTER, 2,
291116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                       views::GridLayout::USE_PREF, 0, 0);
292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     views::GridLayout::USE_PREF, 0, 0);
295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  grid_layout->StartRow(0, 0);
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // If this zoom change was initiated by an extension, that extension will be
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // attributed by showing its icon in the zoom bubble.
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (extension_info_.icon_image) {
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    image_button_ = new views::ImageButton(this);
301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    image_button_->SetTooltipText(l10n_util::GetStringFUTF16(
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        IDS_TOOLTIP_ZOOM_EXTENSION_ICON,
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        base::UTF8ToUTF16(extension_info_.name)));
304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    image_button_->SetImage(views::Button::STATE_NORMAL,
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                            &extension_info_.icon_image->image_skia());
306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    grid_layout->AddView(image_button_);
307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Add zoom label with the new zoom percent.
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ZoomController* zoom_controller =
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ZoomController::FromWebContents(web_contents_);
312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int zoom_percent = zoom_controller->GetZoomPercent();
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  label_ = new views::Label(
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      l10n_util::GetStringFUTF16Int(IDS_TOOLTIP_ZOOM, zoom_percent));
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  label_->SetFontList(
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ui::ResourceBundle::GetSharedInstance().GetFontList(
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          ui::ResourceBundle::MediumFont));
318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  grid_layout->AddView(label_);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Second row.
321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  grid_layout->AddPaddingRow(0, 8);
322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  columns = grid_layout->AddColumnSet(1);
323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
324116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                     views::GridLayout::USE_PREF, 0, 0);
325116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  grid_layout->StartRow(0, 1);
326116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
327116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Add "Reset to Default" button.
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  views::LabelButton* set_default_button = new views::LabelButton(
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this, l10n_util::GetStringUTF16(IDS_ZOOM_SET_DEFAULT));
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  set_default_button->SetStyle(views::Button::STYLE_BUTTON);
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  set_default_button->SetHorizontalAlignment(gfx::ALIGN_CENTER);
332116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  grid_layout->AddView(set_default_button);
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartTimerIfNecessary();
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ZoomBubbleView::Observe(int type,
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             const content::NotificationSource& source,
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             const content::NotificationDetails& details) {
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(type, chrome::NOTIFICATION_FULLSCREEN_CHANGED);
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CloseBubble();
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
344eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ZoomBubbleView::OnImmersiveRevealStarted() {
345eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CloseBubble();
346eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
347eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ZoomBubbleView::OnImmersiveModeControllerDestroyed() {
349eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  immersive_mode_controller_ = NULL;
350eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
351eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ZoomBubbleView::WindowClosing() {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |zoom_bubble_| can be a new bubble by this point (as Close(); doesn't
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // call this right away). Only set to NULL when it's this bubble.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (zoom_bubble_ == this)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zoom_bubble_ = NULL;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
358116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
359116680a4aac90f2aa7413d9095a592090648e557Ben MurdochZoomBubbleView::ZoomBubbleExtensionInfo::ZoomBubbleExtensionInfo() {}
360116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
361116680a4aac90f2aa7413d9095a592090648e557Ben MurdochZoomBubbleView::ZoomBubbleExtensionInfo::~ZoomBubbleExtensionInfo() {}
362