summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/browser_about_handler.cc113
-rw-r--r--chrome/browser/browser_about_handler_unittest.cc6
-rw-r--r--chrome/browser/browser_resources.grd1
-rw-r--r--chrome/browser/dom_ui/dom_ui_factory.cc3
-rw-r--r--chrome/browser/dom_ui/gpu_internals_ui.cc350
-rw-r--r--chrome/browser/dom_ui/gpu_internals_ui.h20
-rw-r--r--chrome/browser/dom_ui/net_internals_ui.cc23
-rw-r--r--chrome/browser/resources/gpu_internals.html91
-rw-r--r--chrome/browser/resources/gpu_internals/browser_bridge.js59
-rw-r--r--chrome/browser/resources/gpu_internals/info_view.css28
-rw-r--r--chrome/browser/resources/gpu_internals/info_view.html34
-rw-r--r--chrome/browser/resources/gpu_internals/info_view.js119
-rw-r--r--chrome/browser/resources/net_internals/detailsview.js2
-rw-r--r--chrome/browser/resources/net_internals/index.html4
-rw-r--r--chrome/browser/resources/net_internals/main.css48
-rw-r--r--chrome/browser/resources/net_internals/main.js3
-rw-r--r--chrome/browser/resources/net_internals/tabswitcherview.css61
-rw-r--r--chrome/browser/resources/net_internals/tabswitcherview.js8
-rw-r--r--chrome/browser/resources/net_internals/view.js2
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/common/url_constants.cc5
-rw-r--r--chrome/common/url_constants.h5
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[];