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
50namespace {
51
52class 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.
71class 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
131class 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
158GpuHTMLSource::GpuHTMLSource()
159    : DataSource(chrome::kChromeUIGpuInternalsHost, MessageLoop::current()) {
160}
161
162void 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
185std::string GpuHTMLSource::GetMimeType(const std::string&) const {
186  return "text/html";
187}
188
189////////////////////////////////////////////////////////////////////////////////
190//
191// GpuMessageHandler
192//
193////////////////////////////////////////////////////////////////////////////////
194
195GpuMessageHandler::GpuMessageHandler()
196  : gpu_info_update_callback_(NULL)
197  , trace_enabled_(false) {
198  gpu_data_manager_ = GpuDataManager::GetInstance();
199  DCHECK(gpu_data_manager_);
200}
201
202GpuMessageHandler::~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
215WebUIMessageHandler* 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. */
222void 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
248void 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
295void GpuMessageHandler::OnBeginRequestBufferPercentFull(const ListValue* list) {
296  TraceController::GetInstance()->GetTraceBufferPercentFullAsync(this);
297}
298
299class 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
323class 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
351void 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
365void 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
373void 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
387void 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
398void 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
423void GpuMessageHandler::SaveTraceFileComplete() {
424  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
425  std::wstring javascript;
426  web_ui_->CallJavascriptFunction("tracingController.onSaveTraceFileComplete");
427}
428
429void 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
448Value* 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
479DictionaryValue* 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
487DictionaryValue* 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
497ListValue* 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
518DictionaryValue* 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
562Value* GpuMessageHandler::OnRequestLogMessages(const ListValue*) {
563  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
564
565  return gpu_data_manager_->log_messages().DeepCopy();
566}
567
568void 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
586void 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
596void 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
610void GpuMessageHandler::OnEndTracingComplete() {
611  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
612  trace_enabled_ = false;
613  web_ui_->CallJavascriptFunction("tracingController.onEndTracingComplete");
614}
615
616void 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
627void 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
643GpuInternalsUI::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