Index: chrome/browser/ui/views/location_bar/zoom_bubble_view.cc |
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc |
index 80367b88c05a657ac660c074c700deaa4fc231ce..3ab1d2f773bc0faf95a00ffe0d1dd5f24b472a52 100644 |
--- a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc |
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc |
@@ -5,22 +5,29 @@ |
#include "chrome/browser/ui/views/location_bar/zoom_bubble_view.h" |
#include "base/i18n/rtl.h" |
+#include "base/strings/stringprintf.h" |
#include "chrome/browser/chrome_notification_types.h" |
#include "chrome/browser/chrome_page_zoom.h" |
#include "chrome/browser/ui/browser.h" |
#include "chrome/browser/ui/browser_finder.h" |
+#include "chrome/browser/ui/browser_tabstrip.h" |
#include "chrome/browser/ui/browser_window.h" |
#include "chrome/browser/ui/views/frame/browser_view.h" |
#include "chrome/browser/ui/views/location_bar/location_bar_view.h" |
#include "chrome/browser/ui/views/location_bar/zoom_view.h" |
#include "chrome/browser/ui/zoom/zoom_controller.h" |
+#include "chrome/common/extensions/api/extension_action/action_info.h" |
#include "content/public/browser/notification_source.h" |
+#include "extensions/common/manifest_handlers/icons_handler.h" |
#include "grit/generated_resources.h" |
+#include "grit/theme_resources.h" |
#include "ui/base/l10n/l10n_util.h" |
#include "ui/base/resource/resource_bundle.h" |
+#include "ui/gfx/favicon_size.h" |
+#include "ui/views/controls/button/image_button.h" |
#include "ui/views/controls/button/label_button.h" |
#include "ui/views/controls/separator.h" |
-#include "ui/views/layout/box_layout.h" |
+#include "ui/views/layout/grid_layout.h" |
#include "ui/views/layout/layout_constants.h" |
#include "ui/views/widget/widget.h" |
@@ -51,41 +58,53 @@ void ZoomBubbleView::ShowBubble(content::WebContents* web_contents, |
views::View* anchor_view = anchor_to_view ? |
browser_view->GetLocationBarView()->zoom_view() : NULL; |
- // If the bubble is already showing in this window and its |auto_close_| value |
- // is equal to |auto_close|, the bubble can be reused and only the label text |
- // needs to be updated. |
+ // Find the extension that initiated the zoom change, if any. |
+ ZoomController* zoom_controller = |
+ ZoomController::FromWebContents(web_contents); |
+ const extensions::Extension* extension = zoom_controller->last_extension(); |
+ |
+ // If the bubble is already showing in this window, its |auto_close_| value |
+ // is equal to |auto_close|, and the zoom change was not initiated by an |
+ // extension, then the bubble can be reused and only the label text needs to |
+ // be updated. |
if (zoom_bubble_ && |
zoom_bubble_->GetAnchorView() == anchor_view && |
- zoom_bubble_->auto_close_ == auto_close) { |
+ zoom_bubble_->auto_close_ == auto_close && |
+ !extension) { |
zoom_bubble_->Refresh(); |
- } else { |
- // If the bubble is already showing but its |auto_close_| value is not equal |
- // to |auto_close|, the bubble's focus properties must change, so the |
- // current bubble must be closed and a new one created. |
- CloseBubble(); |
- |
- zoom_bubble_ = new ZoomBubbleView(anchor_view, |
- web_contents, |
- auto_close, |
- browser_view->immersive_mode_controller(), |
- browser->fullscreen_controller()); |
- |
- // If we do not have an anchor view, parent the bubble to the content area. |
- if (!anchor_to_view) { |
- zoom_bubble_->set_parent_window(web_contents->GetTopLevelNativeWindow()); |
- } |
+ return; |
+ } |
+ |
+ // If the bubble is already showing but its |auto_close_| value is not equal |
+ // to |auto_close|, the bubble's focus properties must change, so the |
+ // current bubble must be closed and a new one created. |
+ CloseBubble(); |
- views::BubbleDelegateView::CreateBubble(zoom_bubble_); |
+ zoom_bubble_ = new ZoomBubbleView(anchor_view, |
+ web_contents, |
+ auto_close, |
+ browser_view->immersive_mode_controller(), |
+ browser->fullscreen_controller()); |
- // Adjust for fullscreen after creation as it relies on the content size. |
- if (is_fullscreen) |
- zoom_bubble_->AdjustForFullscreen(browser_view->GetBoundsInScreen()); |
+ // If the zoom change was initiated by an extension, capture the relevent |
+ // information from it. |
+ if (extension) |
+ zoom_bubble_->SetExtensionInfo(extension); |
- if (zoom_bubble_->use_focusless()) |
- zoom_bubble_->GetWidget()->ShowInactive(); |
- else |
- zoom_bubble_->GetWidget()->Show(); |
- } |
+ // If we do not have an anchor view, parent the bubble to the content area. |
+ if (!anchor_to_view) |
+ zoom_bubble_->set_parent_window(web_contents->GetTopLevelNativeWindow()); |
+ |
+ views::BubbleDelegateView::CreateBubble(zoom_bubble_); |
+ |
+ // Adjust for fullscreen after creation as it relies on the content size. |
+ if (is_fullscreen) |
+ zoom_bubble_->AdjustForFullscreen(browser_view->GetBoundsInScreen()); |
+ |
+ if (zoom_bubble_->use_focusless()) |
+ zoom_bubble_->GetWidget()->ShowInactive(); |
+ else |
+ zoom_bubble_->GetWidget()->Show(); |
} |
// static |
@@ -113,6 +132,7 @@ ZoomBubbleView::ZoomBubbleView( |
FullscreenController* fullscreen_controller) |
: BubbleDelegateView(anchor_view, anchor_view ? |
views::BubbleBorder::TOP_RIGHT : views::BubbleBorder::NONE), |
+ image_button_(NULL), |
label_(NULL), |
web_contents_(web_contents), |
auto_close_(auto_close), |
@@ -150,7 +170,7 @@ void ZoomBubbleView::AdjustForFullscreen(const gfx::Rect& screen_bounds) { |
void ZoomBubbleView::Refresh() { |
ZoomController* zoom_controller = |
ZoomController::FromWebContents(web_contents_); |
- int zoom_percent = zoom_controller->zoom_percent(); |
+ int zoom_percent = zoom_controller->GetZoomPercent(); |
label_->SetText( |
l10n_util::GetStringFUTF16Int(IDS_TOOLTIP_ZOOM, zoom_percent)); |
StartTimerIfNecessary(); |
@@ -160,6 +180,50 @@ void ZoomBubbleView::Close() { |
GetWidget()->Close(); |
} |
+void ZoomBubbleView::SetExtensionInfo(const extensions::Extension* extension) { |
+ DCHECK(extension); |
+ extension_info_.id = extension->id(); |
+ extension_info_.name = extension->name(); |
+ |
+ ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
+ const gfx::ImageSkia& default_extension_icon_image = |
+ *rb.GetImageSkiaNamed(IDR_EXTENSIONS_FAVICON); |
+ int icon_size = gfx::kFaviconSize; |
+ |
+ // We give first preference to an icon from the extension's icon set that |
+ // matches the size of the default. But not all extensions will declare an |
+ // icon set, or may not have an icon of the default size (we don't want the |
+ // bubble to display, for example, a very large icon). In that case, if there |
+ // is a browser-action icon (size-19) this is an acceptable alternative. |
+ const ExtensionIconSet& icons = extensions::IconsInfo::GetIcons(extension); |
+ bool has_default_sized_icon = |
+ !icons.Get(gfx::kFaviconSize, ExtensionIconSet::MATCH_EXACTLY).empty(); |
+ if (has_default_sized_icon) { |
+ extension_info_.icon_image.reset( |
+ new extensions::IconImage(web_contents_->GetBrowserContext(), |
+ extension, |
+ icons, |
+ icon_size, |
+ default_extension_icon_image, |
+ this)); |
+ return; |
+ } |
+ |
+ const extensions::ActionInfo* browser_action = |
+ extensions::ActionInfo::GetBrowserActionInfo(extension); |
+ if (!browser_action || browser_action->default_icon.empty()) |
+ return; |
+ |
+ icon_size = browser_action->default_icon.map().begin()->first; |
+ extension_info_.icon_image.reset( |
+ new extensions::IconImage(web_contents_->GetBrowserContext(), |
+ extension, |
+ browser_action->default_icon, |
+ icon_size, |
+ default_extension_icon_image, |
+ this)); |
+} |
+ |
void ZoomBubbleView::StartTimerIfNecessary() { |
if (auto_close_) { |
if (timer_.IsRunning()) { |
@@ -178,6 +242,13 @@ void ZoomBubbleView::StopTimer() { |
timer_.Stop(); |
} |
+void ZoomBubbleView::OnExtensionIconImageChanged( |
+ extensions::IconImage* /* image */) { |
+ image_button_->SetImage(views::Button::STATE_NORMAL, |
+ &extension_info_.icon_image->image_skia()); |
+ image_button_->SchedulePaint(); |
+} |
+ |
void ZoomBubbleView::OnMouseEntered(const ui::MouseEvent& event) { |
set_use_focusless(false); |
StopTimer(); |
@@ -202,28 +273,70 @@ void ZoomBubbleView::OnGestureEvent(ui::GestureEvent* event) { |
void ZoomBubbleView::ButtonPressed(views::Button* sender, |
const ui::Event& event) { |
- chrome_page_zoom::Zoom(web_contents_, content::PAGE_ZOOM_RESET); |
+ if (sender == image_button_) { |
+ DCHECK(extension_info_.icon_image) << "Invalid button press."; |
+ Browser* browser = chrome::FindBrowserWithWebContents(web_contents_); |
+ chrome::AddSelectedTabWithURL( |
+ browser, |
+ GURL(base::StringPrintf("chrome://extensions?id=%s", |
+ extension_info_.id.c_str())), |
+ content::PAGE_TRANSITION_FROM_API); |
+ } else { |
+ chrome_page_zoom::Zoom(web_contents_, content::PAGE_ZOOM_RESET); |
+ } |
} |
void ZoomBubbleView::Init() { |
- SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, |
- 0, 0, views::kRelatedControlVerticalSpacing)); |
+ // Set up the layout of the zoom bubble. A grid layout is used because |
+ // sometimes an extension icon is shown next to the zoom label. |
+ views::GridLayout* grid_layout = new views::GridLayout(this); |
+ SetLayoutManager(grid_layout); |
+ views::ColumnSet* columns = grid_layout->AddColumnSet(0); |
+ // First row. |
+ if (extension_info_.icon_image) { |
+ columns->AddColumn(views::GridLayout::CENTER,views::GridLayout::CENTER, 2, |
+ views::GridLayout::USE_PREF, 0, 0); |
+ } |
+ columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1, |
+ views::GridLayout::USE_PREF, 0, 0); |
+ grid_layout->StartRow(0, 0); |
+ |
+ // If this zoom change was initiated by an extension, that extension will be |
+ // attributed by showing its icon in the zoom bubble. |
+ if (extension_info_.icon_image) { |
+ image_button_ = new views::ImageButton(this); |
+ image_button_->SetTooltipText(l10n_util::GetStringFUTF16( |
+ IDS_TOOLTIP_ZOOM_EXTENSION_ICON, |
+ base::UTF8ToUTF16(extension_info_.name))); |
+ image_button_->SetImage(views::Button::STATE_NORMAL, |
+ &extension_info_.icon_image->image_skia()); |
+ grid_layout->AddView(image_button_); |
+ } |
+ // Add zoom label with the new zoom percent. |
ZoomController* zoom_controller = |
ZoomController::FromWebContents(web_contents_); |
- int zoom_percent = zoom_controller->zoom_percent(); |
+ int zoom_percent = zoom_controller->GetZoomPercent(); |
label_ = new views::Label( |
l10n_util::GetStringFUTF16Int(IDS_TOOLTIP_ZOOM, zoom_percent)); |
label_->SetFontList( |
ui::ResourceBundle::GetSharedInstance().GetFontList( |
ui::ResourceBundle::MediumFont)); |
- AddChildView(label_); |
+ grid_layout->AddView(label_); |
+ // Second row. |
+ grid_layout->AddPaddingRow(0, 8); |
+ columns = grid_layout->AddColumnSet(1); |
+ columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1, |
+ views::GridLayout::USE_PREF, 0, 0); |
+ grid_layout->StartRow(0, 1); |
+ |
+ // Add "Reset to Default" button. |
views::LabelButton* set_default_button = new views::LabelButton( |
this, l10n_util::GetStringUTF16(IDS_ZOOM_SET_DEFAULT)); |
set_default_button->SetStyle(views::Button::STYLE_BUTTON); |
set_default_button->SetHorizontalAlignment(gfx::ALIGN_CENTER); |
- AddChildView(set_default_button); |
+ grid_layout->AddView(set_default_button); |
StartTimerIfNecessary(); |
} |
@@ -249,3 +362,7 @@ void ZoomBubbleView::WindowClosing() { |
if (zoom_bubble_ == this) |
zoom_bubble_ = NULL; |
} |
+ |
+ZoomBubbleView::ZoomBubbleExtensionInfo::ZoomBubbleExtensionInfo() {} |
+ |
+ZoomBubbleView::ZoomBubbleExtensionInfo::~ZoomBubbleExtensionInfo() {} |