summaryrefslogtreecommitdiffstats
path: root/components/ui/zoom/zoom_controller.h
blob: 8e22ad21fbe54cf26e804d54f899a281931bb37d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// 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/gtest_prod_util.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);

  // Set and query whether or not the page scale factor is one.
  void SetPageScaleFactorIsOneForTesting(bool is_one);
  bool PageScaleFactorIsOne() const;

  // content::WebContentsObserver overrides:
  void DidNavigateMainFrame(
      const content::LoadCommittedDetails& details,
      const content::FrameNavigateParams& params) override;
  void WebContentsDestroyed() override;
  void RenderFrameHostChanged(content::RenderFrameHost* old_host,
                              content::RenderFrameHost* new_host) override;

 protected:
  // Protected for testing.
  explicit ZoomController(content::WebContents* web_contents);

 private:
  friend class content::WebContentsUserData<ZoomController>;
  friend class ::ZoomControllerTest;

  void ResetZoomModeOnNavigationIfNeeded(const GURL& url);
  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_;
  // Keep track of the HostZoomMap we're currently subscribed to.
  content::HostZoomMap* host_zoom_map_;

  scoped_ptr<content::HostZoomMap::Subscription> zoom_subscription_;

  DISALLOW_COPY_AND_ASSIGN(ZoomController);
};

}  // namespace ui_zoom

#endif  // COMPONENTS_UI_ZOOM_ZOOM_CONTROLLER_H_