diff options
author | klink@chromium.org <klink@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-20 20:12:25 +0000 |
---|---|---|
committer | klink@chromium.org <klink@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-20 20:12:25 +0000 |
commit | 6a983b4e4d28c1e3841f39febeb6a9dd681b53b3 (patch) | |
tree | a4b5d6a01066c026338d071076db9ff7dae210f3 /webkit/glue/glue_accessibility_object.cc | |
parent | fe5a8a4ff6f5758f8dbf7e6e9578df97fb8633db (diff) | |
download | chromium_src-6a983b4e4d28c1e3841f39febeb6a9dd681b53b3.zip chromium_src-6a983b4e4d28c1e3841f39febeb6a9dd681b53b3.tar.gz chromium_src-6a983b4e4d28c1e3841f39febeb6a9dd681b53b3.tar.bz2 |
Removes all use of COM and dependencies on Windows-specific classes (including the use of AccessibleBase and AccessibleDocument) in the glue accessibility implementation.Introduces the GlueAccessibilityObject, which serves as a platform-independent wrapper directly around WebKit's AccessibilityObject (also platoform-independent).Updates naming/comments to reflect the independence of IAccessible both in glue and (where appropriate) in the browser-side accessibility.
Review URL: http://codereview.chromium.org/46013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12207 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/glue_accessibility_object.cc')
-rw-r--r-- | webkit/glue/glue_accessibility_object.cc | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/webkit/glue/glue_accessibility_object.cc b/webkit/glue/glue_accessibility_object.cc new file mode 100644 index 0000000..17a693e --- /dev/null +++ b/webkit/glue/glue_accessibility_object.cc @@ -0,0 +1,445 @@ +// Copyright (c) 2006-2009 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 "config.h" + +#include "AccessibilityObject.h" +#include "EventHandler.h" +#include "FrameView.h" +#include "PlatformKeyboardEvent.h" + +#include "webkit/glue/glue_accessibility_object.h" + +using WebCore::AccessibilityObject; +using WebCore::String; +using webkit_glue::WebAccessibility; + +GlueAccessibilityObject::GlueAccessibilityObject(AccessibilityObject* obj) + : AccessibilityObjectWrapper(obj) { + m_object->setWrapper(this); +} + +GlueAccessibilityObject* GlueAccessibilityObject::CreateInstance( + AccessibilityObject* obj) { + if (!obj) + return NULL; + + return new GlueAccessibilityObject(obj); +} + +bool GlueAccessibilityObject::DoDefaultAction(int child_id) { + AccessibilityObject* child_obj; + + if (!GetAccessibilityObjectForChild(child_id, child_obj) || + !child_obj->performDefaultAction()) { + return false; + } + return true; +} + +GlueAccessibilityObject* GlueAccessibilityObject::HitTest(long x, long y) { + if (!m_object) + return NULL; + + // x, y - coordinates are passed in as window coordinates, to maintain + // sandbox functionality. + WebCore::IntPoint point = + m_object->documentFrameView()->windowToContents(WebCore::IntPoint(x, y)); + AccessibilityObject* child_obj = m_object->doAccessibilityHitTest(point); + + if (!child_obj) { + // If we did not hit any child objects, test whether the point hit us, and + // report that. + if (!m_object->boundingBoxRect().contains(point)) + return NULL; + child_obj = m_object; + } + // TODO(klink): simple object child? + ToWrapper(child_obj)->ref(); + return ToWrapper(child_obj); +} + +bool GlueAccessibilityObject::Location(long* left, long* top, long* width, + long* height, int child_id) { + if (!left || !top || !width || !height) + return false; + + *left = *top = *width = *height = 0; + + AccessibilityObject* child_obj; + if (!GetAccessibilityObjectForChild(child_id, child_obj)) + return false; + + // Returning window coordinates, to be handled and converted appropriately by + // the client. + WebCore::IntRect window_rect(child_obj->documentFrameView()->contentsToWindow( + child_obj->boundingBoxRect())); + *left = window_rect.x(); + *top = window_rect.y(); + *width = window_rect.width(); + *height = window_rect.height(); + return true; +} + +GlueAccessibilityObject* GlueAccessibilityObject::Navigate( + WebAccessibility::Direction dir, int start_child_id) { + AccessibilityObject* child_obj = 0; + + 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 NULL; + case WebAccessibility::DIRECTION_LASTCHILD: + case WebAccessibility::DIRECTION_FIRSTCHILD: + // MSDN states that navigating to first/last child can only be from self. + if (start_child_id != 0 || !m_object) + return NULL; + + if (dir == WebAccessibility::DIRECTION_FIRSTCHILD) { + child_obj = m_object->firstChild(); + } else { + child_obj = m_object->lastChild(); + } + break; + case WebAccessibility::DIRECTION_NEXT: + case WebAccessibility::DIRECTION_PREVIOUS: { + // Navigating to next and previous is allowed from self or any of our + // children. + if (!GetAccessibilityObjectForChild(start_child_id, child_obj)) + return NULL; + + if (dir == WebAccessibility::DIRECTION_NEXT) { + child_obj = child_obj->nextSibling(); + } else { + child_obj = child_obj->previousSibling(); + } + break; + } + default: + return NULL; + } + + if (!child_obj) + return NULL; + + // TODO(klink): simple object child? + ToWrapper(child_obj)->ref(); + return ToWrapper(child_obj); +} + +GlueAccessibilityObject* GlueAccessibilityObject::GetChild(int child_id) { + AccessibilityObject* child_obj; + if (!GetAccessibilityObjectForChild(child_id, child_obj)) + return false; + + // TODO(klink): simple object child? + ToWrapper(child_obj)->ref(); + return ToWrapper(child_obj); +} + +bool GlueAccessibilityObject::ChildCount(long* count) { + if (!m_object || !count) + return false; + + *count = static_cast<long>(m_object->children().size()); + return true; +} + +bool GlueAccessibilityObject::DefaultAction(int child_id, String* action) { + if (!action) + return false; + + AccessibilityObject* child_obj; + if (!GetAccessibilityObjectForChild(child_id, child_obj)) + return false; + + *action = child_obj->actionVerb(); + return !action->isEmpty(); +} + +bool GlueAccessibilityObject::Description(int child_id, String* description) { + if (!description) + return false; + + AccessibilityObject* child_obj; + if (!GetAccessibilityObjectForChild(child_id, child_obj)) + return false; + + // TODO(klink): Description, for SELECT subitems, should be a string + // describing the position of the item in its group and of the group in the + // list (see Firefox). + *description = ToWrapper(child_obj)->description(); + return !description->isEmpty(); +} + +GlueAccessibilityObject* GlueAccessibilityObject::GetFocusedChild() { + if (!m_object) + return NULL; + + AccessibilityObject* focused_obj = m_object->focusedUIElement(); + if (!focused_obj) + return NULL; + + // Only return the focused child if it's us or a child of us. + if (focused_obj == m_object || focused_obj->parentObject() == m_object) { + ToWrapper(focused_obj)->ref(); + return ToWrapper(focused_obj); + } + return NULL; +} + +bool GlueAccessibilityObject::HelpText(int child_id, String* help) { + if (!help) + return false; + + AccessibilityObject* child_obj; + if (!GetAccessibilityObjectForChild(child_id, child_obj)) + return false; + + *help = child_obj->helpText(); + return !help->isEmpty(); +} + +bool GlueAccessibilityObject::KeyboardShortcut(int child_id, String* shortcut) { + if (!shortcut) + return false; + + AccessibilityObject* child_obj; + if (!GetAccessibilityObjectForChild(child_id, child_obj)) + return false; + + String access_key = child_obj->accessKey(); + if (access_key.isNull()) + return false; + + static String access_key_modifiers; + if (access_key_modifiers.isNull()) { + unsigned modifiers = WebCore::EventHandler::accessKeyModifiers(); + // Follow the same order as Mozilla MSAA implementation: + // Ctrl+Alt+Shift+Meta+key. MSDN states that keyboard shortcut strings + // should not be localized and defines the separator as "+". + if (modifiers & WebCore::PlatformKeyboardEvent::CtrlKey) + access_key_modifiers += "Ctrl+"; + if (modifiers & WebCore::PlatformKeyboardEvent::AltKey) + access_key_modifiers += "Alt+"; + if (modifiers & WebCore::PlatformKeyboardEvent::ShiftKey) + access_key_modifiers += "Shift+"; + if (modifiers & WebCore::PlatformKeyboardEvent::MetaKey) + access_key_modifiers += "Win+"; + } + *shortcut = access_key_modifiers + access_key; + return !shortcut->isEmpty(); +} + +bool GlueAccessibilityObject::Name(int child_id, String* name) { + if (!name) + return false; + + AccessibilityObject* child_obj; + if (!GetAccessibilityObjectForChild(child_id, child_obj)) + return false; + + *name = ToWrapper(child_obj)->name(); + return !name->isEmpty(); +} + +GlueAccessibilityObject* GlueAccessibilityObject::GetParent() { + if (!m_object) + return NULL; + + AccessibilityObject* parent_obj = m_object->parentObject(); + + if (parent_obj) { + ToWrapper(parent_obj)->ref(); + return ToWrapper(parent_obj); + } + // No valid parent, or parent is the containing window. + return NULL; +} + +bool GlueAccessibilityObject::Role(int child_id, long* role) { + if (!role) + return false; + + AccessibilityObject* child_obj; + if (!GetAccessibilityObjectForChild(child_id, child_obj)) + return false; + + *role = ToWrapper(child_obj)->role(); + return true; +} + +bool GlueAccessibilityObject::Value(int child_id, String* value) { + if (!value) + return false; + + AccessibilityObject* child_obj; + if (!GetAccessibilityObjectForChild(child_id, child_obj)) + return false; + + *value = ToWrapper(child_obj)->value(); + return !value->isEmpty(); +} + +bool GlueAccessibilityObject::State(int child_id, long* state) { + if (!state) + return false; + + *state = 0; + AccessibilityObject* child_obj; + if (!GetAccessibilityObjectForChild(child_id, child_obj)) + return false; + + if (child_obj->isAnchor()) + *state |= static_cast<long>(1 << WebAccessibility::STATE_LINKED); + + if (child_obj->isHovered()) + *state |= static_cast<long>(1 << WebAccessibility::STATE_HOTTRACKED); + + if (!child_obj->isEnabled()) + *state |= static_cast<long>(1 << WebAccessibility::STATE_UNAVAILABLE); + + if (child_obj->isReadOnly()) + *state |= static_cast<long>(1 << WebAccessibility::STATE_READONLY); + + if (child_obj->isOffScreen()) + *state |= static_cast<long>(1 << WebAccessibility::STATE_OFFSCREEN); + + if (child_obj->isMultiSelect()) + *state |= static_cast<long>(1 << WebAccessibility::STATE_MULTISELECTABLE); + + if (child_obj->isPasswordField()) + *state |= static_cast<long>(1 << WebAccessibility::STATE_PROTECTED); + + if (child_obj->isIndeterminate()) + *state |= static_cast<long>(1 << WebAccessibility::STATE_INDETERMINATE); + + if (child_obj->isChecked()) + *state |= static_cast<long>(1 << WebAccessibility::STATE_CHECKED); + + if (child_obj->isPressed()) + *state |= static_cast<long>(1 << WebAccessibility::STATE_PRESSED); + + if (child_obj->isFocused()) + *state |= static_cast<long>(1 << WebAccessibility::STATE_FOCUSED); + + if (child_obj->isVisited()) + *state |= static_cast<long>(1 << WebAccessibility::STATE_TRAVERSED); + + if (child_obj->canSetFocusAttribute()) + *state |= static_cast<long>(1 << WebAccessibility::STATE_FOCUSABLE); + + // TODO(klink): Add selected and selectable states. + + return true; +} + +// Helper functions +String GlueAccessibilityObject::name() const { + return m_object->title(); +} + +String GlueAccessibilityObject::value() const { + return m_object->stringValue(); +} + +String GlueAccessibilityObject::description() const { + String desc = m_object->accessibilityDescription(); + if (desc.isNull()) + return desc; + + // 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." + return "Description: " + desc; +} + +// Provides a conversion between the WebCore::AccessibilityRole and a +// role supported on the Browser side. Static function. +static WebAccessibility::Role SupportedRole(WebCore::AccessibilityRole role) { + switch (role) { + case WebCore::ButtonRole: + return WebAccessibility::ROLE_PUSHBUTTON; + case WebCore::RadioButtonRole: + return WebAccessibility::ROLE_RADIOBUTTON; + case WebCore::CheckBoxRole: + return WebAccessibility::ROLE_CHECKBUTTON; + case WebCore::SliderRole: + return WebAccessibility::ROLE_SLIDER; + case WebCore::TabGroupRole: + return WebAccessibility::ROLE_PAGETABLIST; + case WebCore::TextFieldRole: + case WebCore::TextAreaRole: + case WebCore::ListMarkerRole: + return WebAccessibility::ROLE_TEXT; + case WebCore::StaticTextRole: + return WebAccessibility::ROLE_STATICTEXT; + case WebCore::OutlineRole: + return WebAccessibility::ROLE_OUTLINE; + case WebCore::ColumnRole: + return WebAccessibility::ROLE_COLUMN; + case WebCore::RowRole: + return WebAccessibility::ROLE_ROW; + case WebCore::GroupRole: + return WebAccessibility::ROLE_GROUPING; + case WebCore::ListRole: + return WebAccessibility::ROLE_LIST; + case WebCore::TableRole: + return WebAccessibility::ROLE_TABLE; + case WebCore::LinkRole: + case WebCore::WebCoreLinkRole: + return WebAccessibility::ROLE_LINK; + case WebCore::ImageMapRole: + case WebCore::ImageRole: + return WebAccessibility::ROLE_GRAPHIC; + default: + // This is the default role. + return WebAccessibility::ROLE_CLIENT; + } +} + +WebAccessibility::Role GlueAccessibilityObject::role() const { + return SupportedRole(m_object->roleValue()); +} + +bool GlueAccessibilityObject::GetAccessibilityObjectForChild(int child_id, + AccessibilityObject*& child_obj) const { + child_obj = 0; + + if (!m_object || child_id < 0) + return false; + + if (child_id == 0) { + child_obj = m_object; + } else { + size_t child_index = static_cast<size_t>(child_id - 1); + + if (child_index >= m_object->children().size()) + return false; + child_obj = m_object->children().at(child_index).get(); + } + + if (!child_obj) + return false; + + return true; +} + +GlueAccessibilityObject* GlueAccessibilityObject::ToWrapper( + AccessibilityObject* obj) { + if (!obj) + return NULL; + + GlueAccessibilityObject* result = + static_cast<GlueAccessibilityObject*>(obj->wrapper()); + if (!result) + result = CreateInstance(obj); + + return result; +} |