Commit 741158fe authored by Kevin McNee's avatar Kevin McNee Committed by Commit Bot

Refresh zoom bubble if visible following whitelisted extension zoom.

Extensions may be whitelisted to suppress the zoom bubble when
performing an extension initiated zoom (e.g. the PDF viewer). However,
this also suppressed updates to the zoom bubble if it was already
being shown.

We now update the zoom bubble (if it exists) in this case.

Bug: 817278
Change-Id: Ia746f25de2760e8349a1ec3d3f4c899392d0fc81
Reviewed-on: https://chromium-review.googlesource.com/1086153Reviewed-by: default avatarIstiaque Ahmed <lazyboy@chromium.org>
Reviewed-by: default avatarJames MacLean <wjmaclean@chromium.org>
Reviewed-by: default avatarPeter Kasting <pkasting@chromium.org>
Commit-Queue: Kevin McNee <mcnee@chromium.org>
Cr-Commit-Position: refs/heads/master@{#571124}
parent f44f7dc2
......@@ -325,9 +325,14 @@ void LocationBarView::ZoomChangedForActiveTab(bool can_show_bubble) {
}
WebContents* web_contents = GetWebContents();
if (can_show_bubble && web_contents) {
if (!web_contents)
return;
if (can_show_bubble) {
ZoomBubbleView::ShowBubble(web_contents, gfx::Point(),
ZoomBubbleView::AUTOMATIC);
} else {
ZoomBubbleView::RefreshBubbleIfShowing(web_contents);
}
}
......
......@@ -114,6 +114,12 @@ class ZoomValue : public views::Label {
DISALLOW_COPY_AND_ASSIGN(ZoomValue);
};
bool IsBrowserFullscreen(Browser* browser) {
DCHECK(browser->window() &&
browser->exclusive_access_manager()->fullscreen_controller());
return browser->window()->IsFullscreen();
}
views::View* GetAnchorViewForBrowser(Browser* browser, bool is_fullscreen) {
#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
#if BUILDFLAG(MAC_VIEWS_BROWSER)
......@@ -134,6 +140,11 @@ views::View* GetAnchorViewForBrowser(Browser* browser, bool is_fullscreen) {
#endif
}
views::View* GetAnchorViewForBrowser(Browser* browser) {
const bool is_fullscreen = IsBrowserFullscreen(browser);
return GetAnchorViewForBrowser(browser, is_fullscreen);
}
ImmersiveModeController* GetImmersiveModeControllerForBrowser(
Browser* browser) {
#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
......@@ -194,6 +205,15 @@ void ParentToBrowser(Browser* browser,
#endif
}
// Find the extension that initiated the zoom change, if any.
const extensions::ExtensionZoomRequestClient* GetExtensionZoomRequestClient(
const content::WebContents* web_contents) {
const zoom::ZoomController* zoom_controller =
zoom::ZoomController::FromWebContents(web_contents);
const zoom::ZoomRequestClient* client = zoom_controller->last_client();
return static_cast<const extensions::ExtensionZoomRequestClient*>(client);
}
} // namespace
// static
......@@ -208,42 +228,29 @@ void ZoomBubbleView::ShowBubble(content::WebContents* web_contents,
// event arrives before the zoom icon gets hidden.
if (!browser)
return;
DCHECK(browser->window() &&
browser->exclusive_access_manager()->fullscreen_controller());
bool is_fullscreen = browser->window()->IsFullscreen();
views::View* anchor_view = GetAnchorViewForBrowser(browser, is_fullscreen);
ImmersiveModeController* immersive_mode_controller =
GetImmersiveModeControllerForBrowser(browser);
// Find the extension that initiated the zoom change, if any.
zoom::ZoomController* zoom_controller =
zoom::ZoomController::FromWebContents(web_contents);
const zoom::ZoomRequestClient* client = zoom_controller->last_client();
// If the bubble is already showing in this window 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 && !client) {
DCHECK_EQ(web_contents, zoom_bubble_->web_contents());
zoom_bubble_->Refresh();
if (RefreshBubbleIfShowing(web_contents))
return;
}
// If the bubble is already showing but in a different tab, the current
// bubble must be closed and a new one created.
CloseCurrentBubble();
const bool is_fullscreen = IsBrowserFullscreen(browser);
views::View* anchor_view = GetAnchorViewForBrowser(browser, is_fullscreen);
ImmersiveModeController* immersive_mode_controller =
GetImmersiveModeControllerForBrowser(browser);
zoom_bubble_ = new ZoomBubbleView(anchor_view, anchor_point, web_contents,
reason, immersive_mode_controller);
const extensions::ExtensionZoomRequestClient* client =
GetExtensionZoomRequestClient(web_contents);
// If the zoom change was initiated by an extension, capture the relevent
// information from it.
if (client) {
zoom_bubble_->SetExtensionInfo(
static_cast<const extensions::ExtensionZoomRequestClient*>(client)
->extension());
}
if (client)
zoom_bubble_->SetExtensionInfo(client->extension());
ParentToBrowser(browser, zoom_bubble_, anchor_view, web_contents);
......@@ -255,6 +262,36 @@ void ZoomBubbleView::ShowBubble(content::WebContents* web_contents,
zoom_bubble_->UpdateZoomIconVisibility();
}
// static
bool ZoomBubbleView::RefreshBubbleIfShowing(
const content::WebContents* web_contents) {
if (!CanRefresh(web_contents))
return false;
DCHECK_EQ(web_contents, zoom_bubble_->web_contents());
zoom_bubble_->Refresh();
return true;
}
// static
bool ZoomBubbleView::CanRefresh(const content::WebContents* web_contents) {
Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
if (!browser)
return false;
const views::View* anchor_view = GetAnchorViewForBrowser(browser);
const extensions::ExtensionZoomRequestClient* client =
GetExtensionZoomRequestClient(web_contents);
// If the bubble is already showing in this window and the zoom change was not
// initiated by an extension that needs attribution in the zoom bubble, then
// the bubble can be reused and only the label text needs to be updated.
return zoom_bubble_ && zoom_bubble_->web_contents() == web_contents &&
zoom_bubble_->GetAnchorView() == anchor_view &&
(!client || client->ShouldSuppressBubble());
}
// static
void ZoomBubbleView::CloseCurrentBubble() {
if (zoom_bubble_)
......
......@@ -38,6 +38,9 @@ class ZoomBubbleView : public LocationBarBubbleDelegateView,
const gfx::Point& anchor_point,
DisplayReason reason);
// If the bubble is being shown for the given |web_contents|, refreshes it.
static bool RefreshBubbleIfShowing(const content::WebContents* web_contents);
// Closes the showing bubble (if one exists).
static void CloseCurrentBubble();
......@@ -51,6 +54,12 @@ class ZoomBubbleView : public LocationBarBubbleDelegateView,
private:
FRIEND_TEST_ALL_PREFIXES(ZoomBubbleBrowserTest, ImmersiveFullscreen);
FRIEND_TEST_ALL_PREFIXES(ZoomBubbleBrowserTest,
BubbleSuppressingExtensionRefreshesExistingBubble);
// Returns true if we can reuse the existing bubble for the given
// |web_contents|.
static bool CanRefresh(const content::WebContents* web_contents);
// Stores information about the extension that initiated the zoom change, if
// any.
......
......@@ -13,6 +13,9 @@
#include "chrome/browser/ui/test/test_browser_dialog.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/views/scoped_macviews_browser_mode.h"
#include "components/zoom/zoom_controller.h"
#include "extensions/browser/extension_zoom_request_client.h"
#include "extensions/common/extension_builder.h"
#include "ui/base/ui_features.h"
#include "ui/views/test/test_widget_observer.h"
......@@ -216,6 +219,60 @@ IN_PROC_BROWSER_TEST_F(ZoomBubbleBrowserTest, DestroyedWebContents) {
EXPECT_TRUE(observer.widget_closed());
}
namespace {
class TestZoomRequestClient : public extensions::ExtensionZoomRequestClient {
public:
TestZoomRequestClient(scoped_refptr<const extensions::Extension> extension,
bool should_suppress_bubble)
: extensions::ExtensionZoomRequestClient(extension),
should_suppress_bubble_(should_suppress_bubble) {}
bool ShouldSuppressBubble() const override { return should_suppress_bubble_; }
protected:
~TestZoomRequestClient() override = default;
private:
const bool should_suppress_bubble_;
};
} // namespace
// Extensions may be whitelisted to not show a bubble when they perform a zoom
// change. However, if a zoom bubble is already showing, zoom changes performed
// by the extension should update the bubble.
IN_PROC_BROWSER_TEST_F(ZoomBubbleBrowserTest,
BubbleSuppressingExtensionRefreshesExistingBubble) {
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
zoom::ZoomController* zoom_controller =
zoom::ZoomController::FromWebContents(web_contents);
ASSERT_TRUE(zoom_controller);
// Extension zoom bubble suppression only happens in manual mode.
zoom_controller->SetZoomMode(zoom::ZoomController::ZOOM_MODE_MANUAL);
ShowInActiveTab(browser());
const ZoomBubbleView* bubble = ZoomBubbleView::GetZoomBubble();
ASSERT_TRUE(bubble);
const double old_zoom_level = zoom_controller->GetZoomLevel();
const base::string16 old_label = bubble->label_->text();
scoped_refptr<const extensions::Extension> extension =
extensions::ExtensionBuilder("Test").Build();
scoped_refptr<const TestZoomRequestClient> client =
base::MakeRefCounted<const TestZoomRequestClient>(extension, true);
const double new_zoom_level = old_zoom_level + 0.5;
zoom_controller->SetZoomLevelByClient(new_zoom_level, client);
ASSERT_EQ(ZoomBubbleView::GetZoomBubble(), bubble);
const base::string16 new_label = bubble->label_->text();
EXPECT_NE(new_label, old_label);
}
class ZoomBubbleDialogTest : public DialogBrowserTest {
public:
ZoomBubbleDialogTest() {}
......
......@@ -26,8 +26,10 @@ class ExtensionZoomRequestClient : public zoom::ZoomRequestClient {
bool ShouldSuppressBubble() const override;
const Extension* extension() const { return extension_.get(); }
private:
protected:
~ExtensionZoomRequestClient() override;
private:
scoped_refptr<const Extension> extension_;
DISALLOW_COPY_AND_ASSIGN(ExtensionZoomRequestClient);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment