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/gpu_internals_ui.h"
6
7 #include <algorithm>
8 #include <string>
9 #include <utility>
10 #include <vector>
11
12 #include "base/command_line.h"
13 #include "base/file_util.h"
14 #include "base/memory/singleton.h"
15 #include "base/message_loop.h"
16 #include "base/path_service.h"
17 #include "base/scoped_ptr.h"
18 #include "base/string_number_conversions.h"
19 #include "base/string_piece.h"
20 #include "base/utf_string_conversions.h"
21 #include "base/values.h"
22 #include "chrome/browser/browser_process.h"
23 #include "chrome/browser/gpu_data_manager.h"
24 #include "chrome/browser/io_thread.h"
25 #include "chrome/browser/net/chrome_net_log.h"
26 #include "chrome/browser/net/connection_tester.h"
27 #include "chrome/browser/net/passive_log_collector.h"
28 #include "chrome/browser/net/url_fixer_upper.h"
29 #include "chrome/browser/platform_util.h"
30 #include "chrome/browser/profiles/profile.h"
31 #include "chrome/browser/ui/shell_dialogs.h"
32 #include "chrome/browser/ui/webui/chrome_url_data_manager.h"
33 #include "chrome/common/chrome_paths.h"
34 #include "chrome/common/chrome_version_info.h"
35 #include "chrome/common/jstemplate_builder.h"
36 #include "chrome/common/url_constants.h"
37 #include "content/browser/browser_thread.h"
38 #include "content/browser/gpu_process_host.h"
39 #include "content/browser/renderer_host/render_view_host.h"
40 #include "content/browser/tab_contents/tab_contents.h"
41 #include "content/browser/tab_contents/tab_contents_view.h"
42 #include "content/browser/trace_controller.h"
43 #include "grit/browser_resources.h"
44 #include "grit/generated_resources.h"
45 #include "net/base/escape.h"
46 #include "net/url_request/url_request_context_getter.h"
47 #include "ui/base/l10n/l10n_util.h"
48 #include "ui/base/resource/resource_bundle.h"
49
50 namespace {
51
52 class GpuHTMLSource : public ChromeURLDataManager::DataSource {
53 public:
54 GpuHTMLSource();
55
56 // Called when the network layer has requested a resource underneath
57 // the path we registered.
58 virtual void StartDataRequest(const std::string& path,
59 bool is_incognito,
60 int request_id);
61 virtual std::string GetMimeType(const std::string&) const;
62
63 private:
~GpuHTMLSource()64 ~GpuHTMLSource() {}
65 DISALLOW_COPY_AND_ASSIGN(GpuHTMLSource);
66 };
67
68 // This class receives javascript messages from the renderer.
69 // Note that the WebUI infrastructure runs on the UI thread, therefore all of
70 // this class's methods are expected to run on the UI thread.
71 class GpuMessageHandler
72 : public WebUIMessageHandler,
73 public SelectFileDialog::Listener,
74 public base::SupportsWeakPtr<GpuMessageHandler>,
75 public TraceSubscriber {
76 public:
77 GpuMessageHandler();
78 virtual ~GpuMessageHandler();
79
80 // WebUIMessageHandler implementation.
81 virtual WebUIMessageHandler* Attach(WebUI* web_ui);
82 virtual void RegisterMessages();
83
84 // Mesages
85 void OnBeginTracing(const ListValue* list);
86 void OnEndTracingAsync(const ListValue* list);
87 void OnBrowserBridgeInitialized(const ListValue* list);
88 void OnCallAsync(const ListValue* list);
89 void OnBeginRequestBufferPercentFull(const ListValue* list);
90 void OnLoadTraceFile(const ListValue* list);
91 void OnSaveTraceFile(const ListValue* list);
92
93 // Submessages dispatched from OnCallAsync
94 Value* OnRequestClientInfo(const ListValue* list);
95 Value* OnRequestLogMessages(const ListValue* list);
96
97 // SelectFileDialog::Listener implementation
98 virtual void FileSelected(const FilePath& path, int index, void* params);
99 virtual void FileSelectionCanceled(void* params);
100
101 // Callbacks.
102 void OnGpuInfoUpdate();
103 void LoadTraceFileComplete(std::string* file_contents);
104 void SaveTraceFileComplete();
105
106 // TraceSubscriber implementation.
107 virtual void OnEndTracingComplete();
108 virtual void OnTraceDataCollected(const std::string& json_events);
109 virtual void OnTraceBufferPercentFullReply(float percent_full);
110
111 // Executes the javascript function |function_name| in the renderer, passing
112 // it the argument |value|.
113 void CallJavascriptFunction(const std::wstring& function_name,
114 const Value* value);
115
116 private:
117 DISALLOW_COPY_AND_ASSIGN(GpuMessageHandler);
118
119 // Cache the Singleton for efficiency.
120 GpuDataManager* gpu_data_manager_;
121
122 Callback0::Type* gpu_info_update_callback_;
123
124 scoped_refptr<SelectFileDialog> select_trace_file_dialog_;
125 SelectFileDialog::Type select_trace_file_dialog_type_;
126 scoped_ptr<std::string> trace_data_to_save_;
127
128 bool trace_enabled_;
129 };
130
131 class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
132 public:
TaskProxy(const base::WeakPtr<GpuMessageHandler> & handler)133 explicit TaskProxy(const base::WeakPtr<GpuMessageHandler>& handler)
134 : handler_(handler) {}
LoadTraceFileCompleteProxy(std::string * file_contents)135 void LoadTraceFileCompleteProxy(std::string* file_contents) {
136 if (handler_)
137 handler_->LoadTraceFileComplete(file_contents);
138 delete file_contents;
139 }
140
SaveTraceFileCompleteProxy()141 void SaveTraceFileCompleteProxy() {
142 if (handler_)
143 handler_->SaveTraceFileComplete();
144 }
145
146 private:
147 base::WeakPtr<GpuMessageHandler> handler_;
148 friend class base::RefCountedThreadSafe<TaskProxy>;
149 DISALLOW_COPY_AND_ASSIGN(TaskProxy);
150 };
151
152 ////////////////////////////////////////////////////////////////////////////////
153 //
154 // GpuHTMLSource
155 //
156 ////////////////////////////////////////////////////////////////////////////////
157
GpuHTMLSource()158 GpuHTMLSource::GpuHTMLSource()
159 : DataSource(chrome::kChromeUIGpuInternalsHost, MessageLoop::current()) {
160 }
161
StartDataRequest(const std::string & path,bool is_incognito,int request_id)162 void GpuHTMLSource::StartDataRequest(const std::string& path,
163 bool is_incognito,
164 int request_id) {
165 DictionaryValue localized_strings;
166 SetFontAndTextDirection(&localized_strings);
167
168 base::StringPiece gpu_html(
169 ResourceBundle::GetSharedInstance().GetRawDataResource(
170 IDR_GPU_INTERNALS_HTML));
171 std::string full_html(gpu_html.data(), gpu_html.size());
172 jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html);
173 jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html);
174 jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html);
175 jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
176
177
178 scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
179 html_bytes->data.resize(full_html.size());
180 std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
181
182 SendResponse(request_id, html_bytes);
183 }
184
GetMimeType(const std::string &) const185 std::string GpuHTMLSource::GetMimeType(const std::string&) const {
186 return "text/html";
187 }
188
189 ////////////////////////////////////////////////////////////////////////////////
190 //
191 // GpuMessageHandler
192 //
193 ////////////////////////////////////////////////////////////////////////////////
194
GpuMessageHandler()195 GpuMessageHandler::GpuMessageHandler()
196 : gpu_info_update_callback_(NULL)
197 , trace_enabled_(false) {
198 gpu_data_manager_ = GpuDataManager::GetInstance();
199 DCHECK(gpu_data_manager_);
200 }
201
~GpuMessageHandler()202 GpuMessageHandler::~GpuMessageHandler() {
203 if (gpu_info_update_callback_) {
204 gpu_data_manager_->RemoveGpuInfoUpdateCallback(gpu_info_update_callback_);
205 delete gpu_info_update_callback_;
206 }
207
208 if (select_trace_file_dialog_)
209 select_trace_file_dialog_->ListenerDestroyed();
210
211 // If we are the current subscriber, this will result in ending tracing.
212 TraceController::GetInstance()->CancelSubscriber(this);
213 }
214
Attach(WebUI * web_ui)215 WebUIMessageHandler* GpuMessageHandler::Attach(WebUI* web_ui) {
216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
217 WebUIMessageHandler* result = WebUIMessageHandler::Attach(web_ui);
218 return result;
219 }
220
221 /* BrowserBridge.callAsync prepends a requestID to these messages. */
RegisterMessages()222 void GpuMessageHandler::RegisterMessages() {
223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
224
225 web_ui_->RegisterMessageCallback(
226 "beginTracing",
227 NewCallback(this, &GpuMessageHandler::OnBeginTracing));
228 web_ui_->RegisterMessageCallback(
229 "endTracingAsync",
230 NewCallback(this, &GpuMessageHandler::OnEndTracingAsync));
231 web_ui_->RegisterMessageCallback(
232 "browserBridgeInitialized",
233 NewCallback(this, &GpuMessageHandler::OnBrowserBridgeInitialized));
234 web_ui_->RegisterMessageCallback(
235 "callAsync",
236 NewCallback(this, &GpuMessageHandler::OnCallAsync));
237 web_ui_->RegisterMessageCallback(
238 "beginRequestBufferPercentFull",
239 NewCallback(this, &GpuMessageHandler::OnBeginRequestBufferPercentFull));
240 web_ui_->RegisterMessageCallback(
241 "loadTraceFile",
242 NewCallback(this, &GpuMessageHandler::OnLoadTraceFile));
243 web_ui_->RegisterMessageCallback(
244 "saveTraceFile",
245 NewCallback(this, &GpuMessageHandler::OnSaveTraceFile));
246 }
247
OnCallAsync(const ListValue * args)248 void GpuMessageHandler::OnCallAsync(const ListValue* args) {
249 DCHECK_GE(args->GetSize(), static_cast<size_t>(2));
250 // unpack args into requestId, submessage and submessageArgs
251 bool ok;
252 Value* requestId;
253 ok = args->Get(0, &requestId);
254 DCHECK(ok);
255
256 std::string submessage;
257 ok = args->GetString(1, &submessage);
258 DCHECK(ok);
259
260 ListValue* submessageArgs = new ListValue();
261 for (size_t i = 2; i < args->GetSize(); ++i) {
262 Value* arg;
263 ok = args->Get(i, &arg);
264 DCHECK(ok);
265
266 Value* argCopy = arg->DeepCopy();
267 submessageArgs->Append(argCopy);
268 }
269
270 // call the submessage handler
271 Value* ret = NULL;
272 if (submessage == "requestClientInfo") {
273 ret = OnRequestClientInfo(submessageArgs);
274 } else if (submessage == "requestLogMessages") {
275 ret = OnRequestLogMessages(submessageArgs);
276 } else { // unrecognized submessage
277 NOTREACHED();
278 delete submessageArgs;
279 return;
280 }
281 delete submessageArgs;
282
283 // call BrowserBridge.onCallAsyncReply with result
284 if (ret) {
285 web_ui_->CallJavascriptFunction("browserBridge.onCallAsyncReply",
286 *requestId,
287 *ret);
288 delete ret;
289 } else {
290 web_ui_->CallJavascriptFunction("browserBridge.onCallAsyncReply",
291 *requestId);
292 }
293 }
294
OnBeginRequestBufferPercentFull(const ListValue * list)295 void GpuMessageHandler::OnBeginRequestBufferPercentFull(const ListValue* list) {
296 TraceController::GetInstance()->GetTraceBufferPercentFullAsync(this);
297 }
298
299 class ReadTraceFileTask : public Task {
300 public:
ReadTraceFileTask(TaskProxy * proxy,const FilePath & path)301 ReadTraceFileTask(TaskProxy* proxy, const FilePath& path)
302 : proxy_(proxy)
303 , path_(path) {}
304
Run()305 virtual void Run() {
306 std::string* file_contents = new std::string();
307 if (!file_util::ReadFileToString(path_, file_contents))
308 return;
309 BrowserThread::PostTask(
310 BrowserThread::UI, FROM_HERE,
311 NewRunnableMethod(proxy_.get(),
312 &TaskProxy::LoadTraceFileCompleteProxy,
313 file_contents));
314 }
315
316 private:
317 scoped_refptr<TaskProxy> proxy_;
318
319 // Path of the file to open.
320 const FilePath path_;
321 };
322
323 class WriteTraceFileTask : public Task {
324 public:
WriteTraceFileTask(TaskProxy * proxy,const FilePath & path,std::string * contents)325 WriteTraceFileTask(TaskProxy* proxy,
326 const FilePath& path,
327 std::string* contents)
328 : proxy_(proxy)
329 , path_(path)
330 , contents_(contents) {}
331
Run()332 virtual void Run() {
333 if (!file_util::WriteFile(path_, contents_->c_str(), contents_->size()))
334 return;
335 BrowserThread::PostTask(
336 BrowserThread::UI, FROM_HERE,
337 NewRunnableMethod(proxy_.get(),
338 &TaskProxy::SaveTraceFileCompleteProxy));
339 }
340
341 private:
342 scoped_refptr<TaskProxy> proxy_;
343
344 // Path of the file to save.
345 const FilePath path_;
346
347 // What to save
348 scoped_ptr<std::string> contents_;
349 };
350
FileSelected(const FilePath & path,int index,void * params)351 void GpuMessageHandler::FileSelected(
352 const FilePath& path, int index, void* params) {
353 if(select_trace_file_dialog_type_ == SelectFileDialog::SELECT_OPEN_FILE)
354 BrowserThread::PostTask(
355 BrowserThread::FILE, FROM_HERE,
356 new ReadTraceFileTask(new TaskProxy(AsWeakPtr()), path));
357 else
358 BrowserThread::PostTask(
359 BrowserThread::FILE, FROM_HERE,
360 new WriteTraceFileTask(new TaskProxy(AsWeakPtr()), path,
361 trace_data_to_save_.release()));
362 select_trace_file_dialog_.release();
363 }
364
FileSelectionCanceled(void * params)365 void GpuMessageHandler::FileSelectionCanceled(void* params) {
366 select_trace_file_dialog_.release();
367 if(select_trace_file_dialog_type_ == SelectFileDialog::SELECT_OPEN_FILE)
368 web_ui_->CallJavascriptFunction("tracingController.onLoadTraceFileCanceled");
369 else
370 web_ui_->CallJavascriptFunction("tracingController.onSaveTraceFileCanceled");
371 }
372
OnLoadTraceFile(const ListValue * list)373 void GpuMessageHandler::OnLoadTraceFile(const ListValue* list) {
374 // Only allow a single dialog at a time.
375 if (select_trace_file_dialog_.get())
376 return;
377 select_trace_file_dialog_type_ = SelectFileDialog::SELECT_OPEN_FILE;
378 select_trace_file_dialog_ = SelectFileDialog::Create(this);
379 select_trace_file_dialog_->SelectFile(
380 SelectFileDialog::SELECT_OPEN_FILE,
381 string16(),
382 FilePath(),
383 NULL, 0, FILE_PATH_LITERAL(""), web_ui_->tab_contents(),
384 web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL);
385 }
386
LoadTraceFileComplete(std::string * file_contents)387 void GpuMessageHandler::LoadTraceFileComplete(std::string* file_contents) {
388 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
389 std::wstring javascript;
390 javascript += L"tracingController.onLoadTraceFileComplete(";
391 javascript += UTF8ToWide(*file_contents);
392 javascript += L");";
393
394 web_ui_->GetRenderViewHost()->ExecuteJavascriptInWebFrame(string16(),
395 WideToUTF16Hack(javascript));
396 }
397
OnSaveTraceFile(const ListValue * list)398 void GpuMessageHandler::OnSaveTraceFile(const ListValue* list) {
399 // Only allow a single dialog at a time.
400 if (select_trace_file_dialog_.get())
401 return;
402
403 DCHECK(list->GetSize() == 1);
404
405 Value* tmp;
406 list->Get(0, &tmp);
407
408 std::string* trace_data = new std::string();
409 bool ok = list->GetString(0, trace_data);
410 DCHECK(ok);
411 trace_data_to_save_.reset(trace_data);
412
413 select_trace_file_dialog_type_ = SelectFileDialog::SELECT_SAVEAS_FILE;
414 select_trace_file_dialog_ = SelectFileDialog::Create(this);
415 select_trace_file_dialog_->SelectFile(
416 SelectFileDialog::SELECT_SAVEAS_FILE,
417 string16(),
418 FilePath(),
419 NULL, 0, FILE_PATH_LITERAL(""), web_ui_->tab_contents(),
420 web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL);
421 }
422
SaveTraceFileComplete()423 void GpuMessageHandler::SaveTraceFileComplete() {
424 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
425 std::wstring javascript;
426 web_ui_->CallJavascriptFunction("tracingController.onSaveTraceFileComplete");
427 }
428
OnBrowserBridgeInitialized(const ListValue * args)429 void GpuMessageHandler::OnBrowserBridgeInitialized(const ListValue* args) {
430 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
431
432 DCHECK(!gpu_info_update_callback_);
433
434 // Watch for changes in GPUInfo
435 gpu_info_update_callback_ =
436 NewCallback(this, &GpuMessageHandler::OnGpuInfoUpdate);
437 gpu_data_manager_->AddGpuInfoUpdateCallback(gpu_info_update_callback_);
438
439 // Tell GpuDataManager it should have full GpuInfo. If the
440 // Gpu process has not run yet, this will trigger its launch.
441 gpu_data_manager_->RequestCompleteGpuInfoIfNeeded();
442
443 // Run callback immediately in case the info is ready and no update in the
444 // future.
445 OnGpuInfoUpdate();
446 }
447
OnRequestClientInfo(const ListValue * list)448 Value* GpuMessageHandler::OnRequestClientInfo(const ListValue* list) {
449 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
450
451 DictionaryValue* dict = new DictionaryValue();
452
453 chrome::VersionInfo version_info;
454
455 if (!version_info.is_valid()) {
456 DLOG(ERROR) << "Unable to create chrome::VersionInfo";
457 } else {
458 // We have everything we need to send the right values.
459 dict->SetString("version", version_info.Version());
460 dict->SetString("cl", version_info.LastChange());
461 dict->SetString("version_mod",
462 platform_util::GetVersionStringModifier());
463 dict->SetString("official",
464 l10n_util::GetStringUTF16(
465 version_info.IsOfficialBuild() ?
466 IDS_ABOUT_VERSION_OFFICIAL :
467 IDS_ABOUT_VERSION_UNOFFICIAL));
468
469 dict->SetString("command_line",
470 CommandLine::ForCurrentProcess()->command_line_string());
471 }
472
473 dict->SetString("blacklist_version",
474 GpuDataManager::GetInstance()->GetBlacklistVersion());
475
476 return dict;
477 }
478
NewDescriptionValuePair(const std::string & desc,const std::string & value)479 DictionaryValue* NewDescriptionValuePair(const std::string& desc,
480 const std::string& value) {
481 DictionaryValue* dict = new DictionaryValue();
482 dict->SetString("description", desc);
483 dict->SetString("value", value);
484 return dict;
485 }
486
NewDescriptionValuePair(const std::string & desc,Value * value)487 DictionaryValue* NewDescriptionValuePair(const std::string& desc,
488 Value* value) {
489 DictionaryValue* dict = new DictionaryValue();
490 dict->SetString("description", desc);
491 dict->Set("value", value);
492 return dict;
493 }
494
495 #if defined(OS_WIN)
496 // Output DxDiagNode tree as nested array of {description,value} pairs
DxDiagNodeToList(const DxDiagNode & node)497 ListValue* DxDiagNodeToList(const DxDiagNode& node) {
498 ListValue* list = new ListValue();
499 for (std::map<std::string, std::string>::const_iterator it =
500 node.values.begin();
501 it != node.values.end();
502 ++it) {
503 list->Append(NewDescriptionValuePair(it->first, it->second));
504 }
505
506 for (std::map<std::string, DxDiagNode>::const_iterator it =
507 node.children.begin();
508 it != node.children.end();
509 ++it) {
510 ListValue* sublist = DxDiagNodeToList(it->second);
511 list->Append(NewDescriptionValuePair(it->first, sublist));
512 }
513 return list;
514 }
515
516 #endif // OS_WIN
517
GpuInfoToDict(const GPUInfo & gpu_info)518 DictionaryValue* GpuInfoToDict(const GPUInfo& gpu_info) {
519 ListValue* basic_info = new ListValue();
520 basic_info->Append(NewDescriptionValuePair("Initialization time",
521 base::Int64ToString(gpu_info.initialization_time.InMilliseconds())));
522 basic_info->Append(NewDescriptionValuePair("Vendor Id",
523 base::StringPrintf("0x%04x", gpu_info.vendor_id)));
524 basic_info->Append(NewDescriptionValuePair("Device Id",
525 base::StringPrintf("0x%04x", gpu_info.device_id)));
526 basic_info->Append(NewDescriptionValuePair("Driver vendor",
527 gpu_info.driver_vendor));
528 basic_info->Append(NewDescriptionValuePair("Driver version",
529 gpu_info.driver_version));
530 basic_info->Append(NewDescriptionValuePair("Driver date",
531 gpu_info.driver_date));
532 basic_info->Append(NewDescriptionValuePair("Pixel shader version",
533 gpu_info.pixel_shader_version));
534 basic_info->Append(NewDescriptionValuePair("Vertex shader version",
535 gpu_info.vertex_shader_version));
536 basic_info->Append(NewDescriptionValuePair("GL version",
537 gpu_info.gl_version));
538 basic_info->Append(NewDescriptionValuePair("GL_VENDOR",
539 gpu_info.gl_vendor));
540 basic_info->Append(NewDescriptionValuePair("GL_RENDERER",
541 gpu_info.gl_renderer));
542 basic_info->Append(NewDescriptionValuePair("GL_VERSION",
543 gpu_info.gl_version_string));
544 basic_info->Append(NewDescriptionValuePair("GL_EXTENSIONS",
545 gpu_info.gl_extensions));
546
547 DictionaryValue* info = new DictionaryValue();
548 info->Set("basic_info", basic_info);
549
550 #if defined(OS_WIN)
551 Value* dx_info;
552 if (gpu_info.dx_diagnostics.children.size())
553 dx_info = DxDiagNodeToList(gpu_info.dx_diagnostics);
554 else
555 dx_info = Value::CreateNullValue();
556 info->Set("diagnostics", dx_info);
557 #endif
558
559 return info;
560 }
561
OnRequestLogMessages(const ListValue *)562 Value* GpuMessageHandler::OnRequestLogMessages(const ListValue*) {
563 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
564
565 return gpu_data_manager_->log_messages().DeepCopy();
566 }
567
OnGpuInfoUpdate()568 void GpuMessageHandler::OnGpuInfoUpdate() {
569 const GPUInfo& gpu_info = gpu_data_manager_->gpu_info();
570
571 // Get GPU Info.
572 DictionaryValue* gpu_info_val = GpuInfoToDict(gpu_info);
573
574 // Add in blacklisting features
575 Value* feature_status = gpu_data_manager_->GetFeatureStatus();
576 if (feature_status)
577 gpu_info_val->Set("featureStatus", feature_status);
578
579 // Send GPU Info to javascript.
580 web_ui_->CallJavascriptFunction("browserBridge.onGpuInfoUpdate",
581 *gpu_info_val);
582
583 delete gpu_info_val;
584 }
585
OnBeginTracing(const ListValue * args)586 void GpuMessageHandler::OnBeginTracing(const ListValue* args) {
587 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
588 trace_enabled_ = true;
589 // TODO(jbates) This may fail, but that's OK for current use cases.
590 // Ex: Multiple about:gpu traces can not trace simultaneously.
591 // TODO(nduca) send feedback to javascript about whether or not BeginTracing
592 // was successful.
593 TraceController::GetInstance()->BeginTracing(this);
594 }
595
OnEndTracingAsync(const ListValue * list)596 void GpuMessageHandler::OnEndTracingAsync(const ListValue* list) {
597 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
598
599 // TODO(nduca): fix javascript code to make sure trace_enabled_ is always true
600 // here. triggered a false condition by just clicking stop
601 // trace a few times when it was going slow, and maybe switching
602 // between tabs.
603 if (trace_enabled_ &&
604 !TraceController::GetInstance()->EndTracingAsync(this)) {
605 // Set to false now, since it turns out we never were the trace subscriber.
606 OnEndTracingComplete();
607 }
608 }
609
OnEndTracingComplete()610 void GpuMessageHandler::OnEndTracingComplete() {
611 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
612 trace_enabled_ = false;
613 web_ui_->CallJavascriptFunction("tracingController.onEndTracingComplete");
614 }
615
OnTraceDataCollected(const std::string & json_events)616 void GpuMessageHandler::OnTraceDataCollected(const std::string& json_events) {
617 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
618 std::wstring javascript;
619 javascript += L"tracingController.onTraceDataCollected(";
620 javascript += UTF8ToWide(json_events);
621 javascript += L");";
622
623 web_ui_->GetRenderViewHost()->ExecuteJavascriptInWebFrame(string16(),
624 WideToUTF16Hack(javascript));
625 }
626
OnTraceBufferPercentFullReply(float percent_full)627 void GpuMessageHandler::OnTraceBufferPercentFullReply(float percent_full) {
628 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
629 web_ui_->CallJavascriptFunction(
630 "tracingController.onRequestBufferPercentFullComplete",
631 *scoped_ptr<Value>(Value::CreateDoubleValue(percent_full)));
632 }
633
634 } // namespace
635
636
637 ////////////////////////////////////////////////////////////////////////////////
638 //
639 // GpuInternalsUI
640 //
641 ////////////////////////////////////////////////////////////////////////////////
642
GpuInternalsUI(TabContents * contents)643 GpuInternalsUI::GpuInternalsUI(TabContents* contents) : WebUI(contents) {
644 AddMessageHandler((new GpuMessageHandler())->Attach(this));
645
646 GpuHTMLSource* html_source = new GpuHTMLSource();
647
648 // Set up the chrome://gpu/ source.
649 contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
650 }
651