• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/host_zoom_map_impl.h"
6 
7 #include <cmath>
8 
9 #include "base/strings/string_piece.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "content/browser/renderer_host/render_process_host_impl.h"
13 #include "content/browser/renderer_host/render_view_host_impl.h"
14 #include "content/common/view_messages.h"
15 #include "content/public/browser/browser_context.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/notification_service.h"
18 #include "content/public/browser/notification_types.h"
19 #include "content/public/browser/resource_context.h"
20 #include "content/public/common/page_zoom.h"
21 #include "net/base/net_util.h"
22 
23 static const char* kHostZoomMapKeyName = "content_host_zoom_map";
24 
25 namespace content {
26 
GetForBrowserContext(BrowserContext * context)27 HostZoomMap* HostZoomMap::GetForBrowserContext(BrowserContext* context) {
28   HostZoomMapImpl* rv = static_cast<HostZoomMapImpl*>(
29       context->GetUserData(kHostZoomMapKeyName));
30   if (!rv) {
31     rv = new HostZoomMapImpl();
32     context->SetUserData(kHostZoomMapKeyName, rv);
33   }
34   return rv;
35 }
36 
HostZoomMapImpl()37 HostZoomMapImpl::HostZoomMapImpl()
38     : default_zoom_level_(0.0) {
39   registrar_.Add(
40       this, NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW,
41       NotificationService::AllSources());
42 }
43 
CopyFrom(HostZoomMap * copy_interface)44 void HostZoomMapImpl::CopyFrom(HostZoomMap* copy_interface) {
45   // This can only be called on the UI thread to avoid deadlocks, otherwise
46   //   UI: a.CopyFrom(b);
47   //   IO: b.CopyFrom(a);
48   // can deadlock.
49   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
50   HostZoomMapImpl* copy = static_cast<HostZoomMapImpl*>(copy_interface);
51   base::AutoLock auto_lock(lock_);
52   base::AutoLock copy_auto_lock(copy->lock_);
53   host_zoom_levels_.
54       insert(copy->host_zoom_levels_.begin(), copy->host_zoom_levels_.end());
55   for (SchemeHostZoomLevels::const_iterator i(copy->
56            scheme_host_zoom_levels_.begin());
57        i != copy->scheme_host_zoom_levels_.end(); ++i) {
58     scheme_host_zoom_levels_[i->first] = HostZoomLevels();
59     scheme_host_zoom_levels_[i->first].
60         insert(i->second.begin(), i->second.end());
61   }
62   default_zoom_level_ = copy->default_zoom_level_;
63 }
64 
GetZoomLevelForHost(const std::string & host) const65 double HostZoomMapImpl::GetZoomLevelForHost(const std::string& host) const {
66   base::AutoLock auto_lock(lock_);
67   HostZoomLevels::const_iterator i(host_zoom_levels_.find(host));
68   return (i == host_zoom_levels_.end()) ? default_zoom_level_ : i->second;
69 }
70 
GetZoomLevelForHostAndScheme(const std::string & scheme,const std::string & host) const71 double HostZoomMapImpl::GetZoomLevelForHostAndScheme(
72     const std::string& scheme,
73     const std::string& host) const {
74   {
75     base::AutoLock auto_lock(lock_);
76     SchemeHostZoomLevels::const_iterator scheme_iterator(
77         scheme_host_zoom_levels_.find(scheme));
78     if (scheme_iterator != scheme_host_zoom_levels_.end()) {
79       HostZoomLevels::const_iterator i(scheme_iterator->second.find(host));
80       if (i != scheme_iterator->second.end())
81         return i->second;
82     }
83   }
84   return GetZoomLevelForHost(host);
85 }
86 
SetZoomLevelForHost(const std::string & host,double level)87 void HostZoomMapImpl::SetZoomLevelForHost(const std::string& host,
88                                           double level) {
89   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
90 
91   {
92     base::AutoLock auto_lock(lock_);
93 
94     if (ZoomValuesEqual(level, default_zoom_level_))
95       host_zoom_levels_.erase(host);
96     else
97       host_zoom_levels_[host] = level;
98   }
99 
100   // Notify renderers from this browser context.
101   for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
102        !i.IsAtEnd(); i.Advance()) {
103     RenderProcessHost* render_process_host = i.GetCurrentValue();
104     if (HostZoomMap::GetForBrowserContext(
105             render_process_host->GetBrowserContext()) == this) {
106       render_process_host->Send(
107           new ViewMsg_SetZoomLevelForCurrentURL(std::string(), host, level));
108     }
109   }
110   HostZoomMap::ZoomLevelChange change;
111   change.mode = HostZoomMap::ZOOM_CHANGED_FOR_HOST;
112   change.host = host;
113   change.zoom_level = level;
114 
115   zoom_level_changed_callbacks_.Notify(change);
116 }
117 
SetZoomLevelForHostAndScheme(const std::string & scheme,const std::string & host,double level)118 void HostZoomMapImpl::SetZoomLevelForHostAndScheme(const std::string& scheme,
119                                                    const std::string& host,
120                                                    double level) {
121   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
122   {
123     base::AutoLock auto_lock(lock_);
124     scheme_host_zoom_levels_[scheme][host] = level;
125   }
126 
127   // Notify renderers from this browser context.
128   for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
129        !i.IsAtEnd(); i.Advance()) {
130     RenderProcessHost* render_process_host = i.GetCurrentValue();
131     if (HostZoomMap::GetForBrowserContext(
132             render_process_host->GetBrowserContext()) == this) {
133       render_process_host->Send(
134           new ViewMsg_SetZoomLevelForCurrentURL(scheme, host, level));
135     }
136   }
137 
138   HostZoomMap::ZoomLevelChange change;
139   change.mode = HostZoomMap::ZOOM_CHANGED_FOR_SCHEME_AND_HOST;
140   change.host = host;
141   change.scheme = scheme;
142   change.zoom_level = level;
143 
144   zoom_level_changed_callbacks_.Notify(change);
145 }
146 
GetDefaultZoomLevel() const147 double HostZoomMapImpl::GetDefaultZoomLevel() const {
148   return default_zoom_level_;
149 }
150 
SetDefaultZoomLevel(double level)151 void HostZoomMapImpl::SetDefaultZoomLevel(double level) {
152   default_zoom_level_ = level;
153 }
154 
155 scoped_ptr<HostZoomMap::Subscription>
AddZoomLevelChangedCallback(const ZoomLevelChangedCallback & callback)156 HostZoomMapImpl::AddZoomLevelChangedCallback(
157     const ZoomLevelChangedCallback& callback) {
158   return zoom_level_changed_callbacks_.Add(callback);
159 }
160 
GetTemporaryZoomLevel(int render_process_id,int render_view_id) const161 double HostZoomMapImpl::GetTemporaryZoomLevel(int render_process_id,
162                                               int render_view_id) const {
163   base::AutoLock auto_lock(lock_);
164   for (size_t i = 0; i < temporary_zoom_levels_.size(); ++i) {
165     if (temporary_zoom_levels_[i].render_process_id == render_process_id &&
166         temporary_zoom_levels_[i].render_view_id == render_view_id) {
167       return temporary_zoom_levels_[i].zoom_level;
168     }
169   }
170   return 0;
171 }
172 
SetTemporaryZoomLevel(int render_process_id,int render_view_id,double level)173 void HostZoomMapImpl::SetTemporaryZoomLevel(int render_process_id,
174                                             int render_view_id,
175                                             double level) {
176   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
177 
178   {
179     base::AutoLock auto_lock(lock_);
180     size_t i;
181     for (i = 0; i < temporary_zoom_levels_.size(); ++i) {
182       if (temporary_zoom_levels_[i].render_process_id == render_process_id &&
183           temporary_zoom_levels_[i].render_view_id == render_view_id) {
184         if (level) {
185           temporary_zoom_levels_[i].zoom_level = level;
186         } else {
187           temporary_zoom_levels_.erase(temporary_zoom_levels_.begin() + i);
188         }
189         break;
190       }
191     }
192 
193     if (level && i == temporary_zoom_levels_.size()) {
194       TemporaryZoomLevel temp;
195       temp.render_process_id = render_process_id;
196       temp.render_view_id = render_view_id;
197       temp.zoom_level = level;
198       temporary_zoom_levels_.push_back(temp);
199     }
200   }
201 
202   HostZoomMap::ZoomLevelChange change;
203   change.mode = HostZoomMap::ZOOM_CHANGED_TEMPORARY_ZOOM;
204   change.zoom_level = level;
205 
206   zoom_level_changed_callbacks_.Notify(change);
207 }
208 
Observe(int type,const NotificationSource & source,const NotificationDetails & details)209 void HostZoomMapImpl::Observe(int type,
210                               const NotificationSource& source,
211                               const NotificationDetails& details) {
212   switch (type) {
213     case NOTIFICATION_RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW: {
214       base::AutoLock auto_lock(lock_);
215       int render_view_id = Source<RenderViewHost>(source)->GetRoutingID();
216       int render_process_id =
217           Source<RenderViewHost>(source)->GetProcess()->GetID();
218 
219       for (size_t i = 0; i < temporary_zoom_levels_.size(); ++i) {
220         if (temporary_zoom_levels_[i].render_process_id == render_process_id &&
221             temporary_zoom_levels_[i].render_view_id == render_view_id) {
222           temporary_zoom_levels_.erase(temporary_zoom_levels_.begin() + i);
223           break;
224         }
225       }
226       break;
227     }
228     default:
229       NOTREACHED() << "Unexpected preference observed.";
230   }
231 }
232 
~HostZoomMapImpl()233 HostZoomMapImpl::~HostZoomMapImpl() {
234 }
235 
236 }  // namespace content
237