|
OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2010 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/dom_ui/gpu_internals_ui.h" | |
6 | |
7 #include <algorithm> | |
8 #include <string> | |
9 #include <utility> | |
10 #include <vector> | |
11 | |
12 #include "app/l10n_util.h" | |
13 #include "app/resource_bundle.h" | |
14 #include "base/command_line.h" | |
15 #include "base/file_util.h" | |
16 #include "base/message_loop.h" | |
17 #include "base/path_service.h" | |
18 #include "base/singleton.h" | |
19 #include "base/string_number_conversions.h" | |
20 #include "base/string_piece.h" | |
21 #include "base/utf_string_conversions.h" | |
22 #include "base/values.h" | |
23 #include "chrome/browser/browser_process.h" | |
24 #include "chrome/browser/browser_thread.h" | |
25 #include "chrome/browser/dom_ui/chrome_url_data_manager.h" | |
26 #include "chrome/browser/gpu_process_host.h" | |
27 #include "chrome/browser/gpu_process_host_ui_shim.h" | |
28 #include "chrome/browser/io_thread.h" | |
29 #include "chrome/browser/net/chrome_net_log.h" | |
30 #include "chrome/browser/net/connection_tester.h" | |
31 #include "chrome/browser/net/passive_log_collector.h" | |
32 #include "chrome/browser/net/url_fixer_upper.h" | |
33 #include "chrome/browser/platform_util.h" | |
34 #include "chrome/common/chrome_paths.h" | |
35 #include "chrome/common/chrome_version_info.h" | |
36 #include "chrome/common/jstemplate_builder.h" | |
37 #include "chrome/common/net/url_request_context_getter.h" | |
38 #include "chrome/common/url_constants.h" | |
39 #include "grit/browser_resources.h" | |
40 #include "grit/generated_resources.h" | |
41 #include "net/base/escape.h" | |
42 | |
43 | |
44 namespace { | |
45 | |
46 class GpuHTMLSource : public ChromeURLDataManager::DataSource { | |
47 public: | |
48 GpuHTMLSource(); | |
49 | |
50 // Called when the network layer has requested a resource underneath | |
51 // the path we registered. | |
52 virtual void StartDataRequest(const std::string& path, | |
53 bool is_off_the_record, | |
54 int request_id); | |
55 virtual std::string GetMimeType(const std::string&) const; | |
56 | |
57 private: | |
58 ~GpuHTMLSource() {} | |
59 DISALLOW_COPY_AND_ASSIGN(GpuHTMLSource); | |
60 }; | |
61 | |
62 // This class receives javascript messages from the renderer. | |
63 // Note that the DOMUI infrastructure runs on the UI thread, therefore all of | |
64 // this class's methods are expected to run on the UI thread. | |
65 // | |
66 // Since the network code we want to run lives on the IO thread, we proxy | |
67 // everything over to GpuMessageHandler::IOThreadImpl, which runs | |
68 // on the IO thread. | |
69 // | |
70 // TODO(eroman): Can we start on the IO thread to begin with? | |
eroman
2010/12/09 02:46:45
Looks like you copied this comment block from net_
nduca
2010/12/09 17:24:54
Done.
| |
71 class GpuMessageHandler | |
72 : public DOMMessageHandler, | |
73 public base::SupportsWeakPtr<GpuMessageHandler> { | |
74 public: | |
75 GpuMessageHandler(); | |
76 virtual ~GpuMessageHandler(); | |
77 | |
78 // DOMMessageHandler implementation. | |
79 virtual DOMMessageHandler* Attach(DOMUI* dom_ui); | |
80 virtual void RegisterMessages(); | |
81 | |
82 // Mesages | |
83 void OnCallAsync(const ListValue* list); | |
84 | |
85 // Submessages dispatched from OnCallAsync | |
86 Value* OnRequestGpuInfo(const ListValue* list); | |
87 Value* OnRequestClientInfo(const ListValue* list); | |
88 | |
89 // Executes the javascript function |function_name| in the renderer, passing | |
90 // it the argument |value|. | |
91 void CallJavascriptFunction(const std::wstring& function_name, | |
92 const Value* value); | |
93 | |
94 private: | |
95 DISALLOW_COPY_AND_ASSIGN(GpuMessageHandler); | |
96 }; | |
97 | |
98 //////////////////////////////////////////////////////////////////////////////// | |
99 // | |
100 // GpuHTMLSource | |
101 // | |
102 //////////////////////////////////////////////////////////////////////////////// | |
103 | |
104 GpuHTMLSource::GpuHTMLSource() | |
105 : DataSource(chrome::kChromeUIGpuInternalsHost, MessageLoop::current()) { | |
106 } | |
107 | |
108 void GpuHTMLSource::StartDataRequest(const std::string& path, | |
109 bool is_off_the_record, | |
eroman
2010/12/09 02:46:45
indentation.
nduca
2010/12/09 17:24:54
Done.
| |
110 int request_id) { | |
111 DictionaryValue localized_strings; | |
112 SetFontAndTextDirection(&localized_strings); | |
113 | |
114 static const base::StringPiece gpu_html( | |
eroman
2010/12/09 02:46:45
Why static?
Seems incorrect to save a StringPiece
nduca
2010/12/09 17:24:54
This is copied from options_ui.cc, which does this
| |
115 ResourceBundle::GetSharedInstance().GetRawDataResource( | |
116 IDR_GPU_INTERNALS_HTML)); | |
117 std::string full_html(gpu_html.data(), gpu_html.size()); | |
118 jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html); | |
119 jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html); | |
120 jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html); | |
121 jstemplate_builder::AppendJsTemplateSourceHtml(&full_html); | |
122 | |
123 | |
124 scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes); | |
125 html_bytes->data.resize(full_html.size()); | |
126 std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin()); | |
127 | |
128 SendResponse(request_id, html_bytes); | |
129 } | |
130 | |
131 std::string GpuHTMLSource::GetMimeType(const std::string&) const { | |
132 return "text/html"; | |
133 } | |
134 | |
135 //////////////////////////////////////////////////////////////////////////////// | |
136 // | |
137 // GpuMessageHandler | |
138 // | |
139 //////////////////////////////////////////////////////////////////////////////// | |
140 | |
141 GpuMessageHandler::GpuMessageHandler() { | |
142 } | |
143 | |
144 GpuMessageHandler::~GpuMessageHandler() {} | |
145 | |
146 DOMMessageHandler* GpuMessageHandler::Attach(DOMUI* dom_ui) { | |
147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
148 DOMMessageHandler* result = DOMMessageHandler::Attach(dom_ui); | |
149 return result; | |
150 } | |
151 | |
152 /* BrowserBridge.callAsync prepends a requestID to these messages. */ | |
153 void GpuMessageHandler::RegisterMessages() { | |
154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
155 | |
156 dom_ui_->RegisterMessageCallback( | |
157 "callAsync", | |
158 NewCallback(this, &GpuMessageHandler::OnCallAsync)); | |
159 } | |
160 | |
161 void GpuMessageHandler::OnCallAsync(const ListValue* args) { | |
162 DCHECK_GE(args->GetSize(), static_cast<size_t>(2)); | |
163 // unpack args into requestId, submessage and submessageArgs | |
164 bool ok; | |
165 Value* requestId; | |
166 ok = args->Get(0, &requestId); | |
167 DCHECK(ok); | |
168 | |
169 std::string submessage; | |
170 ok = args->GetString(1, &submessage); | |
171 DCHECK(ok); | |
172 | |
173 ListValue* submessageArgs = new ListValue(); | |
174 for (size_t i = 2; i < args->GetSize(); ++i) { | |
175 Value* arg; | |
176 ok = args->Get(i, &arg); | |
177 DCHECK(ok); | |
178 | |
179 Value* argCopy = arg->DeepCopy(); | |
180 submessageArgs->Append(argCopy); | |
181 } | |
182 | |
183 // call the submessage handler | |
184 Value* ret = NULL; | |
185 if (submessage == "requestGpuInfo") { | |
186 ret = OnRequestGpuInfo(submessageArgs); | |
187 } else if (submessage == "requestClientInfo") { | |
188 ret = OnRequestClientInfo(submessageArgs); | |
189 } else { // unrecognized submessage | |
190 NOTREACHED(); | |
191 delete submessageArgs; | |
192 return; | |
193 } | |
194 delete submessageArgs; | |
195 | |
196 // call BrowserBridge.onCallAsyncReply with result | |
197 if (ret) { | |
198 dom_ui_->CallJavascriptFunction(L"browserBridge.onCallAsyncReply", | |
199 *requestId, | |
200 *ret); | |
201 delete ret; | |
202 } else { | |
203 dom_ui_->CallJavascriptFunction(L"browserBridge.onCallAsyncReply", | |
204 *requestId); | |
205 } | |
206 } | |
207 | |
208 Value* GpuMessageHandler::OnRequestClientInfo(const ListValue* list) { | |
209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
210 | |
211 DictionaryValue* dict = new DictionaryValue(); | |
212 | |
213 chrome::VersionInfo version_info; | |
214 | |
215 if (!version_info.is_valid()) { | |
216 DLOG(ERROR) << "Unable to create chrome::VersionInfo"; | |
217 } else { | |
218 // We have everything we need to send the right values. | |
219 dict->SetString("version", version_info.Version()); | |
220 dict->SetString("cl", version_info.LastChange()); | |
221 dict->SetString("version_mod", | |
222 platform_util::GetVersionStringModifier()); | |
223 dict->SetString("official", | |
224 l10n_util::GetStringUTF16( | |
225 version_info.IsOfficialBuild() ? | |
226 IDS_ABOUT_VERSION_OFFICIAL | |
227 : IDS_ABOUT_VERSION_UNOFFICIAL)); | |
228 | |
229 dict->SetString("command_line", | |
230 CommandLine::ForCurrentProcess()->command_line_string()); | |
231 } | |
232 | |
233 return dict; | |
234 } | |
235 | |
236 DictionaryValue* NewDescriptionValuePair(const std::string& desc, | |
237 const std::string& value) { | |
238 DictionaryValue* dict = new DictionaryValue(); | |
239 dict->SetString("description", EscapeForHTML(desc)); | |
240 dict->SetString("value", EscapeForHTML(value)); | |
241 return dict; | |
242 } | |
243 | |
244 DictionaryValue* NewDescriptionValuePair(const std::string& desc, | |
245 Value* value) { | |
246 DictionaryValue* dict = new DictionaryValue(); | |
247 dict->SetString("description", EscapeForHTML(desc)); | |
248 dict->Set("value", value); | |
249 return dict; | |
250 } | |
251 | |
252 #if defined(OS_WIN) | |
253 // Output DxDiagNode tree as nested array of {description,value} pairs | |
254 ListValue* DxDiagNodeToList(const DxDiagNode& node) { | |
255 ListValue* list = new ListValue(); | |
256 for (std::map<std::string, std::string>::const_iterator it = | |
257 node.values.begin(); | |
258 it != node.values.end(); | |
259 ++it) { | |
260 list->Append(NewDescriptionValuePair(it->first, it->second)); | |
261 } | |
262 | |
263 for (std::map<std::string, DxDiagNode>::const_iterator it = | |
264 node.children.begin(); | |
265 it != node.children.end(); | |
266 ++it) { | |
267 ListValue* sublist = DxDiagNodeToList(it->second); | |
268 list->Append(NewDescriptionValuePair(it->first, sublist)); | |
269 } | |
270 return list; | |
271 } | |
272 | |
273 #endif // OS_WIN | |
274 | |
275 std::string VersionNumberToString(uint32 value) { | |
276 int hi = (value >> 8) & 0xff; | |
277 int low = value & 0xff; | |
278 return base::IntToString(hi) + "." + base::IntToString(low); | |
279 } | |
280 | |
281 DictionaryValue* GpuInfoToDict(const GPUInfo& gpu_info) { | |
282 ListValue* basic_info = new ListValue(); | |
283 basic_info->Append(NewDescriptionValuePair("Initialization time", | |
284 base::Int64ToString(gpu_info.initialization_time().InMilliseconds()))); | |
285 basic_info->Append(NewDescriptionValuePair("Vendor Id", | |
286 base::StringPrintf("0x%04x", gpu_info.vendor_id()))); | |
287 basic_info->Append(NewDescriptionValuePair("Device Id", | |
288 base::StringPrintf("0x%04x", gpu_info.device_id()))); | |
289 basic_info->Append(NewDescriptionValuePair("Driver version", | |
290 WideToASCII(gpu_info.driver_version()).c_str())); | |
291 basic_info->Append(NewDescriptionValuePair("Pixel shader version", | |
292 VersionNumberToString(gpu_info.pixel_shader_version()))); | |
293 basic_info->Append(NewDescriptionValuePair("Vertex shader version", | |
294 VersionNumberToString(gpu_info.vertex_shader_version()))); | |
295 basic_info->Append(NewDescriptionValuePair("GL version", | |
296 VersionNumberToString(gpu_info.gl_version()))); | |
297 | |
298 DictionaryValue* info = new DictionaryValue(); | |
299 info->Set("basic_info", basic_info); | |
300 | |
301 if (gpu_info.progress() == GPUInfo::kPartial) { | |
302 info->SetString("progress", "partial"); | |
303 } else { | |
304 info->SetString("progress", "complete"); | |
305 } | |
306 #if defined(OS_WIN) | |
307 if (gpu_info.progress() == GPUInfo::kComplete) { | |
308 ListValue* dx_info = DxDiagNodeToList(gpu_info.dx_diagnostics()); | |
309 info->Set("diagnostics", dx_info); | |
310 } | |
311 #endif | |
312 | |
313 return info; | |
314 } | |
315 | |
316 Value* GpuMessageHandler::OnRequestGpuInfo(const ListValue* list) { | |
317 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
318 | |
319 // Get GPU Info. | |
320 GPUInfo gpu_info = GpuProcessHostUIShim::Get()->gpu_info(); | |
321 | |
322 std::string html; | |
323 if (gpu_info.progress() != GPUInfo::kComplete) { | |
324 GpuProcessHostUIShim::Get()->CollectGraphicsInfoAsynchronously(); | |
325 } | |
326 | |
327 if (gpu_info.progress() != GPUInfo::kUninitialized) { | |
328 return GpuInfoToDict(gpu_info); | |
329 } else { | |
330 return NULL; | |
331 } | |
332 } | |
333 | |
334 } // namespace | |
335 | |
336 | |
337 //////////////////////////////////////////////////////////////////////////////// | |
338 // | |
339 // GpuUI | |
340 // | |
341 //////////////////////////////////////////////////////////////////////////////// | |
342 | |
343 GpuUI::GpuUI(TabContents* contents) : DOMUI(contents) { | |
344 AddMessageHandler((new GpuMessageHandler())->Attach(this)); | |
345 | |
346 GpuHTMLSource* html_source = new GpuHTMLSource(); | |
347 | |
348 // Set up the chrome://gpu/ source. | |
349 BrowserThread::PostTask( | |
350 BrowserThread::IO, FROM_HERE, | |
351 NewRunnableMethod( | |
352 Singleton<ChromeURLDataManager>::get(), | |
353 &ChromeURLDataManager::AddDataSource, | |
354 make_scoped_refptr(html_source))); | |
355 } | |
356 | |
OLD | NEW |