diff options
author | tony@chromium.org <tony@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-08 05:18:06 +0000 |
---|---|---|
committer | tony@chromium.org <tony@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-08 05:18:06 +0000 |
commit | 6c32ce70d1b04d1b5982a5833ced60b92cda10fb (patch) | |
tree | a42fab74398b9b4d44eecc80326385a27d3664cd /chrome | |
parent | 31e9bb2767ccded0fe3f2af5c8f105af0eb97a01 (diff) | |
download | chromium_src-6c32ce70d1b04d1b5982a5833ced60b92cda10fb.zip chromium_src-6c32ce70d1b04d1b5982a5833ced60b92cda10fb.tar.gz chromium_src-6c32ce70d1b04d1b5982a5833ced60b92cda10fb.tar.bz2 |
First cut at custom user style sheets.
Enabled with the --enable-user-stylesheet flag which
causes chrome to read
<user-data-dir>/<profile>/User StyleSheet/Custom.css
at startup and set it as the user style sheet.
This version never reloads the user style sheet, I'll
have to bring back FileWatcher for that. I also put the user
stylesheet in a subdir because the implementation of
FileWatcher will watch the parent dir (this is what the OS
apis give me) and watching the profile dir will cause
lots of activity.
BUG=2393
Review URL: http://codereview.chromium.org/660349
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40882 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/extensions/extension_host.cc | 4 | ||||
-rw-r--r-- | chrome/browser/profile.cc | 13 | ||||
-rw-r--r-- | chrome/browser/profile.h | 6 | ||||
-rw-r--r-- | chrome/browser/tab_contents/render_view_host_delegate_helper.cc | 27 | ||||
-rw-r--r-- | chrome/browser/tab_contents/render_view_host_delegate_helper.h | 2 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.cc | 11 | ||||
-rw-r--r-- | chrome/browser/user_style_sheet_watcher.cc | 82 | ||||
-rw-r--r-- | chrome/browser/user_style_sheet_watcher.h | 57 | ||||
-rw-r--r-- | chrome/browser/user_style_sheet_watcher_unittest.cc | 43 | ||||
-rwxr-xr-x | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 3 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 1 | ||||
-rw-r--r-- | chrome/common/notification_type.h | 5 | ||||
-rw-r--r-- | chrome/test/testing_profile.h | 1 |
15 files changed, 242 insertions, 16 deletions
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index 5c01d69..f4ee926 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -469,10 +469,10 @@ RendererPreferences ExtensionHost::GetRendererPrefs(Profile* profile) const { } WebPreferences ExtensionHost::GetWebkitPrefs() { - PrefService* prefs = render_view_host()->process()->profile()->GetPrefs(); + Profile* profile = render_view_host()->process()->profile(); const bool kIsDomUI = true; WebPreferences webkit_prefs = - RenderViewHostDelegateHelper::GetWebkitPrefs(prefs, kIsDomUI); + RenderViewHostDelegateHelper::GetWebkitPrefs(profile, kIsDomUI); if (extension_host_type_ == ViewType::EXTENSION_POPUP) webkit_prefs.allow_scripts_to_close_windows = true; return webkit_prefs; diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index 1e248e2..c78b64a 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -50,6 +50,7 @@ #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/sync/profile_sync_factory_impl.h" #include "chrome/browser/thumbnail_store.h" +#include "chrome/browser/user_style_sheet_watcher.h" #include "chrome/browser/visitedlink_master.h" #include "chrome/browser/visitedlink_event_listener.h" #include "chrome/browser/webdata/web_data_service.h" @@ -410,6 +411,10 @@ class OffTheRecordProfileImpl : public Profile, return profile_->GetPrivacyBlacklist(); } + virtual UserStyleSheetWatcher* GetUserStyleSheetWatcher() { + return profile_->GetUserStyleSheetWatcher(); + } + virtual SessionService* GetSessionService() { // Don't save any sessions when off the record. return NULL; @@ -988,6 +993,14 @@ Blacklist* ProfileImpl::GetPrivacyBlacklist() { return privacy_blacklist_.get(); } +UserStyleSheetWatcher* ProfileImpl::GetUserStyleSheetWatcher() { + if (!user_style_sheet_watcher_.get()) { + user_style_sheet_watcher_ = new UserStyleSheetWatcher(GetPath()); + user_style_sheet_watcher_->Init(); + } + return user_style_sheet_watcher_.get(); +} + HistoryService* ProfileImpl::GetHistoryService(ServiceAccessType sat) { if (!history_service_created_) { history_service_created_ = true; diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h index eaa05b6..5787716 100644 --- a/chrome/browser/profile.h +++ b/chrome/browser/profile.h @@ -66,6 +66,7 @@ class ThemeProvider; class ThumbnailStore; class URLRequestContextGetter; class UserScriptMaster; +class UserStyleSheetWatcher; class VisitedLinkMaster; class VisitedLinkEventListener; class WebDataService; @@ -299,6 +300,9 @@ class Profile { // Returns the Privacy Blacklist for this profile. virtual Blacklist* GetPrivacyBlacklist() = 0; + // Returns the user style sheet watcher. + virtual UserStyleSheetWatcher* GetUserStyleSheetWatcher() = 0; + // Returns the session service for this profile. This may return NULL. If // this profile supports a session service (it isn't off the record), and // the session service hasn't yet been created, this forces creation of @@ -467,6 +471,7 @@ class ProfileImpl : public Profile, virtual HostContentSettingsMap* GetHostContentSettingsMap(); virtual HostZoomMap* GetHostZoomMap(); virtual Blacklist* GetPrivacyBlacklist(); + virtual UserStyleSheetWatcher* GetUserStyleSheetWatcher(); virtual SessionService* GetSessionService(); virtual void ShutdownSessionService(); virtual bool HasSessionService() const; @@ -553,6 +558,7 @@ class ProfileImpl : public Profile, scoped_refptr<HostContentSettingsMap> host_content_settings_map_; scoped_refptr<HostZoomMap> host_zoom_map_; scoped_refptr<Blacklist> privacy_blacklist_; + scoped_refptr<UserStyleSheetWatcher> user_style_sheet_watcher_; scoped_refptr<DownloadManager> download_manager_; scoped_refptr<HistoryService> history_service_; scoped_refptr<FaviconService> favicon_service_; diff --git a/chrome/browser/tab_contents/render_view_host_delegate_helper.cc b/chrome/browser/tab_contents/render_view_host_delegate_helper.cc index 50c6771..64b62f6 100644 --- a/chrome/browser/tab_contents/render_view_host_delegate_helper.cc +++ b/chrome/browser/tab_contents/render_view_host_delegate_helper.cc @@ -17,6 +17,7 @@ #include "chrome/browser/renderer_host/site_instance.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_view.h" +#include "chrome/browser/user_style_sheet_watcher.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" @@ -112,8 +113,8 @@ void RenderViewHostDelegateViewHelper::RenderWidgetHostDestroyed( // static WebPreferences RenderViewHostDelegateHelper::GetWebkitPrefs( - PrefService* prefs, bool is_dom_ui) { - + Profile* profile, bool is_dom_ui) { + PrefService* prefs = profile->GetPrefs(); WebPreferences web_prefs; web_prefs.fixed_font_family = @@ -180,17 +181,24 @@ WebPreferences RenderViewHostDelegateHelper::GetWebkitPrefs( !command_line.HasSwitch(switches::kDisableApplicationCache); web_prefs.local_storage_enabled = - !command_line.HasSwitch(switches::kDisableLocalStorage); + !command_line.HasSwitch(switches::kDisableLocalStorage); web_prefs.databases_enabled = - !command_line.HasSwitch(switches::kDisableDatabases); + !command_line.HasSwitch(switches::kDisableDatabases); web_prefs.experimental_webgl_enabled = - command_line.HasSwitch(switches::kEnableExperimentalWebGL); + command_line.HasSwitch(switches::kEnableExperimentalWebGL); web_prefs.site_specific_quirks_enabled = - !command_line.HasSwitch(switches::kDisableSiteSpecificQuirks); + !command_line.HasSwitch(switches::kDisableSiteSpecificQuirks); web_prefs.allow_file_access_from_file_urls = - command_line.HasSwitch(switches::kAllowFileAccessFromFiles); + command_line.HasSwitch(switches::kAllowFileAccessFromFiles); web_prefs.show_composited_layer_borders = - command_line.HasSwitch(switches::kShowCompositedLayerBorders); + command_line.HasSwitch(switches::kShowCompositedLayerBorders); + web_prefs.user_style_sheet_enabled = + command_line.HasSwitch(switches::kEnableUserStyleSheet); + if (web_prefs.user_style_sheet_enabled) { + web_prefs.user_style_sheet_location = + profile->GetUserStyleSheetWatcher()->user_style_sheet(); + } + } web_prefs.uses_universal_detector = @@ -198,9 +206,6 @@ WebPreferences RenderViewHostDelegateHelper::GetWebkitPrefs( web_prefs.text_areas_are_resizable = prefs->GetBoolean(prefs::kWebKitTextAreasAreResizable); - // User CSS is currently disabled because it crashes chrome. See - // webkit/glue/webpreferences.h for more details. - // Make sure we will set the default_encoding with canonical encoding name. web_prefs.default_encoding = CharacterEncoding::GetCanonicalEncodingNameByAliasName( diff --git a/chrome/browser/tab_contents/render_view_host_delegate_helper.h b/chrome/browser/tab_contents/render_view_host_delegate_helper.h index 5078858..acca99e 100644 --- a/chrome/browser/tab_contents/render_view_host_delegate_helper.h +++ b/chrome/browser/tab_contents/render_view_host_delegate_helper.h @@ -60,7 +60,7 @@ class RenderViewHostDelegateViewHelper { // RenderViewHostDelegate methods. class RenderViewHostDelegateHelper { public: - static WebPreferences GetWebkitPrefs(PrefService* prefs, bool is_dom_ui); + static WebPreferences GetWebkitPrefs(Profile* profile, bool is_dom_ui); private: RenderViewHostDelegateHelper(); diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 891249a..2815391 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -319,6 +319,9 @@ TabContents::TabContents(Profile* profile, NotificationService::AllSources()); #endif + registrar_.Add(this, NotificationType::USER_STYLE_SHEET_UPDATED, + NotificationService::AllSources()); + // Register for notifications about content setting changes. registrar_.Add(this, NotificationType::CONTENT_SETTINGS_CHANGED, NotificationService::AllSources()); @@ -2561,9 +2564,9 @@ GURL TabContents::GetAlternateErrorPageURL() const { } WebPreferences TabContents::GetWebkitPrefs() { - PrefService* prefs = render_view_host()->process()->profile()->GetPrefs(); + Profile* profile = render_view_host()->process()->profile(); bool is_dom_ui = false; - return RenderViewHostDelegateHelper::GetWebkitPrefs(prefs, is_dom_ui); + return RenderViewHostDelegateHelper::GetWebkitPrefs(profile, is_dom_ui); } void TabContents::OnIgnoredUIEvent() { @@ -2779,6 +2782,10 @@ void TabContents::Observe(NotificationType type, } #endif + case NotificationType::USER_STYLE_SHEET_UPDATED: + UpdateWebPreferences(); + break; + case NotificationType::CONTENT_SETTINGS_CHANGED: { Details<HostContentSettingsMap::ContentSettingsDetails> settings_details(details); diff --git a/chrome/browser/user_style_sheet_watcher.cc b/chrome/browser/user_style_sheet_watcher.cc new file mode 100644 index 0000000..2d3e945 --- /dev/null +++ b/chrome/browser/user_style_sheet_watcher.cc @@ -0,0 +1,82 @@ +// 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 "chrome/browser/user_style_sheet_watcher.h" + +#include "base/base64.h" +#include "base/file_util.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_type.h" + +UserStyleSheetWatcher::UserStyleSheetWatcher(const FilePath& profile_path) + : profile_path_(profile_path), + has_loaded_(false) { + // Listen for when the first render view host is created. If we load + // too fast, the first tab won't hear the notification and won't get + // the user style sheet. + registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB, + NotificationService::AllSources()); +} + +void UserStyleSheetWatcher::Observe(NotificationType type, + const NotificationSource& source, const NotificationDetails& details) { + DCHECK(type == NotificationType::RENDER_VIEW_HOST_CREATED_FOR_TAB); + + if (has_loaded_) { + NotificationService::current()->Notify( + NotificationType::USER_STYLE_SHEET_UPDATED, + Source<UserStyleSheetWatcher>(this), + NotificationService::NoDetails()); + } + + registrar_.RemoveAll(); +} + +void UserStyleSheetWatcher::Init() { + ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, &UserStyleSheetWatcher::LoadStyleSheet, + profile_path_)); +} + +void UserStyleSheetWatcher::LoadStyleSheet(const FilePath& profile_path) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + // We keep the user style sheet in a subdir so we can watch for changes + // to the file. + FilePath style_sheet_dir = profile_path.AppendASCII("User StyleSheets"); + if (!file_util::DirectoryExists(style_sheet_dir)) { + if (!file_util::CreateDirectory(style_sheet_dir)) + return; + } + // Create the file if it doesn't exist. + FilePath css_file = style_sheet_dir.AppendASCII("Custom.css"); + if (!file_util::PathExists(css_file)) + file_util::WriteFile(css_file, "", 0); + + std::string css; + bool rv = file_util::ReadFileToString(css_file, &css); + GURL style_sheet_url; + if (rv) { + std::string css_base64; + rv = base::Base64Encode(css, &css_base64); + if (rv) { + // WebKit knows about data urls, so convert the file to a data url. + const char kDataUrlPrefix[] = "data:text/css;charset=utf-8;base64,"; + style_sheet_url = GURL(kDataUrlPrefix + css_base64); + } + } + ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &UserStyleSheetWatcher::SetStyleSheet, + style_sheet_url)); +} + +void UserStyleSheetWatcher::SetStyleSheet(const GURL& url) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + + has_loaded_ = true; + user_style_sheet_ = url; + NotificationService::current()->Notify( + NotificationType::USER_STYLE_SHEET_UPDATED, + Source<UserStyleSheetWatcher>(this), + NotificationService::NoDetails()); +} diff --git a/chrome/browser/user_style_sheet_watcher.h b/chrome/browser/user_style_sheet_watcher.h new file mode 100644 index 0000000..87fa5ce --- /dev/null +++ b/chrome/browser/user_style_sheet_watcher.h @@ -0,0 +1,57 @@ +// 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. + +#ifndef CHROME_BROWSER_USER_STYLE_SHEET_WATCHER_H_ +#define CHROME_BROWSER_USER_STYLE_SHEET_WATCHER_H_ + +#include "base/file_path.h" +#include "base/logging.h" +#include "base/ref_counted.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" +#include "googleurl/src/gurl.h" + +// This loads the user style sheet on the file thread and sends a notification +// when the style sheet is loaded. +// TODO(tony): Watch for file changes and send a notification of the update. +class UserStyleSheetWatcher + : public base::RefCountedThreadSafe<UserStyleSheetWatcher, + ChromeThread::DeleteOnUIThread>, + public NotificationObserver { + public: + explicit UserStyleSheetWatcher(const FilePath& profile_path); + virtual ~UserStyleSheetWatcher() {} + + void Init(); + + GURL user_style_sheet() const { + return user_style_sheet_; + } + + // NotificationObserver interface + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + private: + // Load the user style sheet on the file thread and convert it to a + // base64 URL. Posts the base64 URL back to the UI thread. + void LoadStyleSheet(const FilePath& profile_path); + + void SetStyleSheet(const GURL& url); + + // The directory containing the User StyleSheet. + FilePath profile_path_; + + // The user style sheet as a base64 data:// URL. + GURL user_style_sheet_; + + NotificationRegistrar registrar_; + bool has_loaded_; + + DISALLOW_COPY_AND_ASSIGN(UserStyleSheetWatcher); +}; + +#endif // CHROME_BROWSER_USER_STYLE_SHEET_WATCHER_H_ diff --git a/chrome/browser/user_style_sheet_watcher_unittest.cc b/chrome/browser/user_style_sheet_watcher_unittest.cc new file mode 100644 index 0000000..3e5932e --- /dev/null +++ b/chrome/browser/user_style_sheet_watcher_unittest.cc @@ -0,0 +1,43 @@ +// 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 "chrome/browser/user_style_sheet_watcher.h" + +#include "base/base64.h" +#include "base/file_util.h" +#include "base/message_loop.h" +#include "base/scoped_temp_dir.h" +#include "base/string_util.h" +#include "chrome/browser/chrome_thread.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(UserStyleSheetWatcherTest, StyleLoad) { + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + + std::string css_file_contents = "a { color: green; }"; + FilePath style_sheet_file = dir.path().AppendASCII("User StyleSheets") + .AppendASCII("Custom.css"); + file_util::CreateDirectory(style_sheet_file.DirName()); + ASSERT_TRUE(file_util::WriteFile(style_sheet_file, + css_file_contents.data(), css_file_contents.length())); + + scoped_refptr<UserStyleSheetWatcher> style_sheet_watcher = + new UserStyleSheetWatcher(dir.path()); + MessageLoop loop; + ChromeThread ui_thread(ChromeThread::UI, &loop); + ChromeThread file_thread(ChromeThread::FILE, &loop); + style_sheet_watcher->Init(); + + loop.RunAllPending(); + + GURL result_url = style_sheet_watcher->user_style_sheet(); + std::string result = result_url.spec(); + std::string prefix = "data:text/css;charset=utf-8;base64,"; + EXPECT_TRUE(StartsWithASCII(result, prefix, true)); + result = result.substr(prefix.length()); + std::string decoded; + EXPECT_TRUE(base::Base64Decode(result, &decoded)); + EXPECT_EQ(css_file_contents, decoded); +} diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index d6e16d1..a6db2f2 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1932,6 +1932,8 @@ 'browser/translate/translate_prefs.h', 'browser/user_data_manager.cc', 'browser/user_data_manager.h', + 'browser/user_style_sheet_watcher.cc', + 'browser/user_style_sheet_watcher.h', 'browser/utility_process_host.cc', 'browser/utility_process_host.h', 'browser/view_ids.h', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 2648ee7..aa07ec4 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -873,6 +873,7 @@ 'browser/task_manager_unittest.cc', 'browser/translate/translate_manager_unittest.cc', 'browser/theme_resources_util_unittest.cc', + 'browser/user_style_sheet_watcher_unittest.cc', 'browser/views/bookmark_context_menu_test.cc', 'browser/views/bookmark_editor_view_unittest.cc', 'browser/views/extensions/browser_action_drag_data_unittest.cc', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 31e3ae3..ad82c6f 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -301,6 +301,9 @@ const char kEnableTabbedBookmarkManager[] = "enable-tabbed-bookmark-manager"; // enabled or not. const char kEnableUserDataDirProfiles[] = "enable-udd-profiles"; +// Enable user style sheet (read from User Style Sheet in the profile dir). +const char kEnableUserStyleSheet[] = "enable-user-stylesheet"; + // Enables the option to show tabs as a vertical stack down the side of the // browser window. const char kEnableVerticalTabs[] = "enable-vertical-tabs"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 0e463a6..e7df656 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -102,6 +102,7 @@ extern const char kEnableSyncBookmarks[]; extern const char kEnableSyncPreferences[]; extern const char kEnableTabbedBookmarkManager[]; extern const char kEnableUserDataDirProfiles[]; +extern const char kEnableUserStyleSheet[]; extern const char kEnableVerticalTabs[]; extern const char kEnableVideoLayering[]; extern const char kEnableWatchdog[]; diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h index 700ffb1..2d288c9 100644 --- a/chrome/common/notification_type.h +++ b/chrome/common/notification_type.h @@ -662,6 +662,11 @@ class NotificationType { // pointer to SharedMemory containing the new scripts. USER_SCRIPTS_UPDATED, + // User Style Sheet -------------------------------------------------------- + + // Sent when the user style sheet has changed. + USER_STYLE_SHEET_UPDATED, + // Extensions -------------------------------------------------------------- // Sent when the known installed extensions have all been loaded. In diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index 31711fe..214d70a 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -184,6 +184,7 @@ class TestingProfile : public Profile { virtual net::SSLConfigService* GetSSLConfigService() { return NULL; } virtual Blacklist* GetPrivacyBlacklist() { return NULL; } + virtual UserStyleSheetWatcher* GetUserStyleSheetWatcher() { return NULL; } virtual HostContentSettingsMap* GetHostContentSettingsMap() { if (!host_content_settings_map_.get()) host_content_settings_map_ = new HostContentSettingsMap(this); |