| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/webui/gpu_internals_ui.h" |
| |
| #include <algorithm> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/file_util.h" |
| #include "base/memory/singleton.h" |
| #include "base/message_loop.h" |
| #include "base/path_service.h" |
| #include "base/scoped_ptr.h" |
| #include "base/string_number_conversions.h" |
| #include "base/string_piece.h" |
| #include "base/utf_string_conversions.h" |
| #include "base/values.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/gpu_data_manager.h" |
| #include "chrome/browser/io_thread.h" |
| #include "chrome/browser/net/chrome_net_log.h" |
| #include "chrome/browser/net/connection_tester.h" |
| #include "chrome/browser/net/passive_log_collector.h" |
| #include "chrome/browser/net/url_fixer_upper.h" |
| #include "chrome/browser/platform_util.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/shell_dialogs.h" |
| #include "chrome/browser/ui/webui/chrome_url_data_manager.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "chrome/common/chrome_version_info.h" |
| #include "chrome/common/jstemplate_builder.h" |
| #include "chrome/common/url_constants.h" |
| #include "content/browser/browser_thread.h" |
| #include "content/browser/gpu_process_host.h" |
| #include "content/browser/renderer_host/render_view_host.h" |
| #include "content/browser/tab_contents/tab_contents.h" |
| #include "content/browser/tab_contents/tab_contents_view.h" |
| #include "content/browser/trace_controller.h" |
| #include "grit/browser_resources.h" |
| #include "grit/generated_resources.h" |
| #include "net/base/escape.h" |
| #include "net/url_request/url_request_context_getter.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| |
| namespace { |
| |
| class GpuHTMLSource : public ChromeURLDataManager::DataSource { |
| public: |
| GpuHTMLSource(); |
| |
| // Called when the network layer has requested a resource underneath |
| // the path we registered. |
| virtual void StartDataRequest(const std::string& path, |
| bool is_incognito, |
| int request_id); |
| virtual std::string GetMimeType(const std::string&) const; |
| |
| private: |
| ~GpuHTMLSource() {} |
| DISALLOW_COPY_AND_ASSIGN(GpuHTMLSource); |
| }; |
| |
| // This class receives javascript messages from the renderer. |
| // Note that the WebUI infrastructure runs on the UI thread, therefore all of |
| // this class's methods are expected to run on the UI thread. |
| class GpuMessageHandler |
| : public WebUIMessageHandler, |
| public SelectFileDialog::Listener, |
| public base::SupportsWeakPtr<GpuMessageHandler>, |
| public TraceSubscriber { |
| public: |
| GpuMessageHandler(); |
| virtual ~GpuMessageHandler(); |
| |
| // WebUIMessageHandler implementation. |
| virtual WebUIMessageHandler* Attach(WebUI* web_ui); |
| virtual void RegisterMessages(); |
| |
| // Mesages |
| void OnBeginTracing(const ListValue* list); |
| void OnEndTracingAsync(const ListValue* list); |
| void OnBrowserBridgeInitialized(const ListValue* list); |
| void OnCallAsync(const ListValue* list); |
| void OnBeginRequestBufferPercentFull(const ListValue* list); |
| void OnLoadTraceFile(const ListValue* list); |
| void OnSaveTraceFile(const ListValue* list); |
| |
| // Submessages dispatched from OnCallAsync |
| Value* OnRequestClientInfo(const ListValue* list); |
| Value* OnRequestLogMessages(const ListValue* list); |
| |
| // SelectFileDialog::Listener implementation |
| virtual void FileSelected(const FilePath& path, int index, void* params); |
| virtual void FileSelectionCanceled(void* params); |
| |
| // Callbacks. |
| void OnGpuInfoUpdate(); |
| void LoadTraceFileComplete(std::string* file_contents); |
| void SaveTraceFileComplete(); |
| |
| // TraceSubscriber implementation. |
| virtual void OnEndTracingComplete(); |
| virtual void OnTraceDataCollected(const std::string& json_events); |
| virtual void OnTraceBufferPercentFullReply(float percent_full); |
| |
| // Executes the javascript function |function_name| in the renderer, passing |
| // it the argument |value|. |
| void CallJavascriptFunction(const std::wstring& function_name, |
| const Value* value); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(GpuMessageHandler); |
| |
| // Cache the Singleton for efficiency. |
| GpuDataManager* gpu_data_manager_; |
| |
| Callback0::Type* gpu_info_update_callback_; |
| |
| scoped_refptr<SelectFileDialog> select_trace_file_dialog_; |
| SelectFileDialog::Type select_trace_file_dialog_type_; |
| scoped_ptr<std::string> trace_data_to_save_; |
| |
| bool trace_enabled_; |
| }; |
| |
| class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> { |
| public: |
| explicit TaskProxy(const base::WeakPtr<GpuMessageHandler>& handler) |
| : handler_(handler) {} |
| void LoadTraceFileCompleteProxy(std::string* file_contents) { |
| if (handler_) |
| handler_->LoadTraceFileComplete(file_contents); |
| delete file_contents; |
| } |
| |
| void SaveTraceFileCompleteProxy() { |
| if (handler_) |
| handler_->SaveTraceFileComplete(); |
| } |
| |
| private: |
| base::WeakPtr<GpuMessageHandler> handler_; |
| friend class base::RefCountedThreadSafe<TaskProxy>; |
| DISALLOW_COPY_AND_ASSIGN(TaskProxy); |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // GpuHTMLSource |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| GpuHTMLSource::GpuHTMLSource() |
| : DataSource(chrome::kChromeUIGpuInternalsHost, MessageLoop::current()) { |
| } |
| |
| void GpuHTMLSource::StartDataRequest(const std::string& path, |
| bool is_incognito, |
| int request_id) { |
| DictionaryValue localized_strings; |
| SetFontAndTextDirection(&localized_strings); |
| |
| base::StringPiece gpu_html( |
| ResourceBundle::GetSharedInstance().GetRawDataResource( |
| IDR_GPU_INTERNALS_HTML)); |
| std::string full_html(gpu_html.data(), gpu_html.size()); |
| jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html); |
| jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html); |
| jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html); |
| jstemplate_builder::AppendJsTemplateSourceHtml(&full_html); |
| |
| |
| scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes); |
| html_bytes->data.resize(full_html.size()); |
| std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin()); |
| |
| SendResponse(request_id, html_bytes); |
| } |
| |
| std::string GpuHTMLSource::GetMimeType(const std::string&) const { |
| return "text/html"; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // GpuMessageHandler |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| GpuMessageHandler::GpuMessageHandler() |
| : gpu_info_update_callback_(NULL) |
| , trace_enabled_(false) { |
| gpu_data_manager_ = GpuDataManager::GetInstance(); |
| DCHECK(gpu_data_manager_); |
| } |
| |
| GpuMessageHandler::~GpuMessageHandler() { |
| if (gpu_info_update_callback_) { |
| gpu_data_manager_->RemoveGpuInfoUpdateCallback(gpu_info_update_callback_); |
| delete gpu_info_update_callback_; |
| } |
| |
| if (select_trace_file_dialog_) |
| select_trace_file_dialog_->ListenerDestroyed(); |
| |
| // If we are the current subscriber, this will result in ending tracing. |
| TraceController::GetInstance()->CancelSubscriber(this); |
| } |
| |
| WebUIMessageHandler* GpuMessageHandler::Attach(WebUI* web_ui) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| WebUIMessageHandler* result = WebUIMessageHandler::Attach(web_ui); |
| return result; |
| } |
| |
| /* BrowserBridge.callAsync prepends a requestID to these messages. */ |
| void GpuMessageHandler::RegisterMessages() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| web_ui_->RegisterMessageCallback( |
| "beginTracing", |
| NewCallback(this, &GpuMessageHandler::OnBeginTracing)); |
| web_ui_->RegisterMessageCallback( |
| "endTracingAsync", |
| NewCallback(this, &GpuMessageHandler::OnEndTracingAsync)); |
| web_ui_->RegisterMessageCallback( |
| "browserBridgeInitialized", |
| NewCallback(this, &GpuMessageHandler::OnBrowserBridgeInitialized)); |
| web_ui_->RegisterMessageCallback( |
| "callAsync", |
| NewCallback(this, &GpuMessageHandler::OnCallAsync)); |
| web_ui_->RegisterMessageCallback( |
| "beginRequestBufferPercentFull", |
| NewCallback(this, &GpuMessageHandler::OnBeginRequestBufferPercentFull)); |
| web_ui_->RegisterMessageCallback( |
| "loadTraceFile", |
| NewCallback(this, &GpuMessageHandler::OnLoadTraceFile)); |
| web_ui_->RegisterMessageCallback( |
| "saveTraceFile", |
| NewCallback(this, &GpuMessageHandler::OnSaveTraceFile)); |
| } |
| |
| void GpuMessageHandler::OnCallAsync(const ListValue* args) { |
| DCHECK_GE(args->GetSize(), static_cast<size_t>(2)); |
| // unpack args into requestId, submessage and submessageArgs |
| bool ok; |
| Value* requestId; |
| ok = args->Get(0, &requestId); |
| DCHECK(ok); |
| |
| std::string submessage; |
| ok = args->GetString(1, &submessage); |
| DCHECK(ok); |
| |
| ListValue* submessageArgs = new ListValue(); |
| for (size_t i = 2; i < args->GetSize(); ++i) { |
| Value* arg; |
| ok = args->Get(i, &arg); |
| DCHECK(ok); |
| |
| Value* argCopy = arg->DeepCopy(); |
| submessageArgs->Append(argCopy); |
| } |
| |
| // call the submessage handler |
| Value* ret = NULL; |
| if (submessage == "requestClientInfo") { |
| ret = OnRequestClientInfo(submessageArgs); |
| } else if (submessage == "requestLogMessages") { |
| ret = OnRequestLogMessages(submessageArgs); |
| } else { // unrecognized submessage |
| NOTREACHED(); |
| delete submessageArgs; |
| return; |
| } |
| delete submessageArgs; |
| |
| // call BrowserBridge.onCallAsyncReply with result |
| if (ret) { |
| web_ui_->CallJavascriptFunction("browserBridge.onCallAsyncReply", |
| *requestId, |
| *ret); |
| delete ret; |
| } else { |
| web_ui_->CallJavascriptFunction("browserBridge.onCallAsyncReply", |
| *requestId); |
| } |
| } |
| |
| void GpuMessageHandler::OnBeginRequestBufferPercentFull(const ListValue* list) { |
| TraceController::GetInstance()->GetTraceBufferPercentFullAsync(this); |
| } |
| |
| class ReadTraceFileTask : public Task { |
| public: |
| ReadTraceFileTask(TaskProxy* proxy, const FilePath& path) |
| : proxy_(proxy) |
| , path_(path) {} |
| |
| virtual void Run() { |
| std::string* file_contents = new std::string(); |
| if (!file_util::ReadFileToString(path_, file_contents)) |
| return; |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| NewRunnableMethod(proxy_.get(), |
| &TaskProxy::LoadTraceFileCompleteProxy, |
| file_contents)); |
| } |
| |
| private: |
| scoped_refptr<TaskProxy> proxy_; |
| |
| // Path of the file to open. |
| const FilePath path_; |
| }; |
| |
| class WriteTraceFileTask : public Task { |
| public: |
| WriteTraceFileTask(TaskProxy* proxy, |
| const FilePath& path, |
| std::string* contents) |
| : proxy_(proxy) |
| , path_(path) |
| , contents_(contents) {} |
| |
| virtual void Run() { |
| if (!file_util::WriteFile(path_, contents_->c_str(), contents_->size())) |
| return; |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| NewRunnableMethod(proxy_.get(), |
| &TaskProxy::SaveTraceFileCompleteProxy)); |
| } |
| |
| private: |
| scoped_refptr<TaskProxy> proxy_; |
| |
| // Path of the file to save. |
| const FilePath path_; |
| |
| // What to save |
| scoped_ptr<std::string> contents_; |
| }; |
| |
| void GpuMessageHandler::FileSelected( |
| const FilePath& path, int index, void* params) { |
| if(select_trace_file_dialog_type_ == SelectFileDialog::SELECT_OPEN_FILE) |
| BrowserThread::PostTask( |
| BrowserThread::FILE, FROM_HERE, |
| new ReadTraceFileTask(new TaskProxy(AsWeakPtr()), path)); |
| else |
| BrowserThread::PostTask( |
| BrowserThread::FILE, FROM_HERE, |
| new WriteTraceFileTask(new TaskProxy(AsWeakPtr()), path, |
| trace_data_to_save_.release())); |
| select_trace_file_dialog_.release(); |
| } |
| |
| void GpuMessageHandler::FileSelectionCanceled(void* params) { |
| select_trace_file_dialog_.release(); |
| if(select_trace_file_dialog_type_ == SelectFileDialog::SELECT_OPEN_FILE) |
| web_ui_->CallJavascriptFunction("tracingController.onLoadTraceFileCanceled"); |
| else |
| web_ui_->CallJavascriptFunction("tracingController.onSaveTraceFileCanceled"); |
| } |
| |
| void GpuMessageHandler::OnLoadTraceFile(const ListValue* list) { |
| // Only allow a single dialog at a time. |
| if (select_trace_file_dialog_.get()) |
| return; |
| select_trace_file_dialog_type_ = SelectFileDialog::SELECT_OPEN_FILE; |
| select_trace_file_dialog_ = SelectFileDialog::Create(this); |
| select_trace_file_dialog_->SelectFile( |
| SelectFileDialog::SELECT_OPEN_FILE, |
| string16(), |
| FilePath(), |
| NULL, 0, FILE_PATH_LITERAL(""), web_ui_->tab_contents(), |
| web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL); |
| } |
| |
| void GpuMessageHandler::LoadTraceFileComplete(std::string* file_contents) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| std::wstring javascript; |
| javascript += L"tracingController.onLoadTraceFileComplete("; |
| javascript += UTF8ToWide(*file_contents); |
| javascript += L");"; |
| |
| web_ui_->GetRenderViewHost()->ExecuteJavascriptInWebFrame(string16(), |
| WideToUTF16Hack(javascript)); |
| } |
| |
| void GpuMessageHandler::OnSaveTraceFile(const ListValue* list) { |
| // Only allow a single dialog at a time. |
| if (select_trace_file_dialog_.get()) |
| return; |
| |
| DCHECK(list->GetSize() == 1); |
| |
| Value* tmp; |
| list->Get(0, &tmp); |
| |
| std::string* trace_data = new std::string(); |
| bool ok = list->GetString(0, trace_data); |
| DCHECK(ok); |
| trace_data_to_save_.reset(trace_data); |
| |
| select_trace_file_dialog_type_ = SelectFileDialog::SELECT_SAVEAS_FILE; |
| select_trace_file_dialog_ = SelectFileDialog::Create(this); |
| select_trace_file_dialog_->SelectFile( |
| SelectFileDialog::SELECT_SAVEAS_FILE, |
| string16(), |
| FilePath(), |
| NULL, 0, FILE_PATH_LITERAL(""), web_ui_->tab_contents(), |
| web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(), NULL); |
| } |
| |
| void GpuMessageHandler::SaveTraceFileComplete() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| std::wstring javascript; |
| web_ui_->CallJavascriptFunction("tracingController.onSaveTraceFileComplete"); |
| } |
| |
| void GpuMessageHandler::OnBrowserBridgeInitialized(const ListValue* args) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| DCHECK(!gpu_info_update_callback_); |
| |
| // Watch for changes in GPUInfo |
| gpu_info_update_callback_ = |
| NewCallback(this, &GpuMessageHandler::OnGpuInfoUpdate); |
| gpu_data_manager_->AddGpuInfoUpdateCallback(gpu_info_update_callback_); |
| |
| // Tell GpuDataManager it should have full GpuInfo. If the |
| // Gpu process has not run yet, this will trigger its launch. |
| gpu_data_manager_->RequestCompleteGpuInfoIfNeeded(); |
| |
| // Run callback immediately in case the info is ready and no update in the |
| // future. |
| OnGpuInfoUpdate(); |
| } |
| |
| Value* GpuMessageHandler::OnRequestClientInfo(const ListValue* list) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| DictionaryValue* dict = new DictionaryValue(); |
| |
| chrome::VersionInfo version_info; |
| |
| if (!version_info.is_valid()) { |
| DLOG(ERROR) << "Unable to create chrome::VersionInfo"; |
| } else { |
| // We have everything we need to send the right values. |
| dict->SetString("version", version_info.Version()); |
| dict->SetString("cl", version_info.LastChange()); |
| dict->SetString("version_mod", |
| platform_util::GetVersionStringModifier()); |
| dict->SetString("official", |
| l10n_util::GetStringUTF16( |
| version_info.IsOfficialBuild() ? |
| IDS_ABOUT_VERSION_OFFICIAL : |
| IDS_ABOUT_VERSION_UNOFFICIAL)); |
| |
| dict->SetString("command_line", |
| CommandLine::ForCurrentProcess()->command_line_string()); |
| } |
| |
| dict->SetString("blacklist_version", |
| GpuDataManager::GetInstance()->GetBlacklistVersion()); |
| |
| return dict; |
| } |
| |
| DictionaryValue* NewDescriptionValuePair(const std::string& desc, |
| const std::string& value) { |
| DictionaryValue* dict = new DictionaryValue(); |
| dict->SetString("description", desc); |
| dict->SetString("value", value); |
| return dict; |
| } |
| |
| DictionaryValue* NewDescriptionValuePair(const std::string& desc, |
| Value* value) { |
| DictionaryValue* dict = new DictionaryValue(); |
| dict->SetString("description", desc); |
| dict->Set("value", value); |
| return dict; |
| } |
| |
| #if defined(OS_WIN) |
| // Output DxDiagNode tree as nested array of {description,value} pairs |
| ListValue* DxDiagNodeToList(const DxDiagNode& node) { |
| ListValue* list = new ListValue(); |
| for (std::map<std::string, std::string>::const_iterator it = |
| node.values.begin(); |
| it != node.values.end(); |
| ++it) { |
| list->Append(NewDescriptionValuePair(it->first, it->second)); |
| } |
| |
| for (std::map<std::string, DxDiagNode>::const_iterator it = |
| node.children.begin(); |
| it != node.children.end(); |
| ++it) { |
| ListValue* sublist = DxDiagNodeToList(it->second); |
| list->Append(NewDescriptionValuePair(it->first, sublist)); |
| } |
| return list; |
| } |
| |
| #endif // OS_WIN |
| |
| DictionaryValue* GpuInfoToDict(const GPUInfo& gpu_info) { |
| ListValue* basic_info = new ListValue(); |
| basic_info->Append(NewDescriptionValuePair("Initialization time", |
| base::Int64ToString(gpu_info.initialization_time.InMilliseconds()))); |
| basic_info->Append(NewDescriptionValuePair("Vendor Id", |
| base::StringPrintf("0x%04x", gpu_info.vendor_id))); |
| basic_info->Append(NewDescriptionValuePair("Device Id", |
| base::StringPrintf("0x%04x", gpu_info.device_id))); |
| basic_info->Append(NewDescriptionValuePair("Driver vendor", |
| gpu_info.driver_vendor)); |
| basic_info->Append(NewDescriptionValuePair("Driver version", |
| gpu_info.driver_version)); |
| basic_info->Append(NewDescriptionValuePair("Driver date", |
| gpu_info.driver_date)); |
| basic_info->Append(NewDescriptionValuePair("Pixel shader version", |
| gpu_info.pixel_shader_version)); |
| basic_info->Append(NewDescriptionValuePair("Vertex shader version", |
| gpu_info.vertex_shader_version)); |
| basic_info->Append(NewDescriptionValuePair("GL version", |
| gpu_info.gl_version)); |
| basic_info->Append(NewDescriptionValuePair("GL_VENDOR", |
| gpu_info.gl_vendor)); |
| basic_info->Append(NewDescriptionValuePair("GL_RENDERER", |
| gpu_info.gl_renderer)); |
| basic_info->Append(NewDescriptionValuePair("GL_VERSION", |
| gpu_info.gl_version_string)); |
| basic_info->Append(NewDescriptionValuePair("GL_EXTENSIONS", |
| gpu_info.gl_extensions)); |
| |
| DictionaryValue* info = new DictionaryValue(); |
| info->Set("basic_info", basic_info); |
| |
| #if defined(OS_WIN) |
| Value* dx_info; |
| if (gpu_info.dx_diagnostics.children.size()) |
| dx_info = DxDiagNodeToList(gpu_info.dx_diagnostics); |
| else |
| dx_info = Value::CreateNullValue(); |
| info->Set("diagnostics", dx_info); |
| #endif |
| |
| return info; |
| } |
| |
| Value* GpuMessageHandler::OnRequestLogMessages(const ListValue*) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| return gpu_data_manager_->log_messages().DeepCopy(); |
| } |
| |
| void GpuMessageHandler::OnGpuInfoUpdate() { |
| const GPUInfo& gpu_info = gpu_data_manager_->gpu_info(); |
| |
| // Get GPU Info. |
| DictionaryValue* gpu_info_val = GpuInfoToDict(gpu_info); |
| |
| // Add in blacklisting features |
| Value* feature_status = gpu_data_manager_->GetFeatureStatus(); |
| if (feature_status) |
| gpu_info_val->Set("featureStatus", feature_status); |
| |
| // Send GPU Info to javascript. |
| web_ui_->CallJavascriptFunction("browserBridge.onGpuInfoUpdate", |
| *gpu_info_val); |
| |
| delete gpu_info_val; |
| } |
| |
| void GpuMessageHandler::OnBeginTracing(const ListValue* args) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| trace_enabled_ = true; |
| // TODO(jbates) This may fail, but that's OK for current use cases. |
| // Ex: Multiple about:gpu traces can not trace simultaneously. |
| // TODO(nduca) send feedback to javascript about whether or not BeginTracing |
| // was successful. |
| TraceController::GetInstance()->BeginTracing(this); |
| } |
| |
| void GpuMessageHandler::OnEndTracingAsync(const ListValue* list) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| |
| // TODO(nduca): fix javascript code to make sure trace_enabled_ is always true |
| // here. triggered a false condition by just clicking stop |
| // trace a few times when it was going slow, and maybe switching |
| // between tabs. |
| if (trace_enabled_ && |
| !TraceController::GetInstance()->EndTracingAsync(this)) { |
| // Set to false now, since it turns out we never were the trace subscriber. |
| OnEndTracingComplete(); |
| } |
| } |
| |
| void GpuMessageHandler::OnEndTracingComplete() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| trace_enabled_ = false; |
| web_ui_->CallJavascriptFunction("tracingController.onEndTracingComplete"); |
| } |
| |
| void GpuMessageHandler::OnTraceDataCollected(const std::string& json_events) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| std::wstring javascript; |
| javascript += L"tracingController.onTraceDataCollected("; |
| javascript += UTF8ToWide(json_events); |
| javascript += L");"; |
| |
| web_ui_->GetRenderViewHost()->ExecuteJavascriptInWebFrame(string16(), |
| WideToUTF16Hack(javascript)); |
| } |
| |
| void GpuMessageHandler::OnTraceBufferPercentFullReply(float percent_full) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| web_ui_->CallJavascriptFunction( |
| "tracingController.onRequestBufferPercentFullComplete", |
| *scoped_ptr<Value>(Value::CreateDoubleValue(percent_full))); |
| } |
| |
| } // namespace |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // GpuInternalsUI |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| GpuInternalsUI::GpuInternalsUI(TabContents* contents) : WebUI(contents) { |
| AddMessageHandler((new GpuMessageHandler())->Attach(this)); |
| |
| GpuHTMLSource* html_source = new GpuHTMLSource(); |
| |
| // Set up the chrome://gpu/ source. |
| contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source); |
| } |