From 0b76a9c073c3ec6aaf2b4fb9114cff7e0250762e Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Mon, 30 Jan 2017 17:25:46 +0530 Subject: [PATCH] Persist zoom levels per partition --- brightray/browser/browser_context.cc | 5 + brightray/browser/zoom_level_delegate.cc | 176 +++++++++++++++++++++++ brightray/browser/zoom_level_delegate.h | 61 ++++++++ brightray/filenames.gypi | 2 + 4 files changed, 244 insertions(+) create mode 100644 brightray/browser/zoom_level_delegate.cc create mode 100644 brightray/browser/zoom_level_delegate.h diff --git a/brightray/browser/browser_context.cc b/brightray/browser/browser_context.cc index a28fec5d832b..e482b156f35c 100644 --- a/brightray/browser/browser_context.cc +++ b/brightray/browser/browser_context.cc @@ -11,6 +11,7 @@ #include "browser/network_delegate.h" #include "browser/permission_manager.h" #include "browser/special_storage_policy.h" +#include "browser/zoom_level_delegate.h" #include "common/application_info.h" #include "base/files/file_path.h" @@ -123,6 +124,7 @@ void BrowserContext::InitPrefs() { void BrowserContext::RegisterInternalPrefs(PrefRegistrySimple* registry) { InspectableWebContentsImpl::RegisterPrefs(registry); MediaDeviceIDSalt::RegisterPrefs(registry); + ZoomLevelDelegate::RegisterPrefs(registry); } URLRequestContextGetter* BrowserContext::GetRequestContext() { @@ -166,6 +168,9 @@ base::FilePath BrowserContext::GetPath() const { std::unique_ptr BrowserContext::CreateZoomLevelDelegate( const base::FilePath& partition_path) { + if (!IsOffTheRecord()) { + return base::MakeUnique(prefs(), partition_path); + } return std::unique_ptr(); } diff --git a/brightray/browser/zoom_level_delegate.cc b/brightray/browser/zoom_level_delegate.cc new file mode 100644 index 000000000000..7148b18e18a4 --- /dev/null +++ b/brightray/browser/zoom_level_delegate.cc @@ -0,0 +1,176 @@ +// Copyright 2014 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 "browser/zoom_level_delegate.h" + +#include + +#include "base/bind.h" +#include "base/strings/string_number_conversions.h" +#include "base/values.h" +#include "components/prefs/json_pref_store.h" +#include "components/prefs/pref_filter.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service_factory.h" +#include "components/prefs/scoped_user_pref_update.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/common/page_zoom.h" + +namespace std { + +template <> +struct hash { + size_t operator()(const base::FilePath& f) const { + return hash()(f.value()); + } +}; + +} // namespace std + +namespace brightray { + +namespace { + +// Double that indicates the default zoom level. +const char kPartitionDefaultZoomLevel[] = "partition.default_zoom_level"; + +// Dictionary that maps hostnames to zoom levels. Hosts not in this pref will +// be displayed at the default zoom level. +const char kPartitionPerHostZoomLevels[] = "partition.per_host_zoom_levels"; + +std::string GetHash(const base::FilePath& partition_path) { + size_t int_key = std::hash()(partition_path); + return base::SizeTToString(int_key); +} + +} // namespace + +// static +void ZoomLevelDelegate::RegisterPrefs(PrefRegistrySimple* registry) { + registry->RegisterDictionaryPref(kPartitionDefaultZoomLevel); + registry->RegisterDictionaryPref(kPartitionPerHostZoomLevels); +} + +ZoomLevelDelegate::ZoomLevelDelegate(PrefService* pref_service, + const base::FilePath& partition_path) + : pref_service_(pref_service), host_zoom_map_(nullptr) { + DCHECK(pref_service_); + partition_key_ = GetHash(partition_path); +} + +ZoomLevelDelegate::~ZoomLevelDelegate() {} + +void ZoomLevelDelegate::SetDefaultZoomLevelPref(double level) { + if (content::ZoomValuesEqual(level, host_zoom_map_->GetDefaultZoomLevel())) + return; + + DictionaryPrefUpdate update(pref_service_, kPartitionDefaultZoomLevel); + update->SetDouble(partition_key_, level); + host_zoom_map_->SetDefaultZoomLevel(level); +} + +double ZoomLevelDelegate::GetDefaultZoomLevelPref() const { + double default_zoom_level = 0.0; + + const base::DictionaryValue* default_zoom_level_dictionary = + pref_service_->GetDictionary(kPartitionDefaultZoomLevel); + // If no default has been previously set, the default returned is the + // value used to initialize default_zoom_level in this function. + default_zoom_level_dictionary->GetDouble(partition_key_, &default_zoom_level); + return default_zoom_level; +} + +void ZoomLevelDelegate::OnZoomLevelChanged( + const content::HostZoomMap::ZoomLevelChange& change) { + if (change.mode != content::HostZoomMap::ZOOM_CHANGED_FOR_HOST) + return; + + double level = change.zoom_level; + DictionaryPrefUpdate update(pref_service_, kPartitionPerHostZoomLevels); + base::DictionaryValue* host_zoom_dictionaries = update.Get(); + DCHECK(host_zoom_dictionaries); + + bool modification_is_removal = + content::ZoomValuesEqual(level, host_zoom_map_->GetDefaultZoomLevel()); + + base::DictionaryValue* host_zoom_dictionary = nullptr; + if (!host_zoom_dictionaries->GetDictionary(partition_key_, + &host_zoom_dictionary)) { + host_zoom_dictionary = new base::DictionaryValue(); + host_zoom_dictionaries->Set(partition_key_, host_zoom_dictionary); + } + + if (modification_is_removal) + host_zoom_dictionary->RemoveWithoutPathExpansion(change.host, nullptr); + else + host_zoom_dictionary->SetDoubleWithoutPathExpansion(change.host, level); +} + +void ZoomLevelDelegate::ExtractPerHostZoomLevels( + const base::DictionaryValue* host_zoom_dictionary) { + std::vector keys_to_remove; + std::unique_ptr host_zoom_dictionary_copy = + host_zoom_dictionary->DeepCopyWithoutEmptyChildren(); + for (base::DictionaryValue::Iterator i(*host_zoom_dictionary_copy); + !i.IsAtEnd(); i.Advance()) { + const std::string& host(i.key()); + double zoom_level = 0; + + bool has_valid_zoom_level = i.value().GetAsDouble(&zoom_level); + + // Filter out A) the empty host, B) zoom levels equal to the default; and + // remember them, so that we can later erase them from Prefs. + // Values of type B could further have been stored before the default zoom + // level was set to its current value. In either case, SetZoomLevelForHost + // will ignore type B values, thus, to have consistency with HostZoomMap's + // internal state, these values must also be removed from Prefs. + if (host.empty() || !has_valid_zoom_level || + content::ZoomValuesEqual(zoom_level, + host_zoom_map_->GetDefaultZoomLevel())) { + keys_to_remove.push_back(host); + continue; + } + + host_zoom_map_->SetZoomLevelForHost(host, zoom_level); + } + + // Sanitize prefs to remove entries that match the default zoom level and/or + // have an empty host. + { + DictionaryPrefUpdate update(pref_service_, kPartitionPerHostZoomLevels); + base::DictionaryValue* host_zoom_dictionaries = update.Get(); + base::DictionaryValue* sanitized_host_zoom_dictionary = nullptr; + host_zoom_dictionaries->GetDictionary(partition_key_, + &sanitized_host_zoom_dictionary); + for (const std::string& s : keys_to_remove) + sanitized_host_zoom_dictionary->RemoveWithoutPathExpansion(s, nullptr); + } +} + +void ZoomLevelDelegate::InitHostZoomMap(content::HostZoomMap* host_zoom_map) { + // This init function must be called only once. + DCHECK(!host_zoom_map_); + DCHECK(host_zoom_map); + host_zoom_map_ = host_zoom_map; + + // Initialize the default zoom level. + host_zoom_map_->SetDefaultZoomLevel(GetDefaultZoomLevelPref()); + + // Initialize the HostZoomMap with per-host zoom levels from the persisted + // zoom-level preference values. + const base::DictionaryValue* host_zoom_dictionaries = + pref_service_->GetDictionary(kPartitionPerHostZoomLevels); + const base::DictionaryValue* host_zoom_dictionary = nullptr; + if (host_zoom_dictionaries->GetDictionary(partition_key_, + &host_zoom_dictionary)) { + // Since we're calling this before setting up zoom_subscription_ below we + // don't need to worry that host_zoom_dictionary is indirectly affected + // by calls to HostZoomMap::SetZoomLevelForHost(). + ExtractPerHostZoomLevels(host_zoom_dictionary); + } + zoom_subscription_ = host_zoom_map_->AddZoomLevelChangedCallback(base::Bind( + &ZoomLevelDelegate::OnZoomLevelChanged, base::Unretained(this))); +} + +} // namespace brightray diff --git a/brightray/browser/zoom_level_delegate.h b/brightray/browser/zoom_level_delegate.h new file mode 100644 index 000000000000..aed065d7ec66 --- /dev/null +++ b/brightray/browser/zoom_level_delegate.h @@ -0,0 +1,61 @@ +// Copyright 2014 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 BRIGHTRAY_BROWSER_ZOOM_LEVEL_DELEGATE_H_ +#define BRIGHTRAY_BROWSER_ZOOM_LEVEL_DELEGATE_H_ + +#include "base/files/file_path.h" +#include "base/macros.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/host_zoom_map.h" +#include "content/public/browser/zoom_level_delegate.h" + +namespace base { +class DictionaryValue; +} + +class PrefRegistrySimple; + +namespace brightray { + +// A class to manage per-partition default and per-host zoom levels. +// It implements an interface between the content/ zoom +// levels in HostZoomMap and preference system. All changes +// to the per-partition default zoom levels flow through this +// class. Any changes to per-host levels are updated when HostZoomMap calls +// OnZoomLevelChanged. +class ZoomLevelDelegate : public content::ZoomLevelDelegate { + public: + static void RegisterPrefs(PrefRegistrySimple* pref_registry); + + ZoomLevelDelegate(PrefService* pref_service, + const base::FilePath& partition_path); + ~ZoomLevelDelegate() override; + + void SetDefaultZoomLevelPref(double level); + double GetDefaultZoomLevelPref() const; + + // content::ZoomLevelDelegate: + void InitHostZoomMap(content::HostZoomMap* host_zoom_map) override; + + private: + void ExtractPerHostZoomLevels( + const base::DictionaryValue* host_zoom_dictionary); + + // This is a callback function that receives notifications from HostZoomMap + // when per-host zoom levels change. It is used to update the per-host + // zoom levels (if any) managed by this class (for its associated partition). + void OnZoomLevelChanged(const content::HostZoomMap::ZoomLevelChange& change); + + PrefService* pref_service_; + content::HostZoomMap* host_zoom_map_; + std::unique_ptr zoom_subscription_; + std::string partition_key_; + + DISALLOW_COPY_AND_ASSIGN(ZoomLevelDelegate); +}; + +} // namespace brightray + +#endif // BRIGHTRAY_BROWSER_ZOOM_LEVEL_DELEGATE_H_ diff --git a/brightray/filenames.gypi b/brightray/filenames.gypi index 7b2db49869df..a0858ea926c8 100644 --- a/brightray/filenames.gypi +++ b/brightray/filenames.gypi @@ -100,6 +100,8 @@ 'browser/views/views_delegate.h', 'browser/web_ui_controller_factory.cc', 'browser/web_ui_controller_factory.h', + 'browser/zoom_level_delegate.cc', + 'browser/zoom_level_delegate.h', 'common/application_info.h', 'common/application_info_mac.mm', 'common/application_info_win.cc',