diff options
Diffstat (limited to 'WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp')
-rw-r--r-- | WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp | 150 |
1 files changed, 118 insertions, 32 deletions
diff --git a/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp b/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp index 726cdb1..ca0d80b 100644 --- a/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp +++ b/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp @@ -58,6 +58,7 @@ #include "RenderListItem.h" #include "RenderListMarker.h" #include "RenderText.h" +#include "SelectElement.h" #include "TextEncoding.h" #include "TextIterator.h" #include "WebKitAccessibleHyperlink.h" @@ -500,6 +501,12 @@ static void setAtkStateSetFromCoreObject(AccessibilityObject* coreObject, AtkSta atk_state_set_add_state(stateSet, ATK_STATE_SENSITIVE); } + if (coreObject->canSetExpandedAttribute()) + atk_state_set_add_state(stateSet, ATK_STATE_EXPANDABLE); + + if (coreObject->isExpanded()) + atk_state_set_add_state(stateSet, ATK_STATE_EXPANDED); + if (coreObject->canSetFocusAttribute()) atk_state_set_add_state(stateSet, ATK_STATE_FOCUSABLE); @@ -694,13 +701,44 @@ static void atk_action_interface_init(AtkActionIface* iface) // Selection (for controls) +static AccessibilityObject* listObjectForSelection(AtkSelection* selection) +{ + AccessibilityObject* coreSelection = core(selection); + + // Only list boxes and menu lists supported so far. + if (!coreSelection->isListBox() && !coreSelection->isMenuList()) + return 0; + + // For list boxes the list object is just itself. + if (coreSelection->isListBox()) + return coreSelection; + + // For menu lists we need to return the first accessible child, + // with role MenuListPopupRole, since that's the one holding the list + // of items with role MenuListOptionRole. + AccessibilityObject::AccessibilityChildrenVector children = coreSelection->children(); + if (!children.size()) + return 0; + + AccessibilityObject* listObject = children.at(0).get(); + if (!listObject->isMenuListPopup()) + return 0; + + return listObject; +} + static AccessibilityObject* optionFromList(AtkSelection* selection, gint i) { AccessibilityObject* coreSelection = core(selection); if (!coreSelection || i < 0) return 0; - AccessibilityRenderObject::AccessibilityChildrenVector options = core(selection)->children(); + // Need to select the proper list object depending on the type. + AccessibilityObject* listObject = listObjectForSelection(selection); + if (!listObject) + return 0; + + AccessibilityRenderObject::AccessibilityChildrenVector options = listObject->children(); if (i < static_cast<gint>(options.size())) return options.at(i).get(); @@ -712,14 +750,26 @@ static AccessibilityObject* optionFromSelection(AtkSelection* selection, gint i) // i is the ith selection as opposed to the ith child. AccessibilityObject* coreSelection = core(selection); - if (!coreSelection || i < 0) + if (!coreSelection || !coreSelection->isAccessibilityRenderObject() || i < 0) return 0; AccessibilityRenderObject::AccessibilityChildrenVector selectedItems; if (coreSelection->isListBox()) - static_cast<AccessibilityListBox*>(coreSelection)->selectedChildren(selectedItems); + coreSelection->selectedChildren(selectedItems); + else if (coreSelection->isMenuList()) { + RenderObject* renderer = toAccessibilityRenderObject(coreSelection)->renderer(); + if (!renderer) + return 0; + + SelectElement* selectNode = toSelectElement(static_cast<Element*>(renderer->node())); + int selectedIndex = selectNode->selectedIndex(); + const Vector<Element*> listItems = selectNode->listItems(); - // TODO: Combo boxes + if (selectedIndex < 0 || selectedIndex >= static_cast<int>(listItems.size())) + return 0; + + return optionFromList(selection, selectedIndex); + } if (i < static_cast<gint>(selectedItems.size())) return selectedItems.at(i).get(); @@ -729,11 +779,14 @@ static AccessibilityObject* optionFromSelection(AtkSelection* selection, gint i) static gboolean webkit_accessible_selection_add_selection(AtkSelection* selection, gint i) { + AccessibilityObject* coreSelection = core(selection); + if (!coreSelection) + return false; + AccessibilityObject* option = optionFromList(selection, i); - if (option && core(selection)->isListBox()) { - AccessibilityListBoxOption* listBoxOption = static_cast<AccessibilityListBoxOption*>(option); - listBoxOption->setSelected(true); - return listBoxOption->isSelected(); + if (option && (coreSelection->isListBox() || coreSelection->isMenuList())) { + option->setSelected(true); + return option->isSelected(); } return false; @@ -746,7 +799,7 @@ static gboolean webkit_accessible_selection_clear_selection(AtkSelection* select return false; AccessibilityRenderObject::AccessibilityChildrenVector selectedItems; - if (coreSelection->isListBox()) { + if (coreSelection->isListBox() || coreSelection->isMenuList()) { // Set the list of selected items to an empty list; then verify that it worked. AccessibilityListBox* listBox = static_cast<AccessibilityListBox*>(coreSelection); listBox->setSelectedChildren(selectedItems); @@ -771,32 +824,54 @@ static AtkObject* webkit_accessible_selection_ref_selection(AtkSelection* select static gint webkit_accessible_selection_get_selection_count(AtkSelection* selection) { AccessibilityObject* coreSelection = core(selection); - if (coreSelection && coreSelection->isListBox()) { + if (!coreSelection || !coreSelection->isAccessibilityRenderObject()) + return 0; + + if (coreSelection->isListBox()) { AccessibilityRenderObject::AccessibilityChildrenVector selectedItems; - static_cast<AccessibilityListBox*>(coreSelection)->selectedChildren(selectedItems); + coreSelection->selectedChildren(selectedItems); return static_cast<gint>(selectedItems.size()); } + if (coreSelection->isMenuList()) { + RenderObject* renderer = toAccessibilityRenderObject(coreSelection)->renderer(); + if (!renderer) + return 0; + + SelectElement* selectNode = toSelectElement(static_cast<Element*>(renderer->node())); + int selectedIndex = selectNode->selectedIndex(); + const Vector<Element*> listItems = selectNode->listItems(); + + return selectedIndex >= 0 && selectedIndex < static_cast<int>(listItems.size()); + } + return 0; } static gboolean webkit_accessible_selection_is_child_selected(AtkSelection* selection, gint i) { + AccessibilityObject* coreSelection = core(selection); + if (!coreSelection) + return 0; + AccessibilityObject* option = optionFromList(selection, i); - if (option && core(selection)->isListBox()) - return static_cast<AccessibilityListBoxOption*>(option)->isSelected(); + if (option && (coreSelection->isListBox() || coreSelection->isMenuList())) + return option->isSelected(); return false; } static gboolean webkit_accessible_selection_remove_selection(AtkSelection* selection, gint i) { + AccessibilityObject* coreSelection = core(selection); + if (!coreSelection) + return 0; + // TODO: This is only getting called if i == 0. What is preventing the rest? AccessibilityObject* option = optionFromSelection(selection, i); - if (option && core(selection)->isListBox()) { - AccessibilityListBoxOption* listBoxOption = static_cast<AccessibilityListBoxOption*>(option); - listBoxOption->setSelected(false); - return !listBoxOption->isSelected(); + if (option && (coreSelection->isListBox() || coreSelection->isMenuList())) { + option->setSelected(false); + return !option->isSelected(); } return false; @@ -969,8 +1044,11 @@ static gchar* webkit_accessible_text_get_text(AtkText* text, gint startOffset, g if (coreObject->isTextControl()) ret = coreObject->doAXStringForRange(PlainTextRange(start, length)); - else - ret = coreObject->textUnderElement().substring(start, length); + else { + ret = coreObject->stringValue().substring(start, length); + if (!ret) + ret = coreObject->textUnderElement().substring(start, length); + } if (!ret.length()) { // This can happen at least with anonymous RenderBlocks (e.g. body text amongst paragraphs) @@ -1433,13 +1511,13 @@ static void getSelectionOffsetsForObject(AccessibilityObject* coreObject, Visibl if (!coreObject->isAccessibilityRenderObject()) return; - // Early return if the selection doesn't affect the selected node + // Early return if the selection doesn't affect the selected node. if (!selectionBelongsToObject(coreObject, selection)) return; // We need to find the exact start and end positions in the // selected node that intersects the selection, to later on get - // the right values for the effective start and end offsets + // the right values for the effective start and end offsets. ExceptionCode ec = 0; Position nodeRangeStart; Position nodeRangeEnd; @@ -1449,7 +1527,7 @@ static void getSelectionOffsetsForObject(AccessibilityObject* coreObject, Visibl // If the selection affects the selected node and its first // possible position is also in the selection, we must set // nodeRangeStart to that position, otherwise to the selection's - // start position (it would belong to the node anyway) + // start position (it would belong to the node anyway). Node* firstLeafNode = node->firstDescendant(); if (selRange->isPointInRange(firstLeafNode, 0, ec)) nodeRangeStart = firstPositionInNode(firstLeafNode); @@ -1459,16 +1537,20 @@ static void getSelectionOffsetsForObject(AccessibilityObject* coreObject, Visibl // If the selection affects the selected node and its last // possible position is also in the selection, we must set // nodeRangeEnd to that position, otherwise to the selection's - // end position (it would belong to the node anyway) + // end position (it would belong to the node anyway). Node* lastLeafNode = node->lastDescendant(); if (selRange->isPointInRange(lastLeafNode, lastOffsetInNode(lastLeafNode), ec)) nodeRangeEnd = lastPositionInNode(lastLeafNode); else nodeRangeEnd = selRange->endPosition(); - // Set values for start and end offsets + // Calculate position of the selected range inside the object. + Position parentFirstPosition = firstPositionInNode(node); + RefPtr<Range> rangeInParent = Range::create(node->document(), parentFirstPosition, nodeRangeStart); + + // Set values for start and end offsets. + startOffset = TextIterator::rangeLength(rangeInParent.get()); RefPtr<Range> nodeRange = Range::create(node->document(), nodeRangeStart, nodeRangeEnd); - startOffset = nodeRangeStart.offsetInContainerNode(); endOffset = startOffset + TextIterator::rangeLength(nodeRange.get()); } @@ -2173,19 +2255,23 @@ static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject) AccessibilityRole role = coreObject->roleValue(); // Action - if (!coreObject->actionVerb().isEmpty()) { - interfaceMask |= 1 << WAI_ACTION; + // As the implementation of the AtkAction interface is a very + // basic one (just relays in executing the default action for each + // object, and only supports having one action per object), it is + // better just to implement this interface for every instance of + // the WebKitAccessible class and let WebCore decide what to do. + interfaceMask |= 1 << WAI_ACTION; - if (!coreObject->accessibilityIsIgnored() && coreObject->isLink()) - interfaceMask |= 1 << WAI_HYPERLINK; - } + // Hyperlink + if (coreObject->isLink()) + interfaceMask |= 1 << WAI_HYPERLINK; // Selection - if (coreObject->isListBox()) + if (coreObject->isListBox() || coreObject->isMenuList()) interfaceMask |= 1 << WAI_SELECTION; // Text & Editable Text - if (role == StaticTextRole) + if (role == StaticTextRole || coreObject->isMenuListOption()) interfaceMask |= 1 << WAI_TEXT; else if (coreObject->isAccessibilityRenderObject()) { if (coreObject->isTextControl()) { |