diff options
Diffstat (limited to 'chrome/browser/user_style_sheet_watcher.cc')
-rw-r--r-- | chrome/browser/user_style_sheet_watcher.cc | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/chrome/browser/user_style_sheet_watcher.cc b/chrome/browser/user_style_sheet_watcher.cc new file mode 100644 index 0000000..2bc9568 --- /dev/null +++ b/chrome/browser/user_style_sheet_watcher.cc @@ -0,0 +1,103 @@ +// 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" + +namespace { + +// The subdirectory of the profile that contains the style sheet. +const char kStyleSheetDir[] = "User StyleSheets"; +// The filename of the stylesheet. +const char kUserStyleSheetFile[] = "Custom.css"; + +} // namespace + +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::OnFileChanged(const FilePath& path) { + ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, &UserStyleSheetWatcher::LoadStyleSheet, + profile_path_)); +} + +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(kStyleSheetDir); + 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(kUserStyleSheetFile); + 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 && !css.empty()) { + 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)); + + if (!file_watcher_.get()) { + file_watcher_.reset(new FileWatcher); + file_watcher_->Watch(profile_path_.AppendASCII(kStyleSheetDir) + .AppendASCII(kUserStyleSheetFile), this); + } +} + +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()); +} |