diff options
author | zork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-07 00:39:41 +0000 |
---|---|---|
committer | zork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-07 00:39:41 +0000 |
commit | 2ee0e7564803f87b195d63c497a1101a2b29ab4f (patch) | |
tree | 0795001761a54463b710c58799cc41655dd842c0 /webkit | |
parent | 3a51cfdd1775075f13dab50f6d8a9cb04bd6beb9 (diff) | |
download | chromium_src-2ee0e7564803f87b195d63c497a1101a2b29ab4f.zip chromium_src-2ee0e7564803f87b195d63c497a1101a2b29ab4f.tar.gz chromium_src-2ee0e7564803f87b195d63c497a1101a2b29ab4f.tar.bz2 |
Revert 46567 - Reimplement accessibility of web content by caching the entire
accessibility tree in the browser process.
Adds new RPCs for a browser tab to request accessibility info from
a renderer; the renderer responds with a complete tree of
accessibility metadata for the entire DOM, which is then cached
in the RenderWidgetHostView. This part is crossplatform and will
help with accessibility on both Windows and Mac OS X.
For Windows, MSAA support for web content has been rewritten to
use this new cache. Tested in JAWS and NVDA screen readers.
Using Chrome with a screen reader is now fast and stable,
unlike the previous implementation. However, note that most
advanced functionality is still not supported, and much work remains
to make Chrome work well with a screen reader. This is a necessary
step to improve stability first.
BUG=25564
BUG=13291
TEST=See http://codereview.chromium.org/1806001
Review URL: http://codereview.chromium.org/1637018
TBR=dmazzoni@chromium.org
Review URL: http://codereview.chromium.org/2031004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46642 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/glue/webaccessibility.cc | 253 | ||||
-rw-r--r-- | webkit/glue/webaccessibility.h | 158 | ||||
-rw-r--r-- | webkit/glue/webaccessibilitymanager.h | 62 | ||||
-rw-r--r-- | webkit/glue/webkit_glue.gypi | 4 |
4 files changed, 387 insertions, 90 deletions
diff --git a/webkit/glue/webaccessibility.cc b/webkit/glue/webaccessibility.cc index 33232ca..1af91d6 100644 --- a/webkit/glue/webaccessibility.cc +++ b/webkit/glue/webaccessibility.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2008 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. @@ -7,11 +7,16 @@ #include "third_party/WebKit/WebKit/chromium/public/WebAccessibilityCache.h" #include "third_party/WebKit/WebKit/chromium/public/WebAccessibilityObject.h" #include "third_party/WebKit/WebKit/chromium/public/WebAccessibilityRole.h" +#include "third_party/WebKit/WebKit/chromium/public/WebPoint.h" +#include "third_party/WebKit/WebKit/chromium/public/WebRect.h" #include "third_party/WebKit/WebKit/chromium/public/WebString.h" using WebKit::WebAccessibilityCache; using WebKit::WebAccessibilityRole; using WebKit::WebAccessibilityObject; +using WebKit::WebPoint; +using WebKit::WebRect; +using WebKit::WebString; namespace webkit_glue { @@ -96,82 +101,240 @@ WebAccessibility::Role ConvertRole(WebKit::WebAccessibilityRole role) { } } -uint32 ConvertState(const WebAccessibilityObject& o) { - uint32 state = 0; +long ConvertState(const WebAccessibilityObject& o) { + long state = 0; if (o.isChecked()) - state |= (1 << WebAccessibility::STATE_CHECKED); + state |= static_cast<long>(1 << WebAccessibility::STATE_CHECKED); if (o.canSetFocusAttribute()) - state |= (1 << WebAccessibility::STATE_FOCUSABLE); + state |= static_cast<long>(1 << WebAccessibility::STATE_FOCUSABLE); if (o.isFocused()) - state |= (1 << WebAccessibility::STATE_FOCUSED); + state |= static_cast<long>(1 << WebAccessibility::STATE_FOCUSED); if (o.isHovered()) - state |= (1 << WebAccessibility::STATE_HOTTRACKED); + state |= static_cast<long>(1 << WebAccessibility::STATE_HOTTRACKED); if (o.isIndeterminate()) - state |= (1 << WebAccessibility::STATE_INDETERMINATE); + state |= static_cast<long>(1 << WebAccessibility::STATE_INDETERMINATE); if (o.isAnchor()) - state |= (1 << WebAccessibility::STATE_LINKED); + state |= static_cast<long>(1 << WebAccessibility::STATE_LINKED); if (o.isMultiSelectable()) - state |= (1 << WebAccessibility::STATE_MULTISELECTABLE); + state |= static_cast<long>(1 << WebAccessibility::STATE_MULTISELECTABLE); if (o.isOffScreen()) - state |= (1 << WebAccessibility::STATE_OFFSCREEN); + state |= static_cast<long>(1 << WebAccessibility::STATE_OFFSCREEN); if (o.isPressed()) - state |= (1 << WebAccessibility::STATE_PRESSED); + state |= static_cast<long>(1 << WebAccessibility::STATE_PRESSED); if (o.isPasswordField()) - state |= (1 << WebAccessibility::STATE_PROTECTED); + state |= static_cast<long>(1 << WebAccessibility::STATE_PROTECTED); if (o.isReadOnly()) - state |= (1 << WebAccessibility::STATE_READONLY); + state |= static_cast<long>(1 << WebAccessibility::STATE_READONLY); if (o.isVisited()) - state |= (1 << WebAccessibility::STATE_TRAVERSED); + state |= static_cast<long>(1 << WebAccessibility::STATE_TRAVERSED); if (!o.isEnabled()) - state |= (1 << WebAccessibility::STATE_UNAVAILABLE); + state |= static_cast<long>(1 << WebAccessibility::STATE_UNAVAILABLE); return state; } -WebAccessibility::WebAccessibility() - : id(-1), - role(ROLE_NONE), - state(-1) { -} +int32 WebAccessibility::GetAccObjInfo(WebAccessibilityCache* cache, + const WebAccessibility::InParams& in_params, + WebAccessibility::OutParams* out_params) { + // Find object requested by |object_id|. + WebAccessibilityObject active_acc_obj; -WebAccessibility::WebAccessibility(const WebKit::WebAccessibilityObject& src, - WebKit::WebAccessibilityCache* cache) { - Init(src, cache); -} + // Since ids assigned by Chrome starts at 1000, whereas platform-specific ids + // used to reference a child will be in a wholly different range, we know + // that any id that high should be treated as a non-direct descendant. + bool local_child = false; + if (cache->isValidId(in_params.child_id)) { + // Object is not a direct child, re-map the input parameters accordingly. + // The object to be retrieved is referred to by the |in_params.child_id|, as + // a result of e.g. a focus event. + active_acc_obj = cache->getObjectById(in_params.child_id); + } else { + local_child = true; + + active_acc_obj = cache->getObjectById(in_params.object_id); + if (active_acc_obj.isNull()) + return RETURNCODE_FAIL; + + // child_id == 0 means self. Otherwise, it's a local child - 1. + if (in_params.child_id > 0) { + unsigned index = in_params.child_id - 1; + if (index >= active_acc_obj.childCount()) + return RETURNCODE_FAIL; + + active_acc_obj = active_acc_obj.childAt(index); + } + } + + if (active_acc_obj.isNull()) + return RETURNCODE_FAIL; + + // Temp paramters for holding output information. + WebAccessibilityObject out_acc_obj; + string16 out_string; -void WebAccessibility::Init(const WebKit::WebAccessibilityObject& src, - WebKit::WebAccessibilityCache* cache) { - name = src.title(); - value = src.stringValue(); - action = src.actionVerb(); - description = src.accessibilityDescription(); - help = src.helpText(); - shortcut = src.keyboardShortcut(); - role = ConvertRole(src.roleValue()); - state = ConvertState(src); - location = src.boundingBoxRect(); - - // Add the source object to the cache and store its id. - id = cache->addOrGetId(src); - - // Recursively create children. - int child_count = src.childCount(); - children.resize(child_count); - for (int i = 0; i < child_count; i++) { - children[i].Init(src.childAt(i), cache); + switch (in_params.function_id) { + case WebAccessibility::FUNCTION_DODEFAULTACTION: { + if (!active_acc_obj.performDefaultAction()) + return RETURNCODE_FALSE; + break; + } + case WebAccessibility::FUNCTION_HITTEST: { + WebPoint point(in_params.input_long1, in_params.input_long2); + out_acc_obj = active_acc_obj.hitTest(point); + if (out_acc_obj.isNull()) + return RETURNCODE_FALSE; + break; + } + case WebAccessibility::FUNCTION_LOCATION: { + WebRect rect = active_acc_obj.boundingBoxRect(); + out_params->output_long1 = rect.x; + out_params->output_long2 = rect.y; + out_params->output_long3 = rect.width; + out_params->output_long4 = rect.height; + break; + } + case WebAccessibility::FUNCTION_NAVIGATE: { + WebAccessibility::Direction dir = + static_cast<WebAccessibility::Direction>(in_params.input_long1); + switch (dir) { + case WebAccessibility::DIRECTION_DOWN: + case WebAccessibility::DIRECTION_UP: + case WebAccessibility::DIRECTION_LEFT: + case WebAccessibility::DIRECTION_RIGHT: + // These directions are not implemented, matching Mozilla and IE. + return RETURNCODE_FALSE; + case WebAccessibility::DIRECTION_LASTCHILD: + case WebAccessibility::DIRECTION_FIRSTCHILD: + // MSDN states that navigating to first/last child can only be from + // self. + if (!local_child) + return RETURNCODE_FALSE; + + if (dir == WebAccessibility::DIRECTION_FIRSTCHILD) { + out_acc_obj = active_acc_obj.firstChild(); + } else { + out_acc_obj = active_acc_obj.lastChild(); + } + break; + case WebAccessibility::DIRECTION_NEXT: + case WebAccessibility::DIRECTION_PREVIOUS: { + if (dir == WebAccessibility::DIRECTION_NEXT) { + out_acc_obj = active_acc_obj.nextSibling(); + } else { + out_acc_obj = active_acc_obj.previousSibling(); + } + break; + } + default: + return RETURNCODE_FALSE; + } + + if (out_acc_obj.isNull()) + return RETURNCODE_FALSE; + + break; + } + case WebAccessibility::FUNCTION_GETCHILD: { + out_params->object_id = in_params.object_id; + out_acc_obj = active_acc_obj; + break; + } + case WebAccessibility::FUNCTION_CHILDCOUNT: { + out_params->output_long1 = active_acc_obj.childCount(); + break; + } + case WebAccessibility::FUNCTION_DEFAULTACTION: { + out_string = active_acc_obj.actionVerb(); + if (out_string.empty()) + return RETURNCODE_FALSE; + break; + } + case WebAccessibility::FUNCTION_DESCRIPTION: { + out_string = active_acc_obj.accessibilityDescription(); + if (out_string.empty()) + return RETURNCODE_FALSE; + // From the Mozilla MSAA implementation: + // "Signal to screen readers that this description is speakable and is not + // a formatted positional information description. Don't localize the + // 'Description: ' part of this string, it will be parsed out by assistive + // technologies." + out_string = L"Description: " + out_string; + break; + } + case WebAccessibility::FUNCTION_GETFOCUSEDCHILD: { + out_acc_obj = active_acc_obj.focusedChild(); + if (out_acc_obj.isNull()) + return RETURNCODE_FALSE; + break; + } + case WebAccessibility::FUNCTION_HELPTEXT: { + out_string = active_acc_obj.helpText(); + if (out_string.empty()) + return RETURNCODE_FALSE; + break; + } + case WebAccessibility::FUNCTION_KEYBOARDSHORTCUT: { + out_string = active_acc_obj.keyboardShortcut(); + if (out_string.empty()) + return RETURNCODE_FALSE; + break; + } + case WebAccessibility::FUNCTION_NAME: { + out_string = active_acc_obj.title(); + if (out_string.empty()) + return RETURNCODE_FALSE; + break; + } + case WebAccessibility::FUNCTION_GETPARENT: { + out_acc_obj = active_acc_obj.parentObject(); + if (out_acc_obj.isNull()) + return RETURNCODE_FALSE; + break; + } + case WebAccessibility::FUNCTION_ROLE: { + out_params->output_long1 = ConvertRole(active_acc_obj.roleValue()); + break; + } + case WebAccessibility::FUNCTION_STATE: { + out_params->output_long1 = ConvertState(active_acc_obj); + break; + } + case WebAccessibility::FUNCTION_VALUE: { + out_string = active_acc_obj.stringValue(); + if (out_string.empty()) + return RETURNCODE_FALSE; + break; + } + default: + // Non-supported function id. + return RETURNCODE_FAIL; } + + // Output and hashmap assignments, as appropriate. + if (!out_string.empty()) + out_params->output_string = out_string; + + if (out_acc_obj.isNull()) + return RETURNCODE_TRUE; + + int id = cache->addOrGetId(out_acc_obj); + out_params->object_id = id; + out_params->output_long1 = -1; + + // TODO(ctguil): Handle simple objects returned. + return RETURNCODE_TRUE; } } // namespace webkit_glue diff --git a/webkit/glue/webaccessibility.h b/webkit/glue/webaccessibility.h index ea000e7..4bfd7743 100644 --- a/webkit/glue/webaccessibility.h +++ b/webkit/glue/webaccessibility.h @@ -1,16 +1,11 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2008 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 WEBKIT_GLUE_WEBACCESSIBILITY_H_ #define WEBKIT_GLUE_WEBACCESSIBILITY_H_ -#include <vector> - #include "base/string16.h" -#include "third_party/WebKit/WebKit/chromium/public/WebAccessibilityObject.h" -#include "third_party/WebKit/WebKit/chromium/public/WebAccessibilityRole.h" -#include "third_party/WebKit/WebKit/chromium/public/WebRect.h" namespace WebKit { class WebAccessibilityCache; @@ -18,15 +13,62 @@ class WebAccessibilityCache; namespace webkit_glue { -// A compact representation of the accessibility information for a -// single web object, in a form that can be serialized and sent from -// the renderer process to the browser process. -struct WebAccessibility { +class WebAccessibility { public: - // An alphabetical enumeration of accessibility roles. - enum Role { - ROLE_NONE = 0, + // This defines an enumeration of IDs that can uniquely identify a call to a + // specific accessibility information function. Should match the support + // implemented in WebKit and GlueAccessibilityObject (functions marked with + // return value E_NOTIMPL in WebKit are also excluded). + enum Function { + FUNCTION_NONE = 0, + + // Supported accessibility information retrieval functions. + FUNCTION_DODEFAULTACTION, + FUNCTION_HITTEST, + FUNCTION_LOCATION, + FUNCTION_NAVIGATE, + FUNCTION_GETCHILD, + FUNCTION_CHILDCOUNT, + FUNCTION_DEFAULTACTION, + FUNCTION_DESCRIPTION, + FUNCTION_GETFOCUSEDCHILD, + FUNCTION_HELPTEXT, + FUNCTION_KEYBOARDSHORTCUT, + FUNCTION_NAME, + FUNCTION_GETPARENT, + FUNCTION_ROLE, + FUNCTION_STATE, + FUNCTION_VALUE + + // The deprecated put_accName and put_accValue (IAccessible) are not + // supported here, nor is accSelect, get_accHelpTopic and get_accSelection + // (matching WebKit's support for IAccessible). + }; + + // This defines an enumeration of navigation directions based on (but + // independent of) the MSAA Navigation Constants. However, to avoid the use of + // COM in our Glue layer, we use this as a substitute with a one-to-one + // conversion between Browser side (has COM) and Glue. + enum Direction { + DIRECTION_NONE = 0, + // Valid directions. + DIRECTION_UP, + DIRECTION_DOWN, + DIRECTION_LEFT, + DIRECTION_RIGHT, + DIRECTION_NEXT, + DIRECTION_PREVIOUS, + DIRECTION_FIRSTCHILD, + DIRECTION_LASTCHILD + }; + + // This defines an enumeration (in alphabetical order) of the supported + // accessibility roles in our Glue layer (used in + // GlueAccessibilityObject::Role). Any interface using roles must provide a + // conversion to its own roles (see e.g. BrowserAccessibility::get_accRole and + // BrowserAccessibility::MSAARole). + enum Role { ROLE_APPLICATION, ROLE_CELL, ROLE_CHECKBUTTON, @@ -57,14 +99,14 @@ struct WebAccessibility { ROLE_TABLE, ROLE_TEXT, ROLE_TOOLBAR, - ROLE_TOOLTIP, - NUM_ROLES + ROLE_TOOLTIP }; - // An alphabetical enumeration of accessibility states. - // A state bitmask is formed by shifting 1 to the left by each state, - // for example: - // int mask = (1 << STATE_CHECKED) | (1 << STATE_FOCUSED); + // This defines an enumeration (in alphabetical order) of the supported + // accessibility states in our Glue layer (used in + // GlueAccessibilityObject::State). Any interface using states must provide a + // conversion to its own states (see e.g. BrowserAccessibility::get_accState + // and BrowserAccessibility::MSAAState). enum State { STATE_CHECKED, STATE_FOCUSABLE, @@ -81,32 +123,58 @@ struct WebAccessibility { STATE_UNAVAILABLE }; - // Empty constructor, for serialization. - WebAccessibility(); - - // Construct from a WebAccessibilityObject. Recursively creates child - // nodes as needed to complete the tree. Adds |src| to |cache| and - // stores its cache ID. - WebAccessibility(const WebKit::WebAccessibilityObject& src, - WebKit::WebAccessibilityCache* cache); - - // Initialize an already-created struct, same as the constructor a - void Init(const WebKit::WebAccessibilityObject& src, - WebKit::WebAccessibilityCache* cache); - - // This is a simple serializable struct. All member variables should be - // copyable. - int32 id; - string16 name; - string16 value; - string16 action; - string16 description; - string16 help; - string16 shortcut; - Role role; - uint32 state; - WebKit::WebRect location; - std::vector<WebAccessibility> children; + enum ReturnCode { + RETURNCODE_TRUE, // MSAA S_OK + RETURNCODE_FALSE, // MSAA S_FALSE + RETURNCODE_FAIL // E_FAIL + }; + + // Parameters structure to hold a union of the possible accessibility function + // INPUT variables, with the unused fields always set to default value. Used + // in ViewMsg_GetAccessibilityInfo, as only parameter. + struct InParams { + // Identifier to uniquely distinguish which instance of accessibility + // information is being called upon on the renderer side. + int object_id; + + // Identifier to resolve which accessibility information retrieval function + // is being called. + int function_id; + + // Id of accessible child, whose information is being requested. + int child_id; + + // LONG input parameters, used differently depending on the function called. + long input_long1; + long input_long2; + }; + + // Parameters structure to hold a union of the possible accessibility function + // OUTPUT variables, with the unused fields always set to default value. Used + // in ViewHostMsg_GetAccessibilityInfoResponse, as only parameter. + struct OutParams { + // Identifier to uniquely distinguish which instance of accessibility + // information is being called upon on the renderer side. + int object_id; + + // LONG output parameters, used differently depending on the function + // called. [output_long1] can in some cases be set to -1 to indicate that + // the child object found by the called IAccessible function is not a simple + // object. + long output_long1; + long output_long2; + long output_long3; + long output_long4; + + // String output parameter. + string16 output_string; + + // Return code of the accessibility function call. + int32 return_code; + }; + + static int32 GetAccObjInfo(WebKit::WebAccessibilityCache* cache, + const InParams& in_params, OutParams* out_params); }; } // namespace webkit_glue diff --git a/webkit/glue/webaccessibilitymanager.h b/webkit/glue/webaccessibilitymanager.h new file mode 100644 index 0000000..2debcb7 --- /dev/null +++ b/webkit/glue/webaccessibilitymanager.h @@ -0,0 +1,62 @@ +// Copyright (c) 2006-2008 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 WEBKIT_GLUE_WEBACCESSIBILITYMANAGER_H_ +#define WEBKIT_GLUE_WEBACCESSIBILITYMANAGER_H_ + +#include "webkit/glue/webaccessibility.h" + +namespace WebKit { +class WebAccessibilityObject; +class WebView; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// WebAccessibilityManager +// +// Responds to incoming accessibility requests from the browser side. Retrieves +// the requested information from the active AccessibilityObject, through the +// GlueAccessibilityObject. +//////////////////////////////////////////////////////////////////////////////// +namespace webkit_glue { + +class WebAccessibilityManager { + public: + WebAccessibilityManager() {} + virtual ~WebAccessibilityManager() {} + + // Creates a new instance of WebAccessibilityManager. + static WebAccessibilityManager* Create(); + + // Retrieves the accessibility information as requested in in_params, by + // calling into WebKit's AccessibilityObject. Maintains a hashmap of the + // currently active (browser side ref-count non-zero) instances. Returns true + // if successful, false otherwise. + virtual bool GetAccObjInfo(WebKit::WebView* view, + const WebAccessibility::InParams& in_params, + WebAccessibility::OutParams* out_params) = 0; + + // Erases the entry identified by the [acc_obj_id] from the hash maps. If + // [clear_all] is true, all entries are erased. Returns true if successful, + // false otherwise. + virtual bool ClearAccObjMap(int acc_obj_id, bool clear_all) = 0; + + // Retrieves the id of the input AccessibilityObject, due to a focus event. + // Returns an id greater than or equal to 0 if successful, -1 otherwise. + virtual int FocusAccObj(const WebKit::WebAccessibilityObject& object) = 0; + + private: + // Retrieves the RenderObject associated with this WebView, and uses it to + // initialize the root of the GlueAccessibilityObject tree with the + // associated accessibility information. Returns true if successful, false + // otherwise. + virtual bool InitAccObjRoot(WebKit::WebView* view) = 0; + + DISALLOW_COPY_AND_ASSIGN(WebAccessibilityManager); +}; + +} // namespace webkit_glue + +#endif // WEBKIT_GLUE_WEBACCESSIBILITYMANAGER_H_ diff --git a/webkit/glue/webkit_glue.gypi b/webkit/glue/webkit_glue.gypi index aec0904..e6b3a35 100644 --- a/webkit/glue/webkit_glue.gypi +++ b/webkit/glue/webkit_glue.gypi @@ -332,6 +332,10 @@ ['OS!="win"', { 'sources/': [['exclude', '_win\\.cc$']], 'sources!': [ + # These files are Windows-only now but may be ported to other + # platforms. + 'webaccessibility.cc', + 'webaccessibility.h', 'webthemeengine_impl_win.cc', ], }, { # else: OS=="win" |