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: 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: 133 explicit TaskProxy(const base::WeakPtr<GpuMessageHandler>& handler) 134 : handler_(handler) {} 135 void LoadTraceFileCompleteProxy(std::string* file_contents) { 136 if (handler_) 137 handler_->LoadTraceFileComplete(file_contents); 138 delete file_contents; 139 } 140 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 158 GpuHTMLSource::GpuHTMLSource() 159 : DataSource(chrome::kChromeUIGpuInternalsHost, MessageLoop::current()) { 160 } 161 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 185 std::string GpuHTMLSource::GetMimeType(const std::string&) const { 186 return "text/html"; 187 } 188 189 //////////////////////////////////////////////////////////////////////////////// 190 // 191 // GpuMessageHandler 192 // 193 //////////////////////////////////////////////////////////////////////////////// 194 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 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 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. */ 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 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 295 void GpuMessageHandler::OnBeginRequestBufferPercentFull(const ListValue* list) { 296 TraceController::GetInstance()->GetTraceBufferPercentFullAsync(this); 297 } 298 299 class ReadTraceFileTask : public Task { 300 public: 301 ReadTraceFileTask(TaskProxy* proxy, const FilePath& path) 302 : proxy_(proxy) 303 , path_(path) {} 304 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: 325 WriteTraceFileTask(TaskProxy* proxy, 326 const FilePath& path, 327 std::string* contents) 328 : proxy_(proxy) 329 , path_(path) 330 , contents_(contents) {} 331 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 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 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 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 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 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 423 void GpuMessageHandler::SaveTraceFileComplete() { 424 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 425 std::wstring javascript; 426 web_ui_->CallJavascriptFunction("tracingController.onSaveTraceFileComplete"); 427 } 428 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 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 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 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 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 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 562 Value* GpuMessageHandler::OnRequestLogMessages(const ListValue*) { 563 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 564 565 return gpu_data_manager_->log_messages().DeepCopy(); 566 } 567 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 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 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 610 void GpuMessageHandler::OnEndTracingComplete() { 611 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 612 trace_enabled_ = false; 613 web_ui_->CallJavascriptFunction("tracingController.onEndTracingComplete"); 614 } 615 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 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 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