// Copyright (c) 2011 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/ui/webui/chrome_url_data_manager.h" #include <vector> #include "base/i18n/rtl.h" #include "base/memory/ref_counted_memory.h" #include "base/message_loop.h" #include "base/string_util.h" #include "base/synchronization/lock.h" #include "base/values.h" #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/chrome_url_data_manager_backend.h" #include "content/browser/browser_thread.h" #include "grit/platform_locale_settings.h" #include "ui/base/l10n/l10n_util.h" #if defined(OS_WIN) #include "base/win/windows_version.h" #endif // static base::Lock ChromeURLDataManager::delete_lock_; // static ChromeURLDataManager::DataSources* ChromeURLDataManager::data_sources_ = NULL; // Invoked on the IO thread to do the actual adding of the DataSource. static void AddDataSourceOnIOThread( scoped_refptr<net::URLRequestContextGetter> context_getter, scoped_refptr<ChromeURLDataManager::DataSource> data_source) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); static_cast<ChromeURLRequestContext*>( context_getter->GetURLRequestContext())-> GetChromeURLDataManagerBackend()->AddDataSource(data_source.get()); } ChromeURLDataManager::ChromeURLDataManager(Profile* profile) : profile_(profile) { } ChromeURLDataManager::~ChromeURLDataManager() { } void ChromeURLDataManager::AddDataSource(DataSource* source) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableFunction(AddDataSourceOnIOThread, make_scoped_refptr(profile_->GetRequestContext()), make_scoped_refptr(source))); } // static void ChromeURLDataManager::DeleteDataSources() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DataSources sources; { base::AutoLock lock(delete_lock_); if (!data_sources_) return; data_sources_->swap(sources); } for (size_t i = 0; i < sources.size(); ++i) delete sources[i]; } // static void ChromeURLDataManager::DeleteDataSource(const DataSource* data_source) { // Invoked when a DataSource is no longer referenced and needs to be deleted. if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { // We're on the UI thread, delete right away. delete data_source; return; } // We're not on the UI thread, add the DataSource to the list of DataSources // to delete. bool schedule_delete = false; { base::AutoLock lock(delete_lock_); if (!data_sources_) data_sources_ = new DataSources(); schedule_delete = data_sources_->empty(); data_sources_->push_back(data_source); } if (schedule_delete) { // Schedule a task to delete the DataSource back on the UI thread. BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableFunction( &ChromeURLDataManager::DeleteDataSources)); } } // static bool ChromeURLDataManager::IsScheduledForDeletion( const DataSource* data_source) { base::AutoLock lock(delete_lock_); if (!data_sources_) return false; return std::find(data_sources_->begin(), data_sources_->end(), data_source) != data_sources_->end(); } ChromeURLDataManager::DataSource::DataSource(const std::string& source_name, MessageLoop* message_loop) : source_name_(source_name), message_loop_(message_loop), backend_(NULL) { } ChromeURLDataManager::DataSource::~DataSource() { } void ChromeURLDataManager::DataSource::SendResponse(int request_id, RefCountedMemory* bytes) { if (IsScheduledForDeletion(this)) { // We're scheduled for deletion. Servicing the request would result in // this->AddRef being invoked, even though the ref count is 0 and 'this' is // about to be deleted. If the AddRef were allowed through, when 'this' is // released it would be deleted again. // // This scenario occurs with DataSources that make history requests. Such // DataSources do a history query in |StartDataRequest| and the request is // live until the object is deleted (history requests don't up the ref // count). This means it's entirely possible for the DataSource to invoke // |SendResponse| between the time when there are no more refs and the time // when the object is deleted. return; } BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, NewRunnableMethod(this, &DataSource::SendResponseOnIOThread, request_id, make_scoped_refptr(bytes))); } MessageLoop* ChromeURLDataManager::DataSource::MessageLoopForRequestPath( const std::string& path) const { return message_loop_; } bool ChromeURLDataManager::DataSource::ShouldReplaceExistingSource() const { return true; } // static void ChromeURLDataManager::DataSource::SetFontAndTextDirection( DictionaryValue* localized_strings) { localized_strings->SetString("fontfamily", l10n_util::GetStringUTF16(IDS_WEB_FONT_FAMILY)); int web_font_size_id = IDS_WEB_FONT_SIZE; #if defined(OS_WIN) // Some fonts used for some languages changed a lot in terms of the font // metric in Vista. So, we need to use different size before Vista. if (base::win::GetVersion() < base::win::VERSION_VISTA) web_font_size_id = IDS_WEB_FONT_SIZE_XP; #endif localized_strings->SetString("fontsize", l10n_util::GetStringUTF16(web_font_size_id)); localized_strings->SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr"); } void ChromeURLDataManager::DataSource::SendResponseOnIOThread( int request_id, scoped_refptr<RefCountedMemory> bytes) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); if (backend_) backend_->DataAvailable(request_id, bytes); }