summaryrefslogtreecommitdiffstats
path: root/content/browser/host_zoom_map.cc
diff options
context:
space:
mode:
Diffstat (limited to 'content/browser/host_zoom_map.cc')
-rw-r--r--content/browser/host_zoom_map.cc260
1 files changed, 260 insertions, 0 deletions
diff --git a/content/browser/host_zoom_map.cc b/content/browser/host_zoom_map.cc
new file mode 100644
index 0000000..0581036
--- /dev/null
+++ b/content/browser/host_zoom_map.cc
@@ -0,0 +1,260 @@
+// Copyright (c) 2010 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 <cmath>
+
+#include "content/browser/host_zoom_map.h"
+
+#include "base/string_piece.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prefs/scoped_pref_update.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/pref_names.h"
+#include "content/browser/renderer_host/render_process_host.h"
+#include "content/browser/renderer_host/render_view_host.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/net_util.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
+
+using WebKit::WebView;
+
+HostZoomMap::HostZoomMap(Profile* profile)
+ : profile_(profile),
+ updating_preferences_(false) {
+ Load();
+ default_zoom_level_ =
+ profile_->GetPrefs()->GetDouble(prefs::kDefaultZoomLevel);
+ registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
+ Source<Profile>(profile));
+ // Don't observe pref changes (e.g. from sync) in Incognito; once we create
+ // the incognito window it should have no further connection to the main
+ // profile/prefs.
+ if (!profile_->IsOffTheRecord()) {
+ pref_change_registrar_.Init(profile_->GetPrefs());
+ pref_change_registrar_.Add(prefs::kPerHostZoomLevels, this);
+ pref_change_registrar_.Add(prefs::kDefaultZoomLevel, this);
+ }
+
+ registrar_.Add(
+ this, NotificationType::RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW,
+ NotificationService::AllSources());
+}
+
+void HostZoomMap::Load() {
+ if (!profile_)
+ return;
+
+ base::AutoLock auto_lock(lock_);
+ host_zoom_levels_.clear();
+ const DictionaryValue* host_zoom_dictionary =
+ profile_->GetPrefs()->GetDictionary(prefs::kPerHostZoomLevels);
+ // Careful: The returned value could be NULL if the pref has never been set.
+ if (host_zoom_dictionary != NULL) {
+ for (DictionaryValue::key_iterator i(host_zoom_dictionary->begin_keys());
+ i != host_zoom_dictionary->end_keys(); ++i) {
+ const std::string& host(*i);
+ double zoom_level = 0;
+
+ bool success = host_zoom_dictionary->GetDoubleWithoutPathExpansion(
+ host, &zoom_level);
+ if (!success) {
+ // The data used to be stored as ints, so try that.
+ int int_zoom_level;
+ success = host_zoom_dictionary->GetIntegerWithoutPathExpansion(
+ host, &int_zoom_level);
+ if (success) {
+ zoom_level = static_cast<double>(int_zoom_level);
+ // Since the values were once stored as non-clamped, clamp now.
+ double zoom_factor = WebView::zoomLevelToZoomFactor(zoom_level);
+ if (zoom_factor < WebView::minTextSizeMultiplier) {
+ zoom_level =
+ WebView::zoomFactorToZoomLevel(WebView::minTextSizeMultiplier);
+ } else if (zoom_factor > WebView::maxTextSizeMultiplier) {
+ zoom_level =
+ WebView::zoomFactorToZoomLevel(WebView::maxTextSizeMultiplier);
+ }
+ }
+ }
+ DCHECK(success);
+ host_zoom_levels_[host] = zoom_level;
+ }
+ }
+}
+
+// static
+void HostZoomMap::RegisterUserPrefs(PrefService* prefs) {
+ prefs->RegisterDictionaryPref(prefs::kPerHostZoomLevels);
+}
+
+double HostZoomMap::GetZoomLevel(const GURL& url) const {
+ std::string host(net::GetHostOrSpecFromURL(url));
+ base::AutoLock auto_lock(lock_);
+ HostZoomLevels::const_iterator i(host_zoom_levels_.find(host));
+ return (i == host_zoom_levels_.end()) ? default_zoom_level_ : i->second;
+}
+
+void HostZoomMap::SetZoomLevel(const GURL& url, double level) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!profile_)
+ return;
+
+ std::string host(net::GetHostOrSpecFromURL(url));
+
+ {
+ base::AutoLock auto_lock(lock_);
+ if (level == default_zoom_level_)
+ host_zoom_levels_.erase(host);
+ else
+ host_zoom_levels_[host] = level;
+ }
+
+ NotificationService::current()->Notify(NotificationType::ZOOM_LEVEL_CHANGED,
+ Source<Profile>(profile_),
+ NotificationService::NoDetails());
+
+ // If we're in incognito mode, don't persist changes to the prefs. We'll keep
+ // them in memory only so they will be forgotten on exiting incognito.
+ if (profile_->IsOffTheRecord())
+ return;
+
+ updating_preferences_ = true;
+ {
+ ScopedPrefUpdate update(profile_->GetPrefs(), prefs::kPerHostZoomLevels);
+ DictionaryValue* host_zoom_dictionary =
+ profile_->GetPrefs()->GetMutableDictionary(prefs::kPerHostZoomLevels);
+ if (level == default_zoom_level_) {
+ host_zoom_dictionary->RemoveWithoutPathExpansion(host, NULL);
+ } else {
+ host_zoom_dictionary->SetWithoutPathExpansion(
+ host, Value::CreateDoubleValue(level));
+ }
+ }
+ updating_preferences_ = false;
+}
+
+double HostZoomMap::GetTemporaryZoomLevel(int render_process_id,
+ int render_view_id) const {
+ base::AutoLock auto_lock(lock_);
+ for (size_t i = 0; i < temporary_zoom_levels_.size(); ++i) {
+ if (temporary_zoom_levels_[i].render_process_id == render_process_id &&
+ temporary_zoom_levels_[i].render_view_id == render_view_id) {
+ return temporary_zoom_levels_[i].zoom_level;
+ }
+ }
+ return 0;
+}
+
+void HostZoomMap::SetTemporaryZoomLevel(int render_process_id,
+ int render_view_id,
+ double level) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!profile_)
+ return;
+
+ {
+ base::AutoLock auto_lock(lock_);
+ size_t i;
+ for (i = 0; i < temporary_zoom_levels_.size(); ++i) {
+ if (temporary_zoom_levels_[i].render_process_id == render_process_id &&
+ temporary_zoom_levels_[i].render_view_id == render_view_id) {
+ if (level) {
+ temporary_zoom_levels_[i].zoom_level = level;
+ } else {
+ temporary_zoom_levels_.erase(temporary_zoom_levels_.begin() + i);
+ }
+ break;
+ }
+ }
+
+ if (level && i == temporary_zoom_levels_.size()) {
+ TemporaryZoomLevel temp;
+ temp.render_process_id = render_process_id;
+ temp.render_view_id = render_view_id;
+ temp.zoom_level = level;
+ temporary_zoom_levels_.push_back(temp);
+ }
+ }
+
+ NotificationService::current()->Notify(NotificationType::ZOOM_LEVEL_CHANGED,
+ Source<Profile>(profile_),
+ NotificationService::NoDetails());
+}
+
+void HostZoomMap::ResetToDefaults() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!profile_)
+ return;
+
+ {
+ base::AutoLock auto_lock(lock_);
+ host_zoom_levels_.clear();
+ }
+
+ updating_preferences_ = true;
+ profile_->GetPrefs()->ClearPref(prefs::kPerHostZoomLevels);
+ updating_preferences_ = false;
+}
+
+void HostZoomMap::Shutdown() {
+ if (!profile_)
+ return;
+
+ registrar_.RemoveAll();
+ if (!profile_->IsOffTheRecord())
+ pref_change_registrar_.RemoveAll();
+ profile_ = NULL;
+}
+
+void HostZoomMap::Observe(
+ NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ switch (type.value) {
+ case NotificationType::PROFILE_DESTROYED:
+ // If the profile is going away, we need to stop using it.
+ Shutdown();
+ break;
+ case NotificationType::RENDER_VIEW_HOST_WILL_CLOSE_RENDER_VIEW: {
+ base::AutoLock auto_lock(lock_);
+ int render_view_id = Source<RenderViewHost>(source)->routing_id();
+ int render_process_id = Source<RenderViewHost>(source)->process()->id();
+
+ for (size_t i = 0; i < temporary_zoom_levels_.size(); ++i) {
+ if (temporary_zoom_levels_[i].render_process_id == render_process_id &&
+ temporary_zoom_levels_[i].render_view_id == render_view_id) {
+ temporary_zoom_levels_.erase(temporary_zoom_levels_.begin() + i);
+ break;
+ }
+ }
+ break;
+ }
+ case NotificationType::PREF_CHANGED: {
+ // If we are updating our own preference, don't reload.
+ if (!updating_preferences_) {
+ std::string* name = Details<std::string>(details).ptr();
+ if (prefs::kPerHostZoomLevels == *name)
+ Load();
+ else if (prefs::kDefaultZoomLevel == *name) {
+ default_zoom_level_ =
+ profile_->GetPrefs()->GetDouble(prefs::kDefaultZoomLevel);
+ }
+ }
+ break;
+ }
+ default:
+ NOTREACHED() << "Unexpected preference observed.";
+ }
+}
+
+HostZoomMap::~HostZoomMap() {
+ Shutdown();
+}