| 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 |