1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/webui/chrome_url_data_manager.h" 6 7 #include <vector> 8 9 #include "base/i18n/rtl.h" 10 #include "base/memory/ref_counted_memory.h" 11 #include "base/message_loop.h" 12 #include "base/string_util.h" 13 #include "base/synchronization/lock.h" 14 #include "base/values.h" 15 #include "chrome/browser/net/chrome_url_request_context.h" 16 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/ui/webui/chrome_url_data_manager_backend.h" 18 #include "content/browser/browser_thread.h" 19 #include "grit/platform_locale_settings.h" 20 #include "ui/base/l10n/l10n_util.h" 21 22 #if defined(OS_WIN) 23 #include "base/win/windows_version.h" 24 #endif 25 26 // static 27 base::Lock ChromeURLDataManager::delete_lock_; 28 29 // static 30 ChromeURLDataManager::DataSources* ChromeURLDataManager::data_sources_ = NULL; 31 32 // Invoked on the IO thread to do the actual adding of the DataSource. 33 static void AddDataSourceOnIOThread( 34 scoped_refptr<net::URLRequestContextGetter> context_getter, 35 scoped_refptr<ChromeURLDataManager::DataSource> data_source) { 36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 37 static_cast<ChromeURLRequestContext*>( 38 context_getter->GetURLRequestContext())-> 39 GetChromeURLDataManagerBackend()->AddDataSource(data_source.get()); 40 } 41 42 ChromeURLDataManager::ChromeURLDataManager(Profile* profile) 43 : profile_(profile) { 44 } 45 46 ChromeURLDataManager::~ChromeURLDataManager() { 47 } 48 49 void ChromeURLDataManager::AddDataSource(DataSource* source) { 50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 51 BrowserThread::PostTask( 52 BrowserThread::IO, FROM_HERE, 53 NewRunnableFunction(AddDataSourceOnIOThread, 54 make_scoped_refptr(profile_->GetRequestContext()), 55 make_scoped_refptr(source))); 56 } 57 58 // static 59 void ChromeURLDataManager::DeleteDataSources() { 60 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 61 DataSources sources; 62 { 63 base::AutoLock lock(delete_lock_); 64 if (!data_sources_) 65 return; 66 data_sources_->swap(sources); 67 } 68 for (size_t i = 0; i < sources.size(); ++i) 69 delete sources[i]; 70 } 71 72 // static 73 void ChromeURLDataManager::DeleteDataSource(const DataSource* data_source) { 74 // Invoked when a DataSource is no longer referenced and needs to be deleted. 75 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 76 // We're on the UI thread, delete right away. 77 delete data_source; 78 return; 79 } 80 81 // We're not on the UI thread, add the DataSource to the list of DataSources 82 // to delete. 83 bool schedule_delete = false; 84 { 85 base::AutoLock lock(delete_lock_); 86 if (!data_sources_) 87 data_sources_ = new DataSources(); 88 schedule_delete = data_sources_->empty(); 89 data_sources_->push_back(data_source); 90 } 91 if (schedule_delete) { 92 // Schedule a task to delete the DataSource back on the UI thread. 93 BrowserThread::PostTask(BrowserThread::UI, 94 FROM_HERE, 95 NewRunnableFunction( 96 &ChromeURLDataManager::DeleteDataSources)); 97 } 98 } 99 100 // static 101 bool ChromeURLDataManager::IsScheduledForDeletion( 102 const DataSource* data_source) { 103 base::AutoLock lock(delete_lock_); 104 if (!data_sources_) 105 return false; 106 return std::find(data_sources_->begin(), data_sources_->end(), data_source) != 107 data_sources_->end(); 108 } 109 110 ChromeURLDataManager::DataSource::DataSource(const std::string& source_name, 111 MessageLoop* message_loop) 112 : source_name_(source_name), 113 message_loop_(message_loop), 114 backend_(NULL) { 115 } 116 117 ChromeURLDataManager::DataSource::~DataSource() { 118 } 119 120 void ChromeURLDataManager::DataSource::SendResponse(int request_id, 121 RefCountedMemory* bytes) { 122 if (IsScheduledForDeletion(this)) { 123 // We're scheduled for deletion. Servicing the request would result in 124 // this->AddRef being invoked, even though the ref count is 0 and 'this' is 125 // about to be deleted. If the AddRef were allowed through, when 'this' is 126 // released it would be deleted again. 127 // 128 // This scenario occurs with DataSources that make history requests. Such 129 // DataSources do a history query in |StartDataRequest| and the request is 130 // live until the object is deleted (history requests don't up the ref 131 // count). This means it's entirely possible for the DataSource to invoke 132 // |SendResponse| between the time when there are no more refs and the time 133 // when the object is deleted. 134 return; 135 } 136 BrowserThread::PostTask( 137 BrowserThread::IO, FROM_HERE, 138 NewRunnableMethod(this, &DataSource::SendResponseOnIOThread, 139 request_id, make_scoped_refptr(bytes))); 140 } 141 142 MessageLoop* ChromeURLDataManager::DataSource::MessageLoopForRequestPath( 143 const std::string& path) const { 144 return message_loop_; 145 } 146 147 bool ChromeURLDataManager::DataSource::ShouldReplaceExistingSource() const { 148 return true; 149 } 150 151 // static 152 void ChromeURLDataManager::DataSource::SetFontAndTextDirection( 153 DictionaryValue* localized_strings) { 154 localized_strings->SetString("fontfamily", 155 l10n_util::GetStringUTF16(IDS_WEB_FONT_FAMILY)); 156 157 int web_font_size_id = IDS_WEB_FONT_SIZE; 158 #if defined(OS_WIN) 159 // Some fonts used for some languages changed a lot in terms of the font 160 // metric in Vista. So, we need to use different size before Vista. 161 if (base::win::GetVersion() < base::win::VERSION_VISTA) 162 web_font_size_id = IDS_WEB_FONT_SIZE_XP; 163 #endif 164 localized_strings->SetString("fontsize", 165 l10n_util::GetStringUTF16(web_font_size_id)); 166 167 localized_strings->SetString("textdirection", 168 base::i18n::IsRTL() ? "rtl" : "ltr"); 169 } 170 171 void ChromeURLDataManager::DataSource::SendResponseOnIOThread( 172 int request_id, 173 scoped_refptr<RefCountedMemory> bytes) { 174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 175 if (backend_) 176 backend_->DataAvailable(request_id, bytes); 177 } 178