OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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 <cmath> | |
6 | |
7 #include "chrome/browser/host_zoom_map.h" | |
8 | |
9 #include "base/string_piece.h" | |
10 #include "base/utf_string_conversions.h" | |
11 #include "chrome/browser/browser_thread.h" | |
12 #include "chrome/browser/prefs/pref_service.h" | |
13 #include "chrome/browser/prefs/scoped_pref_update.h" | |
14 #include "chrome/browser/profiles/profile.h" | |
15 #include "chrome/browser/renderer_host/render_process_host.h" | |
16 #include "chrome/browser/renderer_host/render_view_host.h" | |
17 #include "chrome/common/notification_details.h" | |
18 #include "chrome/common/notification_service.h" | |
19 #include "chrome/common/notification_source.h" | |
20 #include "chrome/common/notification_type.h" | |
21 #include "chrome/common/pref_names.h" | |
22 #include "googleurl/src/gurl.h" | |
23 #include "net/base/net_util.h" | |
24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | |
25 | |
26 using WebKit::WebView; | |
27 | |
28 HostZoomMap::HostZoomMap(Profile* profile) | |
29 : profile_(profile), | |
30 updating_preferences_(false) { | |
31 Load(); | |
32 default_zoom_level_ = | |
33 profile_->GetPrefs()->GetDouble(prefs::kDefaultZoomLevel); | |
34 registrar_.Add(this, NotificationType::PROFILE_DESTROYED, | |
35 Source<Profile>(profile)); | |
36 // Don't observe pref changes (e.g. from sync) in Incognito; once we create | |
37 // the incognito window it should have no further connection to the main | |
38 // profile/prefs. | |
39 if (!profile_->IsOffTheRecord()) { | |
40 pref_change_registrar_.Init(profile_->GetPrefs()); | |
41 pref_change_registrar_.Add(prefs::kPerHostZoomLevels, this); | |
42 pref_change_registrar_.Add(prefs::kDefaultZoomLevel, this); | |
43 } | |
44 | |
45 registrar_.Add( | |
46 this, NotificationType::RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW, | |
47 NotificationService::AllSources()); | |
48 } | |
49 | |
50 void HostZoomMap::Load() { | |
51 if (!profile_) | |
52 return; | |
53 | |
54 base::AutoLock auto_lock(lock_); | |
55 host_zoom_levels_.clear(); | |
56 const DictionaryValue* host_zoom_dictionary = | |
57 profile_->GetPrefs()->GetDictionary(prefs::kPerHostZoomLevels); | |
58 // Careful: The returned value could be NULL if the pref has never been set. | |
59 if (host_zoom_dictionary != NULL) { | |
60 for (DictionaryValue::key_iterator i(host_zoom_dictionary->begin_keys()); | |
61 i != host_zoom_dictionary->end_keys(); ++i) { | |
62 const std::string& host(*i); | |
63 double zoom_level = 0; | |
64 | |
65 bool success = host_zoom_dictionary->GetDoubleWithoutPathExpansion( | |
66 host, &zoom_level); | |
67 if (!success) { | |
68 // The data used to be stored as ints, so try that. | |
69 int int_zoom_level; | |
70 success = host_zoom_dictionary->GetIntegerWithoutPathExpansion( | |
71 host, &int_zoom_level); | |
72 if (success) { | |
73 zoom_level = static_cast<double>(int_zoom_level); | |
74 // Since the values were once stored as non-clamped, clamp now. | |
75 double zoom_factor = WebView::zoomLevelToZoomFactor(zoom_level); | |
76 if (zoom_factor < WebView::minTextSizeMultiplier) { | |
77 zoom_level = | |
78 WebView::zoomFactorToZoomLevel(WebView::minTextSizeMultiplier); | |
79 } else if (zoom_factor > WebView::maxTextSizeMultiplier) { | |
80 zoom_level = | |
81 WebView::zoomFactorToZoomLevel(WebView::maxTextSizeMultiplier); | |
82 } | |
83 } | |
84 } | |
85 DCHECK(success); | |
86 host_zoom_levels_[host] = zoom_level; | |
87 } | |
88 } | |
89 } | |
90 | |
91 // static | |
92 void HostZoomMap::RegisterUserPrefs(PrefService* prefs) { | |
93 prefs->RegisterDictionaryPref(prefs::kPerHostZoomLevels); | |
94 } | |
95 | |
96 double HostZoomMap::GetZoomLevel(const GURL& url) const { | |
97 std::string host(net::GetHostOrSpecFromURL(url)); | |
98 base::AutoLock auto_lock(lock_); | |
99 HostZoomLevels::const_iterator i(host_zoom_levels_.find(host)); | |
100 return (i == host_zoom_levels_.end()) ? default_zoom_level_ : i->second; | |
101 } | |
102 | |
103 void HostZoomMap::SetZoomLevel(const GURL& url, double level) { | |
104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
105 if (!profile_) | |
106 return; | |
107 | |
108 std::string host(net::GetHostOrSpecFromURL(url)); | |
109 | |
110 { | |
111 base::AutoLock auto_lock(lock_); | |
112 if (level == default_zoom_level_) | |
113 host_zoom_levels_.erase(host); | |
114 else | |
115 host_zoom_levels_[host] = level; | |
116 } | |
117 | |
118 NotificationService::current()->Notify(NotificationType::ZOOM_LEVEL_CHANGED, | |
119 Source<Profile>(profile_), | |
120 NotificationService::NoDetails()); | |
121 | |
122 // If we're in incognito mode, don't persist changes to the prefs. We'll keep | |
123 // them in memory only so they will be forgotten on exiting incognito. | |
124 if (profile_->IsOffTheRecord()) | |
125 return; | |
126 | |
127 updating_preferences_ = true; | |
128 { | |
129 ScopedPrefUpdate update(profile_->GetPrefs(), prefs::kPerHostZoomLevels); | |
130 DictionaryValue* host_zoom_dictionary = | |
131 profile_->GetPrefs()->GetMutableDictionary(prefs::kPerHostZoomLevels); | |
132 if (level == default_zoom_level_) { | |
133 host_zoom_dictionary->RemoveWithoutPathExpansion(host, NULL); | |
134 } else { | |
135 host_zoom_dictionary->SetWithoutPathExpansion( | |
136 host, Value::CreateDoubleValue(level)); | |
137 } | |
138 } | |
139 updating_preferences_ = false; | |
140 } | |
141 | |
142 double HostZoomMap::GetTemporaryZoomLevel(int render_process_id, | |
143 int render_view_id) const { | |
144 base::AutoLock auto_lock(lock_); | |
145 for (size_t i = 0; i < temporary_zoom_levels_.size(); ++i) { | |
146 if (temporary_zoom_levels_[i].render_process_id == render_process_id && | |
147 temporary_zoom_levels_[i].render_view_id == render_view_id) { | |
148 return temporary_zoom_levels_[i].zoom_level; | |
149 } | |
150 } | |
151 return 0; | |
152 } | |
153 | |
154 void HostZoomMap::SetTemporaryZoomLevel(int render_process_id, | |
155 int render_view_id, | |
156 double level) { | |
157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
158 if (!profile_) | |
159 return; | |
160 | |
161 { | |
162 base::AutoLock auto_lock(lock_); | |
163 size_t i; | |
164 for (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 if (level) { | |
168 temporary_zoom_levels_[i].zoom_level = level; | |
169 } else { | |
170 temporary_zoom_levels_.erase(temporary_zoom_levels_.begin() + i); | |
171 } | |
172 break; | |
173 } | |
174 } | |
175 | |
176 if (level && i == temporary_zoom_levels_.size()) { | |
177 TemporaryZoomLevel temp; | |
178 temp.render_process_id = render_process_id; | |
179 temp.render_view_id = render_view_id; | |
180 temp.zoom_level = level; | |
181 temporary_zoom_levels_.push_back(temp); | |
182 } | |
183 } | |
184 | |
185 NotificationService::current()->Notify(NotificationType::ZOOM_LEVEL_CHANGED, | |
186 Source<Profile>(profile_), | |
187 NotificationService::NoDetails()); | |
188 } | |
189 | |
190 void HostZoomMap::ResetToDefaults() { | |
191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
192 if (!profile_) | |
193 return; | |
194 | |
195 { | |
196 base::AutoLock auto_lock(lock_); | |
197 host_zoom_levels_.clear(); | |
198 } | |
199 | |
200 updating_preferences_ = true; | |
201 profile_->GetPrefs()->ClearPref(prefs::kPerHostZoomLevels); | |
202 updating_preferences_ = false; | |
203 } | |
204 | |
205 void HostZoomMap::Shutdown() { | |
206 if (!profile_) | |
207 return; | |
208 | |
209 registrar_.RemoveAll(); | |
210 if (!profile_->IsOffTheRecord()) | |
211 pref_change_registrar_.RemoveAll(); | |
212 profile_ = NULL; | |
213 } | |
214 | |
215 void HostZoomMap::Observe( | |
216 NotificationType type, | |
217 const NotificationSource& source, | |
218 const NotificationDetails& details) { | |
219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
220 | |
221 switch (type.value) { | |
222 case NotificationType::PROFILE_DESTROYED: | |
223 // If the profile is going away, we need to stop using it. | |
224 Shutdown(); | |
225 break; | |
226 case NotificationType::RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW: { | |
227 base::AutoLock auto_lock(lock_); | |
228 int render_view_id = Source<RenderViewHost>(source)->routing_id(); | |
229 int render_process_id = Source<RenderViewHost>(source)->process()->id(); | |
230 | |
231 for (size_t i = 0; i < temporary_zoom_levels_.size(); ++i) { | |
232 if (temporary_zoom_levels_[i].render_process_id == render_process_id && | |
233 temporary_zoom_levels_[i].render_view_id == render_view_id) { | |
234 temporary_zoom_levels_.erase(temporary_zoom_levels_.begin() + i); | |
235 break; | |
236 } | |
237 } | |
238 break; | |
239 } | |
240 case NotificationType::PREF_CHANGED: { | |
241 // If we are updating our own preference, don't reload. | |
242 if (!updating_preferences_) { | |
243 std::string* name = Details<std::string>(details).ptr(); | |
244 if (prefs::kPerHostZoomLevels == *name) | |
245 Load(); | |
246 else if (prefs::kDefaultZoomLevel == *name) { | |
247 default_zoom_level_ = | |
248 profile_->GetPrefs()->GetDouble(prefs::kDefaultZoomLevel); | |
249 } | |
250 } | |
251 break; | |
252 } | |
253 default: | |
254 NOTREACHED() << "Unexpected preference observed."; | |
255 } | |
256 } | |
257 | |
258 HostZoomMap::~HostZoomMap() { | |
259 Shutdown(); | |
260 } | |
OLD | NEW |