diff options
22 files changed, 821 insertions, 166 deletions
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc index d76163c..abc35eb 100644 --- a/chrome/browser/browser_about_handler.cc +++ b/chrome/browser/browser_about_handler.cc @@ -280,6 +280,7 @@ std::string AboutAbout() { kAllAboutPaths[i] == kConflictsPath || #endif kAllAboutPaths[i] == kFlagsPath || + kAllAboutPaths[i] == kGpuPath || kAllAboutPaths[i] == kNetInternalsPath || kAllAboutPaths[i] == kPluginsPath) { html.append("<li><a href='chrome://"); @@ -721,110 +722,6 @@ std::string VersionNumberToString(uint32 value) { return base::IntToString(hi) + "." + base::IntToString(low); } -namespace { - -#if defined(OS_WIN) - -// Output DxDiagNode tree as HTML tables and nested HTML unordered list -// elements. -void DxDiagNodeToHTML(std::string* output, const DxDiagNode& node) { - output->append("<table>\n"); - - for (std::map<std::string, std::string>::const_iterator it = - node.values.begin(); - it != node.values.end(); - ++it) { - output->append("<tr><td><strong>"); - output->append(EscapeForHTML(it->first)); - output->append("</strong></td><td>"); - output->append(EscapeForHTML(it->second)); - output->append("</td></tr>\n"); - } - - output->append("</table>\n<ul>\n"); - - for (std::map<std::string, DxDiagNode>::const_iterator it = - node.children.begin(); - it != node.children.end(); - ++it) { - output->append("<li><strong>"); - output->append(EscapeForHTML(it->first)); - output->append("</strong>"); - - DxDiagNodeToHTML(output, it->second); - - output->append("</li>\n"); - } - - output->append("</ul>\n"); -} - -#endif // OS_WIN - -} - -std::string AboutGpu() { - const GPUInfo& gpu_info = GpuProcessHostUIShim::GetInstance()->gpu_info(); - - std::string html; - - html.append("<html><head><title>About GPU</title></head>\n"); - - if (gpu_info.progress() != GPUInfo::kComplete) { - GpuProcessHostUIShim::GetInstance()->CollectGraphicsInfoAsynchronously(); - - // If it's not fully initialized yet, set a timeout to reload the page. - html.append("<body onload=\"setTimeout('window.location.reload(true)',"); - html.append("2000)\">\n"); - } else { - html.append("<body>\n"); - } - - html.append("<h2>GPU Information</h2>\n"); - - if (gpu_info.progress() == GPUInfo::kUninitialized) { - html.append("<p>Retrieving GPU information . . .</p>\n"); - } else { - html.append("<table><tr>"); - html.append("<td><strong>Initialization time</strong></td><td>"); - html.append(base::Int64ToString( - gpu_info.initialization_time().InMilliseconds())); - html.append("</td></tr><tr><td>"); - html.append("<strong>Vendor ID</strong></td><td>"); - html.append(base::StringPrintf("0x%04x", gpu_info.vendor_id())); - html.append("</td></tr><tr><td>"); - html.append("<strong>Device ID</strong></td><td>"); - html.append(base::StringPrintf("0x%04x", gpu_info.device_id())); - html.append("</td></tr><tr><td>"); - html.append("<strong>Driver Version</strong></td><td>"); - html.append(WideToASCII(gpu_info.driver_version()).c_str()); - html.append("</td></tr><tr><td>"); - html.append("<strong>Pixel Shader Version</strong></td><td>"); - html.append(VersionNumberToString(gpu_info.pixel_shader_version()).c_str()); - html.append("</td></tr><tr><td>"); - html.append("<strong>Vertex Shader Version</strong></td><td>"); - html.append(VersionNumberToString( - gpu_info.vertex_shader_version()).c_str()); - html.append("</td></tr><tr><td>"); - html.append("<strong>GL Version</strong></td><td>"); - html.append(VersionNumberToString(gpu_info.gl_version()).c_str()); - html.append("</td></tr></table>"); - -#if defined(OS_WIN) - if (gpu_info.progress() != GPUInfo::kComplete) { - html.append("<p>Retrieving DirectX Diagnostics . . .</p>\n"); - } else { - html.append("<h2>DirectX Diagnostics</h2>"); - DxDiagNodeToHTML(&html, gpu_info.dx_diagnostics()); - } -#endif - } - - html.append("</body></html>"); - - return html; -} - // AboutSource ----------------------------------------------------------------- AboutSource::AboutSource() @@ -909,8 +806,6 @@ void AboutSource::StartDataRequest(const std::string& path_raw, #endif } else if (path == kSyncPath) { response = AboutSync(); - } else if (path == kGpuPath) { - response = AboutGpu(); } FinishDataRequest(response, request_id); @@ -1144,6 +1039,12 @@ bool WillHandleBrowserAboutURL(GURL* url, Profile* profile) { return true; } + // Rewrite about:gpu/* URLs to chrome://gpu-internals/* + if (StartsWithAboutSpecifier(*url, chrome::kAboutGpuURL)) { + *url = RemapAboutURL(chrome::kGpuInternalsURL, *url); + return true; + } + // Rewrite about:appcache-internals/* URLs to chrome://appcache/* if (StartsWithAboutSpecifier(*url, chrome::kAboutAppCacheInternalsURL)) { *url = RemapAboutURL(chrome::kAppCacheViewInternalsURL, *url); diff --git a/chrome/browser/browser_about_handler_unittest.cc b/chrome/browser/browser_about_handler_unittest.cc index be08e564f..9b234a2 100644 --- a/chrome/browser/browser_about_handler_unittest.cc +++ b/chrome/browser/browser_about_handler_unittest.cc @@ -42,6 +42,12 @@ TEST(BrowserAboutHandlerTest, WillHandleBrowserAboutURL) { true }, { + GURL(std::string(chrome::kAboutGpuURL) + "/jupiter"), + GURL(std::string(chrome::kGpuInternalsURL) + "jupiter"), + false, + true + }, + { GURL(std::string(chrome::kAboutAppCacheInternalsURL) + "/earth"), GURL(std::string(chrome::kAppCacheViewInternalsURL) + "earth"), false, diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index 6bbf3ab..af317b1 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd @@ -38,6 +38,7 @@ without changes to the corresponding grd file. etaa --> <include name="IDR_EXTENSIONS_UI_HTML" file="resources\extensions_ui.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_FLAGS_HTML" file="resources\flags.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_GAIA_LOGIN_HTML" file="sync\resources\gaia_login.html" flattenhtml="true" type="BINDATA" /> + <include name="IDR_GPU_INTERNALS_HTML" file="resources\gpu_internals.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_HISTORY_HTML" file="resources\history.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_HISTORY2_HTML" file="resources\history2.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_INCOGNITO_TAB_HTML" file="resources\incognito_tab.html" flattenhtml="true" type="BINDATA" /> diff --git a/chrome/browser/dom_ui/dom_ui_factory.cc b/chrome/browser/dom_ui/dom_ui_factory.cc index e49abba..b1aca94 100644 --- a/chrome/browser/dom_ui/dom_ui_factory.cc +++ b/chrome/browser/dom_ui/dom_ui_factory.cc @@ -11,6 +11,7 @@ #include "chrome/browser/dom_ui/constrained_html_ui.h" #include "chrome/browser/dom_ui/downloads_ui.h" #include "chrome/browser/dom_ui/devtools_ui.h" +#include "chrome/browser/dom_ui/gpu_internals_ui.h" #include "chrome/browser/dom_ui/history_ui.h" #include "chrome/browser/dom_ui/history2_ui.h" #include "chrome/browser/dom_ui/html_dialog_ui.h" @@ -159,6 +160,8 @@ static DOMUIFactoryFunction GetDOMUIFactoryFunction(Profile* profile, if (url.host() == chrome::kChromeUILoginHost) return &NewDOMUI<chromeos::LoginUI>; #endif + if (url.host() == chrome::kChromeUIGpuInternalsHost) + return &NewDOMUI<GpuInternalsUI>; if (url.host() == chrome::kChromeUINetInternalsHost) return &NewDOMUI<NetInternalsUI>; if (url.host() == chrome::kChromeUIPluginsHost) diff --git a/chrome/browser/dom_ui/gpu_internals_ui.cc b/chrome/browser/dom_ui/gpu_internals_ui.cc new file mode 100644 index 0000000..9b93bfb --- /dev/null +++ b/chrome/browser/dom_ui/gpu_internals_ui.cc @@ -0,0 +1,350 @@ +// Copyright (c) 2010 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/dom_ui/gpu_internals_ui.h" + +#include <algorithm> +#include <string> +#include <utility> +#include <vector> + +#include "app/l10n_util.h" +#include "app/resource_bundle.h" +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/message_loop.h" +#include "base/path_service.h" +#include "base/singleton.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/browser_thread.h" +#include "chrome/browser/dom_ui/chrome_url_data_manager.h" +#include "chrome/browser/gpu_process_host.h" +#include "chrome/browser/gpu_process_host_ui_shim.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/common/chrome_paths.h" +#include "chrome/common/chrome_version_info.h" +#include "chrome/common/jstemplate_builder.h" +#include "chrome/common/net/url_request_context_getter.h" +#include "chrome/common/url_constants.h" +#include "grit/browser_resources.h" +#include "grit/generated_resources.h" +#include "net/base/escape.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_off_the_record, + 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 DOMUI infrastructure runs on the UI thread, therefore all of +// this class's methods are expected to run on the UI thread. +class GpuMessageHandler + : public DOMMessageHandler, + public base::SupportsWeakPtr<GpuMessageHandler> { + public: + GpuMessageHandler(); + virtual ~GpuMessageHandler(); + + // DOMMessageHandler implementation. + virtual DOMMessageHandler* Attach(DOMUI* dom_ui); + virtual void RegisterMessages(); + + // Mesages + void OnCallAsync(const ListValue* list); + + // Submessages dispatched from OnCallAsync + Value* OnRequestGpuInfo(const ListValue* list); + Value* OnRequestClientInfo(const ListValue* list); + + // 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); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// GpuHTMLSource +// +//////////////////////////////////////////////////////////////////////////////// + +GpuHTMLSource::GpuHTMLSource() + : DataSource(chrome::kChromeUIGpuInternalsHost, MessageLoop::current()) { +} + +void GpuHTMLSource::StartDataRequest(const std::string& path, + bool is_off_the_record, + 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() { +} + +GpuMessageHandler::~GpuMessageHandler() {} + +DOMMessageHandler* GpuMessageHandler::Attach(DOMUI* dom_ui) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DOMMessageHandler* result = DOMMessageHandler::Attach(dom_ui); + return result; +} + +/* BrowserBridge.callAsync prepends a requestID to these messages. */ +void GpuMessageHandler::RegisterMessages() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + dom_ui_->RegisterMessageCallback( + "callAsync", + NewCallback(this, &GpuMessageHandler::OnCallAsync)); +} + +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 == "requestGpuInfo") { + ret = OnRequestGpuInfo(submessageArgs); + } else if (submessage == "requestClientInfo") { + ret = OnRequestClientInfo(submessageArgs); + } else { // unrecognized submessage + NOTREACHED(); + delete submessageArgs; + return; + } + delete submessageArgs; + + // call BrowserBridge.onCallAsyncReply with result + if (ret) { + dom_ui_->CallJavascriptFunction(L"browserBridge.onCallAsyncReply", + *requestId, + *ret); + delete ret; + } else { + dom_ui_->CallJavascriptFunction(L"browserBridge.onCallAsyncReply", + *requestId); + } +} + +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()); + } + + 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 + +std::string VersionNumberToString(uint32 value) { + int hi = (value >> 8) & 0xff; + int low = value & 0xff; + return base::IntToString(hi) + "." + base::IntToString(low); +} + +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 version", + WideToASCII(gpu_info.driver_version()).c_str())); + basic_info->Append(NewDescriptionValuePair("Pixel shader version", + VersionNumberToString(gpu_info.pixel_shader_version()))); + basic_info->Append(NewDescriptionValuePair("Vertex shader version", + VersionNumberToString(gpu_info.vertex_shader_version()))); + basic_info->Append(NewDescriptionValuePair("GL version", + VersionNumberToString(gpu_info.gl_version()))); + + DictionaryValue* info = new DictionaryValue(); + info->Set("basic_info", basic_info); + + if (gpu_info.progress() == GPUInfo::kPartial) { + info->SetString("progress", "partial"); + } else { + info->SetString("progress", "complete"); + } +#if defined(OS_WIN) + if (gpu_info.progress() == GPUInfo::kComplete) { + ListValue* dx_info = DxDiagNodeToList(gpu_info.dx_diagnostics()); + info->Set("diagnostics", dx_info); + } +#endif + + return info; +} + +Value* GpuMessageHandler::OnRequestGpuInfo(const ListValue* list) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // Get GPU Info. + GPUInfo gpu_info = GpuProcessHostUIShim::GetInstance()->gpu_info(); + + std::string html; + if (gpu_info.progress() != GPUInfo::kComplete) { + GpuProcessHostUIShim::GetInstance()->CollectGraphicsInfoAsynchronously(); + } + + if (gpu_info.progress() != GPUInfo::kUninitialized) { + return GpuInfoToDict(gpu_info); + } else { + return NULL; + } +} + +} // namespace + + +//////////////////////////////////////////////////////////////////////////////// +// +// GpuInternalsUI +// +//////////////////////////////////////////////////////////////////////////////// + +GpuInternalsUI::GpuInternalsUI(TabContents* contents) : DOMUI(contents) { + AddMessageHandler((new GpuMessageHandler())->Attach(this)); + + GpuHTMLSource* html_source = new GpuHTMLSource(); + + // Set up the chrome://gpu/ source. + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + NewRunnableMethod( + ChromeURLDataManager::GetInstance(), + &ChromeURLDataManager::AddDataSource, + make_scoped_refptr(html_source))); +} + diff --git a/chrome/browser/dom_ui/gpu_internals_ui.h b/chrome/browser/dom_ui/gpu_internals_ui.h new file mode 100644 index 0000000..8b45692 --- /dev/null +++ b/chrome/browser/dom_ui/gpu_internals_ui.h @@ -0,0 +1,20 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_BROWSER_DOM_UI_GPU_INTERNALS_UI_H_ +#define CHROME_BROWSER_DOM_UI_GPU_INTERNALS_UI_H_ +#pragma once + +#include "chrome/browser/dom_ui/dom_ui.h" + +class GpuInternalsUI : public DOMUI { + public: + explicit GpuInternalsUI(TabContents* contents); + + private: + DISALLOW_COPY_AND_ASSIGN(GpuInternalsUI); +}; + +#endif // CHROME_BROWSER_DOM_UI_GPU_INTERNALS_UI_H_ + diff --git a/chrome/browser/dom_ui/net_internals_ui.cc b/chrome/browser/dom_ui/net_internals_ui.cc index 8fa9e9b8..f44ac9e 100644 --- a/chrome/browser/dom_ui/net_internals_ui.cc +++ b/chrome/browser/dom_ui/net_internals_ui.cc @@ -32,6 +32,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_version_info.h" +#include "chrome/common/jstemplate_builder.h" #include "chrome/common/net/url_request_context_getter.h" #include "chrome/common/url_constants.h" #include "grit/generated_resources.h" @@ -319,6 +320,9 @@ NetInternalsHTMLSource::NetInternalsHTMLSource() void NetInternalsHTMLSource::StartDataRequest(const std::string& path, bool is_off_the_record, int request_id) { + DictionaryValue localized_strings; + SetFontAndTextDirection(&localized_strings); + // The provided "path" may contain a fragment, or query section. We only // care about the path itself, and will disregard anything else. std::string filename = @@ -329,13 +333,20 @@ void NetInternalsHTMLSource::StartDataRequest(const std::string& path, // Note that users can type anything into the address bar, though, so we must // handle arbitrary input. if (filename.empty() || filename == "index.html") { - scoped_refptr<RefCountedStaticMemory> bytes( - ResourceBundle::GetSharedInstance().LoadDataResourceBytes( + base::StringPiece html( + ResourceBundle::GetSharedInstance().GetRawDataResource( IDR_NET_INTERNALS_INDEX_HTML)); - if (bytes && bytes->front()) { - SendResponse(request_id, bytes); - return; - } + std::string full_html(html.data(), 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); + return; } const std::string data_string("<p style='color:red'>Failed to read resource" + diff --git a/chrome/browser/resources/gpu_internals.html b/chrome/browser/resources/gpu_internals.html new file mode 100644 index 0000000..9b3fb86 --- /dev/null +++ b/chrome/browser/resources/gpu_internals.html @@ -0,0 +1,91 @@ +<!DOCTYPE HTML> +<html> +<!-- +Copyright (c) 2010 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. +--> +<head i18n-values="dir:textdirection;"> +<link rel="stylesheet" href="dom_ui.css"> +<link rel="stylesheet" href="net_internals/tabswitcherview.css"> +<style> +* { + box-sizing: border-box; +} +body { + font-family: sans-serif; +} +</style> +<link rel="stylesheet" href="gpu_internals/info_view.css"> +<script src="chrome://resources/js/cr.js"></script> +<script src="net_internals/util.js"></script> +<script src="net_internals/view.js"></script> +<script src="net_internals/tabswitcherview.js"></script> +<script src="gpu_internals/browser_bridge.js"></script> +<script src="gpu_internals/info_view.js"></script> + + +<script> +var browser = null; + +/** + * Main entry point. called once the page has loaded. + */ +function onLoad() { + browserBridge = new gpu.BrowserBridge(); + + // Create a view which will display general information + // about the gpu. + var infoView = new gpu.InfoView('info-view'); + + // Create a view which lets you tab between the different sub-views. + var categoryTabSwitcher = + new TabSwitcherView('category-tab-handles'); + + // Populate the main tabs. + categoryTabSwitcher.addTab('info-tab', infoView, false); + + // Build a map from the anchor name of each tab handle to its 'tab ID'. + // We will consider navigations to the #hash as a switch tab request. + var anchorMap = {}; + var tabIds = categoryTabSwitcher.getAllTabIds(); + for (var i = 0; i < tabIds.length; i++) { + var aNode = document.getElementById(tabIds[i]); + anchorMap[aNode.hash] = tabIds[i]; + } + // Default the empty hash to the info tab. + anchorMap['#'] = anchorMap[''] = 'info-tab'; + + window.onhashchange = function() { + var tabId = anchorMap[window.location.hash]; + if (tabId) + categoryTabSwitcher.switchToTab(tabId); + }; + + // Make this category tab widget the primary view, that fills the whole page. + var windowView = new WindowView(categoryTabSwitcher); + + // Trigger initial layout. + windowView.resetGeometry(); + + // Select the initial view based on the current URL. + window.onhashchange(); +} + +document.addEventListener('DOMContentLoaded', onLoad); + +</script> +</head> +<body> + + <!-- Tab switcher for main categories. --> + <div id=category-tab-handles> + <ul> + <li><a href="#info" id="info-tab">GPU Info</a></li> + </ul> + </div> + + <!-- Tabs --> + <include src="gpu_internals/info_view.html"> +</body> +</html> diff --git a/chrome/browser/resources/gpu_internals/browser_bridge.js b/chrome/browser/resources/gpu_internals/browser_bridge.js new file mode 100644 index 0000000..cd1bf6d --- /dev/null +++ b/chrome/browser/resources/gpu_internals/browser_bridge.js @@ -0,0 +1,59 @@ +// Copyright (c) 2010 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. + +cr.define('gpu', function() { + /** + * This class provides a 'bridge' for communicating between javascript and + * the browser. + * @constructor + */ + function BrowserBridge() { + // If we are not running inside DOMUI, output chrome.send messages + // to the console to help with quick-iteration debugging. + if (chrome.send === undefined && console.log) { + chrome.send = function(messageHandler, args) { + console.log('chrome.send', messageHandler, args); + }; + } + + this.nextRequestId_ = 0; + this.pendingCallbacks_ = []; + } + + BrowserBridge.prototype = { + __proto__: Object.prototype, + + /** + * Sends a message to the browser with specified args. The + * browser will reply asynchronously via the provided callback. + */ + callAsync: function(submessage, args, callback) { + var requestId = this.nextRequestId_; + this.nextRequestId_ += 1; + this.pendingCallbacks_[requestId] = callback; + if (!args) { + chrome.send('callAsync', [requestId.toString(), submessage]); + } else { + var allArgs = [requestId.toString(), submessage].concat(args); + chrome.send('callAsync', allArgs); + } + }, + + /** + * Called by gpu c++ code when client info is ready. + */ + onCallAsyncReply: function(requestId, args) { + if (this.pendingCallbacks_[requestId] === undefined) { + throw new Error('requestId ' + requestId + ' is not pending'); + } + var callback = this.pendingCallbacks_[requestId]; + callback(args); + delete this.pendingCallbacks_[requestId]; + } + }; + + return { + BrowserBridge : BrowserBridge + }; +}); diff --git a/chrome/browser/resources/gpu_internals/info_view.css b/chrome/browser/resources/gpu_internals/info_view.css new file mode 100644 index 0000000..a877032 --- /dev/null +++ b/chrome/browser/resources/gpu_internals/info_view.css @@ -0,0 +1,28 @@ +/* +Copyright (c) 2010 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. +*/ +#info-view { + padding: 10px; +} + +#info-view h3 { + margin-bottom: 5px; +} + +#info-view .row-title { + font-weight: bold; +} + +#info-view table { + border-collapse: collapse; +} + +#info-view table, +#info-view th, +#info-view td { + border: 1px solid #777; + padding-right: 4px; + padding-left: 4px; +} diff --git a/chrome/browser/resources/gpu_internals/info_view.html b/chrome/browser/resources/gpu_internals/info_view.html new file mode 100644 index 0000000..9ef43b8 --- /dev/null +++ b/chrome/browser/resources/gpu_internals/info_view.html @@ -0,0 +1,34 @@ +<!-- +Copyright (c) 2010 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. +--> +<div id=info-view> + <h3>Chrome Version</h3> + <div id="client-info"></div> + <h3>Driver Information</h3> + <div id="basic-info"></div> + + <h3>Diagnostics</h3> + <div id="diagnostics">None</div> + + <!-- templates --> + <div style="display:none"> + <div id="info-view-table-template"> + <table id="info-view-table"> + <tr jsselect="value"> + <td jsdisplay="!(value instanceof Array)"> + <span class="row-title" jscontent="description">title</span> + </td> + <td jsdisplay="!(value instanceof Array)"> + <span jscontent="value">value</span> + </td> + <td jsdisplay="value instanceof Array" colspan=2> + <span jscontent="description" class="row-title"></span> + <div transclude="info-view-table-template"> + </td> + </tr> + </table> + </div> + </div> +</div> diff --git a/chrome/browser/resources/gpu_internals/info_view.js b/chrome/browser/resources/gpu_internals/info_view.js new file mode 100644 index 0000000..acc4efc --- /dev/null +++ b/chrome/browser/resources/gpu_internals/info_view.js @@ -0,0 +1,119 @@ +// Copyright (c) 2010 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. + +/** + * This view displays options for importing/exporting the captured data. Its + * primarily usefulness is to allow users to copy-paste their data in an easy + * to read format for bug reports. + * + * - Has a button to generate a text report. + * + * - Shows how many events have been captured. + */ +cr.define('gpu', function() { + /** + * Provides information on the GPU process and underlying graphics hardware. + * @constructor + */ + function InfoView(mainBoxId) { + DivView.call(this, mainBoxId); + + this.beginRequestClientInfo(); + this.beginRequestGpuInfo(); + this.refresh(); + } + + InfoView.prototype = { + __proto__: DivView.prototype, + + /** + * This function begins a request for the ClientInfo. If it comes back + * as undefined, then we will issue the request again in 250ms. + */ + beginRequestClientInfo : function() { + browserBridge.callAsync('requestClientInfo', undefined, (function(data) { + this.clientInfo_ = data; + this.refresh(); + if (data === undefined) { // try again in 250 ms + window.setTimeout(this.beginRequestClientInfo.bind(this), 250); + } + }).bind(this)); + }, + + /** + * This function begins a request for the GpuInfo. If it comes back + * as undefined, then we will issue the request again in 250ms. + */ + beginRequestGpuInfo : function() { + browserBridge.callAsync('requestGpuInfo', undefined, (function(data) { + this.gpuInfo_ = data; + this.refresh(); + if (!data || data.progress != 'complete') { // try again in 250 ms + window.setTimeout(this.beginRequestGpuInfo.bind(this), 250); + } + }).bind(this)); + }, + + /** + * Updates the view based on its currently known data + */ + refresh: function(data) { + // Client info + if (this.clientInfo_) { + var chromeVersion = this.clientInfo_.version + + ' (' + this.clientInfo_.official + + ' ' + this.clientInfo_.cl + + ') ' + this.clientInfo_.version_mod; + this.setTable_('client-info', [ + { + description: 'Data exported', + value: (new Date()).toLocaleString() + }, + { + description: 'Chrome version', + value: chromeVersion + }]); + } else { + this.setText_('client-info', '... loading...'); + } + + // GPU info, basic + if (this.gpuInfo_) { + this.setTable_('basic-info', this.gpuInfo_.basic_info); + if (this.gpuInfo_.diagnostics) { + this.setTable_('diagnostics', this.gpuInfo_.diagnostics); + } else if (this.gpuInfo_.progress == 'partial') { + this.setText_('diagnostics', '... loading...'); + } else { + this.setText_('diagnostics', 'None'); + } + } else { + this.setText_('basic-info', '... loading ...'); + this.setText_('diagnostics', '... loading ...'); + } + }, + + setText_: function(outputElementId, text) { + var peg = document.getElementById(outputElementId); + peg.innerText = text; + }, + + setTable_: function(outputElementId, inputData) { + var template = jstGetTemplate('info-view-table-template'); + jstProcess(new JsEvalContext({value: inputData}), + template); + + var peg = document.getElementById(outputElementId); + if (!peg) + throw new Error('Node ' + outputElementId + ' not found'); + + peg.innerHTML = ''; + peg.appendChild(template); + } + }; + + return { + InfoView: InfoView + }; +});
\ No newline at end of file diff --git a/chrome/browser/resources/net_internals/detailsview.js b/chrome/browser/resources/net_internals/detailsview.js index f9b532e..e3543d4 100644 --- a/chrome/browser/resources/net_internals/detailsview.js +++ b/chrome/browser/resources/net_internals/detailsview.js @@ -14,7 +14,7 @@ function DetailsView(tabHandlesContainerId, timelineTabId, logBoxId, timelineBoxId) { - TabSwitcherView.call(this, new DivView(tabHandlesContainerId)); + TabSwitcherView.call(this, tabHandlesContainerId); this.logView_ = new DetailsLogView(logBoxId); this.timelineView_ = new DetailsTimelineView(timelineBoxId); diff --git a/chrome/browser/resources/net_internals/index.html b/chrome/browser/resources/net_internals/index.html index d4ebeb7..732c4be 100644 --- a/chrome/browser/resources/net_internals/index.html +++ b/chrome/browser/resources/net_internals/index.html @@ -1,4 +1,5 @@ -<html> +<!DOCTYPE HTML> +<head i18n-values="dir:textdirection;"> <!-- Copyright (c) 2010 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be @@ -6,6 +7,7 @@ found in the LICENSE file. --> <head> <link rel="stylesheet" href="main.css"> + <link rel="stylesheet" href="tabswitcherview.css"> <script src="util.js"></script> <script src="view.js"></script> <script src="tabswitcherview.js"></script> diff --git a/chrome/browser/resources/net_internals/main.css b/chrome/browser/resources/net_internals/main.css index 1494d21..be3abee 100644 --- a/chrome/browser/resources/net_internals/main.css +++ b/chrome/browser/resources/net_internals/main.css @@ -147,54 +147,6 @@ body { font-size: 10px; } -#categoryTabHandles ul { - list-style: none; - padding: 0; - margin: 0; -} - -#categoryTabHandles { - border-bottom: 1px solid #555; - background: #aaa; - overflow: hidden; -} - -#categoryTabHandles li { - float: left; - margin-left: 5px; -} - -#categoryTabHandles a { - text-decoration: none; - text-align: center; - display: inline-block; - margin-top: 4px; - padding: 5px 10px 3px 10px; - border-top-right-radius: 8px; - border-top-left-radius: 8px; - background-clip: border-box; - background: #ccc; -} - -#categoryTabHandles a:hover { - background: #eee; -} - -#categoryTabHandles a:visited, -#categoryTabHandles a { - color: blue; -} - -#categoryTabHandles .selected { - background: white; -} - -#categoryTabHandles a.selected { - position:relative; - top: 3px; - color: black; -} - #detailsLogBox, #detailsTimelineBox, #httpCacheTabContent, diff --git a/chrome/browser/resources/net_internals/main.js b/chrome/browser/resources/net_internals/main.js index b85bc55..70a1b51 100644 --- a/chrome/browser/resources/net_internals/main.js +++ b/chrome/browser/resources/net_internals/main.js @@ -107,8 +107,7 @@ function onLoaded() { } // Create a view which lets you tab between the different sub-views. - var categoryTabSwitcher = - new TabSwitcherView(new DivView('categoryTabHandles')); + var categoryTabSwitcher = new TabSwitcherView('categoryTabHandles'); // Populate the main tabs. categoryTabSwitcher.addTab('eventsTab', eventsView, false); diff --git a/chrome/browser/resources/net_internals/tabswitcherview.css b/chrome/browser/resources/net_internals/tabswitcherview.css new file mode 100644 index 0000000..4b8fb50 --- /dev/null +++ b/chrome/browser/resources/net_internals/tabswitcherview.css @@ -0,0 +1,61 @@ +/* +Copyright (c) 2010 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. +*/ +.tab-switcher-view { + font-family: sans-serif; +} + +.tab-switcher-view ul { + list-style: none; + padding: 0; + margin: 0; +} + +.tab-switcher-view { + border-bottom: 1px solid #555; + background: #aaa; + overflow: hidden; +} + +.tab-switcher-view li { + float: left; + -webkit-margin-start: 5px; +} + +xhtml[dir=rtl] .tab-switcher-view li { + float: right; +} + +.tab-switcher-view a { + text-decoration: none; + text-align: center; + display: inline-block; + margin-top: 4px; + padding: 5px 10px 3px 10px; + border-top-right-radius: 8px; + border-top-left-radius: 8px; + background-clip: border-box; + background: #ccc; +} + +.tab-switcher-view a:hover { + background: #eee; +} + + +.tab-switcher-view a:visited, +.tab-switcher-view a { + color: blue; +} + +.tab-switcher-view .selected { + background: white; +} + +.tab-switcher-view a.selected { + position: relative; + top: 3px; + color: black; +}
\ No newline at end of file diff --git a/chrome/browser/resources/net_internals/tabswitcherview.js b/chrome/browser/resources/net_internals/tabswitcherview.js index 1e6843c..646c983 100644 --- a/chrome/browser/resources/net_internals/tabswitcherview.js +++ b/chrome/browser/resources/net_internals/tabswitcherview.js @@ -22,7 +22,10 @@ * * @constructor */ -function TabSwitcherView(tabHandleView) { +function TabSwitcherView(tabHandleDivId) { + document.getElementById(tabHandleDivId).classList.add('tab-switcher-view'); + var tabHandleView = new DivView(tabHandleDivId); + View.call(this); this.tabHandleView_ = tabHandleView; this.tabs_ = []; @@ -122,7 +125,8 @@ TabSwitcherView.prototype.switchToTab = function(id, params) { // Update data needed by newly active tab, as it may be // significantly out of date. - g_browser.checkForUpdatedInfo(); + if (typeof g_browser != 'undefined' && g_browser.checkForUpdatedInfo) + g_browser.checkForUpdatedInfo(); }; TabSwitcherView.prototype.getAllTabIds = function() { diff --git a/chrome/browser/resources/net_internals/view.js b/chrome/browser/resources/net_internals/view.js index bf76b4d..68f485e 100644 --- a/chrome/browser/resources/net_internals/view.js +++ b/chrome/browser/resources/net_internals/view.js @@ -80,6 +80,8 @@ function DivView(divId) { View.call(this); this.node_ = document.getElementById(divId); + if (!this.node_) + throw new Error('Element ' + divId + ' not found'); // Initialize the default values to those of the DIV. this.width_ = this.node_.offsetWidth; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 5a6fbb7..e64c1a0 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -885,6 +885,8 @@ 'browser/dom_ui/flags_ui.h', 'browser/dom_ui/foreign_session_handler.cc', 'browser/dom_ui/foreign_session_handler.h', + 'browser/dom_ui/gpu_internals_ui.cc', + 'browser/dom_ui/gpu_internals_ui.h', 'browser/dom_ui/history_ui.cc', 'browser/dom_ui/history_ui.h', 'browser/dom_ui/history2_ui.cc', diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index 7b5fe36..12ab2de 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc @@ -54,6 +54,7 @@ const char kAboutCrashURL[] = "about:crash"; const char kAboutCreditsURL[] = "about:credits"; const char kAboutDNSURL[] = "about:dns"; const char kAboutFlagsURL[] = "about:flags"; +const char kAboutGpuURL[] = "about:gpu"; const char kAboutGpuCrashURL[] = "about:gpucrash"; const char kAboutGpuHangURL[] = "about:gpuhang"; const char kAboutHangURL[] = "about:hang"; @@ -113,6 +114,7 @@ const char kChromeUIDownloadsHost[] = "downloads"; const char kChromeUIExtensionsHost[] = "extensions"; const char kChromeUIFavIconHost[] = "favicon"; const char kChromeUIFlagsHost[] = "flags"; +const char kChromeUIGpuInternalsHost[] = "gpu-internals"; const char kChromeUIHistoryHost[] = "history"; const char kChromeUIHistory2Host[] = "history2"; const char kChromeUIInspectorHost[] = "inspector"; @@ -159,6 +161,9 @@ const char kCloudPrintSetupHost[] = "cloudprintsetup"; const char kNetworkViewInternalsURL[] = "chrome://net-internals/"; const char kNetworkViewCacheURL[] = "chrome://view-http-cache/"; +// GPU sub pages +const char kGpuInternalsURL[] = "chrome://gpu-internals/"; + // Option sub pages. const char kAdvancedOptionsSubPage[] = "advanced"; const char kAutoFillSubPage[] = "autoFillOptions"; diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h index 3735d5e..9b7c519 100644 --- a/chrome/common/url_constants.h +++ b/chrome/common/url_constants.h @@ -47,6 +47,7 @@ extern const char kAboutCrashURL[]; extern const char kAboutCreditsURL[]; extern const char kAboutDNSURL[]; extern const char kAboutFlagsURL[]; +extern const char kAboutGpuURL[]; extern const char kAboutGpuCrashURL[]; extern const char kAboutGpuHangURL[]; extern const char kAboutHangURL[]; @@ -105,6 +106,7 @@ extern const char kChromeUIDownloadsHost[]; extern const char kChromeUIExtensionsHost[]; extern const char kChromeUIFavIconHost[]; extern const char kChromeUIFlagsHost[]; +extern const char kChromeUIGpuInternalsHost[]; extern const char kChromeUIHistory2Host[]; extern const char kChromeUIHistoryHost[]; extern const char kChromeUIKeyboardHost[]; @@ -155,6 +157,9 @@ extern const char kCloudPrintSetupHost[]; extern const char kNetworkViewCacheURL[]; extern const char kNetworkViewInternalsURL[]; +// GPU related URLs +extern const char kGpuInternalsURL[]; + // Options sub-pages. extern const char kAdvancedOptionsSubPage[]; extern const char kAutoFillSubPage[]; |