summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraboxhall@chromium.org <aboxhall@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-12 00:09:10 +0000
committeraboxhall@chromium.org <aboxhall@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-12 00:09:10 +0000
commita17df8e38de1dd7ecc68f3bdf7a9c87bb2410e16 (patch)
tree64ae44e814964de0596fc8b2ae9a41ed571de193
parentdab7720f282ec9d55f3a5eb56ee78a38e4a305c2 (diff)
downloadchromium_src-a17df8e38de1dd7ecc68f3bdf7a9c87bb2410e16.zip
chromium_src-a17df8e38de1dd7ecc68f3bdf7a9c87bb2410e16.tar.gz
chromium_src-a17df8e38de1dd7ecc68f3bdf7a9c87bb2410e16.tar.bz2
Adds a chrome://accessibility page, which:
Adds a toggle for global accessibility mode (on/off) For each renderer: - shows an accessibility mode toggle - if accessibility mode is On, shows a 'Show(/hide) accessibility tree' toggle, which shows(/hides) a text representation of the accessibility tree inline in the page. The accessibility tree may also be refreshed. BUG=178756 Review URL: https://chromiumcodereview.appspot.com/11791028 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@187417 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/autocomplete/builtin_provider_unittest.cc22
-rw-r--r--chrome/browser/browser_about_handler.cc1
-rw-r--r--content/browser/accessibility/accessibility_ui.cc282
-rw-r--r--content/browser/accessibility/accessibility_ui.h31
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.cc2
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.h7
-rw-r--r--content/browser/resources/accessibility/accessibility.css30
-rw-r--r--content/browser/resources/accessibility/accessibility.html25
-rw-r--r--content/browser/resources/accessibility/accessibility.js212
-rw-r--r--content/browser/webui/content_web_ui_controller_factory.cc6
-rw-r--r--content/content_browser.gypi2
-rw-r--r--content/content_resources.grd3
-rw-r--r--content/public/common/url_constants.cc1
-rw-r--r--content/public/common/url_constants.h1
14 files changed, 604 insertions, 21 deletions
diff --git a/chrome/browser/autocomplete/builtin_provider_unittest.cc b/chrome/browser/autocomplete/builtin_provider_unittest.cc
index 1d71131..0beaf29 100644
--- a/chrome/browser/autocomplete/builtin_provider_unittest.cc
+++ b/chrome/browser/autocomplete/builtin_provider_unittest.cc
@@ -143,8 +143,6 @@ TEST_F(BuiltinProviderTest, ChromeURLs) {
// This makes assumptions about the chrome URLs listed by the BuiltinProvider.
// Currently they are derived from ChromePaths() in browser_about_handler.cc.
- const string16 kHostA = ASCIIToUTF16(chrome::kChromeUIAppCacheInternalsHost);
- const GURL kURLA = GURL(kChrome + kSeparator3 + kHostA);
const string16 kHostM1 = ASCIIToUTF16(chrome::kChromeUIMediaInternalsHost);
const string16 kHostM2 = ASCIIToUTF16(chrome::kChromeUIMemoryHost);
const GURL kURLM1 = GURL(kChrome + kSeparator3 + kHostM1);
@@ -161,23 +159,7 @@ TEST_F(BuiltinProviderTest, ChromeURLs) {
{kChrome + kSeparator2 + ASCIIToUTF16("host"), 0, {}},
{kChrome + kSeparator3 + ASCIIToUTF16("host"), 0, {}},
- // Typing an about URL for a unique host should provide that full URL.
- {kAbout + kSeparator1 + kHostA.substr(0, 1), 1, {kURLA}},
- {kAbout + kSeparator2 + kHostA.substr(0, 2), 1, {kURLA}},
- {kAbout + kSeparator3 + kHostA.substr(0, kHostA.length() - 1), 1, {kURLA}},
- {kAbout + kSeparator1 + kHostA, 1, {kURLA}},
- {kAbout + kSeparator2 + kHostA, 1, {kURLA}},
- {kAbout + kSeparator3 + kHostA, 1, {kURLA}},
-
- // Typing a chrome URL for a unique host should provide that full URL.
- {kChrome + kSeparator1 + kHostA.substr(0, 1), 1, {kURLA}},
- {kChrome + kSeparator2 + kHostA.substr(0, 2), 1, {kURLA}},
- {kChrome + kSeparator3 + kHostA.substr(0, kHostA.length() - 1), 1, {kURLA}},
- {kChrome + kSeparator1 + kHostA, 1, {kURLA}},
- {kChrome + kSeparator2 + kHostA, 1, {kURLA}},
- {kChrome + kSeparator3 + kHostA, 1, {kURLA}},
-
- // Typing an about URL with a non-unique host should provide matching URLs.
+ // Typing an about URL should provide matching URLs.
{kAbout + kSeparator1 + kHostM1.substr(0, 1), 2, {kURLM1, kURLM2}},
{kAbout + kSeparator2 + kHostM1.substr(0, 2), 2, {kURLM1, kURLM2}},
{kAbout + kSeparator3 + kHostM1.substr(0, 3), 1, {kURLM1}},
@@ -185,7 +167,7 @@ TEST_F(BuiltinProviderTest, ChromeURLs) {
{kAbout + kSeparator3 + kHostM1, 1, {kURLM1}},
{kAbout + kSeparator2 + kHostM2, 1, {kURLM2}},
- // Typing a chrome URL with a non-unique host should provide matching URLs.
+ // Typing a chrome URL should provide matching URLs.
{kChrome + kSeparator1 + kHostM1.substr(0, 1), 2, {kURLM1, kURLM2}},
{kChrome + kSeparator2 + kHostM1.substr(0, 2), 2, {kURLM1, kURLM2}},
{kChrome + kSeparator3 + kHostM1.substr(0, 3), 1, {kURLM1}},
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index dcbd918..b09c624 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -21,6 +21,7 @@ namespace {
// Add paths here to be included in chrome://chrome-urls (about:about).
// These paths will also be suggested by BuiltinProvider.
const char* const kPaths[] = {
+ chrome::kChromeUIAccessibilityHost,
chrome::kChromeUIAppCacheInternalsHost,
chrome::kChromeUIBlobInternalsHost,
chrome::kChromeUICacheHost,
diff --git a/content/browser/accessibility/accessibility_ui.cc b/content/browser/accessibility/accessibility_ui.cc
new file mode 100644
index 0000000..9307e9a
--- /dev/null
+++ b/content/browser/accessibility/accessibility_ui.cc
@@ -0,0 +1,282 @@
+// Copyright (c) 2013 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 "content/browser/accessibility/accessibility_ui.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/json/json_writer.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "content/browser/accessibility/accessibility_tree_formatter.h"
+#include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "content/browser/accessibility/browser_accessibility_state_impl.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/common/view_message_enums.h"
+#include "content/port/browser/render_widget_host_view_port.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/favicon_status.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "content/public/common/url_constants.h"
+#include "grit/content_resources.h"
+#include "net/base/escape.h"
+
+using base::FundamentalValue;
+using base::ListValue;
+
+static const char kDataFile[] = "targets-data.json";
+
+static const char kProcessIdField[] = "processId";
+static const char kRouteIdField[] = "routeId";
+static const char kUrlField[] = "url";
+static const char kNameField[] = "name";
+static const char kFaviconUrlField[] = "favicon_url";
+static const char kPidField[] = "pid";
+static const char kAccessibilityModeField[] = "a11y_mode";
+
+namespace content {
+
+namespace {
+
+DictionaryValue* BuildTargetDescriptor(
+ const GURL& url,
+ const std::string& name,
+ const GURL& favicon_url,
+ int process_id,
+ int route_id,
+ AccessibilityMode accessibility_mode,
+ base::ProcessHandle handle = base::kNullProcessHandle) {
+ DictionaryValue* target_data = new DictionaryValue();
+ target_data->SetInteger(kProcessIdField, process_id);
+ target_data->SetInteger(kRouteIdField, route_id);
+ target_data->SetString(kUrlField, url.spec());
+ target_data->SetString(kNameField, net::EscapeForHTML(name));
+ target_data->SetInteger(kPidField, base::GetProcId(handle));
+ target_data->SetString(kFaviconUrlField, favicon_url.spec());
+ target_data->SetInteger(kAccessibilityModeField,
+ accessibility_mode);
+ return target_data;
+}
+
+DictionaryValue* BuildTargetDescriptor(RenderViewHost* rvh) {
+ WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
+ std::string title;
+ RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(rvh);
+ AccessibilityMode accessibility_mode = rwhi->accessibility_mode();
+
+ GURL url;
+ GURL favicon_url;
+ if (web_contents) {
+ url = web_contents->GetURL();
+ title = UTF16ToUTF8(web_contents->GetTitle());
+ NavigationController& controller = web_contents->GetController();
+ NavigationEntry* entry = controller.GetActiveEntry();
+ if (entry != NULL && entry->GetURL().is_valid())
+ favicon_url = entry->GetFavicon().url;
+ }
+
+ return BuildTargetDescriptor(url,
+ title,
+ favicon_url,
+ rvh->GetProcess()->GetID(),
+ rvh->GetRoutingID(),
+ accessibility_mode);
+}
+
+void SendTargetsData(
+ const WebUIDataSource::GotDataCallback& callback) {
+ scoped_ptr<ListValue> rvh_list(new ListValue());
+
+ for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
+ !it.IsAtEnd(); it.Advance()) {
+ RenderProcessHost* render_process_host = it.GetCurrentValue();
+ DCHECK(render_process_host);
+
+ // Ignore processes that don't have a connection, such as crashed tabs.
+ if (!render_process_host->HasConnection())
+ continue;
+
+ RenderProcessHost::RenderWidgetHostsIterator rwh_it(
+ render_process_host->GetRenderWidgetHostsIterator());
+ for (; !rwh_it.IsAtEnd(); rwh_it.Advance()) {
+ const RenderWidgetHost* rwh = rwh_it.GetCurrentValue();
+ DCHECK(rwh);
+ if (!rwh || !rwh->IsRenderView())
+ continue;
+
+ RenderViewHost* rvh =
+ RenderViewHost::From(const_cast<RenderWidgetHost*>(rwh));
+
+ rvh_list->Append(BuildTargetDescriptor(rvh));
+ }
+ }
+
+ scoped_ptr<DictionaryValue> data(new DictionaryValue());
+ data->Set("list", rvh_list.release());
+ scoped_ptr<FundamentalValue> a11y_mode(new FundamentalValue(
+ BrowserAccessibilityStateImpl::GetInstance()->GetAccessibilityMode()));
+ data->Set("global_a11y_mode", a11y_mode.release());
+
+ std::string json_string;
+ base::JSONWriter::Write(data.get(), &json_string);
+
+ callback.Run(base::RefCountedString::TakeString(&json_string));
+}
+
+bool HandleRequestCallback(
+ const std::string& path,
+ const WebUIDataSource::GotDataCallback& callback) {
+ if (path != kDataFile)
+ return false;
+
+ SendTargetsData(callback);
+ return true;
+}
+
+} // namespace
+
+AccessibilityUI::AccessibilityUI(WebUI* web_ui)
+ : WebUIController(web_ui) {
+ // Set up the chrome://accessibility source.
+ WebUIDataSource* html_source =
+ WebUIDataSource::Create(chrome::kChromeUIAccessibilityHost);
+ html_source->SetUseJsonJSFormatV2();
+
+ web_ui->RegisterMessageCallback(
+ "toggleAccessibility",
+ base::Bind(&AccessibilityUI::ToggleAccessibility,
+ base::Unretained(this)));
+ web_ui->RegisterMessageCallback(
+ "toggleGlobalAccessibility",
+ base::Bind(&AccessibilityUI::ToggleGlobalAccessibility,
+ base::Unretained(this)));
+ web_ui->RegisterMessageCallback(
+ "requestAccessibilityTree",
+ base::Bind(&AccessibilityUI::RequestAccessibilityTree,
+ base::Unretained(this)));
+
+ // Add required resources.
+ html_source->SetJsonPath("strings.js");
+ html_source->AddResourcePath("accessibility.css", IDR_ACCESSIBILITY_CSS);
+ html_source->AddResourcePath("accessibility.js", IDR_ACCESSIBILITY_JS);
+ html_source->SetDefaultResource(IDR_ACCESSIBILITY_HTML);
+ html_source->SetRequestFilter(base::Bind(&HandleRequestCallback));
+
+ BrowserContext* browser_context =
+ web_ui->GetWebContents()->GetBrowserContext();
+ WebUIDataSource::Add(browser_context, html_source);
+}
+
+AccessibilityUI::~AccessibilityUI() {
+}
+
+void AccessibilityUI::ToggleAccessibility(const base::ListValue* args) {
+ std::string process_id_str;
+ std::string route_id_str;
+ int process_id;
+ int route_id;
+ CHECK(args->GetSize() == 2);
+ CHECK(args->GetString(0, &process_id_str));
+ CHECK(args->GetString(1, &route_id_str));
+ CHECK(base::StringToInt(process_id_str,
+ &process_id));
+ CHECK(base::StringToInt(route_id_str, &route_id));
+
+ RenderViewHost* rvh = RenderViewHost::FromID(process_id, route_id);
+ if (!rvh)
+ return;
+ RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(rvh);
+ if (!rwhi)
+ return;
+ AccessibilityMode mode = rwhi->accessibility_mode();
+ if (mode == AccessibilityModeOff)
+ rwhi->SetAccessibilityMode(AccessibilityModeComplete);
+ else
+ rwhi->SetAccessibilityMode(AccessibilityModeOff);
+}
+
+void AccessibilityUI::ToggleGlobalAccessibility(const base::ListValue* args) {
+ BrowserAccessibilityStateImpl* state =
+ BrowserAccessibilityStateImpl::GetInstance();
+ AccessibilityMode mode = state->GetAccessibilityMode();
+ AccessibilityMode new_mode = (mode == AccessibilityModeOff
+ ? AccessibilityModeComplete
+ : AccessibilityModeOff);
+ state->SetAccessibilityMode(new_mode);
+ for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
+ !it.IsAtEnd(); it.Advance()) {
+ RenderProcessHost* render_process_host = it.GetCurrentValue();
+ DCHECK(render_process_host);
+
+ // Ignore processes that don't have a connection, such as crashed tabs.
+ if (!render_process_host->HasConnection())
+ continue;
+
+ RenderProcessHost::RenderWidgetHostsIterator rwit(
+ render_process_host->GetRenderWidgetHostsIterator());
+ for (; !rwit.IsAtEnd(); rwit.Advance()) {
+ RenderWidgetHost* rwh = const_cast<RenderWidgetHost*>(
+ rwit.GetCurrentValue());
+ DCHECK(rwh);
+ if (!rwh || !rwh->IsRenderView())
+ continue;
+ RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(rwh);
+ rwhi->SetAccessibilityMode(new_mode);
+ }
+ }
+}
+
+void AccessibilityUI::RequestAccessibilityTree(const base::ListValue* args) {
+ std::string process_id_str;
+ std::string route_id_str;
+ int process_id;
+ int route_id;
+ CHECK(args->GetSize() == 2);
+ CHECK(args->GetString(0, &process_id_str));
+ CHECK(args->GetString(1, &route_id_str));
+ CHECK(base::StringToInt(process_id_str, &process_id));
+ CHECK(base::StringToInt(route_id_str, &route_id));
+
+ RenderViewHost* rvh = RenderViewHost::FromID(process_id, route_id);
+ if (!rvh) {
+ scoped_ptr<DictionaryValue> result(new DictionaryValue());
+ result->SetInteger(kProcessIdField, process_id);
+ result->SetInteger(kRouteIdField, route_id);
+ result->Set("error", new StringValue("Renderer no longer exists."));
+ web_ui()->CallJavascriptFunction("accessibility.showTree", *(result.get()));
+ return;
+ }
+
+ scoped_ptr<DictionaryValue> result(BuildTargetDescriptor(rvh));
+ RenderWidgetHostViewPort* host_view = static_cast<RenderWidgetHostViewPort*>(
+ WebContents::FromRenderViewHost(rvh)->GetRenderWidgetHostView());
+ if (!host_view) {
+ result->Set("error", new StringValue("Could not get accessibility tree."));
+ web_ui()->CallJavascriptFunction("accessibility.showTree", *(result.get()));
+ return;
+ }
+ scoped_ptr<AccessibilityTreeFormatter> formatter(
+ AccessibilityTreeFormatter::Create(rvh));
+ string16 accessibility_contents_utf16;
+ BrowserAccessibilityManager* manager =
+ host_view->GetBrowserAccessibilityManager();
+ if (!manager) {
+ result->Set("error", new StringValue("Could not get accessibility tree."));
+ web_ui()->CallJavascriptFunction("accessibility.showTree", *(result.get()));
+ return;
+ }
+ formatter->FormatAccessibilityTree(&accessibility_contents_utf16);
+
+ result->Set("tree",
+ new StringValue(UTF16ToUTF8(accessibility_contents_utf16)));
+ web_ui()->CallJavascriptFunction("accessibility.showTree", *(result.get()));
+}
+
+} // namespace content
diff --git a/content/browser/accessibility/accessibility_ui.h b/content/browser/accessibility/accessibility_ui.h
new file mode 100644
index 0000000..1b239f8
--- /dev/null
+++ b/content/browser/accessibility/accessibility_ui.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2013 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_UI_WEBUI_ACCESSIBILITY_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_ACCESSIBILITY_UI_H_
+
+#include "content/public/browser/web_ui_controller.h"
+
+namespace base {
+ class ListValue;
+} // namespace base
+
+namespace content {
+
+class AccessibilityUI : public WebUIController {
+ public:
+ explicit AccessibilityUI(WebUI* web_ui);
+ virtual ~AccessibilityUI();
+
+ private:
+ void ToggleAccessibility(const base::ListValue* args);
+ void ToggleGlobalAccessibility(const base::ListValue* args);
+ void RequestAccessibilityTree(const base::ListValue* args);
+
+ DISALLOW_COPY_AND_ASSIGN(AccessibilityUI);
+};
+
+} // namespace content
+
+#endif // CHROME_BROWSER_UI_WEBUI_ACCESSIBILITY_UI_H_
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 176784c..716227a 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -148,6 +148,7 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
waiting_for_screen_rects_ack_(false),
mouse_move_pending_(false),
mouse_wheel_pending_(false),
+ accessibility_mode_(AccessibilityModeOff),
select_range_pending_(false),
move_caret_pending_(false),
needs_repainting_on_restore_(false),
@@ -2217,6 +2218,7 @@ void RenderWidgetHostImpl::SetEditCommandsForNextKeyEvent(
}
void RenderWidgetHostImpl::SetAccessibilityMode(AccessibilityMode mode) {
+ accessibility_mode_ = mode;
Send(new ViewMsg_SetAccessibilityMode(routing_id_, mode));
}
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 61d8bfd..9485aa8 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -328,6 +328,11 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost,
void SetEditCommandsForNextKeyEvent(
const std::vector<EditCommand>& commands);
+ // Gets the accessibility mode.
+ AccessibilityMode accessibility_mode() const {
+ return accessibility_mode_;
+ }
+
// Send a message to the renderer process to change the accessibility mode.
void SetAccessibilityMode(AccessibilityMode mode);
@@ -738,6 +743,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost,
// would be queued) results in very slow scrolling.
WheelEventQueue coalesced_mouse_wheel_events_;
+ AccessibilityMode accessibility_mode_;
+
// (Similar to |mouse_move_pending_|.) True while waiting for SelectRange_ACK.
bool select_range_pending_;
diff --git a/content/browser/resources/accessibility/accessibility.css b/content/browser/resources/accessibility/accessibility.css
new file mode 100644
index 0000000..e00a922
--- /dev/null
+++ b/content/browser/resources/accessibility/accessibility.css
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013 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.
+ */
+
+body {
+ font-family: Arial, sans-serif;
+ font-size: 12px;
+ margin: 10px;
+ min-width: 47em;
+ padding-bottom: 65px;
+}
+
+img {
+ float: left;
+ height: 16px;
+ padding-right: 5px;
+ width: 16px;
+}
+
+.row {
+ border-bottom: 1px solid #A0A0A0;
+ padding: 5px;
+}
+
+.url {
+ color: #A0A0A0;
+}
+
diff --git a/content/browser/resources/accessibility/accessibility.html b/content/browser/resources/accessibility/accessibility.html
new file mode 100644
index 0000000..c1a2d8d
--- /dev/null
+++ b/content/browser/resources/accessibility/accessibility.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Copyright (c) 2013 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>
+ <meta charset="utf-8">
+ <title>Accessibility</title>
+ <link rel="stylesheet" href="accessibility.css">
+ <script src="chrome://resources/js/cr.js"></script>
+ <script src="chrome://resources/js/load_time_data.js"></script>
+ <script src="chrome://resources/js/util.js"></script>
+ <script src="strings.js"></script>
+ <script src="accessibility.js"></script>
+</head>
+<body>
+ <h1>Accessibility</h1>
+ <div id="global" class="row">Global accessibility mode:
+ <a id="toggle_global" href="#"></a></div>
+ <div id="pages" class="list"></div>
+ <script src="chrome://resources/js/i18n_template2.js"></script>
+</body>
+</html>
diff --git a/content/browser/resources/accessibility/accessibility.js b/content/browser/resources/accessibility/accessibility.js
new file mode 100644
index 0000000..5d98b48
--- /dev/null
+++ b/content/browser/resources/accessibility/accessibility.js
@@ -0,0 +1,212 @@
+// Copyright (c) 2013 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('accessibility', function() {
+ 'use strict';
+
+ function requestData() {
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', 'targets-data.json', false);
+ xhr.send(null);
+ if (xhr.status === 200) {
+ console.log(xhr.responseText);
+ return JSON.parse(xhr.responseText);
+ }
+ return [];
+ }
+
+ // TODO(aboxhall): add a mechanism to request individual and global a11y
+ // mode, xhr them on toggle... or just re-requestData and be smarter about
+ // ID-ing rows?
+
+ function toggleAccessibility(data, element) {
+ chrome.send('toggleAccessibility',
+ [String(data.processId), String(data.routeId)]);
+ var a11y_was_on = (element.textContent.match(/on/) != null);
+ element.textContent = ' accessibility ' + (a11y_was_on ? ' off' : ' on');
+ var row = element.parentElement;
+ if (a11y_was_on) {
+ while (row.lastChild != element)
+ row.removeChild(row.lastChild);
+ } else {
+ row.appendChild(document.createTextNode(' | '));
+ row.appendChild(createShowAccessibilityTreeElement(data, row, false));
+ }
+ }
+
+ function requestAccessibilityTree(data, element) {
+ chrome.send('requestAccessibilityTree',
+ [String(data.processId), String(data.routeId)]);
+ }
+
+ function toggleGlobalAccessibility() {
+ chrome.send('toggleGlobalAccessibility');
+ document.location.reload(); // FIXME see TODO above
+ }
+
+ function initialize() {
+ console.log('initialize');
+ var data = requestData();
+
+ addGlobalAccessibilityModeToggle(data['global_a11y_mode']);
+
+ $('pages').textContent = '';
+
+ var list = data['list'];
+ for (var i = 0; i < list.length; i++) {
+ addToPagesList(list[i]);
+ }
+ }
+
+ function addGlobalAccessibilityModeToggle(global_a11y_mode) {
+ $('toggle_global').textContent = (global_a11y_mode == 0 ? 'off' : 'on');
+ $('toggle_global').addEventListener('click',
+ toggleGlobalAccessibility);
+ }
+
+ function addToPagesList(data) {
+ // TODO: iterate through data and pages rows instead
+ var id = data['processId'] + '.' + data['routeId'];
+ var row = document.createElement('div');
+ row.className = 'row';
+ row.id = id;
+ formatRow(row, data);
+
+ row.processId = data.processId;
+ row.routeId = data.routeId;
+
+ var list = $('pages');
+ list.appendChild(row);
+ }
+
+ function formatRow(row, data) {
+ if (!('url' in data)) {
+ if ('error' in data) {
+ row.appendChild(createErrorMessageElement(data, row));
+ return;
+ }
+ }
+ var properties = ['favicon_url', 'name', 'url'];
+ for (var j = 0; j < properties.length; j++)
+ row.appendChild(formatValue(data, properties[j]));
+
+ row.appendChild(createToggleAccessibilityElement(data));
+ if (data['a11y_mode'] != 0) {
+ row.appendChild(document.createTextNode(' | '));
+ if ('tree' in data) {
+ row.appendChild(createShowAccessibilityTreeElement(data, row, true));
+ row.appendChild(document.createTextNode(' | '));
+ row.appendChild(createHideAccessibilityTreeElement(row.id));
+ row.appendChild(createAccessibilityTreeElement(data));
+ }
+ else {
+ row.appendChild(createShowAccessibilityTreeElement(data, row, false));
+ if ('error' in data)
+ row.appendChild(createErrorMessageElement(data, row));
+ }
+ }
+ }
+
+ function formatValue(data, property) {
+ var value = data[property];
+
+ if (property == 'favicon_url') {
+ var faviconElement = document.createElement('img');
+ if (value)
+ faviconElement.src = value;
+ faviconElement.alt = "";
+ return faviconElement;
+ }
+
+ var text = value ? String(value) : '';
+ if (text.length > 100)
+ text = text.substring(0, 100) + '\u2026'; // ellipsis
+
+ var span = document.createElement('span');
+ span.textContent = ' ' + text + ' ';
+ span.className = property;
+ return span;
+ }
+
+ function createToggleAccessibilityElement(data) {
+ var link = document.createElement('a');
+ link.setAttribute('href', '#');
+ var a11y_mode = data['a11y_mode'];
+ link.textContent = 'accessibility ' + (a11y_mode == 0 ? 'off' : 'on');
+ link.addEventListener('click',
+ toggleAccessibility.bind(this, data, link));
+ return link;
+ }
+
+ function createShowAccessibilityTreeElement(data, row, opt_refresh) {
+ var link = document.createElement('a');
+ link.setAttribute('href', '#');
+ if (opt_refresh)
+ link.textContent = 'refresh accessibility tree';
+ else
+ link.textContent = 'show accessibility tree';
+ link.id = row.id + ':showTree';
+ link.addEventListener('click',
+ requestAccessibilityTree.bind(this, data, link));
+ return link;
+ }
+
+ function createHideAccessibilityTreeElement(id) {
+ var link = document.createElement('a');
+ link.setAttribute('href', '#');
+ link.textContent = 'hide accessibility tree';
+ link.addEventListener('click',
+ function() {
+ $(id + ':showTree').textContent = 'show accessibility tree';
+ var existingTreeElements = $(id).getElementsByTagName('pre');
+ for (var i = 0; i < existingTreeElements.length; i++)
+ $(id).removeChild(existingTreeElements[i]);
+ var row = $(id);
+ while (row.lastChild != $(id + ':showTree'))
+ row.removeChild(row.lastChild);
+ });
+ return link;
+ }
+
+ function createErrorMessageElement(data) {
+ var errorMessageElement = document.createElement('div');
+ var errorMessage = data.error;
+ errorMessageElement.innerHTML = errorMessage + '&nbsp;';
+ var closeLink = document.createElement('a');
+ closeLink.href='#';
+ closeLink.textContent = '[close]';
+ closeLink.addEventListener('click', function() {
+ var parentElement = errorMessageElement.parentElement;
+ parentElement.removeChild(errorMessageElement);
+ if (parentElement.childElementCount == 0)
+ parentElement.parentElement.removeChild(parentElement);
+ });
+ errorMessageElement.appendChild(closeLink);
+ return errorMessageElement;
+ }
+
+ function showTree(data) {
+ var id = data.processId + '.' + data.routeId;
+ var row = $(id);
+ if (!row)
+ return;
+
+ row.textContent = '';
+ formatRow(row, data);
+ }
+
+ function createAccessibilityTreeElement(data) {
+ var treeElement = document.createElement('pre');
+ var tree = data.tree;
+ treeElement.textContent = tree;
+ return treeElement;
+ }
+
+ return {
+ initialize: initialize,
+ showTree: showTree
+ };
+});
+
+document.addEventListener('DOMContentLoaded', accessibility.initialize);
diff --git a/content/browser/webui/content_web_ui_controller_factory.cc b/content/browser/webui/content_web_ui_controller_factory.cc
index 38a5de4..7f486d8 100644
--- a/content/browser/webui/content_web_ui_controller_factory.cc
+++ b/content/browser/webui/content_web_ui_controller_factory.cc
@@ -4,6 +4,7 @@
#include "content/browser/webui/content_web_ui_controller_factory.h"
+#include "content/browser/accessibility/accessibility_ui.h"
#include "content/browser/gpu/gpu_internals_ui.h"
#include "content/browser/media/media_internals_ui.h"
#include "content/browser/media/webrtc_internals_ui.h"
@@ -21,7 +22,8 @@ WebUI::TypeID ContentWebUIControllerFactory::GetWebUIType(
url.host() == chrome::kChromeUITracingHost ||
#endif
url.host() == chrome::kChromeUIGpuHost ||
- url.host() == chrome::kChromeUIMediaInternalsHost) {
+ url.host() == chrome::kChromeUIMediaInternalsHost ||
+ url.host() == chrome::kChromeUIAccessibilityHost) {
return const_cast<ContentWebUIControllerFactory*>(this);
}
return WebUI::kNoWebUI;
@@ -45,6 +47,8 @@ WebUIController* ContentWebUIControllerFactory::CreateWebUIControllerForURL(
return new GpuInternalsUI(web_ui);
if (url.host() == chrome::kChromeUIMediaInternalsHost)
return new MediaInternalsUI(web_ui);
+ if (url.host() == chrome::kChromeUIAccessibilityHost)
+ return new AccessibilityUI(web_ui);
#if !defined(OS_ANDROID)
if (url.host() == chrome::kChromeUITracingHost)
return new TracingUI(web_ui);
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 733a0ba..5cf5a91 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -186,6 +186,8 @@
'browser/accessibility/accessibility_tree_formatter_utils_win.cc',
'browser/accessibility/accessibility_tree_formatter_utils_win.h',
'browser/accessibility/accessibility_tree_formatter_win.cc',
+ 'browser/accessibility/accessibility_ui.cc',
+ 'browser/accessibility/accessibility_ui.h',
'browser/accessibility/browser_accessibility.cc',
'browser/accessibility/browser_accessibility.h',
'browser/accessibility/browser_accessibility_cocoa.h',
diff --git a/content/content_resources.grd b/content/content_resources.grd
index 04ebe89..83b0cb4 100644
--- a/content/content_resources.grd
+++ b/content/content_resources.grd
@@ -11,6 +11,9 @@
<translations />
<release seq="1">
<includes>
+ <include name="IDR_ACCESSIBILITY_HTML" file="browser/resources/accessibility/accessibility.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+ <include name="IDR_ACCESSIBILITY_CSS" file="browser/resources/accessibility/accessibility.css" type="BINDATA" />
+ <include name="IDR_ACCESSIBILITY_JS" file="browser/resources/accessibility/accessibility.js" flattenhtml="true" type="BINDATA" />
<include name="IDR_GPU_BLACKLIST" file="browser/gpu/software_rendering_list.json" type="BINDATA" />
<include name="IDR_GPU_INTERNALS_HTML" file="browser/resources/gpu/gpu_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
<include name="IDR_GPU_INTERNALS_JS" file="browser/resources/gpu/gpu_internals.js" flattenhtml="true" type="BINDATA" />
diff --git a/content/public/common/url_constants.cc b/content/public/common/url_constants.cc
index 057545c..40b3b03 100644
--- a/content/public/common/url_constants.cc
+++ b/content/public/common/url_constants.cc
@@ -33,6 +33,7 @@ const char kViewSourceScheme[] = "view-source";
const char kAboutBlankURL[] = "about:blank";
const char kAboutSrcDocURL[] = "about:srcdoc";
const char kChromeUIAppCacheInternalsHost[] = "appcache-internals";
+const char kChromeUIAccessibilityHost[] = "accessibility";
const char kChromeUIBlobInternalsHost[] = "blob-internals";
const char kChromeUIBrowserCrashHost[] = "inducebrowsercrashforrealz";
const char kChromeUIDevToolsHost[] = "devtools";
diff --git a/content/public/common/url_constants.h b/content/public/common/url_constants.h
index ece09e65..ef45d26 100644
--- a/content/public/common/url_constants.h
+++ b/content/public/common/url_constants.h
@@ -39,6 +39,7 @@ CONTENT_EXPORT extern const char kViewSourceScheme[];
// Hosts for about URLs.
CONTENT_EXPORT extern const char kAboutBlankURL[];
CONTENT_EXPORT extern const char kAboutSrcDocURL[];
+CONTENT_EXPORT extern const char kChromeUIAccessibilityHost[];
CONTENT_EXPORT extern const char kChromeUIAppCacheInternalsHost[];
CONTENT_EXPORT extern const char kChromeUIBlobInternalsHost[];
CONTENT_EXPORT extern const char kChromeUIBrowserCrashHost[];