diff options
Diffstat (limited to 'WebCore/accessibility')
35 files changed, 613 insertions, 180 deletions
diff --git a/WebCore/accessibility/AXObjectCache.cpp b/WebCore/accessibility/AXObjectCache.cpp index c347a81..b7622b8 100644 --- a/WebCore/accessibility/AXObjectCache.cpp +++ b/WebCore/accessibility/AXObjectCache.cpp @@ -38,8 +38,9 @@ #include "AccessibilityListBoxOption.h" #include "AccessibilityMediaControls.h" #include "AccessibilityMenuList.h" -#include "AccessibilityMenuListPopup.h" #include "AccessibilityMenuListOption.h" +#include "AccessibilityMenuListPopup.h" +#include "AccessibilityProgressIndicator.h" #include "AccessibilityRenderObject.h" #include "AccessibilityScrollbar.h" #include "AccessibilitySlider.h" @@ -59,6 +60,7 @@ #include "InputElement.h" #include "Page.h" #include "RenderObject.h" +#include "RenderProgress.h" #include "RenderView.h" #include <wtf/PassRefPtr.h> @@ -159,7 +161,7 @@ AccessibilityObject* AXObjectCache::get(RenderObject* renderer) return obj; } -bool AXObjectCache::nodeIsAriaType(Node* node, String role) +bool AXObjectCache::nodeHasRole(Node* node, const AtomicString& role) { if (!node || !node->isElementNode()) return false; @@ -183,16 +185,16 @@ AccessibilityObject* AXObjectCache::getOrCreate(RenderObject* renderer) newObj = AccessibilityMenuList::create(renderer); // If the node is aria role="list" or the aria role is empty and its a ul/ol/dl type (it shouldn't be a list if aria says otherwise). - else if (node && ((nodeIsAriaType(node, "list") || nodeIsAriaType(node, "directory")) - || (nodeIsAriaType(node, nullAtom) && (node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(dlTag))))) + else if (node && ((nodeHasRole(node, "list") || nodeHasRole(node, "directory")) + || (nodeHasRole(node, nullAtom) && (node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(dlTag))))) newObj = AccessibilityList::create(renderer); // aria tables - else if (nodeIsAriaType(node, "grid") || nodeIsAriaType(node, "treegrid")) + else if (nodeHasRole(node, "grid") || nodeHasRole(node, "treegrid")) newObj = AccessibilityARIAGrid::create(renderer); - else if (nodeIsAriaType(node, "row")) + else if (nodeHasRole(node, "row")) newObj = AccessibilityARIAGridRow::create(renderer); - else if (nodeIsAriaType(node, "gridcell") || nodeIsAriaType(node, "columnheader") || nodeIsAriaType(node, "rowheader")) + else if (nodeHasRole(node, "gridcell") || nodeHasRole(node, "columnheader") || nodeHasRole(node, "rowheader")) newObj = AccessibilityARIAGridCell::create(renderer); // standard tables @@ -209,6 +211,12 @@ AccessibilityObject* AXObjectCache::getOrCreate(RenderObject* renderer) newObj = AccessibilityMediaControl::create(renderer); #endif +#if ENABLE(PROGRESS_TAG) + // progress bar + else if (renderer->isProgress()) + newObj = AccessibilityProgressIndicator::create(toRenderProgress(renderer)); +#endif + // input type=range else if (renderer->isSlider()) newObj = AccessibilitySlider::create(renderer); @@ -441,7 +449,9 @@ void AXObjectCache::postNotification(AccessibilityObject* object, Document* docu void AXObjectCache::selectedChildrenChanged(RenderObject* renderer) { - postNotification(renderer, AXSelectedChildrenChanged, true); + // postToElement is false so that you can pass in any child of an element and it will go up the parent tree + // to find the container which should send out the notification. + postNotification(renderer, AXSelectedChildrenChanged, false); } #endif diff --git a/WebCore/accessibility/AXObjectCache.h b/WebCore/accessibility/AXObjectCache.h index dad73f2..25f5347 100644 --- a/WebCore/accessibility/AXObjectCache.h +++ b/WebCore/accessibility/AXObjectCache.h @@ -121,6 +121,8 @@ public: void postNotification(RenderObject*, AXNotification, bool postToElement, PostType = PostAsynchronously); void postNotification(AccessibilityObject*, Document*, AXNotification, bool postToElement, PostType = PostAsynchronously); + bool nodeHasRole(Node*, const AtomicString& role); + protected: void postPlatformNotification(AccessibilityObject*, AXNotification); @@ -139,7 +141,6 @@ private: static AccessibilityObject* focusedImageMapUIElement(HTMLAreaElement*); AXID getAXID(AccessibilityObject*); - bool nodeIsAriaType(Node*, String role); }; #if !HAVE(ACCESSIBILITY) diff --git a/WebCore/accessibility/AccessibilityARIAGrid.cpp b/WebCore/accessibility/AccessibilityARIAGrid.cpp index a0cf77a..58b3fa1 100644 --- a/WebCore/accessibility/AccessibilityARIAGrid.cpp +++ b/WebCore/accessibility/AccessibilityARIAGrid.cpp @@ -131,8 +131,7 @@ AccessibilityTableCell* AccessibilityARIAGrid::cellForColumnAndRow(unsigned colu if (!m_renderer) return 0; - if (!hasChildren()) - addChildren(); + updateChildrenIfNecessary(); if (column >= columnCount() || row >= rowCount()) return 0; diff --git a/WebCore/accessibility/AccessibilityImageMapLink.cpp b/WebCore/accessibility/AccessibilityImageMapLink.cpp index 06150b9..2eac8d3 100644 --- a/WebCore/accessibility/AccessibilityImageMapLink.cpp +++ b/WebCore/accessibility/AccessibilityImageMapLink.cpp @@ -103,6 +103,9 @@ String AccessibilityImageMapLink::accessibilityDescription() const if (!m_areaElement) return String(); + const AtomicString& ariaLabel = m_areaElement->getAttribute(aria_labelAttr); + if (!ariaLabel.isEmpty()) + return ariaLabel; const AtomicString& alt = m_areaElement->getAttribute(altAttr); if (!alt.isEmpty()) return alt; diff --git a/WebCore/accessibility/AccessibilityList.cpp b/WebCore/accessibility/AccessibilityList.cpp index feceee5..073b0fc 100644 --- a/WebCore/accessibility/AccessibilityList.cpp +++ b/WebCore/accessibility/AccessibilityList.cpp @@ -55,8 +55,10 @@ PassRefPtr<AccessibilityList> AccessibilityList::create(RenderObject* renderer) bool AccessibilityList::accessibilityIsIgnored() const { - // Is the platform interested in the object? - if (accessibilityPlatformIncludesObject() == IgnoreObject) + AccessibilityObjectInclusion decision = accessibilityIsIgnoredBase(); + if (decision == IncludeObject) + return false; + if (decision == IgnoreObject) return true; // lists don't appear on tiger/leopard on the mac diff --git a/WebCore/accessibility/AccessibilityListBox.cpp b/WebCore/accessibility/AccessibilityListBox.cpp index 2c267c1..8a9e062 100644 --- a/WebCore/accessibility/AccessibilityListBox.cpp +++ b/WebCore/accessibility/AccessibilityListBox.cpp @@ -80,7 +80,7 @@ void AccessibilityListBox::addChildren() // The cast to HTMLElement below is safe because the only other possible listItem type // would be a WMLElement, but WML builds don't use accessibility features at all. AccessibilityObject* listOption = listBoxOptionAccessibilityObject(static_cast<HTMLElement*>(listItems[i])); - if (listOption) + if (listOption && !listOption->accessibilityIsIgnored()) m_children.append(listOption); } } @@ -151,6 +151,17 @@ AccessibilityObject* AccessibilityListBox::listBoxOptionAccessibilityObject(HTML return listBoxObject; } + +bool AccessibilityListBox::accessibilityIsIgnored() const +{ + AccessibilityObjectInclusion decision = accessibilityIsIgnoredBase(); + if (decision == IncludeObject) + return false; + if (decision == IgnoreObject) + return true; + + return false; +} AccessibilityObject* AccessibilityListBox::doAccessibilityHitTest(const IntPoint& point) const { @@ -165,16 +176,21 @@ AccessibilityObject* AccessibilityListBox::doAccessibilityHitTest(const IntPoint IntRect parentRect = boundingBoxRect(); - const Vector<Element*>& listItems = static_cast<HTMLSelectElement*>(node)->listItems(); - unsigned length = listItems.size(); + AccessibilityObject* listBoxOption = 0; + unsigned length = m_children.size(); for (unsigned i = 0; i < length; i++) { IntRect rect = toRenderListBox(m_renderer)->itemBoundingBoxRect(parentRect.x(), parentRect.y(), i); // The cast to HTMLElement below is safe because the only other possible listItem type // would be a WMLElement, but WML builds don't use accessibility features at all. - if (rect.contains(point)) - return listBoxOptionAccessibilityObject(static_cast<HTMLElement*>(listItems[i])); + if (rect.contains(point)) { + listBoxOption = m_children[i].get(); + break; + } } + if (listBoxOption && !listBoxOption->accessibilityIsIgnored()) + return listBoxOption; + return axObjectCache()->getOrCreate(m_renderer); } diff --git a/WebCore/accessibility/AccessibilityListBox.h b/WebCore/accessibility/AccessibilityListBox.h index ce1abe0..72ce82f 100644 --- a/WebCore/accessibility/AccessibilityListBox.h +++ b/WebCore/accessibility/AccessibilityListBox.h @@ -49,9 +49,7 @@ public: virtual bool canSetSelectedChildrenAttribute() const; void setSelectedChildren(AccessibilityChildrenVector&); virtual AccessibilityRole roleValue() const { return ListBoxRole; } - - virtual bool accessibilityIsIgnored() const { return false; } - + virtual void selectedChildren(AccessibilityChildrenVector&); virtual void visibleChildren(AccessibilityChildrenVector&); @@ -59,6 +57,7 @@ public: private: AccessibilityObject* listBoxOptionAccessibilityObject(HTMLElement*) const; + virtual bool accessibilityIsIgnored() const; }; } // namespace WebCore diff --git a/WebCore/accessibility/AccessibilityListBoxOption.cpp b/WebCore/accessibility/AccessibilityListBoxOption.cpp index 6a77dac..57519e3 100644 --- a/WebCore/accessibility/AccessibilityListBoxOption.cpp +++ b/WebCore/accessibility/AccessibilityListBoxOption.cpp @@ -105,6 +105,22 @@ IntRect AccessibilityListBoxOption::elementRect() const return rect; } +bool AccessibilityListBoxOption::accessibilityIsIgnored() const +{ + if (!m_optionElement) + return true; + + if (equalIgnoringCase(getAttribute(m_optionElement, aria_hiddenAttr), "true")) + return true; + + return parentObject()->accessibilityIsIgnored(); +} + +String AccessibilityListBoxOption::language() const +{ + return AccessibilityObject::language(m_optionElement); +} + bool AccessibilityListBoxOption::canSetSelectedAttribute() const { if (!m_optionElement) @@ -128,6 +144,10 @@ String AccessibilityListBoxOption::stringValue() const if (!m_optionElement) return String(); + const AtomicString& ariaLabel = getAttribute(m_optionElement, aria_labelAttr); + if (!ariaLabel.isNull()) + return ariaLabel; + if (m_optionElement->hasTagName(optionTag)) return static_cast<HTMLOptionElement*>(m_optionElement)->text(); diff --git a/WebCore/accessibility/AccessibilityListBoxOption.h b/WebCore/accessibility/AccessibilityListBoxOption.h index f8fd5f0..1da77e7 100644 --- a/WebCore/accessibility/AccessibilityListBoxOption.h +++ b/WebCore/accessibility/AccessibilityListBoxOption.h @@ -51,7 +51,7 @@ public: void setHTMLElement(HTMLElement* element) { m_optionElement = element; } virtual AccessibilityRole roleValue() const { return ListBoxOptionRole; } - virtual bool accessibilityIsIgnored() const { return false; } + virtual bool accessibilityIsIgnored() const; virtual bool isSelected() const; virtual bool isEnabled() const; virtual String stringValue() const; @@ -68,6 +68,7 @@ public: private: HTMLElement* m_optionElement; + virtual String language() const; virtual bool canHaveChildren() const { return false; } HTMLSelectElement* listBoxOptionParentNode() const; int listBoxOptionIndex() const; diff --git a/WebCore/accessibility/AccessibilityMediaControls.cpp b/WebCore/accessibility/AccessibilityMediaControls.cpp index 6151840..2f98acd 100644 --- a/WebCore/accessibility/AccessibilityMediaControls.cpp +++ b/WebCore/accessibility/AccessibilityMediaControls.cpp @@ -89,7 +89,7 @@ PassRefPtr<AccessibilityObject> AccessibilityMediaControl::create(RenderObject* MediaControlElementType AccessibilityMediaControl::controlType() const { if (!renderer() || !renderer()->node()) - return MediaTimelineContainer; // Timeline container is not accessible. + return MediaTimelineContainer; // Timeline container is not accessible. Node* node = renderer()->node(); diff --git a/WebCore/accessibility/AccessibilityObject.cpp b/WebCore/accessibility/AccessibilityObject.cpp index 7c616ea..8dedc36 100644 --- a/WebCore/accessibility/AccessibilityObject.cpp +++ b/WebCore/accessibility/AccessibilityObject.cpp @@ -148,6 +148,15 @@ bool AccessibilityObject::press() const return true; } +String AccessibilityObject::language(Node* node) const +{ + const AtomicString& lang = getAttribute(node, langAttr); + if (lang.isEmpty()) + return AccessibilityObject::language(); + + return lang; +} + String AccessibilityObject::language() const { AccessibilityObject* parent = parentObject(); @@ -731,8 +740,8 @@ FrameView* AccessibilityObject::documentFrameView() const void AccessibilityObject::clearChildren() { - m_haveChildren = false; m_children.clear(); + m_haveChildren = false; } AccessibilityObject* AccessibilityObject::anchorElementForNode(Node* node) @@ -835,6 +844,18 @@ const String& AccessibilityObject::actionVerb() const } } +const AtomicString& AccessibilityObject::getAttribute(Node* node, const QualifiedName& attribute) +{ + if (!node) + return nullAtom; + + if (!node->isElementNode()) + return nullAtom; + + Element* element = static_cast<Element*>(node); + return element->getAttribute(attribute); +} + // Lacking concrete evidence of orientation, horizontal means width > height. vertical is height > width; AccessibilityOrientation AccessibilityObject::orientation() const { @@ -949,6 +970,11 @@ bool AccessibilityObject::isInsideARIALiveRegion() const return false; } +bool AccessibilityObject::supportsARIAAttributes() const +{ + return supportsARIALiveRegion() || supportsARIADragging() || supportsARIADropping() || supportsARIAFlowTo() || supportsARIAOwns(); +} + bool AccessibilityObject::supportsARIALiveRegion() const { const AtomicString& liveRegion = ariaLiveRegionStatus(); diff --git a/WebCore/accessibility/AccessibilityObject.h b/WebCore/accessibility/AccessibilityObject.h index e4b1d99..8b4923a 100644 --- a/WebCore/accessibility/AccessibilityObject.h +++ b/WebCore/accessibility/AccessibilityObject.h @@ -34,7 +34,6 @@ #include "Range.h" #include "VisiblePosition.h" #include "VisibleSelection.h" -#include <wtf/Platform.h> #include <wtf/RefPtr.h> #include <wtf/Vector.h> @@ -204,7 +203,7 @@ enum AccessibilityOrientation { AccessibilityOrientationHorizontal, }; -enum AccessibilityObjectPlatformInclusion { +enum AccessibilityObjectInclusion { IncludeObject, IgnoreObject, DefaultBehavior, @@ -326,6 +325,9 @@ public: virtual bool hasIntValue() const { return false; } + // A programmatic way to set a name on an AccessibleObject. + virtual void setAccessibleName(String&) { } + bool accessibilityShouldUseUniqueId() const { return true; } virtual bool accessibilityIsIgnored() const { return true; } @@ -345,10 +347,11 @@ public: virtual void ariaOwnsElements(AccessibilityChildrenVector&) const { } virtual bool supportsARIAFlowTo() const { return false; } virtual void ariaFlowToElements(AccessibilityChildrenVector&) const { } + virtual bool ariaHasPopup() const { return false; } // ARIA drag and drop - virtual bool supportsARIADropping() { return false; } - virtual bool supportsARIADragging() { return false; } + virtual bool supportsARIADropping() const { return false; } + virtual bool supportsARIADragging() const { return false; } virtual bool isARIAGrabbed() { return false; } virtual void setARIAGrabbed(bool) { } virtual void determineARIADropEffects(Vector<String>&) { } @@ -415,6 +418,7 @@ public: virtual FrameView* topDocumentFrameView() const { return 0; } virtual FrameView* documentFrameView() const; virtual String language() const; + String language(Node*) const; virtual unsigned hierarchicalLevel() const { return 0; } virtual void setFocused(bool) { } @@ -446,7 +450,8 @@ public: virtual void handleActiveDescendantChanged() { } static AccessibilityRole ariaRoleToWebCoreRole(const String&); - + static const AtomicString& getAttribute(Node*, const QualifiedName&); + virtual VisiblePositionRange visiblePositionRange() const { return VisiblePositionRange(); } virtual VisiblePositionRange visiblePositionRangeForLine(unsigned) const { return VisiblePositionRange(); } @@ -518,6 +523,8 @@ public: virtual bool ariaLiveRegionAtomic() const { return false; } virtual bool ariaLiveRegionBusy() const { return false; } + bool supportsARIAAttributes() const; + #if HAVE(ACCESSIBILITY) #if PLATFORM(GTK) AccessibilityObjectWrapper* wrapper() const; @@ -531,18 +538,14 @@ public: #endif #endif - // a platform-specific method for determining if an attachment is ignored #if HAVE(ACCESSIBILITY) + // a platform-specific method for determining if an attachment is ignored bool accessibilityIgnoreAttachment() const; -#else - bool accessibilityIgnoreAttachment() const { return true; } -#endif - // gives platforms the opportunity to indicate if and how an object should be included -#if HAVE(ACCESSIBILITY) - AccessibilityObjectPlatformInclusion accessibilityPlatformIncludesObject() const; + AccessibilityObjectInclusion accessibilityPlatformIncludesObject() const; #else - AccessibilityObjectPlatformInclusion accessibilityPlatformIncludesObject() const { return DefaultBehavior; } + bool accessibilityIgnoreAttachment() const { return true; } + AccessibilityObjectInclusion accessibilityPlatformIncludesObject() const { return DefaultBehavior; } #endif // allows for an AccessibilityObject to update its render tree or perform diff --git a/WebCore/accessibility/AccessibilityProgressIndicator.cpp b/WebCore/accessibility/AccessibilityProgressIndicator.cpp new file mode 100644 index 0000000..c7202f0 --- /dev/null +++ b/WebCore/accessibility/AccessibilityProgressIndicator.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" + +#if ENABLE(PROGRESS_TAG) + +#include "AccessibilityProgressIndicator.h" + +#include "FloatConversion.h" +#include "HTMLNames.h" +#include "HTMLProgressElement.h" +#include "RenderObject.h" +#include "RenderProgress.h" + +namespace WebCore { + +using namespace HTMLNames; + +AccessibilityProgressIndicator::AccessibilityProgressIndicator(RenderProgress* renderer) + : AccessibilityRenderObject(renderer) +{ +} + +PassRefPtr<AccessibilityProgressIndicator> AccessibilityProgressIndicator::create(RenderProgress* renderer) +{ + return adoptRef(new AccessibilityProgressIndicator(renderer)); +} + +bool AccessibilityProgressIndicator::accessibilityIsIgnored() const +{ + return accessibilityIsIgnoredBase() == IgnoreObject; +} + +float AccessibilityProgressIndicator::valueForRange() const +{ + if (element()->position() >= 0) + return narrowPrecisionToFloat(element()->value()); + // Indeterminate progress bar should return 0. + return 0.0f; +} + +float AccessibilityProgressIndicator::maxValueForRange() const +{ + return narrowPrecisionToFloat(element()->max()); +} + +float AccessibilityProgressIndicator::minValueForRange() const +{ + return 0.0f; +} + +HTMLProgressElement* AccessibilityProgressIndicator::element() const +{ + return toRenderProgress(m_renderer)->progressElement(); +} + + +} // namespace WebCore + +#endif // ENABLE(PROGRESS_TAG) diff --git a/WebCore/accessibility/AccessibilityProgressIndicator.h b/WebCore/accessibility/AccessibilityProgressIndicator.h new file mode 100644 index 0000000..b52a619 --- /dev/null +++ b/WebCore/accessibility/AccessibilityProgressIndicator.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef AccessibilityProgressIndicator_h +#define AccessibilityProgressIndicator_h + +#if ENABLE(PROGRESS_TAG) + +#include "AccessibilityRenderObject.h" + +namespace WebCore { + +class HTMLProgressElement; +class RenderProgress; + +class AccessibilityProgressIndicator : public AccessibilityRenderObject { +public: + static PassRefPtr<AccessibilityProgressIndicator> create(RenderProgress*); + +private: + virtual AccessibilityRole roleValue() const { return ProgressIndicatorRole; } + + virtual bool isProgressIndicator() const { return true; } + + virtual float valueForRange() const; + virtual float maxValueForRange() const; + virtual float minValueForRange() const; + + AccessibilityProgressIndicator(RenderProgress*); + + HTMLProgressElement* element() const; + virtual bool accessibilityIsIgnored() const; +}; + + +} // namespace WebCore + +#endif // ENABLE(PROGRESS_TAG) + +#endif // AccessibilityProgressIndicator_h diff --git a/WebCore/accessibility/AccessibilityRenderObject.cpp b/WebCore/accessibility/AccessibilityRenderObject.cpp index d738ca8..3463546 100644 --- a/WebCore/accessibility/AccessibilityRenderObject.cpp +++ b/WebCore/accessibility/AccessibilityRenderObject.cpp @@ -69,6 +69,7 @@ #include "RenderTheme.h" #include "RenderView.h" #include "RenderWidget.h" +#include "SelectElement.h" #include "SelectionController.h" #include "Text.h" #include "TextIterator.h" @@ -547,15 +548,7 @@ AccessibilityObject* AccessibilityRenderObject::selectedTabItem() const AtomicString& AccessibilityRenderObject::getAttribute(const QualifiedName& attribute) const { - Node* node = m_renderer->node(); - if (!node) - return nullAtom; - - if (!node->isElementNode()) - return nullAtom; - - Element* element = static_cast<Element*>(node); - return element->getAttribute(attribute); + return AccessibilityObject::getAttribute(m_renderer->node(), attribute); } Element* AccessibilityRenderObject::anchorElement() const @@ -731,6 +724,15 @@ String AccessibilityRenderObject::helpText() const if (!title.isEmpty()) return title; } + + // Only take help text from an ancestor element if its a group or an unknown role. If help was + // added to those kinds of elements, it is likely it was meant for a child element. + AccessibilityObject* axObj = axObjectCache()->getOrCreate(curr); + if (axObj) { + AccessibilityRole role = axObj->roleValue(); + if (role != GroupRole && role != UnknownRole) + break; + } } return String(); @@ -775,18 +777,7 @@ String AccessibilityRenderObject::language() const if (!m_renderer) return String(); - // Defer to parent if this element doesn't have a language set - Node* node = m_renderer->node(); - if (!node) - return AccessibilityObject::language(); - - if (!node->isElementNode()) - return AccessibilityObject::language(); - - String language = static_cast<Element*>(node)->getAttribute(langAttr); - if (language.isEmpty()) - return AccessibilityObject::language(); - return language; + return AccessibilityObject::language(m_renderer->node()); } String AccessibilityRenderObject::textUnderElement() const @@ -898,8 +889,22 @@ String AccessibilityRenderObject::stringValue() const if (m_renderer->isText()) return textUnderElement(); - if (m_renderer->isMenuList()) + if (m_renderer->isMenuList()) { + // RenderMenuList will go straight to the text() of its selected item. + // This has to be overriden in the case where the selected item has an aria label + SelectElement* selectNode = toSelectElement(static_cast<Element*>(m_renderer->node())); + int selectedIndex = selectNode->selectedIndex(); + const Vector<Element*> listItems = selectNode->listItems(); + + Element* selectedOption = 0; + if (selectedIndex >= 0 && selectedIndex < (int)listItems.size()) + selectedOption = listItems[selectedIndex]; + String overridenDescription = AccessibilityObject::getAttribute(selectedOption, aria_labelAttr); + if (!overridenDescription.isNull()) + return overridenDescription; + return toRenderMenuList(m_renderer)->text(); + } if (m_renderer->isListMarker()) return toRenderListMarker(m_renderer)->text(); @@ -1133,6 +1138,13 @@ String AccessibilityRenderObject::accessibilityDescription() const if (isWebArea()) { Document* document = m_renderer->document(); + + // Check if the HTML element has an aria-label for the webpage. + Element* documentElement = document->documentElement(); + const AtomicString& ariaLabel = AccessibilityObject::getAttribute(documentElement, aria_labelAttr); + if (!ariaLabel.isEmpty()) + return ariaLabel; + Node* owner = document->ownerElement(); if (owner) { if (owner->hasTagName(frameTag) || owner->hasTagName(iframeTag)) { @@ -1318,6 +1330,11 @@ bool AccessibilityRenderObject::hasTextAlternative() const return false; } +bool AccessibilityRenderObject::ariaHasPopup() const +{ + return elementAttributeValue(aria_haspopupAttr); +} + bool AccessibilityRenderObject::supportsARIAFlowTo() const { return !getAttribute(aria_flowtoAttr).string().isEmpty(); @@ -1339,13 +1356,13 @@ void AccessibilityRenderObject::ariaFlowToElements(AccessibilityChildrenVector& } -bool AccessibilityRenderObject::supportsARIADropping() +bool AccessibilityRenderObject::supportsARIADropping() const { const AtomicString& dropEffect = getAttribute(aria_dropeffectAttr).string(); return !dropEffect.isEmpty(); } -bool AccessibilityRenderObject::supportsARIADragging() +bool AccessibilityRenderObject::supportsARIADragging() const { const AtomicString& grabbed = getAttribute(aria_grabbedAttr).string(); return equalIgnoringCase(grabbed, "true") || equalIgnoringCase(grabbed, "false"); @@ -1410,13 +1427,13 @@ AccessibilityObject* AccessibilityRenderObject::titleUIElement() const bool AccessibilityRenderObject::ariaIsHidden() const { - if (equalIgnoringCase(getAttribute(aria_hiddenAttr).string(), "true")) + if (equalIgnoringCase(getAttribute(aria_hiddenAttr), "true")) return true; // aria-hidden hides this object and any children AccessibilityObject* object = parentObject(); while (object) { - if (object->isAccessibilityRenderObject() && equalIgnoringCase(static_cast<AccessibilityRenderObject*>(object)->getAttribute(aria_hiddenAttr).string(), "true")) + if (object->isAccessibilityRenderObject() && equalIgnoringCase(static_cast<AccessibilityRenderObject*>(object)->getAttribute(aria_hiddenAttr), "true")) return true; object = object->parentObject(); } @@ -1456,26 +1473,43 @@ bool AccessibilityRenderObject::isAllowedChildOfTree() const return true; } -bool AccessibilityRenderObject::accessibilityIsIgnored() const +AccessibilityObjectInclusion AccessibilityRenderObject::accessibilityIsIgnoredBase() const { - // Is the platform interested in this object? - AccessibilityObjectPlatformInclusion decision = accessibilityPlatformIncludesObject(); - if (decision == IncludeObject) - return false; - if (decision == IgnoreObject) - return true; - // the decision must, therefore, be DefaultBehavior. - - // ignore invisible element + // The following cases can apply to any element that's a subclass of AccessibilityRenderObject. + + // Ignore invisible elements. if (!m_renderer || m_renderer->style()->visibility() != VISIBLE) - return true; + return IgnoreObject; + // Anything marked as aria-hidden or a child of something aria-hidden must be hidden. if (ariaIsHidden()) - return true; + return IgnoreObject; + // Anything that is a presentational role must be hidden. if (isPresentationalChildOfAriaRole()) - return true; + return IgnoreObject; + + // Allow the platform to make a decision. + AccessibilityObjectInclusion decision = accessibilityPlatformIncludesObject(); + if (decision == IncludeObject) + return IncludeObject; + if (decision == IgnoreObject) + return IgnoreObject; + return DefaultBehavior; +} + +bool AccessibilityRenderObject::accessibilityIsIgnored() const +{ + // Check first if any of the common reasons cause this element to be ignored. + // Then process other use cases that need to be applied to all the various roles + // that AccessibilityRenderObjects take on. + AccessibilityObjectInclusion decision = accessibilityIsIgnoredBase(); + if (decision == IncludeObject) + return false; + if (decision == IgnoreObject) + return true; + // If this element is within a parent that cannot have children, it should not be exposed. if (isDescendantOfBarrenParent()) return true; @@ -1531,6 +1565,9 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const if (ariaRole != UnknownRole) return false; + + if (!helpText().isEmpty()) + return false; // don't ignore labels, because they serve as TitleUIElements Node* node = m_renderer->node(); @@ -1547,6 +1584,10 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const return false; } + // if this element has aria attributes on it, it should not be ignored. + if (supportsARIAAttributes()) + return false; + if (m_renderer->isBlockFlow() && m_renderer->childrenInline()) return !toRenderBlock(m_renderer)->firstLineBox() && !mouseButtonListener(); @@ -1779,7 +1820,8 @@ KURL AccessibilityRenderObject::url() const bool AccessibilityRenderObject::isVisited() const { - return m_renderer->style()->pseudoState() == PseudoVisited; + // FIXME: Is it a privacy violation to expose visited information to accessibility APIs? + return m_renderer->style()->isLink() && m_renderer->style()->insideLink() == InsideVisitedLink; } bool AccessibilityRenderObject::isExpanded() const @@ -2479,14 +2521,21 @@ AccessibilityObject* AccessibilityRenderObject::doAccessibilityHitTest(const Int if (node->hasTagName(areaTag)) return accessibilityImageMapHitTest(static_cast<HTMLAreaElement*>(node), point); + if (node->hasTagName(optionTag)) + node = static_cast<HTMLOptionElement*>(node)->ownerSelectElement(); + RenderObject* obj = node->renderer(); if (!obj) return 0; AccessibilityObject* result = obj->document()->axObjectCache()->getOrCreate(obj); - if (obj->isListBox()) - return static_cast<AccessibilityListBox*>(result)->doAccessibilityHitTest(point); + if (obj->isListBox()) { + // Make sure the children are initialized so that hit testing finds the right element. + AccessibilityListBox* listBox = static_cast<AccessibilityListBox*>(result); + listBox->updateChildrenIfNecessary(); + return listBox->doAccessibilityHitTest(point); + } if (result->accessibilityIsIgnored()) { // If this element is the label of a control, a hit test should return the control. @@ -2605,11 +2654,25 @@ AccessibilityObject* AccessibilityRenderObject::correspondingLabelForControlElem return 0; } +bool AccessibilityRenderObject::renderObjectIsObservable(RenderObject* renderer) const +{ + // AX clients will listen for AXValueChange on a text control. + if (renderer->isTextControl()) + return true; + + // AX clients will listen for AXSelectedChildrenChanged on listboxes. + if (renderer->isListBox() || axObjectCache()->nodeHasRole(renderer->node(), "listbox")) + return true; + + return false; +} + AccessibilityObject* AccessibilityRenderObject::observableObject() const { + // Find the object going up the parent chain that is used in accessibility to monitor certain notifications. for (RenderObject* renderer = m_renderer; renderer && renderer->node(); renderer = renderer->parent()) { - if (renderer->isTextControl()) - return renderer->document()->axObjectCache()->getOrCreate(renderer); + if (renderObjectIsObservable(renderer)) + return axObjectCache()->getOrCreate(renderer); } return 0; @@ -2623,7 +2686,7 @@ AccessibilityRole AccessibilityRenderObject::determineAriaRoleAttribute() const AccessibilityRole role = ariaRoleToWebCoreRole(ariaRole); - if (role == ButtonRole && elementAttributeValue(aria_haspopupAttr)) + if (role == ButtonRole && ariaHasPopup()) role = PopUpButtonRole; if (role) @@ -2726,7 +2789,19 @@ AccessibilityRole AccessibilityRenderObject::determineAccessibilityRole() if (node && (node->hasTagName(rpTag) || node->hasTagName(rtTag))) return AnnotationRole; - + +#if PLATFORM(GTK) + // Gtk ATs expect all tables, data and layout, to be exposed as tables. + if (node && (node->hasTagName(tdTag) || node->hasTagName(thTag))) + return CellRole; + + if (node && node->hasTagName(trTag)) + return RowRole; + + if (node && node->hasTagName(tableTag)) + return TableRole; +#endif + if (m_renderer->isBlockFlow() || (node && node->hasTagName(labelTag))) return GroupRole; @@ -2761,7 +2836,7 @@ bool AccessibilityRenderObject::ariaRoleHasPresentationalChildren() const case SliderRole: case ImageRole: case ProgressIndicatorRole: - //case SeparatorRole: + // case SeparatorRole: return true; default: return false; @@ -2794,7 +2869,7 @@ bool AccessibilityRenderObject::canSetFocusAttribute() const case SliderRole: return true; default: - return false; + return node->supportsFocus(); } } @@ -2823,8 +2898,9 @@ bool AccessibilityRenderObject::canSetTextRangeAttributes() const void AccessibilityRenderObject::contentChanged() { // If this element supports ARIA live regions, then notify the AT of changes. - for (RenderObject* renderParent = m_renderer->parent(); renderParent; renderParent = renderParent->parent()) { - AccessibilityObject* parent = m_renderer->document()->axObjectCache()->get(renderParent); + AXObjectCache* cache = m_renderer->document()->axObjectCache(); + for (RenderObject* renderParent = m_renderer; renderParent; renderParent = renderParent->parent()) { + AccessibilityObject* parent = cache->get(renderParent); if (!parent) continue; @@ -2889,15 +2965,25 @@ bool AccessibilityRenderObject::canHaveChildren() const } } -const AccessibilityObject::AccessibilityChildrenVector& AccessibilityRenderObject::children() +void AccessibilityRenderObject::clearChildren() { - if (m_childrenDirty) { + AccessibilityObject::clearChildren(); + m_childrenDirty = false; +} + +void AccessibilityRenderObject::updateChildrenIfNecessary() +{ + if (needsToUpdateChildren()) clearChildren(); - m_childrenDirty = false; - } - if (!m_haveChildren) - addChildren(); + if (!hasChildren()) + addChildren(); +} + +const AccessibilityObject::AccessibilityChildrenVector& AccessibilityRenderObject::children() +{ + updateChildrenIfNecessary(); + return m_children; } @@ -3026,32 +3112,18 @@ void AccessibilityRenderObject::ariaSelectedRows(AccessibilityChildrenVector& re void AccessibilityRenderObject::ariaListboxSelectedChildren(AccessibilityChildrenVector& result) { - AccessibilityObject* child = firstChild(); - - Element* element = static_cast<Element*>(renderer()->node()); - if (!element || !element->isElementNode()) // do this check to ensure safety of static_cast above - return; - bool isMulti = isMultiSelectable(); - - while (child) { - // every child should have aria-role option, and if so, check for selected attribute/state - AccessibilityRole ariaRole = child->ariaRoleAttribute(); - RenderObject* childRenderer = 0; - if (child->isAccessibilityRenderObject()) - childRenderer = static_cast<AccessibilityRenderObject*>(child)->renderer(); - if (childRenderer && ariaRole == ListBoxOptionRole) { - Element* childElement = static_cast<Element*>(childRenderer->node()); - if (childElement && childElement->isElementNode()) { // do this check to ensure safety of static_cast above - String selectedAttrString = childElement->getAttribute(aria_selectedAttr).string(); - if (equalIgnoringCase(selectedAttrString, "true")) { - result.append(child); - if (isMulti) - return; - } - } + + AccessibilityChildrenVector childObjects = children(); + unsigned childrenSize = childObjects.size(); + for (unsigned k = 0; k < childrenSize; ++k) { + // Every child should have aria-role option, and if so, check for selected attribute/state. + AccessibilityObject* child = childObjects[k].get(); + if (child->isSelected() && child->ariaRoleAttribute() == ListBoxOptionRole) { + result.append(child); + if (!isMulti) + return; } - child = child->nextSibling(); } } @@ -3130,7 +3202,24 @@ const String& AccessibilityRenderObject::actionVerb() const return noAction; } } - + +void AccessibilityRenderObject::setAccessibleName(String& name) +{ + // Setting the accessible name can store the value in the DOM + if (!m_renderer) + return; + + Node* domNode = 0; + // For web areas, set the aria-label on the HTML element. + if (isWebArea()) + domNode = m_renderer->document()->documentElement(); + else + domNode = m_renderer->node(); + + if (domNode && domNode->isElementNode()) + static_cast<Element*>(domNode)->setAttribute(aria_labelAttr, name); +} + void AccessibilityRenderObject::updateBackingStore() { if (!m_renderer) diff --git a/WebCore/accessibility/AccessibilityRenderObject.h b/WebCore/accessibility/AccessibilityRenderObject.h index 6735076..494e6bb 100644 --- a/WebCore/accessibility/AccessibilityRenderObject.h +++ b/WebCore/accessibility/AccessibilityRenderObject.h @@ -114,6 +114,10 @@ public: virtual bool hasIntValue() const; + virtual void setAccessibleName(String&); + + // Provides common logic used by all elements when determining isIgnored. + AccessibilityObjectInclusion accessibilityIsIgnoredBase() const; virtual bool accessibilityIsIgnored() const; virtual int headingLevel() const; @@ -191,10 +195,11 @@ public: virtual Widget* widgetForAttachmentView() const; virtual void getDocumentLinks(AccessibilityChildrenVector&); virtual FrameView* documentFrameView() const; - virtual String language() const; virtual unsigned hierarchicalLevel() const; virtual const AccessibilityChildrenVector& children(); + virtual void clearChildren(); + void updateChildrenIfNecessary(); virtual void setFocused(bool); virtual void setSelectedTextRange(const PlainTextRange&); @@ -224,9 +229,10 @@ public: virtual void setSelectedVisiblePositionRange(const VisiblePositionRange&) const; virtual bool supportsARIAFlowTo() const; virtual void ariaFlowToElements(AccessibilityChildrenVector&) const; + virtual bool ariaHasPopup() const; - virtual bool supportsARIADropping(); - virtual bool supportsARIADragging(); + virtual bool supportsARIADropping() const; + virtual bool supportsARIADragging() const; virtual bool isARIAGrabbed(); virtual void setARIAGrabbed(bool); virtual void determineARIADropEffects(Vector<String>&); @@ -259,6 +265,7 @@ protected: void setRenderObject(RenderObject* renderer) { m_renderer = renderer; } void ariaLabeledByElements(Vector<Element*>& elements) const; + bool needsToUpdateChildren() const { return m_childrenDirty; } virtual bool isDetached() const { return !m_renderer; } @@ -270,6 +277,7 @@ private: bool isAllowedChildOfTree() const; bool hasTextAlternative() const; String positionalDescriptionForMSAA() const; + virtual String language() const; Element* menuElementForMenuButton() const; Element* menuItemElementForMenu() const; @@ -282,7 +290,8 @@ private: AccessibilityObject* internalLinkElement() const; AccessibilityObject* accessibilityImageMapHitTest(HTMLAreaElement*, const IntPoint&) const; AccessibilityObject* accessibilityParentForImageMap(HTMLMapElement* map) const; - + bool renderObjectIsObservable(RenderObject*) const; + void ariaSelectedRows(AccessibilityChildrenVector&); bool elementAttributeValue(const QualifiedName&) const; @@ -297,7 +306,6 @@ private: virtual bool ariaLiveRegionBusy() const; void setNeedsToUpdateChildren() const { m_childrenDirty = true; } - bool needsToUpdateChildren() const { return m_childrenDirty; } mutable AccessibilityRole m_roleForMSAA; }; diff --git a/WebCore/accessibility/AccessibilitySlider.cpp b/WebCore/accessibility/AccessibilitySlider.cpp index 77f4dcc..e8d1f41 100644 --- a/WebCore/accessibility/AccessibilitySlider.cpp +++ b/WebCore/accessibility/AccessibilitySlider.cpp @@ -99,6 +99,17 @@ const AtomicString& AccessibilitySlider::getAttribute(const QualifiedName& attri return element()->getAttribute(attribute); } +bool AccessibilitySlider::accessibilityIsIgnored() const +{ + AccessibilityObjectInclusion decision = accessibilityIsIgnoredBase(); + if (decision == IncludeObject) + return false; + if (decision == IgnoreObject) + return true; + + return false; +} + float AccessibilitySlider::valueForRange() const { return element()->value().toFloat(); diff --git a/WebCore/accessibility/AccessibilitySlider.h b/WebCore/accessibility/AccessibilitySlider.h index e1e3812..461f62b 100644 --- a/WebCore/accessibility/AccessibilitySlider.h +++ b/WebCore/accessibility/AccessibilitySlider.h @@ -42,7 +42,6 @@ public: virtual ~AccessibilitySlider() { } virtual AccessibilityRole roleValue() const { return SliderRole; } - virtual bool accessibilityIsIgnored() const { return false; } virtual bool isSlider() const { return true; } @@ -63,6 +62,7 @@ protected: private: HTMLInputElement* element() const; + virtual bool accessibilityIsIgnored() const; }; class AccessibilitySliderThumb : public AccessibilityObject { @@ -72,7 +72,6 @@ public: virtual ~AccessibilitySliderThumb() { } virtual AccessibilityRole roleValue() const { return SliderThumbRole; } - virtual bool accessibilityIsIgnored() const { return false; } void setParentObject(AccessibilitySlider* slider) { m_parentSlider = slider; } virtual AccessibilityObject* parentObject() const { return m_parentSlider; } @@ -82,6 +81,7 @@ public: private: AccessibilitySliderThumb(); + virtual bool accessibilityIsIgnored() const { return false; } AccessibilitySlider* m_parentSlider; }; diff --git a/WebCore/accessibility/AccessibilityTable.cpp b/WebCore/accessibility/AccessibilityTable.cpp index 9ac1046..aed8867 100644 --- a/WebCore/accessibility/AccessibilityTable.cpp +++ b/WebCore/accessibility/AccessibilityTable.cpp @@ -94,6 +94,11 @@ bool AccessibilityTable::isTableExposableThroughAccessibility() Node* tableNode = table->node(); if (!tableNode || !tableNode->hasTagName(tableTag)) return false; + + // Gtk+ ATs expect all tables to be exposed as tables. +#if PLATFORM(GTK) + return true; +#endif // if there is a caption element, summary, THEAD, or TFOOT section, it's most certainly a data table HTMLTableElement* tableElement = static_cast<HTMLTableElement*>(tableNode); @@ -193,10 +198,9 @@ bool AccessibilityTable::isTableExposableThroughAccessibility() void AccessibilityTable::clearChildren() { - m_children.clear(); + AccessibilityRenderObject::clearChildren(); m_rows.clear(); m_columns.clear(); - m_haveChildren = false; } void AccessibilityTable::addChildren() @@ -251,7 +255,12 @@ void AccessibilityTable::addChildren() row->setRowIndex((int)m_rows.size()); m_rows.append(row); - m_children.append(row); + if (!row->accessibilityIsIgnored()) + m_children.append(row); +#if PLATFORM(GTK) + else + m_children.append(row->children()); +#endif appendedRows.add(row); } } @@ -266,11 +275,12 @@ void AccessibilityTable::addChildren() column->setColumnIndex((int)i); column->setParentTable(this); m_columns.append(column); - m_children.append(column); + if (!column->accessibilityIsIgnored()) + m_children.append(column); } AccessibilityObject* headerContainerObject = headerContainer(); - if (headerContainerObject) + if (headerContainerObject && !headerContainerObject->accessibilityIsIgnored()) m_children.append(headerContainerObject); } @@ -287,17 +297,15 @@ AccessibilityObject* AccessibilityTable::headerContainer() AccessibilityObject::AccessibilityChildrenVector& AccessibilityTable::columns() { - if (!hasChildren()) - addChildren(); + updateChildrenIfNecessary(); return m_columns; } AccessibilityObject::AccessibilityChildrenVector& AccessibilityTable::rows() { - if (!hasChildren()) - addChildren(); - + updateChildrenIfNecessary(); + return m_rows; } @@ -306,8 +314,7 @@ void AccessibilityTable::rowHeaders(AccessibilityChildrenVector& headers) if (!m_renderer) return; - if (!hasChildren()) - addChildren(); + updateChildrenIfNecessary(); unsigned rowCount = m_rows.size(); for (unsigned k = 0; k < rowCount; ++k) { @@ -323,8 +330,7 @@ void AccessibilityTable::columnHeaders(AccessibilityChildrenVector& headers) if (!m_renderer) return; - if (!hasChildren()) - addChildren(); + updateChildrenIfNecessary(); unsigned colCount = m_columns.size(); for (unsigned k = 0; k < colCount; ++k) { @@ -340,8 +346,7 @@ void AccessibilityTable::cells(AccessibilityObject::AccessibilityChildrenVector& if (!m_renderer) return; - if (!hasChildren()) - addChildren(); + updateChildrenIfNecessary(); int numRows = m_rows.size(); for (int row = 0; row < numRows; ++row) { @@ -352,16 +357,14 @@ void AccessibilityTable::cells(AccessibilityObject::AccessibilityChildrenVector& unsigned AccessibilityTable::columnCount() { - if (!hasChildren()) - addChildren(); + updateChildrenIfNecessary(); return m_columns.size(); } unsigned AccessibilityTable::rowCount() { - if (!hasChildren()) - addChildren(); + updateChildrenIfNecessary(); return m_rows.size(); } @@ -371,8 +374,7 @@ AccessibilityTableCell* AccessibilityTable::cellForColumnAndRow(unsigned column, if (!m_renderer || !m_renderer->isTable()) return 0; - if (!hasChildren()) - addChildren(); + updateChildrenIfNecessary(); RenderTable* table = toRenderTable(m_renderer); RenderTableSection* tableSection = table->header(); @@ -448,9 +450,15 @@ AccessibilityRole AccessibilityTable::roleValue() const bool AccessibilityTable::accessibilityIsIgnored() const { + AccessibilityObjectInclusion decision = accessibilityIsIgnoredBase(); + if (decision == IncludeObject) + return false; + if (decision == IgnoreObject) + return true; + if (!isDataTable()) return AccessibilityRenderObject::accessibilityIsIgnored(); - + return false; } diff --git a/WebCore/accessibility/AccessibilityTableCell.cpp b/WebCore/accessibility/AccessibilityTableCell.cpp index 7674cb8..318c619 100644 --- a/WebCore/accessibility/AccessibilityTableCell.cpp +++ b/WebCore/accessibility/AccessibilityTableCell.cpp @@ -56,6 +56,12 @@ PassRefPtr<AccessibilityTableCell> AccessibilityTableCell::create(RenderObject* bool AccessibilityTableCell::accessibilityIsIgnored() const { + AccessibilityObjectInclusion decision = accessibilityIsIgnoredBase(); + if (decision == IncludeObject) + return false; + if (decision == IgnoreObject) + return true; + if (!isTableCell()) return AccessibilityRenderObject::accessibilityIsIgnored(); diff --git a/WebCore/accessibility/AccessibilityTableColumn.cpp b/WebCore/accessibility/AccessibilityTableColumn.cpp index ee8531e..5872706 100644 --- a/WebCore/accessibility/AccessibilityTableColumn.cpp +++ b/WebCore/accessibility/AccessibilityTableColumn.cpp @@ -158,6 +158,18 @@ AccessibilityObject* AccessibilityTableColumn::headerObjectForSection(RenderTabl return m_parentTable->axObjectCache()->getOrCreate(cell); } +bool AccessibilityTableColumn::accessibilityIsIgnored() const +{ + if (!m_parentTable) + return true; + +#if PLATFORM(GTK) + return true; +#endif + + return m_parentTable->accessibilityIsIgnored(); +} + void AccessibilityTableColumn::addChildren() { ASSERT(!m_haveChildren); diff --git a/WebCore/accessibility/AccessibilityTableColumn.h b/WebCore/accessibility/AccessibilityTableColumn.h index 6270398..15d300c 100644 --- a/WebCore/accessibility/AccessibilityTableColumn.h +++ b/WebCore/accessibility/AccessibilityTableColumn.h @@ -49,8 +49,8 @@ public: virtual AccessibilityObject* parentObject() const { return m_parentTable; } AccessibilityObject* headerObject(); + virtual bool accessibilityIsIgnored() const; virtual AccessibilityRole roleValue() const { return ColumnRole; } - virtual bool accessibilityIsIgnored() const { return false; } virtual bool isTableColumn() const { return true; } void setColumnIndex(int columnIndex) { m_columnIndex = columnIndex; } diff --git a/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp b/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp index 3a2a241..e2da83c 100644 --- a/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp +++ b/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp @@ -68,6 +68,18 @@ IntSize AccessibilityTableHeaderContainer::size() const return elementRect().size(); } +bool AccessibilityTableHeaderContainer::accessibilityIsIgnored() const +{ + if (!m_parentTable) + return true; + +#if PLATFORM(GTK) + return true; +#endif + + return m_parentTable->accessibilityIsIgnored(); +} + void AccessibilityTableHeaderContainer::addChildren() { ASSERT(!m_haveChildren); diff --git a/WebCore/accessibility/AccessibilityTableHeaderContainer.h b/WebCore/accessibility/AccessibilityTableHeaderContainer.h index 8a9448a..79521c0 100644 --- a/WebCore/accessibility/AccessibilityTableHeaderContainer.h +++ b/WebCore/accessibility/AccessibilityTableHeaderContainer.h @@ -48,8 +48,6 @@ public: void setParentTable(AccessibilityTable* table) { m_parentTable = table; } virtual AccessibilityObject* parentObject() const { return m_parentTable; } - virtual bool accessibilityIsIgnored() const { return false; } - virtual const AccessibilityChildrenVector& children(); virtual void addChildren(); @@ -60,6 +58,7 @@ private: AccessibilityTable* m_parentTable; IntRect m_headerRect; + virtual bool accessibilityIsIgnored() const; }; } // namespace WebCore diff --git a/WebCore/accessibility/AccessibilityTableRow.cpp b/WebCore/accessibility/AccessibilityTableRow.cpp index 71f8b2b..e2a1157 100644 --- a/WebCore/accessibility/AccessibilityTableRow.cpp +++ b/WebCore/accessibility/AccessibilityTableRow.cpp @@ -76,6 +76,12 @@ bool AccessibilityTableRow::isTableRow() const bool AccessibilityTableRow::accessibilityIsIgnored() const { + AccessibilityObjectInclusion decision = accessibilityIsIgnoredBase(); + if (decision == IncludeObject) + return false; + if (decision == IgnoreObject) + return true; + if (!isTableRow()) return AccessibilityRenderObject::accessibilityIsIgnored(); diff --git a/WebCore/accessibility/chromium/AccessibilityObjectChromium.cpp b/WebCore/accessibility/chromium/AccessibilityObjectChromium.cpp index 6749f77..5b4cfd5 100644 --- a/WebCore/accessibility/chromium/AccessibilityObjectChromium.cpp +++ b/WebCore/accessibility/chromium/AccessibilityObjectChromium.cpp @@ -34,7 +34,7 @@ bool AccessibilityObject::accessibilityIgnoreAttachment() const return false; } -AccessibilityObjectPlatformInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const +AccessibilityObjectInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const { if (isMenuListPopup() || isMenuListOption()) return IgnoreObject; diff --git a/WebCore/accessibility/efl/AccessibilityObjectEfl.cpp b/WebCore/accessibility/efl/AccessibilityObjectEfl.cpp new file mode 100644 index 0000000..d57c3fa --- /dev/null +++ b/WebCore/accessibility/efl/AccessibilityObjectEfl.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2008 Apple Ltd. + * Copyright (C) 2009-2010 ProFUSION embedded systems + * Copyright (C) 2009-2010 Samsung Electronics + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "AccessibilityObject.h" + +#if HAVE(ACCESSIBILITY) + +namespace WebCore { + +bool AccessibilityObject::accessibilityIgnoreAttachment() const +{ + return false; +} + +} // namespace WebCore + +#endif // HAVE(ACCESSIBILITY) diff --git a/WebCore/accessibility/gtk/AccessibilityObjectAtk.cpp b/WebCore/accessibility/gtk/AccessibilityObjectAtk.cpp index f48770f..ca3e8cc 100644 --- a/WebCore/accessibility/gtk/AccessibilityObjectAtk.cpp +++ b/WebCore/accessibility/gtk/AccessibilityObjectAtk.cpp @@ -32,7 +32,7 @@ bool AccessibilityObject::accessibilityIgnoreAttachment() const return false; } -AccessibilityObjectPlatformInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const +AccessibilityObjectInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const { AccessibilityObject* parent = parentObject(); if (!parent) @@ -41,17 +41,34 @@ AccessibilityObjectPlatformInclusion AccessibilityObject::accessibilityPlatformI if (isMenuListPopup() || isMenuListOption()) return IgnoreObject; - // When a list item is made up entirely of children (e.g. paragraphs) - // the list item gets ignored. We need it. - if (isGroup() && parent->isList()) - return IncludeObject; + if (isGroup()) { + // When a list item is made up entirely of children (e.g. paragraphs) + // the list item gets ignored. We need it. + if (parent->isList()) + return IncludeObject; + + // We expect the parent of a table cell to be a table. + AccessibilityObject* child = firstChild(); + if (child && child->roleValue() == CellRole) + return IgnoreObject; + } // Entries and password fields have extraneous children which we want to ignore. if (parent->isPasswordField() || parent->isTextControl()) return IgnoreObject; + AccessibilityRole role = roleValue(); + + // Include all tables, even layout tables. The AT can decide what to do with each. + if (role == CellRole || role == TableRole) + return IncludeObject; + + // We at some point might have a need to expose a table row; but it's not standard Gtk+. + if (role == RowRole) + return IgnoreObject; + // The object containing the text should implement AtkText itself. - if (roleValue() == StaticTextRole) + if (role == StaticTextRole) return IgnoreObject; return DefaultBehavior; diff --git a/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp b/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp index 487fa5b..ffef2a8 100644 --- a/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp +++ b/WebCore/accessibility/gtk/AccessibilityObjectWrapperAtk.cpp @@ -42,7 +42,6 @@ #include "AccessibilityTableColumn.h" #include "AccessibilityTableRow.h" #include "AtomicString.h" -#include "CString.h" #include "Document.h" #include "DocumentType.h" #include "Editor.h" @@ -57,6 +56,7 @@ #include "NotImplemented.h" #include "RenderText.h" #include "TextEncoding.h" +#include <wtf/text/CString.h> #include <atk/atk.h> #include <glib.h> @@ -448,6 +448,8 @@ static AtkRole webkit_accessible_get_role(AtkObject* object) return ATK_ROLE_LABEL; if (node->hasTagName(HTMLNames::divTag)) return ATK_ROLE_SECTION; + if (node->hasTagName(HTMLNames::formTag)) + return ATK_ROLE_FORM; } } @@ -996,8 +998,13 @@ static gint webkit_accessible_text_get_caret_offset(AtkText* text) // coreObject is the unignored object whose offset the caller is requesting. // focusedObject is the object with the caret. It is likely ignored -- unless it's a link. AccessibilityObject* coreObject = core(text); - RenderObject* focusedNode = coreObject->selection().end().node()->renderer(); - AccessibilityObject* focusedObject = coreObject->document()->axObjectCache()->getOrCreate(focusedNode); + Node* focusedNode = coreObject->selection().end().node(); + + if (!focusedNode) + return 0; + + RenderObject* focusedRenderer = focusedNode->renderer(); + AccessibilityObject* focusedObject = coreObject->document()->axObjectCache()->getOrCreate(focusedRenderer); int offset; // Don't ignore links if the offset is being requested for a link. @@ -1563,7 +1570,7 @@ static const gchar* webkit_accessible_document_get_locale(AtkDocument* document) { // TODO: Should we fall back on lang xml:lang when the following comes up empty? - String language = static_cast<AccessibilityRenderObject*>(core(document))->language(); + String language = core(document)->language(); if (!language.isEmpty()) return returnString(language); @@ -1656,7 +1663,7 @@ static guint16 getInterfaceMaskFromObject(AccessibilityObject* coreObject) interfaceMask |= 1 << WAI_TEXT; if (!coreObject->isReadOnly()) interfaceMask |= 1 << WAI_EDITABLE_TEXT; - } else if (static_cast<AccessibilityRenderObject*>(coreObject)->renderer()->childrenInline()) + } else if (role != TableRole && static_cast<AccessibilityRenderObject*>(coreObject)->renderer()->childrenInline()) interfaceMask |= 1 << WAI_TEXT; // Image diff --git a/WebCore/accessibility/mac/AccessibilityObjectMac.mm b/WebCore/accessibility/mac/AccessibilityObjectMac.mm index 1807a9b..37fa65a 100644 --- a/WebCore/accessibility/mac/AccessibilityObjectMac.mm +++ b/WebCore/accessibility/mac/AccessibilityObjectMac.mm @@ -41,7 +41,7 @@ bool AccessibilityObject::accessibilityIgnoreAttachment() const return [attachment accessibilityIsIgnored]; } -AccessibilityObjectPlatformInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const +AccessibilityObjectInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const { if (isMenuListPopup() || isMenuListOption()) return IgnoreObject; diff --git a/WebCore/accessibility/mac/AccessibilityObjectWrapper.h b/WebCore/accessibility/mac/AccessibilityObjectWrapper.h index 1f0a9e3..e6cc706 100644 --- a/WebCore/accessibility/mac/AccessibilityObjectWrapper.h +++ b/WebCore/accessibility/mac/AccessibilityObjectWrapper.h @@ -53,7 +53,7 @@ class VisiblePosition; - (WebCore::AccessibilityObject*)accessibilityObject; // Used to inform an element when a notification is posted for it. Used by DRT. -- (void)accessibilityPostedNotification:(NSString *)notification; +- (void)accessibilityPostedNotification:(NSString *)notificationName; - (NSView*)attachmentView; diff --git a/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm b/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm index b53b167..f13968d 100644 --- a/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm +++ b/WebCore/accessibility/mac/AccessibilityObjectWrapper.mm @@ -152,6 +152,10 @@ using namespace std; #define NSAccessibilityLoadingProgressAttribute @"AXLoadingProgress" #endif +#ifndef NSAccessibilityHasPopupAttribute +#define NSAccessibilityHasPopupAttribute @"AXHasPopup" +#endif + #ifdef BUILDING_ON_TIGER typedef unsigned NSUInteger; #define NSAccessibilityValueDescriptionAttribute @"AXValueDescription" @@ -634,6 +638,9 @@ static WebCoreTextMarkerRange* textMarkerRangeFromVisiblePositions(VisiblePositi [additional addObject:NSAccessibilityARIABusyAttribute]; } + if (m_object->ariaHasPopup()) + [additional addObject:NSAccessibilityHasPopupAttribute]; + return additional; } @@ -1850,6 +1857,9 @@ static NSString* roleValueToNSString(AccessibilityRole value) return dropEffectsArray; } + if ([attributeName isEqualToString:NSAccessibilityHasPopupAttribute]) + return [NSNumber numberWithBool:m_object->ariaHasPopup()]; + // ARIA Live region attributes. if ([attributeName isEqualToString:NSAccessibilityARIALiveAttribute]) return m_object->ariaLiveRegionStatus(); @@ -2657,22 +2667,19 @@ static RenderObject* rendererForView(NSView* view) return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount]; } -// These are used by DRT so that it can know when notifications are sent. -// Since they are static, only one callback can be installed at a time (that's all DRT should need). -typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context); -static AXPostedNotificationCallback AXNotificationCallback = 0; -static void* AXPostedNotificationContext = 0; - -- (void)accessibilitySetPostedNotificationCallback:(AXPostedNotificationCallback)function withContext:(void*)context +// This is set by DRT when it wants to listen for notifications. +static BOOL accessibilityShouldRepostNotifications; +- (void)accessibilitySetShouldRepostNotifications:(BOOL)repost { - AXNotificationCallback = function; - AXPostedNotificationContext = context; + accessibilityShouldRepostNotifications = repost; } -- (void)accessibilityPostedNotification:(NSString *)notification +- (void)accessibilityPostedNotification:(NSString *)notificationName { - if (AXNotificationCallback) - AXNotificationCallback(self, notification, AXPostedNotificationContext); + if (accessibilityShouldRepostNotifications) { + NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:notificationName, @"notificationName", nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"AXDRTNotification" object:nil userInfo:userInfo]; + } } @end diff --git a/WebCore/accessibility/qt/AccessibilityObjectQt.cpp b/WebCore/accessibility/qt/AccessibilityObjectQt.cpp index 5d85f1e..7232642 100644 --- a/WebCore/accessibility/qt/AccessibilityObjectQt.cpp +++ b/WebCore/accessibility/qt/AccessibilityObjectQt.cpp @@ -29,7 +29,7 @@ bool AccessibilityObject::accessibilityIgnoreAttachment() const return false; } -AccessibilityObjectPlatformInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const +AccessibilityObjectInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const { if (isMenuListPopup() || isMenuListOption()) return IgnoreObject; diff --git a/WebCore/accessibility/win/AccessibilityObjectWin.cpp b/WebCore/accessibility/win/AccessibilityObjectWin.cpp index a86988f..44122ef 100644 --- a/WebCore/accessibility/win/AccessibilityObjectWin.cpp +++ b/WebCore/accessibility/win/AccessibilityObjectWin.cpp @@ -35,7 +35,7 @@ bool AccessibilityObject::accessibilityIgnoreAttachment() const return false; } -AccessibilityObjectPlatformInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const +AccessibilityObjectInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const { if (isMenuListPopup() || isMenuListOption()) return IncludeObject; diff --git a/WebCore/accessibility/wx/AccessibilityObjectWx.cpp b/WebCore/accessibility/wx/AccessibilityObjectWx.cpp index 5d85f1e..7232642 100644 --- a/WebCore/accessibility/wx/AccessibilityObjectWx.cpp +++ b/WebCore/accessibility/wx/AccessibilityObjectWx.cpp @@ -29,7 +29,7 @@ bool AccessibilityObject::accessibilityIgnoreAttachment() const return false; } -AccessibilityObjectPlatformInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const +AccessibilityObjectInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const { if (isMenuListPopup() || isMenuListOption()) return IgnoreObject; |