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.
AddDataSourceOnIOThread(scoped_refptr<net::URLRequestContextGetter> context_getter,scoped_refptr<ChromeURLDataManager::DataSource> data_source)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
ChromeURLDataManager(Profile * profile)42 ChromeURLDataManager::ChromeURLDataManager(Profile* profile)
43 : profile_(profile) {
44 }
45
~ChromeURLDataManager()46 ChromeURLDataManager::~ChromeURLDataManager() {
47 }
48
AddDataSource(DataSource * source)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
DeleteDataSources()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
DeleteDataSource(const DataSource * data_source)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
IsScheduledForDeletion(const DataSource * data_source)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
DataSource(const std::string & source_name,MessageLoop * message_loop)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
~DataSource()117 ChromeURLDataManager::DataSource::~DataSource() {
118 }
119
SendResponse(int request_id,RefCountedMemory * bytes)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
MessageLoopForRequestPath(const std::string & path) const142 MessageLoop* ChromeURLDataManager::DataSource::MessageLoopForRequestPath(
143 const std::string& path) const {
144 return message_loop_;
145 }
146
ShouldReplaceExistingSource() const147 bool ChromeURLDataManager::DataSource::ShouldReplaceExistingSource() const {
148 return true;
149 }
150
151 // static
SetFontAndTextDirection(DictionaryValue * localized_strings)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
SendResponseOnIOThread(int request_id,scoped_refptr<RefCountedMemory> bytes)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