summaryrefslogtreecommitdiffstats
path: root/components/ui
diff options
context:
space:
mode:
authorwjmaclean <wjmaclean@chromium.org>2014-12-09 06:59:55 -0800
committerCommit bot <commit-bot@chromium.org>2014-12-09 15:00:15 +0000
commit7f63c6b94ee1d470791c243c4941c55315416171 (patch)
treed831aa080ee31fa0df7fbc8c09dbb43a29e608b2 /components/ui
parent3490213352d10c5fbf71e5d259343914d7c7d86a (diff)
downloadchromium_src-7f63c6b94ee1d470791c243c4941c55315416171.zip
chromium_src-7f63c6b94ee1d470791c243c4941c55315416171.tar.gz
chromium_src-7f63c6b94ee1d470791c243c4941c55315416171.tar.bz2
Move ZoomObserver, ZoomController and ZoomEventManager to components/.
This CL moves the three classes into components, namespace ui_zoom, and moves their associated source files into components/ui/zoom so that they can be used in non-chrome configurations. BUG=none TBR=willchan@chromium.org chrome/browser/profiles TBR=fsamuel@chromium.org */web_view/* TBR=estade@chromium.org chrome/browser/ui/autofill TBR=pkasting@chromium.org chrome/browser/ui not covered above TBR=dgozman@chromium.org chrome/browser/devtools TBR=rsesek@chromium.org chrome/browser/browser_commands_unittest.cc TBR=sky@chromium.org chrome/browser/renderer_preferences_util.cc Review URL: https://codereview.chromium.org/769593003 Cr-Commit-Position: refs/heads/master@{#307470}
Diffstat (limited to 'components/ui')
-rw-r--r--components/ui/zoom/BUILD.gn22
-rw-r--r--components/ui/zoom/DEPS8
-rw-r--r--components/ui/zoom/OWNERS2
-rw-r--r--components/ui/zoom/zoom_controller.cc298
-rw-r--r--components/ui/zoom/zoom_controller.h187
-rw-r--r--components/ui/zoom/zoom_event_manager.cc40
-rw-r--r--components/ui/zoom/zoom_event_manager.h57
-rw-r--r--components/ui/zoom/zoom_observer.h25
8 files changed, 639 insertions, 0 deletions
diff --git a/components/ui/zoom/BUILD.gn b/components/ui/zoom/BUILD.gn
new file mode 100644
index 0000000..2cefb39
--- /dev/null
+++ b/components/ui/zoom/BUILD.gn
@@ -0,0 +1,22 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+static_library("ui_zoom") {
+ sources = [
+ "zoom_controller.cc",
+ "zoom_controller.h",
+ "zoom_event_manager.cc",
+ "zoom_event_manager.h",
+ "zoom_observer.h",
+ ]
+
+ deps = [
+ "//base",
+ "//content/public/browser",
+ "//content/public/common",
+ "//ipc",
+ "//net",
+ "//url",
+ ]
+}
diff --git a/components/ui/zoom/DEPS b/components/ui/zoom/DEPS
new file mode 100644
index 0000000..cdd5019
--- /dev/null
+++ b/components/ui/zoom/DEPS
@@ -0,0 +1,8 @@
+include_rules = [
+ "+content/public/browser",
+ "+content/public/common",
+ "+ipc",
+ "+net/base",
+ "+url",
+]
+
diff --git a/components/ui/zoom/OWNERS b/components/ui/zoom/OWNERS
new file mode 100644
index 0000000..aede306
--- /dev/null
+++ b/components/ui/zoom/OWNERS
@@ -0,0 +1,2 @@
+dbeam@chromium.org
+wjmaclean@chromium.org
diff --git a/components/ui/zoom/zoom_controller.cc b/components/ui/zoom/zoom_controller.cc
new file mode 100644
index 0000000..cc07e31
--- /dev/null
+++ b/components/ui/zoom/zoom_controller.cc
@@ -0,0 +1,298 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/ui/zoom/zoom_controller.h"
+
+#include "components/ui/zoom/zoom_event_manager.h"
+#include "components/ui/zoom/zoom_observer.h"
+#include "content/public/browser/host_zoom_map.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/page_type.h"
+#include "content/public/common/page_zoom.h"
+#include "net/base/net_util.h"
+
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(ui_zoom::ZoomController);
+
+namespace ui_zoom {
+
+ZoomController::ZoomController(content::WebContents* web_contents)
+ : content::WebContentsObserver(web_contents),
+ can_show_bubble_(true),
+ zoom_mode_(ZOOM_MODE_DEFAULT),
+ zoom_level_(1.0),
+ browser_context_(web_contents->GetBrowserContext()) {
+ content::HostZoomMap* host_zoom_map =
+ content::HostZoomMap::GetForWebContents(web_contents);
+ zoom_level_ = host_zoom_map->GetDefaultZoomLevel();
+
+ zoom_subscription_ = host_zoom_map->AddZoomLevelChangedCallback(
+ base::Bind(&ZoomController::OnZoomLevelChanged, base::Unretained(this)));
+
+ UpdateState(std::string());
+}
+
+ZoomController::~ZoomController() {
+}
+
+bool ZoomController::IsAtDefaultZoom() const {
+ return content::ZoomValuesEqual(GetZoomLevel(), GetDefaultZoomLevel());
+}
+
+ZoomController::RelativeZoom ZoomController::GetZoomRelativeToDefault() const {
+ double current_level = GetZoomLevel();
+ double default_level = GetDefaultZoomLevel();
+ if (content::ZoomValuesEqual(current_level, default_level))
+ return ZOOM_AT_DEFAULT_ZOOM;
+ else if (current_level > default_level)
+ return ZOOM_ABOVE_DEFAULT_ZOOM;
+ return ZOOM_BELOW_DEFAULT_ZOOM;
+}
+
+void ZoomController::AddObserver(ZoomObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void ZoomController::RemoveObserver(ZoomObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+double ZoomController::GetZoomLevel() const {
+ return zoom_mode_ == ZOOM_MODE_MANUAL
+ ? zoom_level_
+ : content::HostZoomMap::GetZoomLevel(web_contents());
+}
+
+int ZoomController::GetZoomPercent() const {
+ double zoom_factor = content::ZoomLevelToZoomFactor(GetZoomLevel());
+ // Round double for return.
+ return static_cast<int>(zoom_factor * 100 + 0.5);
+}
+
+bool ZoomController::SetZoomLevel(double zoom_level) {
+ // A client did not initiate this zoom change.
+ return SetZoomLevelByClient(zoom_level, NULL);
+}
+
+bool ZoomController::SetZoomLevelByClient(
+ double zoom_level,
+ const scoped_refptr<const ZoomRequestClient>& client) {
+ content::NavigationEntry* entry =
+ web_contents()->GetController().GetLastCommittedEntry();
+ // Cannot zoom in disabled mode. Also, don't allow changing zoom level on
+ // a crashed tab, an error page or an interstitial page.
+ if (zoom_mode_ == ZOOM_MODE_DISABLED ||
+ !web_contents()->GetRenderViewHost()->IsRenderViewLive())
+ return false;
+
+ // Store client data so the |client| can be attributed when the zoom
+ // change completes. We expect that by the time this function returns that
+ // any observers that require this information will have requested it.
+ last_client_ = client;
+
+ // Do not actually rescale the page in manual mode.
+ if (zoom_mode_ == ZOOM_MODE_MANUAL) {
+ double old_zoom_level = zoom_level_;
+ zoom_level_ = zoom_level;
+
+ // TODO(wjmaclean) Do we care about filling in host/scheme here?
+ content::HostZoomMap::ZoomLevelChange change;
+ change.mode = content::HostZoomMap::ZOOM_CHANGED_TEMPORARY_ZOOM;
+ change.zoom_level = zoom_level;
+ ZoomEventManager::GetForBrowserContext(browser_context_)
+ ->OnZoomLevelChanged(change);
+
+ ZoomChangedEventData zoom_change_data(web_contents(), old_zoom_level,
+ zoom_level_, zoom_mode_,
+ false /* can_show_bubble */);
+ FOR_EACH_OBSERVER(ZoomObserver, observers_,
+ OnZoomChanged(zoom_change_data));
+
+ last_client_ = NULL;
+ return true;
+ }
+
+ content::HostZoomMap* zoom_map =
+ content::HostZoomMap::GetForWebContents(web_contents());
+ DCHECK(zoom_map);
+ DCHECK(!event_data_);
+ event_data_.reset(new ZoomChangedEventData(web_contents(), GetZoomLevel(),
+ zoom_level, zoom_mode_,
+ false /* can_show_bubble */));
+ int render_process_id = web_contents()->GetRenderProcessHost()->GetID();
+ int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
+ if (zoom_mode_ == ZOOM_MODE_ISOLATED ||
+ zoom_map->UsesTemporaryZoomLevel(render_process_id, render_view_id)) {
+ zoom_map->SetTemporaryZoomLevel(render_process_id, render_view_id,
+ zoom_level);
+ } else {
+ if (!entry) {
+ last_client_ = NULL;
+ return false;
+ }
+ std::string host =
+ net::GetHostOrSpecFromURL(content::HostZoomMap::GetURLFromEntry(entry));
+ zoom_map->SetZoomLevelForHost(host, zoom_level);
+ }
+
+ DCHECK(!event_data_);
+ last_client_ = NULL;
+ return true;
+}
+
+void ZoomController::SetZoomMode(ZoomMode new_mode) {
+ if (new_mode == zoom_mode_)
+ return;
+
+ content::HostZoomMap* zoom_map =
+ content::HostZoomMap::GetForWebContents(web_contents());
+ DCHECK(zoom_map);
+ int render_process_id = web_contents()->GetRenderProcessHost()->GetID();
+ int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
+ double original_zoom_level = GetZoomLevel();
+
+ DCHECK(!event_data_);
+ event_data_.reset(new ZoomChangedEventData(
+ web_contents(), original_zoom_level, original_zoom_level, new_mode,
+ new_mode != ZOOM_MODE_DEFAULT));
+
+ switch (new_mode) {
+ case ZOOM_MODE_DEFAULT: {
+ content::NavigationEntry* entry =
+ web_contents()->GetController().GetLastCommittedEntry();
+
+ if (entry) {
+ GURL url = content::HostZoomMap::GetURLFromEntry(entry);
+ std::string host = net::GetHostOrSpecFromURL(url);
+
+ if (zoom_map->HasZoomLevel(url.scheme(), host)) {
+ // If there are other tabs with the same origin, then set this tab's
+ // zoom level to match theirs. The temporary zoom level will be
+ // cleared below, but this call will make sure this tab re-draws at
+ // the correct zoom level.
+ double origin_zoom_level =
+ zoom_map->GetZoomLevelForHostAndScheme(url.scheme(), host);
+ event_data_->new_zoom_level = origin_zoom_level;
+ zoom_map->SetTemporaryZoomLevel(render_process_id, render_view_id,
+ origin_zoom_level);
+ } else {
+ // The host will need a level prior to removing the temporary level.
+ // We don't want the zoom level to change just because we entered
+ // default mode.
+ zoom_map->SetZoomLevelForHost(host, original_zoom_level);
+ }
+ }
+ // Remove per-tab zoom data for this tab. No event callback expected.
+ zoom_map->ClearTemporaryZoomLevel(render_process_id, render_view_id);
+ break;
+ }
+ case ZOOM_MODE_ISOLATED: {
+ // Unless the zoom mode was |ZOOM_MODE_DISABLED| before this call, the
+ // page needs an initial isolated zoom back to the same level it was at
+ // in the other mode.
+ if (zoom_mode_ != ZOOM_MODE_DISABLED) {
+ zoom_map->SetTemporaryZoomLevel(render_process_id, render_view_id,
+ original_zoom_level);
+ } else {
+ // When we don't call any HostZoomMap set functions, we send the event
+ // manually.
+ FOR_EACH_OBSERVER(ZoomObserver, observers_,
+ OnZoomChanged(*event_data_));
+ event_data_.reset();
+ }
+ break;
+ }
+ case ZOOM_MODE_MANUAL: {
+ // Unless the zoom mode was |ZOOM_MODE_DISABLED| before this call, the
+ // page needs to be resized to the default zoom. While in manual mode,
+ // the zoom level is handled independently.
+ if (zoom_mode_ != ZOOM_MODE_DISABLED) {
+ zoom_map->SetTemporaryZoomLevel(render_process_id, render_view_id,
+ GetDefaultZoomLevel());
+ zoom_level_ = original_zoom_level;
+ } else {
+ // When we don't call any HostZoomMap set functions, we send the event
+ // manually.
+ FOR_EACH_OBSERVER(ZoomObserver, observers_,
+ OnZoomChanged(*event_data_));
+ event_data_.reset();
+ }
+ break;
+ }
+ case ZOOM_MODE_DISABLED: {
+ // The page needs to be zoomed back to default before disabling the zoom
+ zoom_map->SetTemporaryZoomLevel(render_process_id, render_view_id,
+ GetDefaultZoomLevel());
+ break;
+ }
+ }
+ // Any event data we've stored should have been consumed by this point.
+ DCHECK(!event_data_);
+
+ zoom_mode_ = new_mode;
+}
+
+void ZoomController::DidNavigateMainFrame(
+ const content::LoadCommittedDetails& details,
+ const content::FrameNavigateParams& params) {
+ if (details.entry && details.entry->GetPageType() == content::PAGE_TYPE_ERROR)
+ content::HostZoomMap::SendErrorPageZoomLevelRefresh(web_contents());
+
+ // If the main frame's content has changed, the new page may have a different
+ // zoom level from the old one.
+ UpdateState(std::string());
+}
+
+void ZoomController::WebContentsDestroyed() {
+ // At this point we should no longer be sending any zoom events with this
+ // WebContents.
+ observers_.Clear();
+}
+
+void ZoomController::OnZoomLevelChanged(
+ const content::HostZoomMap::ZoomLevelChange& change) {
+ UpdateState(change.host);
+}
+
+void ZoomController::UpdateState(const std::string& host) {
+ // If |host| is empty, all observers should be updated.
+ if (!host.empty()) {
+ // Use the navigation entry's URL instead of the WebContents' so virtual
+ // URLs work (e.g. chrome://settings). http://crbug.com/153950
+ content::NavigationEntry* entry =
+ web_contents()->GetController().GetLastCommittedEntry();
+ if (!entry ||
+ host != net::GetHostOrSpecFromURL(
+ content::HostZoomMap::GetURLFromEntry(entry))) {
+ return;
+ }
+ }
+
+ // The zoom bubble should not be shown for zoom changes where the host is
+ // empty.
+ bool can_show_bubble = can_show_bubble_ && !host.empty();
+
+ if (event_data_) {
+ // For state changes initiated within the ZoomController, information about
+ // the change should be sent.
+ ZoomChangedEventData zoom_change_data = *event_data_;
+ event_data_.reset();
+ zoom_change_data.can_show_bubble = can_show_bubble;
+ FOR_EACH_OBSERVER(ZoomObserver, observers_,
+ OnZoomChanged(zoom_change_data));
+ } else {
+ // TODO(wjmaclean) Should we consider having HostZoomMap send both old and
+ // new zoom levels here?
+ double zoom_level = GetZoomLevel();
+ ZoomChangedEventData zoom_change_data(
+ web_contents(), zoom_level, zoom_level, zoom_mode_, can_show_bubble);
+ FOR_EACH_OBSERVER(ZoomObserver, observers_,
+ OnZoomChanged(zoom_change_data));
+ }
+}
+
+} // namespace ui_zoom
diff --git a/components/ui/zoom/zoom_controller.h b/components/ui/zoom/zoom_controller.h
new file mode 100644
index 0000000..5814345
--- /dev/null
+++ b/components/ui/zoom/zoom_controller.h
@@ -0,0 +1,187 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_UI_ZOOM_ZOOM_CONTROLLER_H_
+#define COMPONENTS_UI_ZOOM_ZOOM_CONTROLLER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "base/prefs/pref_member.h"
+#include "content/public/browser/host_zoom_map.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+class ZoomControllerTest;
+
+namespace content {
+class WebContents;
+}
+
+namespace ui_zoom {
+class ZoomObserver;
+
+class ZoomRequestClient : public base::RefCounted<ZoomRequestClient> {
+ public:
+ ZoomRequestClient() {}
+
+ protected:
+ virtual ~ZoomRequestClient() {}
+
+ private:
+ friend class base::RefCounted<ZoomRequestClient>;
+
+ DISALLOW_COPY_AND_ASSIGN(ZoomRequestClient);
+};
+
+// Per-tab class to manage zoom changes and the Omnibox zoom icon.
+class ZoomController : public content::WebContentsObserver,
+ public content::WebContentsUserData<ZoomController> {
+ public:
+ // Defines how zoom changes are handled.
+ enum ZoomMode {
+ // Results in default zoom behavior, i.e. zoom changes are handled
+ // automatically and on a per-origin basis, meaning that other tabs
+ // navigated to the same origin will also zoom.
+ ZOOM_MODE_DEFAULT,
+ // Results in zoom changes being handled automatically, but on a per-tab
+ // basis. Tabs in this zoom mode will not be affected by zoom changes in
+ // other tabs, and vice versa.
+ ZOOM_MODE_ISOLATED,
+ // Overrides the automatic handling of zoom changes. The |onZoomChange|
+ // event will still be dispatched, but the page will not actually be zoomed.
+ // These zoom changes can be handled manually by listening for the
+ // |onZoomChange| event. Zooming in this mode is also on a per-tab basis.
+ ZOOM_MODE_MANUAL,
+ // Disables all zooming in this tab. The tab will revert to default (100%)
+ // zoom, and all attempted zoom changes will be ignored.
+ ZOOM_MODE_DISABLED,
+ };
+
+ enum RelativeZoom {
+ ZOOM_BELOW_DEFAULT_ZOOM,
+ ZOOM_AT_DEFAULT_ZOOM,
+ ZOOM_ABOVE_DEFAULT_ZOOM
+ };
+
+ struct ZoomChangedEventData {
+ ZoomChangedEventData(content::WebContents* web_contents,
+ double old_zoom_level,
+ double new_zoom_level,
+ ZoomController::ZoomMode zoom_mode,
+ bool can_show_bubble)
+ : web_contents(web_contents),
+ old_zoom_level(old_zoom_level),
+ new_zoom_level(new_zoom_level),
+ zoom_mode(zoom_mode),
+ can_show_bubble(can_show_bubble) {}
+ content::WebContents* web_contents;
+ double old_zoom_level;
+ double new_zoom_level;
+ ZoomController::ZoomMode zoom_mode;
+ bool can_show_bubble;
+ };
+
+ ~ZoomController() override;
+
+ ZoomMode zoom_mode() const { return zoom_mode_; }
+
+ // Convenience method to get default zoom level. Implemented here for
+ // inlining.
+ double GetDefaultZoomLevel() const {
+ return content::HostZoomMap::GetForWebContents(web_contents())
+ ->GetDefaultZoomLevel();
+ }
+
+ // Convenience method to quickly check if the tab's at default zoom.
+ bool IsAtDefaultZoom() const;
+
+ // Returns which image should be loaded for the current zoom level.
+ RelativeZoom GetZoomRelativeToDefault() const;
+
+ const ZoomRequestClient* last_client() const { return last_client_.get(); }
+
+ void AddObserver(ZoomObserver* observer);
+ void RemoveObserver(ZoomObserver* observer);
+
+ // Used to set whether the zoom notification bubble can be shown when the
+ // zoom level is changed for this controller. Default behavior is to show
+ // the bubble.
+ void SetShowsNotificationBubble(bool can_show_bubble) {
+ can_show_bubble_ = can_show_bubble;
+ }
+
+ // Gets the current zoom level by querying HostZoomMap (if not in manual zoom
+ // mode) or from the ZoomController local value otherwise.
+ double GetZoomLevel() const;
+ // Calls GetZoomLevel() then converts the returned value to a percentage
+ // zoom factor.
+ // Virtual for testing.
+ virtual int GetZoomPercent() const;
+
+ // Sets the zoom level through HostZoomMap.
+ // Returns true on success.
+ bool SetZoomLevel(double zoom_level);
+
+ // Sets the zoom level via HostZoomMap (or stores it locally if in manual zoom
+ // mode), and attributes the zoom to |client|. Returns true on success.
+ bool SetZoomLevelByClient(
+ double zoom_level,
+ const scoped_refptr<const ZoomRequestClient>& client);
+
+ // Sets the zoom mode, which defines zoom behavior (see enum ZoomMode).
+ void SetZoomMode(ZoomMode zoom_mode);
+
+ // content::WebContentsObserver overrides:
+ void DidNavigateMainFrame(
+ const content::LoadCommittedDetails& details,
+ const content::FrameNavigateParams& params) override;
+ void WebContentsDestroyed() override;
+
+ protected:
+ // Protected for testing.
+ explicit ZoomController(content::WebContents* web_contents);
+
+ private:
+ friend class content::WebContentsUserData<ZoomController>;
+ friend class ::ZoomControllerTest;
+
+ void OnZoomLevelChanged(const content::HostZoomMap::ZoomLevelChange& change);
+
+ // Updates the zoom icon and zoom percentage based on current values and
+ // notifies the observer if changes have occurred. |host| may be empty,
+ // meaning the change should apply to ~all sites. If it is not empty, the
+ // change only affects sites with the given host.
+ void UpdateState(const std::string& host);
+
+ // True if changes to zoom level can trigger the zoom notification bubble.
+ bool can_show_bubble_;
+
+ // The current zoom mode.
+ ZoomMode zoom_mode_;
+
+ // Current zoom level.
+ double zoom_level_;
+
+ scoped_ptr<ZoomChangedEventData> event_data_;
+
+ // Keeps track of the extension (if any) that initiated the last zoom change
+ // that took effect.
+ scoped_refptr<const ZoomRequestClient> last_client_;
+
+ // Observer receiving notifications on state changes.
+ ObserverList<ZoomObserver> observers_;
+
+ content::BrowserContext* browser_context_;
+
+ scoped_ptr<content::HostZoomMap::Subscription> zoom_subscription_;
+
+ DISALLOW_COPY_AND_ASSIGN(ZoomController);
+};
+
+} // namespace ui_zoom
+
+#endif // COMPONENTS_UI_ZOOM_ZOOM_CONTROLLER_H_
diff --git a/components/ui/zoom/zoom_event_manager.cc b/components/ui/zoom/zoom_event_manager.cc
new file mode 100644
index 0000000..7290627
--- /dev/null
+++ b/components/ui/zoom/zoom_event_manager.cc
@@ -0,0 +1,40 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/ui/zoom/zoom_event_manager.h"
+
+#include "content/public/browser/browser_context.h"
+
+namespace {
+static const char kBrowserZoomEventManager[] = "browser_zoom_event_manager";
+}
+
+namespace ui_zoom {
+
+ZoomEventManager* ZoomEventManager::GetForBrowserContext(
+ content::BrowserContext* context) {
+ if (!context->GetUserData(kBrowserZoomEventManager))
+ context->SetUserData(kBrowserZoomEventManager, new ZoomEventManager);
+ return static_cast<ZoomEventManager*>(
+ context->GetUserData(kBrowserZoomEventManager));
+}
+
+ZoomEventManager::ZoomEventManager() : weak_ptr_factory_(this) {
+}
+
+ZoomEventManager::~ZoomEventManager() {
+}
+
+void ZoomEventManager::OnZoomLevelChanged(
+ const content::HostZoomMap::ZoomLevelChange& change) {
+ zoom_level_changed_callbacks_.Notify(change);
+}
+
+scoped_ptr<content::HostZoomMap::Subscription>
+ZoomEventManager::AddZoomLevelChangedCallback(
+ const content::HostZoomMap::ZoomLevelChangedCallback& callback) {
+ return zoom_level_changed_callbacks_.Add(callback);
+}
+
+} // namespace ui_zoom
diff --git a/components/ui/zoom/zoom_event_manager.h b/components/ui/zoom/zoom_event_manager.h
new file mode 100644
index 0000000..3f0fcf0
--- /dev/null
+++ b/components/ui/zoom/zoom_event_manager.h
@@ -0,0 +1,57 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_UI_ZOOM_ZOOM_EVENT_MANAGER_H_
+#define COMPONENTS_UI_ZOOM_ZOOM_EVENT_MANAGER_H_
+
+#include "base/callback_list.h"
+#include "base/memory/weak_ptr.h"
+#include "base/supports_user_data.h"
+#include "content/public/browser/host_zoom_map.h"
+
+namespace content {
+class BrowserContext;
+} // namespace content
+
+namespace ui_zoom {
+
+// This class serves as a target for event notifications from all ZoomController
+// objects. Classes that need to know about browser-specific zoom events (e.g.
+// manual-mode zoom) should subscribe here.
+class ZoomEventManager : public base::SupportsUserData::Data {
+ public:
+ ZoomEventManager();
+ ~ZoomEventManager() override;
+
+ // Returns the ZoomEventManager for the specified BrowserContext. This
+ // function creates the ZoomEventManager if it hasn't been created already.
+ static ZoomEventManager* GetForBrowserContext(
+ content::BrowserContext* context);
+
+ // Called by ZoomControllers when changes are made to zoom levels in manual
+ // mode in order that browser listeners can be notified.
+ void OnZoomLevelChanged(const content::HostZoomMap::ZoomLevelChange& change);
+
+ // Add and remove zoom level changed callbacks.
+ scoped_ptr<content::HostZoomMap::Subscription> AddZoomLevelChangedCallback(
+ const content::HostZoomMap::ZoomLevelChangedCallback& callback);
+
+ // Get a weak ptr to be used by clients who may themselves be UserData for
+ // the context, since the order of destruction is undefined between the client
+ // and this class.
+ base::WeakPtr<ZoomEventManager> GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+ }
+
+ private:
+ base::CallbackList<void(const content::HostZoomMap::ZoomLevelChange&)>
+ zoom_level_changed_callbacks_;
+ base::WeakPtrFactory<ZoomEventManager> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ZoomEventManager);
+};
+
+} // namespace ui_zoom
+
+#endif // COMPONENTS_UI_ZOOM_ZOOM_EVENT_MANAGER_H_
diff --git a/components/ui/zoom/zoom_observer.h b/components/ui/zoom/zoom_observer.h
new file mode 100644
index 0000000..5d99975
--- /dev/null
+++ b/components/ui/zoom/zoom_observer.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_UI_ZOOM_ZOOM_OBSERVER_H_
+#define COMPONENTS_UI_ZOOM_ZOOM_OBSERVER_H_
+
+#include "components/ui/zoom/zoom_controller.h"
+
+namespace ui_zoom {
+
+// Interface for objects that wish to be notified of changes in ZoomController.
+class ZoomObserver {
+ public:
+ // Notification that the zoom percentage has changed.
+ virtual void OnZoomChanged(const ZoomController::ZoomChangedEventData& data) {
+ }
+
+ protected:
+ virtual ~ZoomObserver() {}
+};
+
+} // namespace ui_zoom
+
+#endif // COMPONENTS_UI_ZOOM_ZOOM_OBSERVER_H_