diff options
Diffstat (limited to 'src/3rdparty/webkit/WebCore/accessibility')
40 files changed, 2522 insertions, 686 deletions
diff --git a/src/3rdparty/webkit/WebCore/accessibility/AXObjectCache.cpp b/src/3rdparty/webkit/WebCore/accessibility/AXObjectCache.cpp index 55199a3..c347a81 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AXObjectCache.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AXObjectCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,14 +30,18 @@ #include "AXObjectCache.h" #include "AccessibilityARIAGrid.h" -#include "AccessibilityARIAGridRow.h" #include "AccessibilityARIAGridCell.h" +#include "AccessibilityARIAGridRow.h" +#include "AccessibilityImageMapLink.h" #include "AccessibilityList.h" #include "AccessibilityListBox.h" #include "AccessibilityListBoxOption.h" -#include "AccessibilityImageMapLink.h" #include "AccessibilityMediaControls.h" +#include "AccessibilityMenuList.h" +#include "AccessibilityMenuListPopup.h" +#include "AccessibilityMenuListOption.h" #include "AccessibilityRenderObject.h" +#include "AccessibilityScrollbar.h" #include "AccessibilitySlider.h" #include "AccessibilityTable.h" #include "AccessibilityTableCell.h" @@ -46,6 +50,8 @@ #include "AccessibilityTableRow.h" #include "FocusController.h" #include "Frame.h" +#include "HTMLAreaElement.h" +#include "HTMLImageElement.h" #include "HTMLNames.h" #if ENABLE(VIDEO) #include "MediaControlElements.h" @@ -80,6 +86,35 @@ AXObjectCache::~AXObjectCache() } } +AccessibilityObject* AXObjectCache::focusedImageMapUIElement(HTMLAreaElement* areaElement) +{ + // Find the corresponding accessibility object for the HTMLAreaElement. This should be + // in the list of children for its corresponding image. + if (!areaElement) + return 0; + + HTMLImageElement* imageElement = areaElement->imageElement(); + if (!imageElement) + return 0; + + AccessibilityObject* axRenderImage = areaElement->document()->axObjectCache()->getOrCreate(imageElement->renderer()); + if (!axRenderImage) + return 0; + + AccessibilityObject::AccessibilityChildrenVector imageChildren = axRenderImage->children(); + unsigned count = imageChildren.size(); + for (unsigned k = 0; k < count; ++k) { + AccessibilityObject* child = imageChildren[k].get(); + if (!child->isImageMapLink()) + continue; + + if (static_cast<AccessibilityImageMapLink*>(child)->areaElement() == areaElement) + return child; + } + + return 0; +} + AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page* page) { // get the focused node in the page @@ -88,6 +123,9 @@ AccessibilityObject* AXObjectCache::focusedUIElementForPage(const Page* page) if (!focusedNode) focusedNode = focusedDocument; + if (focusedNode->hasTagName(areaTag)) + return focusedImageMapUIElement(static_cast<HTMLAreaElement*>(focusedNode)); + RenderObject* focusedNodeRenderer = focusedNode->renderer(); if (!focusedNodeRenderer) return 0; @@ -141,11 +179,16 @@ AccessibilityObject* AXObjectCache::getOrCreate(RenderObject* renderer) RefPtr<AccessibilityObject> newObj = 0; if (renderer->isListBox()) newObj = AccessibilityListBox::create(renderer); - else if (node && (nodeIsAriaType(node, "list") || node->hasTagName(ulTag) || node->hasTagName(olTag) || node->hasTagName(dlTag))) + else if (renderer->isMenuList()) + 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))))) newObj = AccessibilityList::create(renderer); // aria tables - else if (nodeIsAriaType(node, "grid")) + else if (nodeIsAriaType(node, "grid") || nodeIsAriaType(node, "treegrid")) newObj = AccessibilityARIAGrid::create(renderer); else if (nodeIsAriaType(node, "row")) newObj = AccessibilityARIAGridRow::create(renderer); @@ -191,23 +234,32 @@ AccessibilityObject* AXObjectCache::getOrCreate(AccessibilityRole role) // will be filled in... switch (role) { - case ListBoxOptionRole: - obj = AccessibilityListBoxOption::create(); - break; - case ImageMapLinkRole: - obj = AccessibilityImageMapLink::create(); - break; - case ColumnRole: - obj = AccessibilityTableColumn::create(); - break; - case TableHeaderContainerRole: - obj = AccessibilityTableHeaderContainer::create(); - break; - case SliderThumbRole: - obj = AccessibilitySliderThumb::create(); - break; - default: - obj = 0; + case ListBoxOptionRole: + obj = AccessibilityListBoxOption::create(); + break; + case ImageMapLinkRole: + obj = AccessibilityImageMapLink::create(); + break; + case ColumnRole: + obj = AccessibilityTableColumn::create(); + break; + case TableHeaderContainerRole: + obj = AccessibilityTableHeaderContainer::create(); + break; + case SliderThumbRole: + obj = AccessibilitySliderThumb::create(); + break; + case MenuListPopupRole: + obj = AccessibilityMenuListPopup::create(); + break; + case MenuListOptionRole: + obj = AccessibilityMenuListOption::create(); + break; + case ScrollBarRole: + obj = AccessibilityScrollbar::create(); + break; + default: + obj = 0; } if (obj) @@ -235,9 +287,8 @@ void AXObjectCache::remove(AXID axID) removeAXID(obj); // finally remove the object - if (!m_objects.take(axID)) { + if (!m_objects.take(axID)) return; - } ASSERT(m_objects.size() >= m_idsInUse.size()); } @@ -261,7 +312,7 @@ AXID AXObjectCache::platformGenerateAXID() const AXID objID = lastUsedID; do { ++objID; - } while (objID == 0 || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID)); + } while (!objID || HashTraits<AXID>::isDeletedValue(objID) || m_idsInUse.contains(objID)); lastUsedID = objID; @@ -286,20 +337,29 @@ AXID AXObjectCache::getAXID(AccessibilityObject* obj) return objID; } -void AXObjectCache::removeAXID(AccessibilityObject* obj) +void AXObjectCache::removeAXID(AccessibilityObject* object) { - if (!obj) + if (!object) return; - AXID objID = obj->axObjectID(); - if (objID == 0) + AXID objID = object->axObjectID(); + if (!objID) return; ASSERT(!HashTraits<AXID>::isDeletedValue(objID)); ASSERT(m_idsInUse.contains(objID)); - obj->setAXObjectID(0); + object->setAXObjectID(0); m_idsInUse.remove(objID); } +#if HAVE(ACCESSIBILITY) +void AXObjectCache::contentChanged(RenderObject* renderer) +{ + AccessibilityObject* object = getOrCreate(renderer); + if (object) + object->contentChanged(); +} +#endif + void AXObjectCache::childrenChanged(RenderObject* renderer) { if (!renderer) @@ -339,7 +399,7 @@ void AXObjectCache::notificationPostTimerFired(Timer<AXObjectCache>*) } #if HAVE(ACCESSIBILITY) -void AXObjectCache::postNotification(RenderObject* renderer, AXNotification notification, bool postToElement) +void AXObjectCache::postNotification(RenderObject* renderer, AXNotification notification, bool postToElement, PostType postType) { // Notifications for text input objects are sent to that object. // All others are sent to the top WebArea. @@ -348,28 +408,35 @@ void AXObjectCache::postNotification(RenderObject* renderer, AXNotification noti // Get an accessibility object that already exists. One should not be created here // because a render update may be in progress and creating an AX object can re-trigger a layout - RefPtr<AccessibilityObject> obj = get(renderer); - while (!obj && renderer) { + RefPtr<AccessibilityObject> object = get(renderer); + while (!object && renderer) { renderer = renderer->parent(); - obj = get(renderer); + object = get(renderer); } if (!renderer) return; - - if (obj && !postToElement) - obj = obj->observableObject(); - - Document* document = renderer->document(); - if (!obj && document) - obj = get(document->renderer()); - if (!obj) + postNotification(object.get(), renderer->document(), notification, postToElement, postType); +} + +void AXObjectCache::postNotification(AccessibilityObject* object, Document* document, AXNotification notification, bool postToElement, PostType postType) +{ + if (object && !postToElement) + object = object->observableObject(); + + if (!object && document) + object = get(document->renderer()); + + if (!object) return; - m_notificationsToPost.append(make_pair(obj, notification)); - if (!m_notificationPostTimer.isActive()) - m_notificationPostTimer.startOneShot(0); + if (postType == PostAsynchronously) { + m_notificationsToPost.append(make_pair(object, notification)); + if (!m_notificationPostTimer.isActive()) + m_notificationPostTimer.startOneShot(0); + } else + postPlatformNotification(object, notification); } void AXObjectCache::selectedChildrenChanged(RenderObject* renderer) diff --git a/src/3rdparty/webkit/WebCore/accessibility/AXObjectCache.h b/src/3rdparty/webkit/WebCore/accessibility/AXObjectCache.h index 5a75f84..dad73f2 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AXObjectCache.h +++ b/src/3rdparty/webkit/WebCore/accessibility/AXObjectCache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -42,104 +42,117 @@ class WebCoreTextMarker; namespace WebCore { - class Node; - class Page; - class RenderObject; - class String; - class VisiblePosition; - - struct TextMarkerData { - AXID axID; - Node* node; - int offset; - EAffinity affinity; +class HTMLAreaElement; +class Node; +class Page; +class RenderObject; +class String; +class VisiblePosition; + +struct TextMarkerData { + AXID axID; + Node* node; + int offset; + EAffinity affinity; +}; + +enum PostType { PostSynchronously, PostAsynchronously }; + +class AXObjectCache : public Noncopyable { +public: + AXObjectCache(); + ~AXObjectCache(); + + static AccessibilityObject* focusedUIElementForPage(const Page*); + + // to be used with render objects + AccessibilityObject* getOrCreate(RenderObject*); + + // used for objects without backing elements + AccessibilityObject* getOrCreate(AccessibilityRole); + + // will only return the AccessibilityObject if it already exists + AccessibilityObject* get(RenderObject*); + + void remove(RenderObject*); + void remove(AXID); + + void detachWrapper(AccessibilityObject*); + void attachWrapper(AccessibilityObject*); + void childrenChanged(RenderObject*); + void selectedChildrenChanged(RenderObject*); + // Called by a node when text or a text equivalent (e.g. alt) attribute is changed. + void contentChanged(RenderObject*); + + void handleActiveDescendantChanged(RenderObject*); + void handleAriaRoleChanged(RenderObject*); + void handleFocusedUIElementChanged(RenderObject* oldFocusedRenderer, RenderObject* newFocusedRenderer); + void handleScrolledToAnchor(const Node* anchorNode); + + static void enableAccessibility() { gAccessibilityEnabled = true; } + static void enableEnhancedUserInterfaceAccessibility() { gAccessibilityEnhancedUserInterfaceEnabled = true; } + + static bool accessibilityEnabled() { return gAccessibilityEnabled; } + static bool accessibilityEnhancedUserInterfaceEnabled() { return gAccessibilityEnhancedUserInterfaceEnabled; } + + void removeAXID(AccessibilityObject*); + bool isIDinUse(AXID id) const { return m_idsInUse.contains(id); } + AXID platformGenerateAXID() const; + AccessibilityObject* objectFromAXID(AXID id) const { return m_objects.get(id).get(); } + + // Text marker utilities. + static void textMarkerDataForVisiblePosition(TextMarkerData&, const VisiblePosition&); + static VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&); + + enum AXNotification { + AXActiveDescendantChanged, + AXCheckedStateChanged, + AXFocusedUIElementChanged, + AXLayoutComplete, + AXLoadComplete, + AXSelectedChildrenChanged, + AXSelectedTextChanged, + AXValueChanged, + AXScrolledToAnchor, + AXLiveRegionChanged, + AXMenuListValueChanged, }; - class AXObjectCache { - public: - AXObjectCache(); - ~AXObjectCache(); - - static AccessibilityObject* focusedUIElementForPage(const Page*); - - // to be used with render objects - AccessibilityObject* getOrCreate(RenderObject*); - - // used for objects without backing elements - AccessibilityObject* getOrCreate(AccessibilityRole); - - // will only return the AccessibilityObject if it already exists - AccessibilityObject* get(RenderObject*); - - void remove(RenderObject*); - void remove(AXID); - - void detachWrapper(AccessibilityObject*); - void attachWrapper(AccessibilityObject*); - void childrenChanged(RenderObject*); - void selectedChildrenChanged(RenderObject*); - void handleActiveDescendantChanged(RenderObject*); - void handleAriaRoleChanged(RenderObject*); - void handleFocusedUIElementChanged(RenderObject* oldFocusedRenderer, RenderObject* newFocusedRenderer); - void handleScrolledToAnchor(const Node* anchorNode); - - static void enableAccessibility() { gAccessibilityEnabled = true; } - static void enableEnhancedUserInterfaceAccessibility() { gAccessibilityEnhancedUserInterfaceEnabled = true; } - - static bool accessibilityEnabled() { return gAccessibilityEnabled; } - static bool accessibilityEnhancedUserInterfaceEnabled() { return gAccessibilityEnhancedUserInterfaceEnabled; } - - void removeAXID(AccessibilityObject*); - bool isIDinUse(AXID id) const { return m_idsInUse.contains(id); } - AXID platformGenerateAXID() const; - AccessibilityObject* objectFromAXID(AXID id) const { return m_objects.get(id).get(); } - - // Text marker utilities. - static void textMarkerDataForVisiblePosition(TextMarkerData&, const VisiblePosition&); - static VisiblePosition visiblePositionForTextMarkerData(TextMarkerData&); - - enum AXNotification { - AXCheckedStateChanged, - AXFocusedUIElementChanged, - AXLayoutComplete, - AXLoadComplete, - AXSelectedChildrenChanged, - AXSelectedTextChanged, - AXValueChanged, - AXScrolledToAnchor, - }; - - void postNotification(RenderObject*, AXNotification, bool postToElement); - - protected: - void postPlatformNotification(AccessibilityObject*, AXNotification); - - private: - HashMap<AXID, RefPtr<AccessibilityObject> > m_objects; - HashMap<RenderObject*, AXID> m_renderObjectMapping; - static bool gAccessibilityEnabled; - static bool gAccessibilityEnhancedUserInterfaceEnabled; - - HashSet<AXID> m_idsInUse; - - Timer<AXObjectCache> m_notificationPostTimer; - Vector<pair<RefPtr<AccessibilityObject>, AXNotification> > m_notificationsToPost; - void notificationPostTimerFired(Timer<AXObjectCache>*); - - AXID getAXID(AccessibilityObject*); - bool nodeIsAriaType(Node* node, String role); - }; + void postNotification(RenderObject*, AXNotification, bool postToElement, PostType = PostAsynchronously); + void postNotification(AccessibilityObject*, Document*, AXNotification, bool postToElement, PostType = PostAsynchronously); + +protected: + void postPlatformNotification(AccessibilityObject*, AXNotification); + +private: + HashMap<AXID, RefPtr<AccessibilityObject> > m_objects; + HashMap<RenderObject*, AXID> m_renderObjectMapping; + static bool gAccessibilityEnabled; + static bool gAccessibilityEnhancedUserInterfaceEnabled; + + HashSet<AXID> m_idsInUse; + + Timer<AXObjectCache> m_notificationPostTimer; + Vector<pair<RefPtr<AccessibilityObject>, AXNotification> > m_notificationsToPost; + void notificationPostTimerFired(Timer<AXObjectCache>*); + + static AccessibilityObject* focusedImageMapUIElement(HTMLAreaElement*); + + AXID getAXID(AccessibilityObject*); + bool nodeIsAriaType(Node*, String role); +}; #if !HAVE(ACCESSIBILITY) - inline void AXObjectCache::handleActiveDescendantChanged(RenderObject*) { } - inline void AXObjectCache::handleAriaRoleChanged(RenderObject*) { } - inline void AXObjectCache::detachWrapper(AccessibilityObject*) { } - inline void AXObjectCache::attachWrapper(AccessibilityObject*) { } - inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { } - inline void AXObjectCache::postNotification(RenderObject*, AXNotification, bool postToElement) { } - inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification) { } - inline void AXObjectCache::handleFocusedUIElementChanged(RenderObject*, RenderObject*) { } - inline void AXObjectCache::handleScrolledToAnchor(const Node*) { } +inline void AXObjectCache::handleActiveDescendantChanged(RenderObject*) { } +inline void AXObjectCache::handleAriaRoleChanged(RenderObject*) { } +inline void AXObjectCache::detachWrapper(AccessibilityObject*) { } +inline void AXObjectCache::attachWrapper(AccessibilityObject*) { } +inline void AXObjectCache::selectedChildrenChanged(RenderObject*) { } +inline void AXObjectCache::postNotification(RenderObject*, AXNotification, bool postToElement, PostType) { } +inline void AXObjectCache::postPlatformNotification(AccessibilityObject*, AXNotification) { } +inline void AXObjectCache::handleFocusedUIElementChanged(RenderObject*, RenderObject*) { } +inline void AXObjectCache::handleScrolledToAnchor(const Node*) { } +inline void AXObjectCache::contentChanged(RenderObject*) { } #endif } diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGrid.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGrid.cpp index 69c4512..58b3fa1 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGrid.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGrid.cpp @@ -29,11 +29,11 @@ #include "config.h" #include "AccessibilityARIAGrid.h" +#include "AXObjectCache.h" #include "AccessibilityTableCell.h" #include "AccessibilityTableColumn.h" #include "AccessibilityTableHeaderContainer.h" #include "AccessibilityTableRow.h" -#include "AXObjectCache.h" #include "RenderObject.h" using namespace std; @@ -131,13 +131,12 @@ AccessibilityTableCell* AccessibilityARIAGrid::cellForColumnAndRow(unsigned colu if (!m_renderer) return 0; - if (!hasChildren()) - addChildren(); + updateChildrenIfNecessary(); if (column >= columnCount() || row >= rowCount()) return 0; - AccessibilityObject *tableRow = m_rows[row].get(); + AccessibilityObject* tableRow = m_rows[row].get(); if (!tableRow) return 0; diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGrid.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGrid.h index 32c8ce9..3511f0f 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGrid.h +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGrid.h @@ -52,6 +52,9 @@ public: virtual AccessibilityTableCell* cellForColumnAndRow(unsigned column, unsigned row); private: + // ARIA treegrids and grids support selected rows. + virtual bool supportsSelectedRows() { return true; } + void addChild(AccessibilityObject* object, HashSet<AccessibilityObject*>& appendedRows, unsigned& columnCount); }; diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGridRow.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGridRow.cpp index 6e1f1c8..7d562d9 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGridRow.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGridRow.cpp @@ -30,6 +30,7 @@ #include "AccessibilityARIAGridRow.h" #include "AccessibilityObject.h" +#include "AccessibilityTable.h" #include "RenderObject.h" using namespace std; @@ -50,6 +51,71 @@ PassRefPtr<AccessibilityARIAGridRow> AccessibilityARIAGridRow::create(RenderObje return adoptRef(new AccessibilityARIAGridRow(renderer)); } +bool AccessibilityARIAGridRow::isARIATreeGridRow() const +{ + AccessibilityObject* parent = parentTable(); + if (!parent) + return false; + + return parent->ariaRoleAttribute() == TreeGridRole; +} + +void AccessibilityARIAGridRow::disclosedRows(AccessibilityChildrenVector& disclosedRows) +{ + // The contiguous disclosed rows will be the rows in the table that + // have an aria-level of plus 1 from this row. + AccessibilityObject* parent = parentObjectUnignored(); + if (!parent || !parent->isDataTable()) + return; + + // Search for rows that match the correct level. + // Only take the subsequent rows from this one that are +1 from this row's level. + int index = rowIndex(); + if (index < 0) + return; + + unsigned level = hierarchicalLevel(); + AccessibilityChildrenVector& allRows = static_cast<AccessibilityTable*>(parent)->rows(); + int rowCount = allRows.size(); + for (int k = index + 1; k < rowCount; ++k) { + AccessibilityObject* row = allRows[k].get(); + // Stop at the first row that doesn't match the correct level. + if (row->hierarchicalLevel() != level + 1) + break; + + disclosedRows.append(row); + } +} + +AccessibilityObject* AccessibilityARIAGridRow::disclosedByRow() const +{ + // The row that discloses this one is the row in the table + // that is aria-level subtract 1 from this row. + AccessibilityObject* parent = parentObjectUnignored(); + if (!parent || !parent->isDataTable()) + return 0; + + // If the level is 1 or less, than nothing discloses this row. + unsigned level = hierarchicalLevel(); + if (level <= 1) + return 0; + + // Search for the previous row that matches the correct level. + int index = rowIndex(); + AccessibilityChildrenVector& allRows = static_cast<AccessibilityTable*>(parent)->rows(); + int rowCount = allRows.size(); + if (index >= rowCount) + return 0; + + for (int k = index - 1; k >= 0; --k) { + AccessibilityObject* row = allRows[k].get(); + if (row->hierarchicalLevel() == level - 1) + return row; + } + + return 0; +} + AccessibilityObject* AccessibilityARIAGridRow::parentTable() const { AccessibilityObject* parent = parentObjectUnignored(); diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGridRow.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGridRow.h index c2ca8b8..f89ea92 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGridRow.h +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityARIAGridRow.h @@ -41,8 +41,14 @@ public: static PassRefPtr<AccessibilityARIAGridRow> create(RenderObject*); virtual ~AccessibilityARIAGridRow(); + void disclosedRows(AccessibilityChildrenVector&); + AccessibilityObject* disclosedByRow() const; + virtual AccessibilityObject* headerObject(); virtual AccessibilityObject* parentTable() const; + +private: + virtual bool isARIATreeGridRow() const; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityAllInOne.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityAllInOne.cpp index 83cf5d0..9cf2068 100755 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityAllInOne.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityAllInOne.cpp @@ -25,6 +25,7 @@ // This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build. +#include <AXObjectCache.cpp> #include <AccessibilityARIAGrid.cpp> #include <AccessibilityARIAGridCell.cpp> #include <AccessibilityARIAGridRow.cpp> @@ -35,10 +36,10 @@ #include <AccessibilityMediaControls.cpp> #include <AccessibilityObject.cpp> #include <AccessibilityRenderObject.cpp> +#include <AccessibilityScrollbar.cpp> #include <AccessibilitySlider.cpp> #include <AccessibilityTable.cpp> #include <AccessibilityTableCell.cpp> #include <AccessibilityTableColumn.cpp> #include <AccessibilityTableHeaderContainer.cpp> #include <AccessibilityTableRow.cpp> -#include <AXObjectCache.cpp> diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityImageMapLink.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityImageMapLink.cpp index 943122e..06150b9 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityImageMapLink.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityImageMapLink.cpp @@ -29,8 +29,8 @@ #include "config.h" #include "AccessibilityImageMapLink.h" -#include "AccessibilityRenderObject.h" #include "AXObjectCache.h" +#include "AccessibilityRenderObject.h" #include "Document.h" #include "HTMLNames.h" #include "IntRect.h" @@ -68,6 +68,18 @@ AccessibilityObject* AccessibilityImageMapLink::parentObject() const return m_mapElement->document()->axObjectCache()->getOrCreate(m_mapElement->renderer()); } +AccessibilityRole AccessibilityImageMapLink::roleValue() const +{ + if (!m_areaElement) + return WebCoreLinkRole; + + const AtomicString& ariaRole = m_areaElement->getAttribute(roleAttr); + if (!ariaRole.isEmpty()) + return AccessibilityObject::ariaRoleToWebCoreRole(ariaRole); + + return WebCoreLinkRole; +} + Element* AccessibilityImageMapLink::actionElement() const { return anchorElement(); @@ -134,5 +146,15 @@ IntSize AccessibilityImageMapLink::size() const { return elementRect().size(); } - + +String AccessibilityImageMapLink::stringValueForMSAA() const +{ + return url(); +} + +String AccessibilityImageMapLink::nameForMSAA() const +{ + return accessibilityDescription(); +} + } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityImageMapLink.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityImageMapLink.h index 2c27e46..ca4c62c 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityImageMapLink.h +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityImageMapLink.h @@ -44,21 +44,29 @@ public: virtual ~AccessibilityImageMapLink(); void setHTMLAreaElement(HTMLAreaElement* element) { m_areaElement = element; } + HTMLAreaElement* areaElement() const { return m_areaElement; } + void setHTMLMapElement(HTMLMapElement* element) { m_mapElement = element; } + HTMLMapElement* mapElement() const { return m_mapElement; } + void setParent(AccessibilityObject* parent) { m_parent = parent; } - virtual AccessibilityRole roleValue() const { return WebCoreLinkRole; } + virtual AccessibilityRole roleValue() const; virtual bool accessibilityIsIgnored() const { return false; } virtual bool isEnabled() const { return true; } - + virtual AccessibilityObject* parentObject() const; virtual Element* anchorElement() const; virtual Element* actionElement() const; virtual KURL url() const; virtual bool isLink() const { return true; } + virtual bool isLinked() const { return true; } virtual String title() const; virtual String accessibilityDescription() const; - + + virtual String stringValueForMSAA() const; + virtual String nameForMSAA() const; + virtual IntSize size() const; virtual IntRect elementRect() const; @@ -66,6 +74,8 @@ private: HTMLAreaElement* m_areaElement; HTMLMapElement* m_mapElement; AccessibilityObject* m_parent; + + virtual bool isImageMapLink() const { return true; } }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityList.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityList.cpp index 95239b0..073b0fc 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityList.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityList.cpp @@ -55,6 +55,12 @@ PassRefPtr<AccessibilityList> AccessibilityList::create(RenderObject* renderer) bool AccessibilityList::accessibilityIsIgnored() const { + AccessibilityObjectInclusion decision = accessibilityIsIgnoredBase(); + if (decision == IncludeObject) + return false; + if (decision == IgnoreObject) + return true; + // lists don't appear on tiger/leopard on the mac #if ACCESSIBILITY_LISTS return false; @@ -83,7 +89,11 @@ bool AccessibilityList::isOrderedList() const { if (!m_renderer) return false; - + + // ARIA says a directory is like a static table of contents, which sounds like an ordered list. + if (ariaRoleAttribute() == DirectoryRole) + return true; + Node* node = m_renderer->node(); return node && node->hasTagName(olTag); } diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityList.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityList.h index 89befb2..b7265b2 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityList.h +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityList.h @@ -47,7 +47,7 @@ public: static PassRefPtr<AccessibilityList> create(RenderObject*); virtual ~AccessibilityList(); - virtual bool isList() const { return true; }; + virtual bool isList() const { return true; } bool isUnorderedList() const; bool isOrderedList() const; bool isDefinitionList() const; diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBox.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBox.cpp index 1f37481..8a9e062 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBox.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBox.cpp @@ -31,9 +31,9 @@ #include "AXObjectCache.h" #include "AccessibilityListBoxOption.h" -#include "HitTestResult.h" #include "HTMLNames.h" #include "HTMLSelectElement.h" +#include "HitTestResult.h" #include "RenderListBox.h" #include "RenderObject.h" @@ -78,9 +78,9 @@ void AccessibilityListBox::addChildren() unsigned length = listItems.size(); for (unsigned i = 0; i < length; 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 accessbility features at all. + // 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 accessbility features at all. - if (rect.contains(point)) - return listBoxOptionAccessibilityObject(static_cast<HTMLElement*>(listItems[i])); + // would be a WMLElement, but WML builds don't use accessibility features at all. + if (rect.contains(point)) { + listBoxOption = m_children[i].get(); + break; + } } + if (listBoxOption && !listBoxOption->accessibilityIsIgnored()) + return listBoxOption; + return axObjectCache()->getOrCreate(m_renderer); } diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBox.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBox.h index 3f3352d..72ce82f 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBox.h +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBox.h @@ -43,15 +43,13 @@ public: virtual ~AccessibilityListBox(); virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&) const; - virtual bool isListBox() const { return true; }; + virtual bool isListBox() const { return true; } virtual bool canSetFocusAttribute() const { return true; } 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/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBoxOption.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBoxOption.cpp index 6e3bf98..57519e3 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBoxOption.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBoxOption.cpp @@ -34,12 +34,12 @@ #include "Element.h" #include "HTMLElement.h" #include "HTMLNames.h" -#include "HTMLOptionElement.h" #include "HTMLOptGroupElement.h" +#include "HTMLOptionElement.h" #include "HTMLSelectElement.h" #include "IntRect.h" -#include "RenderObject.h" #include "RenderListBox.h" +#include "RenderObject.h" using namespace std; @@ -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/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBoxOption.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBoxOption.h index 933cdeb..1da77e7 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityListBoxOption.h +++ b/src/3rdparty/webkit/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; @@ -63,11 +63,12 @@ public: virtual IntRect elementRect() const; virtual IntSize size() const; virtual AccessibilityObject* parentObject() const; - bool isListBoxOption() const { return true; }; + bool isListBoxOption() const { return true; } private: HTMLElement* m_optionElement; + virtual String language() const; virtual bool canHaveChildren() const { return false; } HTMLSelectElement* listBoxOptionParentNode() const; int listBoxOptionIndex() const; diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMediaControls.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMediaControls.cpp index 7200de9..6151840 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMediaControls.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMediaControls.cpp @@ -113,6 +113,8 @@ String AccessibilityMediaControl::controlTypeName() const DEFINE_STATIC_LOCAL(const String, mediaStatusDisplayName, ("StatusDisplay")); DEFINE_STATIC_LOCAL(const String, mediaCurrentTimeDisplay, ("CurrentTimeDisplay")); DEFINE_STATIC_LOCAL(const String, mediaTimeRemainingDisplay, ("TimeRemainingDisplay")); + DEFINE_STATIC_LOCAL(const String, mediaShowClosedCaptionsButtonName, ("ShowClosedCaptionsButton")); + DEFINE_STATIC_LOCAL(const String, mediaHideClosedCaptionsButtonName, ("HideClosedCaptionsButton")); switch (controlType()) { case MediaFullscreenButton: @@ -139,6 +141,10 @@ String AccessibilityMediaControl::controlTypeName() const return mediaCurrentTimeDisplay; case MediaTimeRemainingDisplay: return mediaTimeRemainingDisplay; + case MediaShowClosedCaptionsButton: + return mediaShowClosedCaptionsButtonName; + case MediaHideClosedCaptionsButton: + return mediaHideClosedCaptionsButtonName; default: break; @@ -187,6 +193,8 @@ AccessibilityRole AccessibilityMediaControl::roleValue() const case MediaReturnToRealtimeButton: case MediaUnMuteButton: case MediaPauseButton: + case MediaShowClosedCaptionsButton: + case MediaHideClosedCaptionsButton: return ButtonRole; case MediaStatusDisplay: diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMediaControls.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMediaControls.h index 9b306fd..6f51b2c 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMediaControls.h +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMediaControls.h @@ -37,77 +37,77 @@ namespace WebCore { - class AccessibilityMediaControl : public AccessibilityRenderObject { +class AccessibilityMediaControl : public AccessibilityRenderObject { - public: - static PassRefPtr<AccessibilityObject> create(RenderObject*); - virtual ~AccessibilityMediaControl() { } +public: + static PassRefPtr<AccessibilityObject> create(RenderObject*); + virtual ~AccessibilityMediaControl() { } - virtual AccessibilityRole roleValue() const; - virtual bool accessibilityIsIgnored() const; + virtual AccessibilityRole roleValue() const; + virtual bool accessibilityIsIgnored() const; - virtual String title() const; - virtual String accessibilityDescription() const; - virtual String helpText() const; + virtual String title() const; + virtual String accessibilityDescription() const; + virtual String helpText() const; - protected: - AccessibilityMediaControl(RenderObject*); - MediaControlElementType controlType() const; - String controlTypeName() const; - }; +protected: + AccessibilityMediaControl(RenderObject*); + MediaControlElementType controlType() const; + String controlTypeName() const; +}; - class AccessibilityMediaTimeline : public AccessibilitySlider { +class AccessibilityMediaTimeline : public AccessibilitySlider { - public: - static PassRefPtr<AccessibilityObject> create(RenderObject*); - virtual ~AccessibilityMediaTimeline() { } +public: + static PassRefPtr<AccessibilityObject> create(RenderObject*); + virtual ~AccessibilityMediaTimeline() { } - virtual bool isMediaTimeline() const { return true; } + virtual bool isMediaTimeline() const { return true; } - virtual String helpText() const; - virtual String valueDescription() const; - const AtomicString& getAttribute(const QualifiedName& attribute) const; + virtual String helpText() const; + virtual String valueDescription() const; + const AtomicString& getAttribute(const QualifiedName& attribute) const; - private: - AccessibilityMediaTimeline(RenderObject*); - }; +private: + AccessibilityMediaTimeline(RenderObject*); +}; - class AccessibilityMediaControlsContainer : public AccessibilityMediaControl { +class AccessibilityMediaControlsContainer : public AccessibilityMediaControl { - public: - static PassRefPtr<AccessibilityObject> create(RenderObject*); - virtual ~AccessibilityMediaControlsContainer() { } +public: + static PassRefPtr<AccessibilityObject> create(RenderObject*); + virtual ~AccessibilityMediaControlsContainer() { } - virtual AccessibilityRole roleValue() const { return ToolbarRole; } - virtual bool accessibilityIsIgnored() const { return false; } + virtual AccessibilityRole roleValue() const { return ToolbarRole; } + virtual bool accessibilityIsIgnored() const { return false; } - virtual String helpText() const; - virtual String accessibilityDescription() const; + virtual String helpText() const; + virtual String accessibilityDescription() const; - private: - AccessibilityMediaControlsContainer(RenderObject*); - bool controllingVideoElement() const; - const String elementTypeName() const; - }; +private: + AccessibilityMediaControlsContainer(RenderObject*); + bool controllingVideoElement() const; + const String elementTypeName() const; +}; - class AccessibilityMediaTimeDisplay : public AccessibilityMediaControl { +class AccessibilityMediaTimeDisplay : public AccessibilityMediaControl { - public: - static PassRefPtr<AccessibilityObject> create(RenderObject*); - virtual ~AccessibilityMediaTimeDisplay() { } +public: + static PassRefPtr<AccessibilityObject> create(RenderObject*); + virtual ~AccessibilityMediaTimeDisplay() { } - virtual AccessibilityRole roleValue() const { return StaticTextRole; } - virtual bool accessibilityIsIgnored() const; + virtual AccessibilityRole roleValue() const { return StaticTextRole; } + virtual bool accessibilityIsIgnored() const; - virtual String stringValue() const; - virtual String accessibilityDescription() const; + virtual String stringValue() const; + virtual String accessibilityDescription() const; - private: - AccessibilityMediaTimeDisplay(RenderObject*); - }; +private: + AccessibilityMediaTimeDisplay(RenderObject*); +}; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuList.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuList.cpp new file mode 100644 index 0000000..05cdf97 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuList.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AccessibilityMenuList.h" + +#include "AXObjectCache.h" +#include "AccessibilityMenuListPopup.h" +#include "RenderMenuList.h" + +namespace WebCore { + +AccessibilityMenuList::AccessibilityMenuList(RenderObject* renderer) + : AccessibilityRenderObject(renderer) +{ + ASSERT_ARG(renderer, renderer->isMenuList()); +} + +bool AccessibilityMenuList::press() const +{ + RenderMenuList* menuList = static_cast<RenderMenuList*>(m_renderer); + if (menuList->popupIsVisible()) + menuList->hidePopup(); + else + menuList->showPopup(); + return true; +} + +void AccessibilityMenuList::addChildren() +{ + m_haveChildren = true; + + AXObjectCache* cache = m_renderer->document()->axObjectCache(); + + AccessibilityObject* list = cache->getOrCreate(MenuListPopupRole); + if (!list) + return; + + if (list->accessibilityPlatformIncludesObject() == IgnoreObject) { + cache->remove(list->axObjectID()); + return; + } + + static_cast<AccessibilityMenuListPopup*>(list)->setMenuList(this); + m_children.append(list); + + list->addChildren(); +} + +void AccessibilityMenuList::childrenChanged() +{ + if (m_children.isEmpty()) + return; + + ASSERT(m_children.size() == 1); + m_children[0]->childrenChanged(); +} + +bool AccessibilityMenuList::isCollapsed() const +{ + return !static_cast<RenderMenuList*>(m_renderer)->popupIsVisible(); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuList.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuList.h new file mode 100644 index 0000000..d00c8b4 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuList.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AccessibilityMenuList_h +#define AccessibilityMenuList_h + +#include "AccessibilityObject.h" +#include "AccessibilityRenderObject.h" + +namespace WebCore { + +class AccessibilityMenuList; +class AccessibilityMenuListPopup; +class HTMLOptionElement; + +class AccessibilityMenuList : public AccessibilityRenderObject { +public: + static PassRefPtr<AccessibilityMenuList> create(RenderObject* renderer) { return adoptRef(new AccessibilityMenuList(renderer)); } + + virtual bool isCollapsed() const; + virtual bool press() const; + +private: + AccessibilityMenuList(RenderObject*); + + virtual bool isMenuList() const { return true; } + virtual AccessibilityRole roleValue() const { return PopUpButtonRole; } + virtual bool accessibilityIsIgnored() const { return false; } + virtual bool canSetFocusAttribute() const { return true; } + + virtual void addChildren(); + virtual void childrenChanged(); +}; + +} // namespace WebCore + +#endif // AccessibilityMenuList_h diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuListOption.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuListOption.cpp new file mode 100644 index 0000000..d7473de --- /dev/null +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuListOption.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AccessibilityMenuListOption.h" + +#include "AXObjectCache.h" +#include "AccessibilityMenuListPopup.h" +#include "HTMLNames.h" +#include "HTMLOptionElement.h" + +namespace WebCore { + +using namespace HTMLNames; + +AccessibilityMenuListOption::AccessibilityMenuListOption() + : m_popup(0) +{ +} + +void AccessibilityMenuListOption::setElement(HTMLElement* element) +{ + ASSERT_ARG(element, element->hasTagName(optionTag)); + m_element = element; +} + +Element* AccessibilityMenuListOption::actionElement() const +{ + return m_element.get(); +} + +AccessibilityObject* AccessibilityMenuListOption::parentObject() const +{ + return m_popup; +} + +bool AccessibilityMenuListOption::isEnabled() const +{ + // disabled() returns true if the parent <select> element is disabled, + // which we don't want. + return !static_cast<HTMLOptionElement*>(m_element.get())->ownElementDisabled(); +} + +bool AccessibilityMenuListOption::isVisible() const +{ + // In a single-option select with the popup collapsed, only the selected + // item is considered visible. + return !m_popup->isOffScreen() || isSelected(); +} + +bool AccessibilityMenuListOption::isOffScreen() const +{ + // Invisible list options are considered to be offscreen. + return !isVisible(); +} + +bool AccessibilityMenuListOption::isSelected() const +{ + return static_cast<HTMLOptionElement*>(m_element.get())->selected(); +} + +void AccessibilityMenuListOption::setSelected(bool b) +{ + if (!canSetSelectedAttribute()) + return; + + static_cast<HTMLOptionElement*>(m_element.get())->setSelected(b); +} + +String AccessibilityMenuListOption::nameForMSAA() const +{ + return static_cast<HTMLOptionElement*>(m_element.get())->text(); +} + +bool AccessibilityMenuListOption::canSetSelectedAttribute() const +{ + return isEnabled(); +} + +IntRect AccessibilityMenuListOption::elementRect() const +{ + AccessibilityObject* parent = parentObject(); + ASSERT(parent->isMenuListPopup()); + + AccessibilityObject* grandparent = parent->parentObject(); + ASSERT(grandparent->isMenuList()); + + return grandparent->elementRect(); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuListOption.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuListOption.h new file mode 100644 index 0000000..7e27888 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuListOption.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AccessibilityMenuListOption_h +#define AccessibilityMenuListOption_h + +#include "AccessibilityObject.h" + +namespace WebCore { + +class AccessibilityMenuListPopup; +class HTMLElement; + +class AccessibilityMenuListOption : public AccessibilityObject { +public: + static PassRefPtr<AccessibilityMenuListOption> create() { return adoptRef(new AccessibilityMenuListOption); } + + void setElement(HTMLElement*); + void setParent(AccessibilityMenuListPopup* popup) { m_popup = popup; } + +private: + AccessibilityMenuListOption(); + + virtual bool isMenuListOption() const { return true; } + + virtual AccessibilityRole roleValue() const { return MenuListOptionRole; } + virtual bool canHaveChildren() const { return false; } + virtual IntSize size() const { return elementRect().size(); } + + virtual Element* actionElement() const; + virtual AccessibilityObject* parentObject() const; + virtual bool isEnabled() const; + virtual bool isVisible() const; + virtual bool isOffScreen() const; + virtual bool isSelected() const; + virtual String nameForMSAA() const; + virtual void setSelected(bool); + virtual bool canSetSelectedAttribute() const; + virtual IntRect elementRect() const; + + RefPtr<HTMLElement> m_element; + AccessibilityMenuListPopup* m_popup; +}; + +} // namespace WebCore + +#endif // AccessibilityMenuListOption_h diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuListPopup.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuListPopup.cpp new file mode 100644 index 0000000..48c2fab --- /dev/null +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuListPopup.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AccessibilityMenuListPopup.h" + +#include "AXObjectCache.h" +#include "AccessibilityMenuList.h" +#include "AccessibilityMenuListOption.h" +#include "HTMLNames.h" +#include "HTMLSelectElement.h" +#include "RenderObject.h" + +namespace WebCore { + +using namespace HTMLNames; + +AccessibilityMenuListPopup::AccessibilityMenuListPopup() + : m_menuList(0) +{ +} + +bool AccessibilityMenuListPopup::isVisible() const +{ + return false; +} + +bool AccessibilityMenuListPopup::isOffScreen() const +{ + return m_menuList->isCollapsed(); +} + +AccessibilityObject* AccessibilityMenuListPopup::parentObject() const +{ + return m_menuList; +} + +bool AccessibilityMenuListPopup::isEnabled() const +{ + return m_menuList->isEnabled(); +} + +AccessibilityMenuListOption* AccessibilityMenuListPopup::menuListOptionAccessibilityObject(HTMLElement* element) const +{ + if (!element || !element->hasTagName(optionTag)) + return 0; + + AccessibilityObject* object = m_menuList->renderer()->document()->axObjectCache()->getOrCreate(MenuListOptionRole); + ASSERT(object->isMenuListOption()); + + AccessibilityMenuListOption* option = static_cast<AccessibilityMenuListOption*>(object); + option->setElement(element); + + return option; +} + +bool AccessibilityMenuListPopup::press() const +{ + m_menuList->press(); + return true; +} + +void AccessibilityMenuListPopup::addChildren() +{ + Node* selectNode = m_menuList->renderer()->node(); + if (!selectNode) + return; + + m_haveChildren = true; + + ASSERT(selectNode->hasTagName(selectTag)); + + const Vector<Element*>& listItems = static_cast<HTMLSelectElement*>(selectNode)->listItems(); + unsigned length = listItems.size(); + for (unsigned i = 0; i < length; 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 accessbility features at all. + AccessibilityMenuListOption* option = menuListOptionAccessibilityObject(static_cast<HTMLElement*>(listItems[i])); + if (option) { + option->setParent(this); + m_children.append(option); + } + } +} + +void AccessibilityMenuListPopup::childrenChanged() +{ + for (size_t i = m_children.size(); i > 0 ; --i) { + AccessibilityObject* child = m_children[i - 1].get(); + if (child->actionElement() && !child->actionElement()->attached()) { + m_menuList->renderer()->document()->axObjectCache()->remove(child->axObjectID()); + m_children.remove(i - 1); + } + } +} + +void AccessibilityMenuListPopup::setMenuList(AccessibilityMenuList* menuList) +{ + ASSERT_ARG(menuList, menuList); + ASSERT(!m_menuList); + m_menuList = menuList; +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuListPopup.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuListPopup.h new file mode 100644 index 0000000..88fbf7c --- /dev/null +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityMenuListPopup.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AccessibilityMenuListPopup_h +#define AccessibilityMenuListPopup_h + +#include "AccessibilityObject.h" + +namespace WebCore { + +class AccessibilityMenuList; +class AccessibilityMenuListOption; +class HTMLElement; + +class AccessibilityMenuListPopup : public AccessibilityObject { +public: + static PassRefPtr<AccessibilityMenuListPopup> create() { return adoptRef(new AccessibilityMenuListPopup); } + + void setMenuList(AccessibilityMenuList*); + + virtual bool isEnabled() const; + virtual bool isOffScreen() const; + +private: + AccessibilityMenuListPopup(); + + virtual bool isMenuListPopup() const { return true; } + + virtual IntRect elementRect() const { return IntRect(); } + virtual IntSize size() const { return IntSize(); } + virtual AccessibilityRole roleValue() const { return MenuListPopupRole; } + + virtual bool isVisible() const; + virtual AccessibilityObject* parentObject() const; + virtual bool press() const; + virtual void addChildren(); + virtual void childrenChanged(); + + AccessibilityMenuListOption* menuListOptionAccessibilityObject(HTMLElement*) const; + + AccessibilityMenuList* m_menuList; +}; + +} // namespace WebCore + +#endif // AccessibilityMenuListPopup_h diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityObject.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityObject.cpp index d7093e4..8dedc36 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityObject.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityObject.cpp @@ -29,8 +29,8 @@ #include "config.h" #include "AccessibilityObject.h" -#include "AccessibilityRenderObject.h" #include "AXObjectCache.h" +#include "AccessibilityRenderObject.h" #include "CharacterNames.h" #include "FloatRect.h" #include "FocusController.h" @@ -85,8 +85,9 @@ void AccessibilityObject::detach() AccessibilityObject* AccessibilityObject::parentObjectUnignored() const { AccessibilityObject* parent; - for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject()) - ; + for (parent = parentObject(); parent && parent->accessibilityIsIgnored(); parent = parent->parentObject()) { + } + return parent; } @@ -147,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(); @@ -275,7 +285,7 @@ VisiblePositionRange AccessibilityObject::rightLineVisiblePositionRange(const Vi VisiblePosition startPosition = startOfLine(nextVisiblePos); // fetch for a valid line start position - if (startPosition.isNull() ) { + if (startPosition.isNull()) { startPosition = visiblePos; nextVisiblePos = nextVisiblePos.next(); } else @@ -381,9 +391,8 @@ static bool replacedNodeNeedsCharacter(Node* replacedNode) { // we should always be given a rendered node and a replaced node, but be safe // replaced nodes are either attachments (widgets) or images - if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) { + if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) return false; - } // create an AX object, but skip it if it is not supposed to be seen AccessibilityObject* object = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer()); @@ -445,7 +454,7 @@ String AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionR RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end); for (TextIterator it(range.get()); !it.atEnd(); it.advance()) { // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX) - if (it.length() != 0) { + if (it.length()) { // Add a textual representation for list marker text String listMarkerText = listMarkerTextForNodeAndPosition(it.node(), visiblePositionRange.start); if (!listMarkerText.isEmpty()) @@ -459,9 +468,8 @@ String AccessibilityObject::stringForVisiblePositionRange(const VisiblePositionR ASSERT(node == it.range()->endContainer(exception)); int offset = it.range()->startOffset(exception); - if (replacedNodeNeedsCharacter(node->childNode(offset))) { + if (replacedNodeNeedsCharacter(node->childNode(offset))) resultVector.append(objectReplacementCharacter); - } } } @@ -478,9 +486,9 @@ int AccessibilityObject::lengthForVisiblePositionRange(const VisiblePositionRang RefPtr<Range> range = makeRange(visiblePositionRange.start, visiblePositionRange.end); for (TextIterator it(range.get()); !it.atEnd(); it.advance()) { // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX) - if (it.length() != 0) { + if (it.length()) length += it.length(); - } else { + else { // locate the node and starting offset for this replaced range int exception = 0; Node* node = it.range()->startContainer(exception); @@ -732,8 +740,8 @@ FrameView* AccessibilityObject::documentFrameView() const void AccessibilityObject::clearChildren() { - m_haveChildren = false; m_children.clear(); + m_haveChildren = false; } AccessibilityObject* AccessibilityObject::anchorElementForNode(Node* node) @@ -754,6 +762,53 @@ AccessibilityObject* AccessibilityObject::anchorElementForNode(Node* node) return anchorRenderer->document()->axObjectCache()->getOrCreate(anchorRenderer); } +void AccessibilityObject::ariaTreeRows(AccessibilityChildrenVector& result) +{ + AccessibilityChildrenVector axChildren = children(); + unsigned count = axChildren.size(); + for (unsigned k = 0; k < count; ++k) { + AccessibilityObject* obj = axChildren[k].get(); + + // Add tree items as the rows. + if (obj->roleValue() == TreeItemRole) + result.append(obj); + + // Now see if this item also has rows hiding inside of it. + obj->ariaTreeRows(result); + } +} + +void AccessibilityObject::ariaTreeItemContent(AccessibilityChildrenVector& result) +{ + // The ARIA tree item content are the item that are not other tree items or their containing groups. + AccessibilityChildrenVector axChildren = children(); + unsigned count = axChildren.size(); + for (unsigned k = 0; k < count; ++k) { + AccessibilityObject* obj = axChildren[k].get(); + AccessibilityRole role = obj->roleValue(); + if (role == TreeItemRole || role == GroupRole) + continue; + + result.append(obj); + } +} + +void AccessibilityObject::ariaTreeItemDisclosedRows(AccessibilityChildrenVector& result) +{ + AccessibilityChildrenVector axChildren = children(); + unsigned count = axChildren.size(); + for (unsigned k = 0; k < count; ++k) { + AccessibilityObject* obj = axChildren[k].get(); + + // Add tree items as the rows. + if (obj->roleValue() == TreeItemRole) + result.append(obj); + // If it's not a tree item, then descend into the group to find more tree items. + else + obj->ariaTreeRows(result); + } +} + const String& AccessibilityObject::actionVerb() const { // FIXME: Need to add verbs for select elements. @@ -763,26 +818,44 @@ const String& AccessibilityObject::actionVerb() const DEFINE_STATIC_LOCAL(const String, checkedCheckBoxAction, (AXCheckedCheckBoxActionVerb())); DEFINE_STATIC_LOCAL(const String, uncheckedCheckBoxAction, (AXUncheckedCheckBoxActionVerb())); DEFINE_STATIC_LOCAL(const String, linkAction, (AXLinkActionVerb())); + DEFINE_STATIC_LOCAL(const String, menuListAction, (AXMenuListActionVerb())); + DEFINE_STATIC_LOCAL(const String, menuListPopupAction, (AXMenuListPopupActionVerb())); DEFINE_STATIC_LOCAL(const String, noAction, ()); switch (roleValue()) { - case ButtonRole: - return buttonAction; - case TextFieldRole: - case TextAreaRole: - return textFieldAction; - case RadioButtonRole: - return radioButtonAction; - case CheckBoxRole: - return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction; - case LinkRole: - case WebCoreLinkRole: - return linkAction; - default: - return noAction; + case ButtonRole: + return buttonAction; + case TextFieldRole: + case TextAreaRole: + return textFieldAction; + case RadioButtonRole: + return radioButtonAction; + case CheckBoxRole: + return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction; + case LinkRole: + case WebCoreLinkRole: + return linkAction; + case PopUpButtonRole: + return menuListAction; + case MenuListPopupRole: + return menuListPopupAction; + default: + return noAction; } } +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 { @@ -794,6 +867,119 @@ AccessibilityOrientation AccessibilityObject::orientation() const // A tie goes to horizontal. return AccessibilityOrientationHorizontal; +} + +typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap; + +struct RoleEntry { + String ariaRole; + AccessibilityRole webcoreRole; +}; + +static ARIARoleMap* createARIARoleMap() +{ + const RoleEntry roles[] = { + { "alert", ApplicationAlertRole }, + { "alertdialog", ApplicationAlertDialogRole }, + { "application", LandmarkApplicationRole }, + { "article", DocumentArticleRole }, + { "banner", LandmarkBannerRole }, + { "button", ButtonRole }, + { "checkbox", CheckBoxRole }, + { "complementary", LandmarkComplementaryRole }, + { "contentinfo", LandmarkContentInfoRole }, + { "dialog", ApplicationDialogRole }, + { "directory", DirectoryRole }, + { "grid", TableRole }, + { "gridcell", CellRole }, + { "columnheader", ColumnHeaderRole }, + { "combobox", ComboBoxRole }, + { "definition", DefinitionListDefinitionRole }, + { "document", DocumentRole }, + { "rowheader", RowHeaderRole }, + { "group", GroupRole }, + { "heading", HeadingRole }, + { "img", ImageRole }, + { "link", WebCoreLinkRole }, + { "list", ListRole }, + { "listitem", GroupRole }, + { "listbox", ListBoxRole }, + { "log", ApplicationLogRole }, + // "option" isn't here because it may map to different roles depending on the parent element's role + { "main", LandmarkMainRole }, + { "marquee", ApplicationMarqueeRole }, + { "math", DocumentMathRole }, + { "menu", MenuRole }, + { "menubar", GroupRole }, + // "menuitem" isn't here because it may map to different roles depending on the parent element's role + { "menuitemcheckbox", MenuItemRole }, + { "menuitemradio", MenuItemRole }, + { "note", DocumentNoteRole }, + { "navigation", LandmarkNavigationRole }, + { "option", ListBoxOptionRole }, + { "presentation", IgnoredRole }, + { "progressbar", ProgressIndicatorRole }, + { "radio", RadioButtonRole }, + { "radiogroup", RadioGroupRole }, + { "region", DocumentRegionRole }, + { "row", RowRole }, + { "range", SliderRole }, + { "scrollbar", ScrollBarRole }, + { "search", LandmarkSearchRole }, + { "separator", SplitterRole }, + { "slider", SliderRole }, + { "spinbutton", ProgressIndicatorRole }, + { "status", ApplicationStatusRole }, + { "tab", TabRole }, + { "tablist", TabListRole }, + { "tabpanel", TabPanelRole }, + { "text", StaticTextRole }, + { "textbox", TextAreaRole }, + { "timer", ApplicationTimerRole }, + { "toolbar", ToolbarRole }, + { "tooltip", UserInterfaceTooltipRole }, + { "tree", TreeRole }, + { "treegrid", TreeGridRole }, + { "treeitem", TreeItemRole } + }; + ARIARoleMap* roleMap = new ARIARoleMap; + + const unsigned numRoles = sizeof(roles) / sizeof(roles[0]); + for (unsigned i = 0; i < numRoles; ++i) + roleMap->set(roles[i].ariaRole, roles[i].webcoreRole); + return roleMap; +} + +AccessibilityRole AccessibilityObject::ariaRoleToWebCoreRole(const String& value) +{ + ASSERT(!value.isEmpty()); + static const ARIARoleMap* roleMap = createARIARoleMap(); + return roleMap->get(value); } + +bool AccessibilityObject::isInsideARIALiveRegion() const +{ + if (supportsARIALiveRegion()) + return true; + + for (AccessibilityObject* axParent = parentObject(); axParent; axParent = axParent->parentObject()) { + if (axParent->supportsARIALiveRegion()) + return true; + } + + return false; +} + +bool AccessibilityObject::supportsARIAAttributes() const +{ + return supportsARIALiveRegion() || supportsARIADragging() || supportsARIADropping() || supportsARIAFlowTo() || supportsARIAOwns(); +} + +bool AccessibilityObject::supportsARIALiveRegion() const +{ + const AtomicString& liveRegion = ariaLiveRegionStatus(); + return equalIgnoringCase(liveRegion, "polite") || equalIgnoringCase(liveRegion, "assertive"); +} + } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityObject.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityObject.h index 8fc40e8..7c52cd5 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityObject.h +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityObject.h @@ -34,13 +34,12 @@ #include "Range.h" #include "VisiblePosition.h" #include "VisibleSelection.h" -#include <wtf/Platform.h> #include <wtf/RefPtr.h> #include <wtf/Vector.h> #if PLATFORM(MAC) #include <wtf/RetainPtr.h> -#elif PLATFORM(WIN) && !PLATFORM(WINCE) +#elif PLATFORM(WIN) && !OS(WINCE) #include "AccessibilityObjectWrapperWin.h" #include "COMPtr.h" #elif PLATFORM(CHROMIUM) @@ -161,7 +160,18 @@ enum AccessibilityRole { AnnotationRole, SliderThumbRole, IgnoredRole, - + TabRole, + TabListRole, + TabPanelRole, + TreeRole, + TreeGridRole, + TreeItemRole, + DirectoryRole, + EditableTextRole, + ListItemRole, + MenuListPopupRole, + MenuListOptionRole, + // ARIA Grouping roles LandmarkApplicationRole, LandmarkBannerRole, @@ -171,6 +181,9 @@ enum AccessibilityRole { LandmarkNavigationRole, LandmarkSearchRole, + ApplicationAlertRole, + ApplicationAlertDialogRole, + ApplicationDialogRole, ApplicationLogRole, ApplicationMarqueeRole, ApplicationStatusRole, @@ -178,6 +191,7 @@ enum AccessibilityRole { DocumentRole, DocumentArticleRole, + DocumentMathRole, DocumentNoteRole, DocumentRegionRole, @@ -189,7 +203,7 @@ enum AccessibilityOrientation { AccessibilityOrientationHorizontal, }; -enum AccessibilityObjectPlatformInclusion { +enum AccessibilityObjectInclusion { IncludeObject, IgnoreObject, DefaultBehavior, @@ -225,7 +239,7 @@ struct PlainTextRange { , length(l) { } - bool isNull() const { return start == 0 && length == 0; } + bool isNull() const { return !start && !length; } }; class AccessibilityObject : public RefCounted<AccessibilityObject> { @@ -237,64 +251,82 @@ public: typedef Vector<RefPtr<AccessibilityObject> > AccessibilityChildrenVector; - virtual bool isAccessibilityRenderObject() const { return false; }; - virtual bool isAnchor() const { return false; }; - virtual bool isAttachment() const { return false; }; - virtual bool isHeading() const { return false; }; - virtual bool isLink() const { return false; }; - virtual bool isImage() const { return false; }; - virtual bool isNativeImage() const { return false; }; - virtual bool isImageButton() const { return false; }; - virtual bool isPasswordField() const { return false; }; - virtual bool isTextControl() const { return false; }; - virtual bool isNativeTextControl() const { return false; }; - virtual bool isWebArea() const { return false; }; - virtual bool isCheckboxOrRadio() const { return false; }; - virtual bool isListBox() const { return roleValue() == ListBoxRole; }; + virtual bool isAccessibilityRenderObject() const { return false; } + virtual bool isAnchor() const { return false; } + virtual bool isAttachment() const { return false; } + virtual bool isHeading() const { return false; } + virtual bool isLink() const { return false; } + virtual bool isImage() const { return false; } + virtual bool isNativeImage() const { return false; } + virtual bool isImageButton() const { return false; } + virtual bool isPasswordField() const { return false; } + virtual bool isTextControl() const { return false; } + virtual bool isNativeTextControl() const { return false; } + virtual bool isWebArea() const { return false; } + virtual bool isCheckboxOrRadio() const { return false; } + virtual bool isListBox() const { return roleValue() == ListBoxRole; } virtual bool isMediaTimeline() const { return false; } virtual bool isMenuRelated() const { return false; } virtual bool isMenu() const { return false; } virtual bool isMenuBar() const { return false; } virtual bool isMenuButton() const { return false; } virtual bool isMenuItem() const { return false; } - virtual bool isFileUploadButton() const { return false; }; + virtual bool isFileUploadButton() const { return false; } virtual bool isInputImage() const { return false; } - virtual bool isProgressIndicator() const { return false; }; - virtual bool isSlider() const { return false; }; - virtual bool isControl() const { return false; }; - virtual bool isList() const { return false; }; - virtual bool isDataTable() const { return false; }; - virtual bool isTableRow() const { return false; }; - virtual bool isTableColumn() const { return false; }; - virtual bool isTableCell() const { return false; }; - virtual bool isFieldset() const { return false; }; - virtual bool isGroup() const { return false; }; + virtual bool isProgressIndicator() const { return false; } + virtual bool isSlider() const { return false; } + virtual bool isControl() const { return false; } + virtual bool isList() const { return false; } + virtual bool isDataTable() const { return false; } + virtual bool isTableRow() const { return false; } + virtual bool isTableColumn() const { return false; } + virtual bool isTableCell() const { return false; } + virtual bool isFieldset() const { return false; } + virtual bool isGroup() const { return false; } + virtual bool isARIATreeGridRow() const { return false; } + virtual bool isImageMapLink() const { return false; } + virtual bool isMenuList() const { return false; } + virtual bool isMenuListPopup() const { return false; } + virtual bool isMenuListOption() const { return false; } + bool isTabList() const { return roleValue() == TabListRole; } + bool isTabItem() const { return roleValue() == TabRole; } bool isRadioGroup() const { return roleValue() == RadioGroupRole; } + bool isComboBox() const { return roleValue() == ComboBoxRole; } + bool isTree() const { return roleValue() == TreeRole; } + bool isTreeItem() const { return roleValue() == TreeItemRole; } + bool isScrollbar() const { return roleValue() == ScrollBarRole; } + bool isButton() const { return roleValue() == ButtonRole; } - virtual bool isChecked() const { return false; }; - virtual bool isEnabled() const { return false; }; - virtual bool isSelected() const { return false; }; - virtual bool isFocused() const { return false; }; - virtual bool isHovered() const { return false; }; - virtual bool isIndeterminate() const { return false; }; - virtual bool isLoaded() const { return false; }; - virtual bool isMultiSelect() const { return false; }; - virtual bool isOffScreen() const { return false; }; - virtual bool isPressed() const { return false; }; - virtual bool isReadOnly() const { return false; }; - virtual bool isVisited() const { return false; }; - virtual bool isRequired() const { return false; }; - - virtual bool canSetFocusAttribute() const { return false; }; - virtual bool canSetTextRangeAttributes() const { return false; }; - virtual bool canSetValueAttribute() const { return false; }; + virtual bool isChecked() const { return false; } + virtual bool isEnabled() const { return false; } + virtual bool isSelected() const { return false; } + virtual bool isFocused() const { return false; } + virtual bool isHovered() const { return false; } + virtual bool isIndeterminate() const { return false; } + virtual bool isLoaded() const { return false; } + virtual bool isMultiSelectable() const { return false; } + virtual bool isOffScreen() const { return false; } + virtual bool isPressed() const { return false; } + virtual bool isReadOnly() const { return false; } + virtual bool isVisited() const { return false; } + virtual bool isRequired() const { return false; } + virtual bool isLinked() const { return false; } + virtual bool isExpanded() const { return false; } + virtual bool isVisible() const { return true; } + virtual bool isCollapsed() const { return false; } + virtual void setIsExpanded(bool) { } + + virtual bool canSetFocusAttribute() const { return false; } + virtual bool canSetTextRangeAttributes() const { return false; } + virtual bool canSetValueAttribute() const { return false; } virtual bool canSetSelectedAttribute() const { return false; } virtual bool canSetSelectedChildrenAttribute() const { return false; } + virtual bool canSetExpandedAttribute() const { return false; } - virtual bool hasIntValue() const { return false; }; + virtual bool hasIntValue() const { return false; } - bool accessibilityShouldUseUniqueId() const { return true; }; - virtual bool accessibilityIsIgnored() const { return true; }; + bool accessibilityShouldUseUniqueId() const { return true; } + virtual bool accessibilityIsIgnored() const { return true; } virtual int headingLevel() const { return 0; } virtual int intValue() const { return 0; } @@ -303,9 +335,22 @@ public: virtual float maxValueForRange() const { return 0.0f; } virtual float minValueForRange() const { return 0.0f; } virtual AccessibilityObject* selectedRadioButton() { return 0; } + virtual AccessibilityObject* selectedTabItem() { return 0; } virtual int layoutCount() const { return 0; } + virtual double estimatedLoadingProgress() const { return 0; } static bool isARIAControl(AccessibilityRole); static bool isARIAInput(AccessibilityRole); + virtual bool supportsARIAOwns() const { return false; } + virtual void ariaOwnsElements(AccessibilityChildrenVector&) const { } + virtual bool supportsARIAFlowTo() const { return false; } + virtual void ariaFlowToElements(AccessibilityChildrenVector&) const { } + + // ARIA drag and drop + 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>&) { } virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&) const { return 0; } virtual AccessibilityObject* focusedUIElement() const { return 0; } @@ -331,7 +376,6 @@ public: void setRoleValue(AccessibilityRole role) { m_role = role; } virtual AccessibilityRole roleValue() const { return m_role; } - virtual String ariaAccessibilityName(const String&) const { return String(); } virtual String ariaLabeledByAttribute() const { return String(); } virtual String ariaDescribedByAttribute() const { return String(); } virtual String accessibilityDescription() const { return String(); } @@ -370,32 +414,40 @@ 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) { } virtual void setSelectedText(const String&) { } virtual void setSelectedTextRange(const PlainTextRange&) { } virtual void setValue(const String&) { } virtual void setSelected(bool) { } - + virtual void setSelectedRows(AccessibilityChildrenVector&) { } + virtual void makeRangeVisible(const PlainTextRange&) { } virtual bool press() const; bool performDefaultAction() const { return press(); } - + virtual AccessibilityOrientation orientation() const; - virtual void increment() { }; - virtual void decrement() { }; + virtual void increment() { } + virtual void decrement() { } virtual void childrenChanged() { } + virtual void contentChanged() { } virtual const AccessibilityChildrenVector& children() { return m_children; } virtual void addChildren() { } virtual bool canHaveChildren() const { return true; } virtual bool hasChildren() const { return m_haveChildren; } virtual void selectedChildren(AccessibilityChildrenVector&) { } virtual void visibleChildren(AccessibilityChildrenVector&) { } + virtual void tabChildren(AccessibilityChildrenVector&) { } virtual bool shouldFocusActiveDescendant() const { return false; } virtual AccessibilityObject* activeDescendant() const { return 0; } 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(); } @@ -446,6 +498,29 @@ public: unsigned doAXLineForIndex(unsigned); + virtual String stringValueForMSAA() const { return String(); } + virtual String stringRoleForMSAA() const { return String(); } + virtual String nameForMSAA() const { return String(); } + virtual String descriptionForMSAA() const { return String(); } + virtual AccessibilityRole roleValueForMSAA() const { return roleValue(); } + + // Used by an ARIA tree to get all its rows. + void ariaTreeRows(AccessibilityChildrenVector&); + // Used by an ARIA tree item to get all of its direct rows that it can disclose. + void ariaTreeItemDisclosedRows(AccessibilityChildrenVector&); + // Used by an ARIA tree item to get only its content, and not its child tree items and groups. + void ariaTreeItemContent(AccessibilityChildrenVector&); + + // ARIA live-region features. + bool supportsARIALiveRegion() const; + bool isInsideARIALiveRegion() const; + virtual const AtomicString& ariaLiveRegionStatus() const { return nullAtom; } + virtual const AtomicString& ariaLiveRegionRelevant() const { return nullAtom; } + virtual bool ariaLiveRegionAtomic() const { return false; } + virtual bool ariaLiveRegionBusy() const { return false; } + + bool supportsARIAAttributes() const; + #if HAVE(ACCESSIBILITY) #if PLATFORM(GTK) AccessibilityObjectWrapper* wrapper() const; @@ -459,18 +534,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 @@ -489,7 +560,7 @@ protected: #if PLATFORM(MAC) RetainPtr<AccessibilityObjectWrapper> m_wrapper; -#elif PLATFORM(WIN) && !PLATFORM(WINCE) +#elif PLATFORM(WIN) && !OS(WINCE) COMPtr<AccessibilityObjectWrapper> m_wrapper; #elif PLATFORM(GTK) AtkObject* m_wrapper; diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityRenderObject.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityRenderObject.cpp index 4c50b9a..8de8e5b 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityRenderObject.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityRenderObject.cpp @@ -30,8 +30,8 @@ #include "AccessibilityRenderObject.h" #include "AXObjectCache.h" -#include "AccessibilityListBox.h" #include "AccessibilityImageMapLink.h" +#include "AccessibilityListBox.h" #include "CharacterNames.h" #include "EventNames.h" #include "FloatRect.h" @@ -53,6 +53,7 @@ #include "HitTestResult.h" #include "LocalizedStrings.h" #include "NodeList.h" +#include "ProgressTracker.h" #include "RenderButton.h" #include "RenderFieldset.h" #include "RenderFileUploadControl.h" @@ -64,9 +65,11 @@ #include "RenderMenuList.h" #include "RenderText.h" #include "RenderTextControl.h" +#include "RenderTextFragment.h" #include "RenderTheme.h" #include "RenderView.h" #include "RenderWidget.h" +#include "SelectElement.h" #include "SelectionController.h" #include "Text.h" #include "TextIterator.h" @@ -84,6 +87,8 @@ AccessibilityRenderObject::AccessibilityRenderObject(RenderObject* renderer) : AccessibilityObject() , m_renderer(renderer) , m_ariaRole(UnknownRole) + , m_childrenDirty(false) + , m_roleForMSAA(UnknownRole) { updateAccessibilityRole(); #ifndef NDEBUG @@ -166,7 +171,7 @@ AccessibilityObject* AccessibilityRenderObject::parentObjectIfExists() const if (!m_renderer) return 0; - RenderObject *parent = m_renderer->parent(); + RenderObject* parent = m_renderer->parent(); if (!parent) return 0; @@ -178,7 +183,7 @@ AccessibilityObject* AccessibilityRenderObject::parentObject() const if (!m_renderer) return 0; - RenderObject *parent = m_renderer->parent(); + RenderObject* parent = m_renderer->parent(); if (!parent) return 0; @@ -296,10 +301,10 @@ bool AccessibilityRenderObject::isSlider() const bool AccessibilityRenderObject::isMenuRelated() const { AccessibilityRole role = roleValue(); - return role == MenuRole || - role == MenuBarRole || - role == MenuButtonRole || - role == MenuItemRole; + return role == MenuRole + || role == MenuBarRole + || role == MenuButtonRole + || role == MenuItemRole; } bool AccessibilityRenderObject::isMenu() const @@ -361,11 +366,21 @@ bool AccessibilityRenderObject::isChecked() const if (!m_renderer->node() || !m_renderer->node()->isElementNode()) return false; + // First test for native checkedness semantics InputElement* inputElement = toInputElement(static_cast<Element*>(m_renderer->node())); - if (!inputElement) + if (inputElement) + return inputElement->isChecked(); + + // Else, if this is an ARIA checkbox or radio, respect the aria-checked attribute + AccessibilityRole ariaRole = ariaRoleAttribute(); + if (ariaRole == RadioButtonRole || ariaRole == CheckBoxRole) { + if (equalIgnoringCase(getAttribute(aria_checkedAttr), "true")) + return true; return false; + } - return inputElement->isChecked(); + // Otherwise it's not checked + return false; } bool AccessibilityRenderObject::isHovered() const @@ -374,9 +389,16 @@ bool AccessibilityRenderObject::isHovered() const return m_renderer->node() && m_renderer->node()->hovered(); } -bool AccessibilityRenderObject::isMultiSelect() const +bool AccessibilityRenderObject::isMultiSelectable() const { ASSERT(m_renderer); + + const AtomicString& ariaMultiSelectable = getAttribute(aria_multiselectableAttr); + if (equalIgnoringCase(ariaMultiSelectable, "true")) + return true; + if (equalIgnoringCase(ariaMultiSelectable, "false")) + return false; + if (!m_renderer->isListBox()) return false; return m_renderer->node() && static_cast<HTMLSelectElement*>(m_renderer->node())->multiple(); @@ -505,18 +527,28 @@ AccessibilityObject* AccessibilityRenderObject::selectedRadioButton() } return 0; } + +AccessibilityObject* AccessibilityRenderObject::selectedTabItem() +{ + if (!isTabList()) + return 0; + + // Find the child tab item that is selected (ie. the intValue == 1). + AccessibilityObject::AccessibilityChildrenVector tabs; + tabChildren(tabs); + + int count = tabs.size(); + for (int i = 0; i < count; ++i) { + AccessibilityObject* object = m_children[i].get(); + if (object->isTabItem() && object->intValue() == 1) + return object; + } + return 0; +} 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 @@ -578,6 +610,10 @@ Element* AccessibilityRenderObject::actionElement() const if (m_renderer->isMenuList()) return static_cast<Element*>(m_renderer->node()); + AccessibilityRole role = roleValue(); + if (role == ButtonRole || role == PopUpButtonRole) + return static_cast<Element*>(m_renderer->node()); + Element* elt = anchorElement(); if (!elt) elt = mouseButtonListener(); @@ -693,23 +729,46 @@ String AccessibilityRenderObject::helpText() const return String(); } -String AccessibilityRenderObject::language() const +unsigned AccessibilityRenderObject::hierarchicalLevel() const { if (!m_renderer) - return String(); - - // Defer to parent if this element doesn't have a language set + return 0; + Node* node = m_renderer->node(); - if (!node) - return AccessibilityObject::language(); + if (!node || !node->isElementNode()) + return 0; + Element* element = static_cast<Element*>(node); + String ariaLevel = element->getAttribute(aria_levelAttr); + if (!ariaLevel.isEmpty()) + return ariaLevel.toInt(); - if (!node->isElementNode()) - return AccessibilityObject::language(); + // Only tree item will calculate its level through the DOM currently. + if (roleValue() != TreeItemRole) + return 0; + + // Hierarchy leveling starts at 0. + // We measure tree hierarchy by the number of groups that the item is within. + unsigned level = 0; + AccessibilityObject* parent = parentObject(); + while (parent) { + AccessibilityRole parentRole = parent->roleValue(); + if (parentRole == GroupRole) + level++; + else if (parentRole == TreeRole) + break; + + parent = parent->parentObject(); + } - String language = static_cast<Element*>(node)->getAttribute(langAttr); - if (language.isEmpty()) - return AccessibilityObject::language(); - return language; + return level; +} + +String AccessibilityRenderObject::language() const +{ + if (!m_renderer) + return String(); + + return AccessibilityObject::language(m_renderer->node()); } String AccessibilityRenderObject::textUnderElement() const @@ -730,6 +789,14 @@ String AccessibilityRenderObject::textUnderElement() const } } + // Sometimes text fragments don't have Node's associated with them (like when + // CSS content is used to insert text). + if (m_renderer->isText()) { + RenderText* renderTextObject = toRenderText(m_renderer); + if (renderTextObject->isTextFragment()) + return String(static_cast<RenderTextFragment*>(m_renderer)->contentString()); + } + // return the null string for anonymous text because it is non-trivial to get // the actual text and, so far, that is not needed return String(); @@ -780,7 +847,7 @@ String AccessibilityRenderObject::valueDescription() const float AccessibilityRenderObject::valueForRange() const { - if (!isProgressIndicator() && !isSlider()) + if (!isProgressIndicator() && !isSlider() && !isScrollbar()) return 0.0f; return getAttribute(aria_valuenowAttr).toFloat(); @@ -807,11 +874,23 @@ String AccessibilityRenderObject::stringValue() const if (!m_renderer || isPasswordField()) return String(); + if (ariaRoleAttribute() == StaticTextRole) + return text(); + 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())); + Element* selectedOption = selectNode->listItems()[selectNode->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(); @@ -864,56 +943,67 @@ static String accessibleNameForNode(Node* node) return String(); } -String AccessibilityRenderObject::ariaAccessibilityName(const String& s) const +String AccessibilityRenderObject::accessibilityDescriptionForElements(Vector<Element*> &elements) const +{ + Vector<UChar> ariaLabel; + unsigned size = elements.size(); + for (unsigned i = 0; i < size; ++i) { + Element* idElement = elements[i]; + + String nameFragment = accessibleNameForNode(idElement); + ariaLabel.append(nameFragment.characters(), nameFragment.length()); + for (Node* n = idElement->firstChild(); n; n = n->traverseNextNode(idElement)) { + nameFragment = accessibleNameForNode(n); + ariaLabel.append(nameFragment.characters(), nameFragment.length()); + } + + if (i != size - 1) + ariaLabel.append(' '); + } + return String::adopt(ariaLabel); +} + + +void AccessibilityRenderObject::elementsFromAttribute(Vector<Element*>& elements, const QualifiedName& attribute) const { + Node* node = m_renderer->node(); + if (!node || !node->isElementNode()) + return; + Document* document = m_renderer->document(); if (!document) - return String(); - - String idList = s; + return; + + String idList = getAttribute(attribute).string(); + if (idList.isEmpty()) + return; + idList.replace('\n', ' '); Vector<String> idVector; idList.split(' ', idVector); - - Vector<UChar> ariaLabel; + unsigned size = idVector.size(); for (unsigned i = 0; i < size; ++i) { String idName = idVector[i]; Element* idElement = document->getElementById(idName); - if (idElement) { - String nameFragment = accessibleNameForNode(idElement); - ariaLabel.append(nameFragment.characters(), nameFragment.length()); - for (Node* n = idElement->firstChild(); n; n = n->traverseNextNode(idElement)) { - nameFragment = accessibleNameForNode(n); - ariaLabel.append(nameFragment.characters(), nameFragment.length()); - } - - if (i != size - 1) - ariaLabel.append(' '); - } + if (idElement) + elements.append(idElement); } - return String::adopt(ariaLabel); } - + +void AccessibilityRenderObject::ariaLabeledByElements(Vector<Element*>& elements) const +{ + elementsFromAttribute(elements, aria_labeledbyAttr); + if (!elements.size()) + elementsFromAttribute(elements, aria_labelledbyAttr); +} + String AccessibilityRenderObject::ariaLabeledByAttribute() const { - Node* node = m_renderer->node(); - if (!node) - return String(); - - if (!node->isElementNode()) - return String(); - - // The ARIA spec uses the British spelling: "labelled." It seems prudent to support the American - // spelling ("labeled") as well. - String idList = getAttribute(aria_labeledbyAttr).string(); - if (idList.isEmpty()) { - idList = getAttribute(aria_labelledbyAttr).string(); - if (idList.isEmpty()) - return String(); - } - - return ariaAccessibilityName(idList); + Vector<Element*> elements; + ariaLabeledByElements(elements); + + return accessibilityDescriptionForElements(elements); } static HTMLLabelElement* labelForElement(Element* element) @@ -990,6 +1080,8 @@ String AccessibilityRenderObject::title() const || ariaRole == MenuItemRole || ariaRole == MenuButtonRole || ariaRole == RadioButtonRole + || ariaRole == CheckBoxRole + || ariaRole == TabRole || isHeading()) return textUnderElement(); @@ -1001,11 +1093,10 @@ String AccessibilityRenderObject::title() const String AccessibilityRenderObject::ariaDescribedByAttribute() const { - String idList = getAttribute(aria_describedbyAttr).string(); - if (idList.isEmpty()) - return String(); + Vector<Element*> elements; + elementsFromAttribute(elements, aria_describedbyAttr); - return ariaAccessibilityName(idList); + return accessibilityDescriptionForElements(elements); } String AccessibilityRenderObject::accessibilityDescription() const @@ -1032,7 +1123,7 @@ String AccessibilityRenderObject::accessibilityDescription() const } if (isWebArea()) { - Document *document = m_renderer->document(); + Document* document = m_renderer->document(); Node* owner = document->ownerElement(); if (owner) { if (owner->hasTagName(frameTag) || owner->hasTagName(iframeTag)) { @@ -1048,12 +1139,7 @@ String AccessibilityRenderObject::accessibilityDescription() const if (owner && owner->isHTMLElement()) return static_cast<HTMLElement*>(owner)->getAttribute(nameAttr); } - - if (roleValue() == DefinitionListTermRole) - return AXDefinitionListTermText(); - if (roleValue() == DefinitionListDefinitionRole) - return AXDefinitionListDefinitionText(); - + return String(); } @@ -1068,7 +1154,10 @@ IntRect AccessibilityRenderObject::boundingBoxRect() const obj = obj->node()->renderer(); Vector<FloatQuad> quads; - obj->absoluteQuads(quads); + if (obj->isText()) + obj->absoluteQuads(quads); + else + obj->absoluteFocusRingQuads(quads); const size_t n = quads.size(); if (!n) return IntRect(); @@ -1198,6 +1287,8 @@ void AccessibilityRenderObject::addRadioButtonGroupMembers(AccessibilityChildren // or an internal anchor connection void AccessibilityRenderObject::linkedUIElements(AccessibilityChildrenVector& linkedUIElements) const { + ariaFlowToElements(linkedUIElements); + if (isAnchor()) { AccessibilityObject* linkedAXElement = internalLinkElement(); if (linkedAXElement) @@ -1208,6 +1299,71 @@ void AccessibilityRenderObject::linkedUIElements(AccessibilityChildrenVector& li addRadioButtonGroupMembers(linkedUIElements); } +bool AccessibilityRenderObject::hasTextAlternative() const +{ + // ARIA: section 2A, bullet #3 says if aria-labeledby or aria-label appears, it should + // override the "label" element association. + if (!ariaLabeledByAttribute().isEmpty() || !getAttribute(aria_labelAttr).string().isEmpty()) + return true; + + return false; +} + +bool AccessibilityRenderObject::supportsARIAFlowTo() const +{ + return !getAttribute(aria_flowtoAttr).string().isEmpty(); +} + +void AccessibilityRenderObject::ariaFlowToElements(AccessibilityChildrenVector& flowTo) const +{ + Vector<Element*> elements; + elementsFromAttribute(elements, aria_flowtoAttr); + + AXObjectCache* cache = axObjectCache(); + unsigned count = elements.size(); + for (unsigned k = 0; k < count; ++k) { + Element* element = elements[k]; + AccessibilityObject* flowToElement = cache->getOrCreate(element->renderer()); + if (flowToElement) + flowTo.append(flowToElement); + } + +} + +bool AccessibilityRenderObject::supportsARIADropping() const +{ + const AtomicString& dropEffect = getAttribute(aria_dropeffectAttr).string(); + return !dropEffect.isEmpty(); +} + +bool AccessibilityRenderObject::supportsARIADragging() const +{ + const AtomicString& grabbed = getAttribute(aria_grabbedAttr).string(); + return equalIgnoringCase(grabbed, "true") || equalIgnoringCase(grabbed, "false"); +} + +bool AccessibilityRenderObject::isARIAGrabbed() +{ + return elementAttributeValue(aria_grabbedAttr); +} + +void AccessibilityRenderObject::setARIAGrabbed(bool grabbed) +{ + setElementAttributeValue(aria_grabbedAttr, grabbed); +} + +void AccessibilityRenderObject::determineARIADropEffects(Vector<String>& effects) +{ + String dropEffects = getAttribute(aria_dropeffectAttr).string(); + if (dropEffects.isEmpty()) { + effects.clear(); + return; + } + + dropEffects.replace('\n', ' '); + dropEffects.split(' ', effects); +} + bool AccessibilityRenderObject::exposesTitleUIElement() const { if (!isControl()) @@ -1217,6 +1373,9 @@ bool AccessibilityRenderObject::exposesTitleUIElement() const if (isCheckboxOrRadio() && getAttribute(titleAttr).isEmpty()) return false; + if (hasTextAlternative()) + return false; + return true; } @@ -1242,13 +1401,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(); } @@ -1256,29 +1415,86 @@ bool AccessibilityRenderObject::ariaIsHidden() const return false; } -bool AccessibilityRenderObject::accessibilityIsIgnored() const +bool AccessibilityRenderObject::isDescendantOfBarrenParent() const { - // is the platform is 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 + for (AccessibilityObject* object = parentObject(); object; object = object->parentObject()) { + if (!object->canHaveChildren()) + return true; + } + + return false; +} + +bool AccessibilityRenderObject::isAllowedChildOfTree() const +{ + // Determine if this is in a tree. If so, we apply special behavior to make it work like an AXOutline. + AccessibilityObject* axObj = parentObject(); + bool isInTree = false; + while (axObj) { + if (axObj->isTree()) { + isInTree = true; + break; + } + axObj = axObj->parentObject(); + } + + // If the object is in a tree, only tree items should be exposed (and the children of tree items). + if (isInTree) { + AccessibilityRole role = roleValue(); + if (role != TreeItemRole && role != StaticTextRole) + return false; + } + return true; +} + +AccessibilityObjectInclusion AccessibilityRenderObject::accessibilityIsIgnoredBase() const +{ + // 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; + if (roleValue() == IgnoredRole) return true; + // An ARIA tree can only have tree items and static text as children. + if (!isAllowedChildOfTree()) + return true; + // ignore popup menu items because AppKit does for (RenderObject* parent = m_renderer->parent(); parent; parent = parent->parent()) { if (parent->isMenuList()) @@ -1288,7 +1504,7 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const // find out if this element is inside of a label element. // if so, it may be ignored because it's the label for a checkbox or radio button AccessibilityObject* controlObject = correspondingControlForLabelElement(); - if (controlObject && !controlObject->exposesTitleUIElement()) + if (controlObject && !controlObject->exposesTitleUIElement() && controlObject->isCheckboxOrRadio()) return true; AccessibilityRole ariaRole = ariaRoleAttribute(); @@ -1300,8 +1516,8 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const // NOTE: BRs always have text boxes now, so the text box check here can be removed if (m_renderer->isText()) { // static text beneath MenuItems and MenuButtons are just reported along with the menu item, so it's ignored on an individual level - if (parentObjectUnignored()->ariaRoleAttribute() == MenuItemRole || - parentObjectUnignored()->ariaRoleAttribute() == MenuButtonRole) + if (parentObjectUnignored()->ariaRoleAttribute() == MenuItemRole + || parentObjectUnignored()->ariaRoleAttribute() == MenuButtonRole) return true; RenderText* renderText = toRenderText(m_renderer); if (m_renderer->isBR() || !renderText->firstTextBox()) @@ -1321,11 +1537,28 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const if (isControl()) return false; + if (ariaRole != UnknownRole) + return false; + // don't ignore labels, because they serve as TitleUIElements Node* node = m_renderer->node(); if (node && node->hasTagName(labelTag)) return false; + // Anything that is content editable should not be ignored. + // However, one cannot just call node->isContentEditable() since that will ask if its parents + // are also editable. Only the top level content editable region should be exposed. + if (node && node->isElementNode()) { + Element* element = static_cast<Element*>(node); + const AtomicString& contentEditable = element->getAttribute(contenteditableAttr); + if (equalIgnoringCase(contentEditable, "true")) + 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(); @@ -1364,9 +1597,6 @@ bool AccessibilityRenderObject::accessibilityIsIgnored() const return false; } - if (ariaRole != UnknownRole) - return false; - // make a platform-specific decision if (isAttachment()) return accessibilityIgnoreAttachment(); @@ -1379,6 +1609,21 @@ bool AccessibilityRenderObject::isLoaded() const return !m_renderer->document()->tokenizer(); } +double AccessibilityRenderObject::estimatedLoadingProgress() const +{ + if (!m_renderer) + return 0; + + if (isLoaded()) + return 1.0; + + Page* page = m_renderer->document()->page(); + if (!page) + return 0; + + return page->progress()->estimatedProgress(); +} + int AccessibilityRenderObject::layoutCount() const { if (!m_renderer->isRenderView()) @@ -1388,6 +1633,10 @@ int AccessibilityRenderObject::layoutCount() const String AccessibilityRenderObject::text() const { + // If this is a user defined static text, use the accessible name computation. + if (ariaRoleAttribute() == StaticTextRole) + return accessibilityDescription(); + if (!isTextControl() || isPasswordField()) return String(); @@ -1545,6 +1794,51 @@ bool AccessibilityRenderObject::isVisited() const return m_renderer->style()->pseudoState() == PseudoVisited; } +bool AccessibilityRenderObject::isExpanded() const +{ + if (equalIgnoringCase(getAttribute(aria_expandedAttr).string(), "true")) + return true; + + return false; +} + +void AccessibilityRenderObject::setElementAttributeValue(const QualifiedName& attributeName, bool value) +{ + if (!m_renderer) + return; + + Node* node = m_renderer->node(); + if (!node || !node->isElementNode()) + return; + + Element* element = static_cast<Element*>(node); + element->setAttribute(attributeName, (value) ? "true" : "false"); +} + +bool AccessibilityRenderObject::elementAttributeValue(const QualifiedName& attributeName) const +{ + if (!m_renderer) + return false; + + return equalIgnoringCase(getAttribute(attributeName), "true"); +} + +void AccessibilityRenderObject::setIsExpanded(bool isExpanded) +{ + // Combo boxes, tree items and rows can be expanded (in different ways on different platforms). + // That action translates into setting the aria-expanded attribute to true. + AccessibilityRole role = roleValue(); + switch (role) { + case ComboBoxRole: + case TreeItemRole: + case RowRole: + setElementAttributeValue(aria_expandedAttr, isExpanded); + break; + default: + break; + } +} + bool AccessibilityRenderObject::isRequired() const { if (equalIgnoringCase(getAttribute(aria_requiredAttr).string(), "true")) @@ -1562,9 +1856,56 @@ bool AccessibilityRenderObject::isSelected() const if (!node) return false; + String ariaSelected = getAttribute(aria_selectedAttr).string(); + if (equalIgnoringCase(ariaSelected, "true")) + return true; + + if (isTabItem() && isTabItemSelected()) + return true; + return false; } +bool AccessibilityRenderObject::isTabItemSelected() const +{ + if (!isTabItem() || !m_renderer) + return false; + + Node* node = m_renderer->node(); + if (!node || !node->isElementNode()) + return false; + + // The ARIA spec says a tab item can also be selected if it is aria-labeled by a tabpanel + // that has keyboard focus inside of it, or if a tabpanel in its aria-controls list has KB + // focus inside of it. + AccessibilityObject* focusedElement = focusedUIElement(); + if (!focusedElement) + return false; + + Vector<Element*> elements; + elementsFromAttribute(elements, aria_controlsAttr); + + unsigned count = elements.size(); + for (unsigned k = 0; k < count; ++k) { + Element* element = elements[k]; + AccessibilityObject* tabPanel = axObjectCache()->getOrCreate(element->renderer()); + + // A tab item should only control tab panels. + if (!tabPanel || tabPanel->roleValue() != TabPanelRole) + continue; + + AccessibilityObject* checkFocusElement = focusedElement; + // Check if the focused element is a descendant of the element controlled by the tab item. + while (checkFocusElement) { + if (tabPanel == checkFocusElement) + return true; + checkFocusElement = checkFocusElement->parentObject(); + } + } + + return false; +} + bool AccessibilityRenderObject::isFocused() const { if (!m_renderer) @@ -1580,8 +1921,8 @@ bool AccessibilityRenderObject::isFocused() const // A web area is represented by the Document node in the DOM tree, which isn't focusable. // Check instead if the frame's selection controller is focused - if (focusedNode == m_renderer->node() || - (roleValue() == WebAreaRole && document->frame()->selection()->isFocusedAndActive())) + if (focusedNode == m_renderer->node() + || (roleValue() == WebAreaRole && document->frame()->selection()->isFocusedAndActive())) return true; return false; @@ -1613,6 +1954,27 @@ void AccessibilityRenderObject::changeValueByPercent(float percentChange) axObjectCache()->postNotification(m_renderer, AXObjectCache::AXValueChanged, true); } +void AccessibilityRenderObject::setSelected(bool enabled) +{ + setElementAttributeValue(aria_selectedAttr, enabled); +} + +void AccessibilityRenderObject::setSelectedRows(AccessibilityChildrenVector& selectedRows) +{ + // Setting selected only makes sense in trees and tables (and tree-tables). + AccessibilityRole role = roleValue(); + if (role != TreeRole && role != TreeGridRole && role != TableRole) + return; + + bool isMulti = isMultiSelectable(); + unsigned count = selectedRows.size(); + if (count > 1 && !isMulti) + count = 1; + + for (unsigned k = 0; k < count; ++k) + selectedRows[k]->setSelected(true); +} + void AccessibilityRenderObject::setValue(const String& string) { if (!m_renderer) @@ -1632,6 +1994,29 @@ void AccessibilityRenderObject::setValue(const String& string) } } +void AccessibilityRenderObject::ariaOwnsElements(AccessibilityChildrenVector& axObjects) const +{ + Vector<Element*> elements; + elementsFromAttribute(elements, aria_ownsAttr); + + unsigned count = elements.size(); + for (unsigned k = 0; k < count; ++k) { + RenderObject* render = elements[k]->renderer(); + AccessibilityObject* obj = axObjectCache()->getOrCreate(render); + if (obj) + axObjects.append(obj); + } +} + +bool AccessibilityRenderObject::supportsARIAOwns() const +{ + if (!m_renderer) + return false; + const AtomicString& ariaOwns = getAttribute(aria_ownsAttr).string(); + + return !ariaOwns.isEmpty(); +} + bool AccessibilityRenderObject::isEnabled() const { ASSERT(m_renderer); @@ -1653,6 +2038,8 @@ RenderView* AccessibilityRenderObject::topRenderer() const Document* AccessibilityRenderObject::document() const { + if (!m_renderer) + return 0; return m_renderer->document(); } @@ -1676,24 +2063,14 @@ AXObjectCache* AccessibilityRenderObject::axObjectCache() const AccessibilityObject* AccessibilityRenderObject::accessibilityParentForImageMap(HTMLMapElement* map) const { // find an image that is using this map - if (!m_renderer || !map) + if (!map) return 0; - String mapName = map->getName().string().lower(); - RefPtr<HTMLCollection> coll = m_renderer->document()->images(); - for (Node* curr = coll->firstItem(); curr; curr = coll->nextItem()) { - RenderObject* obj = curr->renderer(); - if (!obj || !curr->hasTagName(imgTag)) - continue; - - // The HTMLImageElement's useMap() value includes the '#' symbol at the beginning, - // which has to be stripped off - String useMapName = static_cast<HTMLImageElement*>(curr)->getAttribute(usemapAttr).string().substring(1).lower(); - if (useMapName == mapName) - return axObjectCache()->getOrCreate(obj); - } + HTMLImageElement* imageElement = map->imageElement(); + if (!imageElement) + return 0; - return 0; + return axObjectCache()->getOrCreate(imageElement->renderer()); } void AccessibilityRenderObject::getDocumentLinks(AccessibilityChildrenVector& result) @@ -1777,7 +2154,7 @@ VisiblePositionRange AccessibilityRenderObject::visiblePositionRange() const VisiblePositionRange AccessibilityRenderObject::visiblePositionRangeForLine(unsigned lineCount) const { - if (lineCount == 0 || !m_renderer) + if (!lineCount || !m_renderer) return VisiblePositionRange(); // iterate over the lines @@ -1785,7 +2162,7 @@ VisiblePositionRange AccessibilityRenderObject::visiblePositionRangeForLine(unsi // last offset of the last line VisiblePosition visiblePos = m_renderer->document()->renderer()->positionForCoordinates(0, 0); VisiblePosition savedVisiblePos; - while (--lineCount != 0) { + while (--lineCount) { savedVisiblePos = visiblePos; visiblePos = nextLinePosition(visiblePos, 0); if (visiblePos.isNull() || visiblePos == savedVisiblePos) @@ -1900,9 +2277,8 @@ void AccessibilityRenderObject::setSelectedVisiblePositionRange(const VisiblePos return; // make selection and tell the document to use it. if it's zero length, then move to that position - if (range.start == range.end) { + if (range.start == range.end) m_renderer->document()->frame()->selection()->moveTo(range.start, true); - } else { VisibleSelection newSelection = VisibleSelection(range.start, range.end); m_renderer->document()->frame()->selection()->setSelection(newSelection); @@ -1998,7 +2374,7 @@ PlainTextRange AccessibilityRenderObject::doAXRangeForLine(unsigned lineNumber) // iterate to the specified line VisiblePosition visiblePos = visiblePositionForIndex(0); VisiblePosition savedVisiblePos; - for (unsigned lineCount = lineNumber; lineCount != 0; lineCount -= 1) { + for (unsigned lineCount = lineNumber; lineCount; lineCount -= 1) { savedVisiblePos = visiblePos; visiblePos = nextLinePosition(visiblePos, 0); if (visiblePos.isNull() || visiblePos == savedVisiblePos) @@ -2053,8 +2429,8 @@ String AccessibilityRenderObject::doAXStringForRange(const PlainTextRange& range if (isPasswordField()) return String(); - if (range.length == 0) - return ""; + if (!range.length) + return String(); if (!isTextControl()) return String(); @@ -2081,7 +2457,7 @@ AccessibilityObject* AccessibilityRenderObject::accessibilityImageMapHitTest(HTM if (!area) return 0; - HTMLMapElement *map = static_cast<HTMLMapElement*>(area->parent()); + HTMLMapElement* map = static_cast<HTMLMapElement*>(area->parent()); AccessibilityObject* parent = accessibilityParentForImageMap(map); if (!parent) return 0; @@ -2115,14 +2491,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. @@ -2159,14 +2542,14 @@ bool AccessibilityRenderObject::shouldFocusActiveDescendant() const case ProgressIndicatorRole: case ToolbarRole: case OutlineRole: + case TreeRole: + case GridRole: /* FIXME: replace these with actual roles when they are added to AccessibilityRole composite alert alertdialog - grid status timer - tree */ return true; default: @@ -2176,19 +2559,22 @@ bool AccessibilityRenderObject::shouldFocusActiveDescendant() const AccessibilityObject* AccessibilityRenderObject::activeDescendant() const { - if (renderer()->node() && !renderer()->node()->isElementNode()) + if (!m_renderer) return 0; - Element* element = static_cast<Element*>(renderer()->node()); + + if (m_renderer->node() && !m_renderer->node()->isElementNode()) + return 0; + Element* element = static_cast<Element*>(m_renderer->node()); String activeDescendantAttrStr = element->getAttribute(aria_activedescendantAttr).string(); if (activeDescendantAttrStr.isNull() || activeDescendantAttrStr.isEmpty()) return 0; - Element* target = renderer()->document()->getElementById(activeDescendantAttrStr); + Element* target = document()->getElementById(activeDescendantAttrStr); if (!target) return 0; - AccessibilityObject* obj = renderer()->document()->axObjectCache()->getOrCreate(target->renderer()); + AccessibilityObject* obj = axObjectCache()->getOrCreate(target->renderer()); if (obj && obj->isAccessibilityRenderObject()) // an activedescendant is only useful if it has a renderer, because that's what's needed to post the notification return obj; @@ -2207,7 +2593,7 @@ void AccessibilityRenderObject::handleActiveDescendantChanged() AccessibilityRenderObject* activedescendant = static_cast<AccessibilityRenderObject*>(activeDescendant()); if (activedescendant && shouldFocusActiveDescendant()) - doc->axObjectCache()->postNotification(activedescendant->renderer(), AXObjectCache::AXFocusedUIElementChanged, true); + doc->axObjectCache()->postNotification(m_renderer, AXObjectCache::AXActiveDescendantChanged, true); } AccessibilityObject* AccessibilityRenderObject::correspondingControlForLabelElement() const @@ -2247,80 +2633,6 @@ AccessibilityObject* AccessibilityRenderObject::observableObject() const return 0; } - -typedef HashMap<String, AccessibilityRole, CaseFoldingHash> ARIARoleMap; - -struct RoleEntry { - String ariaRole; - AccessibilityRole webcoreRole; -}; - -static const ARIARoleMap& createARIARoleMap() -{ - const RoleEntry roles[] = { - { "application", LandmarkApplicationRole }, - { "article", DocumentArticleRole }, - { "banner", LandmarkBannerRole }, - { "button", ButtonRole }, - { "checkbox", CheckBoxRole }, - { "complementary", LandmarkComplementaryRole }, - { "contentinfo", LandmarkContentInfoRole }, - { "grid", TableRole }, - { "gridcell", CellRole }, - { "columnheader", ColumnHeaderRole }, - { "definition", DefinitionListDefinitionRole }, - { "document", DocumentRole }, - { "rowheader", RowHeaderRole }, - { "group", GroupRole }, - { "heading", HeadingRole }, - { "img", ImageRole }, - { "link", WebCoreLinkRole }, - { "list", ListRole }, - { "listitem", GroupRole }, - { "listbox", ListBoxRole }, - { "log", ApplicationLogRole }, - // "option" isn't here because it may map to different roles depending on the parent element's role - { "main", LandmarkMainRole }, - { "marquee", ApplicationMarqueeRole }, - { "menu", MenuRole }, - { "menubar", GroupRole }, - // "menuitem" isn't here because it may map to different roles depending on the parent element's role - { "menuitemcheckbox", MenuItemRole }, - { "menuitemradio", MenuItemRole }, - { "note", DocumentNoteRole }, - { "navigation", LandmarkNavigationRole }, - { "option", ListBoxOptionRole }, - { "presentation", IgnoredRole }, - { "progressbar", ProgressIndicatorRole }, - { "radio", RadioButtonRole }, - { "radiogroup", RadioGroupRole }, - { "region", DocumentRegionRole }, - { "row", RowRole }, - { "range", SliderRole }, - { "search", LandmarkSearchRole }, - { "separator", SplitterRole }, - { "slider", SliderRole }, - { "spinbutton", ProgressIndicatorRole }, - { "status", ApplicationStatusRole }, - { "textbox", TextAreaRole }, - { "timer", ApplicationTimerRole }, - { "toolbar", ToolbarRole }, - { "tooltip", UserInterfaceTooltipRole } - }; - ARIARoleMap& roleMap = *new ARIARoleMap; - - const unsigned numRoles = sizeof(roles) / sizeof(roles[0]); - for (unsigned i = 0; i < numRoles; ++i) - roleMap.set(roles[i].ariaRole, roles[i].webcoreRole); - return roleMap; -} - -static AccessibilityRole ariaRoleToWebCoreRole(String value) -{ - ASSERT(!value.isEmpty() && !value.isNull()); - static const ARIARoleMap& roleMap = createARIARoleMap(); - return roleMap.get(value); -} AccessibilityRole AccessibilityRenderObject::determineAriaRoleAttribute() const { @@ -2329,17 +2641,21 @@ AccessibilityRole AccessibilityRenderObject::determineAriaRoleAttribute() const return UnknownRole; AccessibilityRole role = ariaRoleToWebCoreRole(ariaRole); + + if (role == ButtonRole && elementAttributeValue(aria_haspopupAttr)) + role = PopUpButtonRole; + if (role) return role; // selects and listboxes both have options as child roles, but they map to different roles within WebCore - if (equalIgnoringCase(ariaRole,"option")) { + if (equalIgnoringCase(ariaRole, "option")) { if (parentObjectUnignored()->ariaRoleAttribute() == MenuRole) return MenuItemRole; if (parentObjectUnignored()->ariaRoleAttribute() == ListBoxRole) return ListBoxOptionRole; } // an aria "menuitem" may map to MenuButton or MenuItem depending on its parent - if (equalIgnoringCase(ariaRole,"menuitem")) { + if (equalIgnoringCase(ariaRole, "menuitem")) { if (parentObjectUnignored()->ariaRoleAttribute() == GroupRole) return MenuButtonRole; if (parentObjectUnignored()->ariaRoleAttribute() == MenuRole) @@ -2418,7 +2734,7 @@ AccessibilityRole AccessibilityRenderObject::determineAccessibilityRole() if (m_renderer->isMenuList()) return PopUpButtonRole; - if (headingLevel() != 0) + if (headingLevel()) return HeadingRole; if (node && node->hasTagName(ddTag)) @@ -2429,19 +2745,43 @@ 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; return UnknownRole; } +AccessibilityOrientation AccessibilityRenderObject::orientation() const +{ + const AtomicString& ariaOrientation = getAttribute(aria_orientationAttr).string(); + if (equalIgnoringCase(ariaOrientation, "horizontal")) + return AccessibilityOrientationHorizontal; + if (equalIgnoringCase(ariaOrientation, "vertical")) + return AccessibilityOrientationVertical; + + return AccessibilityObject::orientation(); +} + bool AccessibilityRenderObject::isPresentationalChildOfAriaRole() const { // Walk the parent chain looking for a parent that has presentational children AccessibilityObject* parent; for (parent = parentObject(); parent && !parent->ariaRoleHasPresentationalChildren(); parent = parent->parentObject()) - ; + { } + return parent; } @@ -2474,30 +2814,36 @@ bool AccessibilityRenderObject::canSetFocusAttribute() const return false; switch (roleValue()) { - case WebCoreLinkRole: - case ImageMapLinkRole: - case TextFieldRole: - case TextAreaRole: - case ButtonRole: - case PopUpButtonRole: - case CheckBoxRole: - case RadioButtonRole: - case SliderRole: - return true; - default: - return false; + case WebCoreLinkRole: + case ImageMapLinkRole: + case TextFieldRole: + case TextAreaRole: + case ButtonRole: + case PopUpButtonRole: + case CheckBoxRole: + case RadioButtonRole: + case SliderRole: + return true; + default: + return node->supportsFocus(); } } + +bool AccessibilityRenderObject::canSetExpandedAttribute() const +{ + // An object can be expanded if it aria-expanded is true or false. + String ariaExpanded = getAttribute(aria_expandedAttr).string(); + return equalIgnoringCase(ariaExpanded, "true") || equalIgnoringCase(ariaExpanded, "false"); +} bool AccessibilityRenderObject::canSetValueAttribute() const { if (equalIgnoringCase(getAttribute(aria_readonlyAttr).string(), "true")) return false; - if (isWebArea() || isTextControl()) - return !isReadOnly(); - - return isProgressIndicator() || isSlider(); + // Any node could be contenteditable, so isReadOnly should be relied upon + // for this information for all elements. + return isProgressIndicator() || isSlider() || !isReadOnly(); } bool AccessibilityRenderObject::canSetTextRangeAttributes() const @@ -2505,22 +2851,50 @@ bool AccessibilityRenderObject::canSetTextRangeAttributes() const return isTextControl(); } +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); + if (!parent) + continue; + + // If we find a parent that has ARIA live region on, send the notification and stop processing. + // The spec does not talk about nested live regions. + if (parent->supportsARIALiveRegion()) { + axObjectCache()->postNotification(renderParent, AXObjectCache::AXLiveRegionChanged, true); + break; + } + } +} + void AccessibilityRenderObject::childrenChanged() { // this method is meant as a quick way of marking dirty // a portion of the accessibility tree - markChildrenDirty(); - if (!m_renderer) return; // Go up the render parent chain, marking children as dirty. // We can't rely on the accessibilityParent() because it may not exist and we must not create an AX object here either - for (RenderObject* renderParent = m_renderer->parent(); renderParent; renderParent = renderParent->parent()) { + // At the same time, process ARIA live region changes. + for (RenderObject* renderParent = m_renderer; renderParent; renderParent = renderParent->parent()) { AccessibilityObject* parent = m_renderer->document()->axObjectCache()->get(renderParent); - if (parent && parent->isAccessibilityRenderObject()) - static_cast<AccessibilityRenderObject *>(parent)->markChildrenDirty(); + if (!parent || !parent->isAccessibilityRenderObject()) + continue; + + AccessibilityRenderObject* axParent = static_cast<AccessibilityRenderObject*>(parent); + // Only do work if the children haven't been marked dirty. This has the effect of blocking + // future live region change notifications until the AX tree has been accessed again. This + // is a good performance win for all parties. + if (!axParent->needsToUpdateChildren()) { + axParent->setNeedsToUpdateChildren(); + + // If this element supports ARIA live regions, then notify the AT of changes. + if (axParent->supportsARIALiveRegion()) + axObjectCache()->postNotification(renderParent, AXObjectCache::AXLiveRegionChanged, true); + } } } @@ -2531,28 +2905,40 @@ bool AccessibilityRenderObject::canHaveChildren() const // Elements that should not have children switch (roleValue()) { - case ImageRole: - case ButtonRole: - case PopUpButtonRole: - case CheckBoxRole: - case RadioButtonRole: - case StaticTextRole: - case ListBoxOptionRole: - return false; - default: - return true; + case ImageRole: + case ButtonRole: + case PopUpButtonRole: + case CheckBoxRole: + case RadioButtonRole: + case TabRole: + case StaticTextRole: + case ListBoxOptionRole: + case ScrollBarRole: + return false; + default: + return true; } } -const AccessibilityObject::AccessibilityChildrenVector& AccessibilityRenderObject::children() +void AccessibilityRenderObject::clearChildren() +{ + AccessibilityObject::clearChildren(); + m_childrenDirty = false; +} + +void AccessibilityRenderObject::updateChildrenIfNecessary() { - if (m_childrenDirty) { + if (needsToUpdateChildren()) clearChildren(); - m_childrenDirty = false; - } - if (!m_haveChildren) - addChildren(); + if (!hasChildren()) + addChildren(); +} + +const AccessibilityObject::AccessibilityChildrenVector& AccessibilityRenderObject::children() +{ + updateChildrenIfNecessary(); + return m_children; } @@ -2603,18 +2989,91 @@ void AccessibilityRenderObject::addChildren() } } } + +const AtomicString& AccessibilityRenderObject::ariaLiveRegionStatus() const +{ + DEFINE_STATIC_LOCAL(const AtomicString, liveRegionStatusAssertive, ("assertive")); + DEFINE_STATIC_LOCAL(const AtomicString, liveRegionStatusPolite, ("polite")); + DEFINE_STATIC_LOCAL(const AtomicString, liveRegionStatusOff, ("off")); + + const AtomicString& liveRegionStatus = getAttribute(aria_liveAttr); + // These roles have implicit live region status. + if (liveRegionStatus.isEmpty()) { + switch (roleValue()) { + case ApplicationAlertDialogRole: + case ApplicationAlertRole: + return liveRegionStatusAssertive; + case ApplicationLogRole: + case ApplicationStatusRole: + return liveRegionStatusPolite; + case ApplicationTimerRole: + return liveRegionStatusOff; + default: + break; + } + } + + return liveRegionStatus; +} + +const AtomicString& AccessibilityRenderObject::ariaLiveRegionRelevant() const +{ + DEFINE_STATIC_LOCAL(const AtomicString, defaultLiveRegionRelevant, ("additions text")); + const AtomicString& relevant = getAttribute(aria_relevantAttr); + // Default aria-relevant = "additions text". + if (relevant.isEmpty()) + return defaultLiveRegionRelevant; + + return relevant; +} + +bool AccessibilityRenderObject::ariaLiveRegionAtomic() const +{ + return elementAttributeValue(aria_atomicAttr); +} + +bool AccessibilityRenderObject::ariaLiveRegionBusy() const +{ + return elementAttributeValue(aria_busyAttr); +} + +void AccessibilityRenderObject::ariaSelectedRows(AccessibilityChildrenVector& result) +{ + // Get all the rows. + AccessibilityChildrenVector allRows; + ariaTreeRows(allRows); + + // Determine which rows are selected. + bool isMulti = isMultiSelectable(); + + // Prefer active descendant over aria-selected. + AccessibilityObject* activeDesc = activeDescendant(); + if (activeDesc && (activeDesc->isTreeItem() || activeDesc->isTableRow())) { + result.append(activeDesc); + if (!isMulti) + return; + } + + unsigned count = allRows.size(); + for (unsigned k = 0; k < count; ++k) { + if (allRows[k]->isSelected()) { + result.append(allRows[k]); + if (!isMulti) + break; + } + } +} + void AccessibilityRenderObject::ariaListboxSelectedChildren(AccessibilityChildrenVector& result) { AccessibilityObject* child = firstChild(); - bool isMultiselectable = false; Element* element = static_cast<Element*>(renderer()->node()); if (!element || !element->isElementNode()) // do this check to ensure safety of static_cast above return; - String multiselectablePropertyStr = element->getAttribute("aria-multiselectable").string(); - isMultiselectable = equalIgnoringCase(multiselectablePropertyStr, "true"); + bool isMulti = isMultiSelectable(); while (child) { // every child should have aria-role option, and if so, check for selected attribute/state @@ -2625,10 +3084,10 @@ void AccessibilityRenderObject::ariaListboxSelectedChildren(AccessibilityChildre 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-selected").string(); + String selectedAttrString = childElement->getAttribute(aria_selectedAttr).string(); if (equalIgnoringCase(selectedAttrString, "true")) { result.append(child); - if (isMultiselectable) + if (isMulti) return; } } @@ -2642,11 +3101,11 @@ void AccessibilityRenderObject::selectedChildren(AccessibilityChildrenVector& re ASSERT(result.isEmpty()); // only listboxes should be asked for their selected children. - if (ariaRoleAttribute() != ListBoxRole) { // native list boxes would be AccessibilityListBoxes, so only check for aria list boxes - ASSERT_NOT_REACHED(); - return; - } - return ariaListboxSelectedChildren(result); + AccessibilityRole role = roleValue(); + if (role == ListBoxRole) // native list boxes would be AccessibilityListBoxes, so only check for aria list boxes + ariaListboxSelectedChildren(result); + else if (role == TreeRole || role == TreeGridRole || role == TableRole) + ariaSelectedRows(result); } void AccessibilityRenderObject::ariaListboxVisibleChildren(AccessibilityChildrenVector& result) @@ -2673,6 +3132,17 @@ void AccessibilityRenderObject::visibleChildren(AccessibilityChildrenVector& res return ariaListboxVisibleChildren(result); } +void AccessibilityRenderObject::tabChildren(AccessibilityChildrenVector& result) +{ + ASSERT(roleValue() == TabListRole); + + unsigned length = m_children.size(); + for (unsigned i = 0; i < length; ++i) { + if (m_children[i]->isTabItem()) + result.append(m_children[i]); + } +} + const String& AccessibilityRenderObject::actionVerb() const { // FIXME: Need to add verbs for select elements. @@ -2685,20 +3155,20 @@ const String& AccessibilityRenderObject::actionVerb() const DEFINE_STATIC_LOCAL(const String, noAction, ()); switch (roleValue()) { - case ButtonRole: - return buttonAction; - case TextFieldRole: - case TextAreaRole: - return textFieldAction; - case RadioButtonRole: - return radioButtonAction; - case CheckBoxRole: - return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction; - case LinkRole: - case WebCoreLinkRole: - return linkAction; - default: - return noAction; + case ButtonRole: + return buttonAction; + case TextFieldRole: + case TextAreaRole: + return textFieldAction; + case RadioButtonRole: + return radioButtonAction; + case CheckBoxRole: + return isChecked() ? checkedCheckBoxAction : uncheckedCheckBoxAction; + case LinkRole: + case WebCoreLinkRole: + return linkAction; + default: + return noAction; } } @@ -2711,4 +3181,128 @@ void AccessibilityRenderObject::updateBackingStore() m_renderer->document()->updateLayoutIgnorePendingStylesheets(); } +static bool isLinkable(const AccessibilityRenderObject& object) +{ + if (!object.renderer()) + return false; + + // See https://wiki.mozilla.org/Accessibility/AT-Windows-API for the elements + // Mozilla considers linkable. + return object.isLink() || object.isImage() || object.renderer()->isText(); +} + +String AccessibilityRenderObject::stringValueForMSAA() const +{ + if (isLinkable(*this)) { + Element* anchor = anchorElement(); + if (anchor && anchor->hasTagName(aTag)) + return static_cast<HTMLAnchorElement*>(anchor)->href(); + } + + return stringValue(); +} + +bool AccessibilityRenderObject::isLinked() const +{ + if (!isLinkable(*this)) + return false; + + Element* anchor = anchorElement(); + if (!anchor || !anchor->hasTagName(aTag)) + return false; + + return !static_cast<HTMLAnchorElement*>(anchor)->href().isEmpty(); +} + +String AccessibilityRenderObject::nameForMSAA() const +{ + if (m_renderer && m_renderer->isText()) + return textUnderElement(); + + return title(); +} + +static bool shouldReturnTagNameAsRoleForMSAA(const Element& element) +{ + // See "document structure", + // https://wiki.mozilla.org/Accessibility/AT-Windows-API + // FIXME: Add the other tag names that should be returned as the role. + return element.hasTagName(h1Tag) || element.hasTagName(h2Tag) + || element.hasTagName(h3Tag) || element.hasTagName(h4Tag) + || element.hasTagName(h5Tag) || element.hasTagName(h6Tag); +} + +String AccessibilityRenderObject::stringRoleForMSAA() const +{ + if (!m_renderer) + return String(); + + Node* node = m_renderer->node(); + if (!node || !node->isElementNode()) + return String(); + + Element* element = static_cast<Element*>(node); + if (!shouldReturnTagNameAsRoleForMSAA(*element)) + return String(); + + return element->tagName(); +} + +String AccessibilityRenderObject::positionalDescriptionForMSAA() const +{ + // See "positional descriptions", + // https://wiki.mozilla.org/Accessibility/AT-Windows-API + if (isHeading()) + return "L" + String::number(headingLevel()); + + // FIXME: Add positional descriptions for other elements. + return String(); +} + +String AccessibilityRenderObject::descriptionForMSAA() const +{ + String description = positionalDescriptionForMSAA(); + if (!description.isEmpty()) + return description; + + description = accessibilityDescription(); + if (!description.isEmpty()) { + // 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: " + description; + } + + return String(); +} + +static AccessibilityRole msaaRoleForRenderer(const RenderObject* renderer) +{ + if (!renderer) + return UnknownRole; + + if (renderer->isText()) + return EditableTextRole; + + if (renderer->isListItem()) + return ListItemRole; + + return UnknownRole; +} + +AccessibilityRole AccessibilityRenderObject::roleValueForMSAA() const +{ + if (m_roleForMSAA != UnknownRole) + return m_roleForMSAA; + + m_roleForMSAA = msaaRoleForRenderer(m_renderer); + + if (m_roleForMSAA == UnknownRole) + m_roleForMSAA = roleValue(); + + return m_roleForMSAA; +} + } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityRenderObject.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityRenderObject.h index c6fd748..244eb60 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityRenderObject.h +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityRenderObject.h @@ -62,7 +62,7 @@ public: static PassRefPtr<AccessibilityRenderObject> create(RenderObject*); virtual ~AccessibilityRenderObject(); - bool isAccessibilityRenderObject() const { return true; }; + bool isAccessibilityRenderObject() const { return true; } virtual bool isAnchor() const; virtual bool isAttachment() const; @@ -96,20 +96,26 @@ public: virtual bool isHovered() const; virtual bool isIndeterminate() const; virtual bool isLoaded() const; - virtual bool isMultiSelect() const; + virtual bool isMultiSelectable() const; virtual bool isOffScreen() const; virtual bool isPressed() const; virtual bool isReadOnly() const; virtual bool isVisited() const; virtual bool isRequired() const; + virtual bool isLinked() const; + virtual bool isExpanded() const; + virtual void setIsExpanded(bool); const AtomicString& getAttribute(const QualifiedName&) const; virtual bool canSetFocusAttribute() const; virtual bool canSetTextRangeAttributes() const; virtual bool canSetValueAttribute() const; - + virtual bool canSetExpandedAttribute() const; + virtual bool hasIntValue() const; + // Provides common logic used by all elements when determining isIgnored. + AccessibilityObjectInclusion accessibilityIsIgnoredBase() const; virtual bool accessibilityIsIgnored() const; virtual int headingLevel() const; @@ -119,7 +125,9 @@ public: virtual float maxValueForRange() const; virtual float minValueForRange() const; virtual AccessibilityObject* selectedRadioButton(); + virtual AccessibilityObject* selectedTabItem(); virtual int layoutCount() const; + virtual double estimatedLoadingProgress() const; virtual AccessibilityObject* doAccessibilityHitTest(const IntPoint&) const; virtual AccessibilityObject* focusedUIElement() const; @@ -136,6 +144,8 @@ public: virtual AccessibilityObject* correspondingControlForLabelElement() const; virtual AccessibilityObject* correspondingLabelForControlElement() const; + virtual void ariaOwnsElements(AccessibilityChildrenVector&) const; + virtual bool supportsARIAOwns() const; virtual AccessibilityRole ariaRoleAttribute() const; virtual bool isPresentationalChildOfAriaRole() const; virtual bool ariaRoleHasPresentationalChildren() const; @@ -167,7 +177,6 @@ public: virtual PlainTextRange selectedTextRange() const; virtual VisibleSelection selection() const; virtual String stringValue() const; - virtual String ariaAccessibilityName(const String&) const; virtual String ariaLabeledByAttribute() const; virtual String title() const; virtual String ariaDescribedByAttribute() const; @@ -184,23 +193,30 @@ 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&); virtual void setValue(const String&); + virtual void setSelected(bool); + virtual void setSelectedRows(AccessibilityChildrenVector&); virtual void changeValueByPercent(float percentChange); + virtual AccessibilityOrientation orientation() const; virtual void increment(); virtual void decrement(); virtual void detach(); virtual void childrenChanged(); + virtual void contentChanged(); virtual void addChildren(); virtual bool canHaveChildren() const; virtual void selectedChildren(AccessibilityChildrenVector&); virtual void visibleChildren(AccessibilityChildrenVector&); + virtual void tabChildren(AccessibilityChildrenVector&); virtual bool shouldFocusActiveDescendant() const; virtual AccessibilityObject* activeDescendant() const; virtual void handleActiveDescendantChanged(); @@ -209,6 +225,14 @@ public: virtual VisiblePositionRange visiblePositionRangeForLine(unsigned) const; virtual IntRect boundsForVisiblePositionRange(const VisiblePositionRange&) const; virtual void setSelectedVisiblePositionRange(const VisiblePositionRange&) const; + virtual bool supportsARIAFlowTo() const; + virtual void ariaFlowToElements(AccessibilityChildrenVector&) const; + + virtual bool supportsARIADropping() const; + virtual bool supportsARIADragging() const; + virtual bool isARIAGrabbed(); + virtual void setARIAGrabbed(bool); + virtual void determineARIADropEffects(Vector<String>&); virtual VisiblePosition visiblePositionForPoint(const IntPoint&) const; virtual VisiblePosition visiblePositionForIndex(unsigned indexValue, bool lastIndexOK) const; @@ -224,13 +248,21 @@ public: virtual IntRect doAXBoundsForRange(const PlainTextRange&) const; virtual void updateBackingStore(); - + + virtual String stringValueForMSAA() const; + virtual String stringRoleForMSAA() const; + virtual String nameForMSAA() const; + virtual String descriptionForMSAA() const; + virtual AccessibilityRole roleValueForMSAA() const; + protected: RenderObject* m_renderer; AccessibilityRole m_ariaRole; mutable bool m_childrenDirty; 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; } @@ -238,19 +270,40 @@ private: void ariaListboxSelectedChildren(AccessibilityChildrenVector&); void ariaListboxVisibleChildren(AccessibilityChildrenVector&); bool ariaIsHidden() const; + bool isDescendantOfBarrenParent() const; + bool isAllowedChildOfTree() const; + bool hasTextAlternative() const; + String positionalDescriptionForMSAA() const; + virtual String language() const; Element* menuElementForMenuButton() const; Element* menuItemElementForMenu() const; AccessibilityRole determineAccessibilityRole(); AccessibilityRole determineAriaRoleAttribute() const; + bool isTabItemSelected() const; IntRect checkboxOrRadioRect() const; void addRadioButtonGroupMembers(AccessibilityChildrenVector& linkedUIElements) const; AccessibilityObject* internalLinkElement() const; AccessibilityObject* accessibilityImageMapHitTest(HTMLAreaElement*, const IntPoint&) const; AccessibilityObject* accessibilityParentForImageMap(HTMLMapElement* map) const; - void markChildrenDirty() const { m_childrenDirty = true; } + void ariaSelectedRows(AccessibilityChildrenVector&); + + bool elementAttributeValue(const QualifiedName&) const; + void setElementAttributeValue(const QualifiedName&, bool); + + String accessibilityDescriptionForElements(Vector<Element*> &elements) const; + void elementsFromAttribute(Vector<Element*>& elements, const QualifiedName& name) const; + + virtual const AtomicString& ariaLiveRegionStatus() const; + virtual const AtomicString& ariaLiveRegionRelevant() const; + virtual bool ariaLiveRegionAtomic() const; + virtual bool ariaLiveRegionBusy() const; + + void setNeedsToUpdateChildren() const { m_childrenDirty = true; } + + mutable AccessibilityRole m_roleForMSAA; }; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityScrollbar.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityScrollbar.cpp new file mode 100644 index 0000000..717d0da --- /dev/null +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityScrollbar.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AccessibilityScrollbar.h" + +#include "Scrollbar.h" + +namespace WebCore { + +AccessibilityScrollbar::AccessibilityScrollbar() + : m_scrollbar(0) +{ +} + +PassRefPtr<AccessibilityScrollbar> AccessibilityScrollbar::create() +{ + return adoptRef(new AccessibilityScrollbar); +} + +float AccessibilityScrollbar::valueForRange() const +{ + if (!m_scrollbar) + return 0; + return m_scrollbar->currentPos(); +} + +} // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityScrollbar.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityScrollbar.h new file mode 100644 index 0000000..d75e60c --- /dev/null +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityScrollbar.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AccessibilityScrollbar_h +#define AccessibilityScrollbar_h + +#include "AccessibilityObject.h" + +namespace WebCore { + +class Scrollbar; + +class AccessibilityScrollbar : public AccessibilityObject { +public: + static PassRefPtr<AccessibilityScrollbar> create(); + + void setScrollbar(Scrollbar* scrollbar) { m_scrollbar = scrollbar; } + + virtual AccessibilityRole roleValue() const { return ScrollBarRole; } + + virtual float valueForRange() const; + +private: + AccessibilityScrollbar(); + + virtual bool accessibilityIsIgnored() const { return false; } + + // These should never be reached since the AccessibilityScrollbar is not part of + // the accessibility tree. + virtual IntSize size() const { ASSERT_NOT_REACHED(); return IntSize(); } + virtual IntRect elementRect() const { ASSERT_NOT_REACHED(); return IntRect(); } + virtual AccessibilityObject* parentObject() const { ASSERT_NOT_REACHED(); return 0; } + + Scrollbar* m_scrollbar; +}; + +} // namespace WebCore + +#endif // AccessibilityScrollbar_h diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilitySlider.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilitySlider.cpp index 5aca672..e8d1f41 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilitySlider.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilitySlider.cpp @@ -68,18 +68,18 @@ AccessibilityOrientation AccessibilitySlider::orientation() const ControlPart styleAppearance = style->appearance(); switch (styleAppearance) { - case SliderThumbHorizontalPart: - case SliderHorizontalPart: - case MediaSliderPart: - return AccessibilityOrientationHorizontal; + case SliderThumbHorizontalPart: + case SliderHorizontalPart: + case MediaSliderPart: + return AccessibilityOrientationHorizontal; + + case SliderThumbVerticalPart: + case SliderVerticalPart: + case MediaVolumeSliderPart: + return AccessibilityOrientationVertical; - case SliderThumbVerticalPart: - case SliderVerticalPart: - case MediaVolumeSliderPart: - return AccessibilityOrientationVertical; - - default: - return AccessibilityOrientationHorizontal; + default: + return AccessibilityOrientationHorizontal; } } @@ -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/src/3rdparty/webkit/WebCore/accessibility/AccessibilitySlider.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilitySlider.h index 254ebdd..461f62b 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilitySlider.h +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilitySlider.h @@ -33,58 +33,58 @@ namespace WebCore { - class HTMLInputElement; +class HTMLInputElement; - class AccessibilitySlider : public AccessibilityRenderObject { - - public: - static PassRefPtr<AccessibilitySlider> create(RenderObject*); - virtual ~AccessibilitySlider() { } +class AccessibilitySlider : public AccessibilityRenderObject { + +public: + static PassRefPtr<AccessibilitySlider> create(RenderObject*); + virtual ~AccessibilitySlider() { } - virtual AccessibilityRole roleValue() const { return SliderRole; } - virtual bool accessibilityIsIgnored() const { return false; } + virtual AccessibilityRole roleValue() const { return SliderRole; } - virtual bool isSlider() const { return true; } + virtual bool isSlider() const { return true; } - virtual const AccessibilityChildrenVector& children(); - virtual void addChildren(); + virtual const AccessibilityChildrenVector& children(); + virtual void addChildren(); - virtual bool canSetValueAttribute() const { return true; }; - const AtomicString& getAttribute(const QualifiedName& attribute) const; + virtual bool canSetValueAttribute() const { return true; } + const AtomicString& getAttribute(const QualifiedName& attribute) const; - virtual void setValue(const String&); - virtual float valueForRange() const; - virtual float maxValueForRange() const; - virtual float minValueForRange() const; - virtual AccessibilityOrientation orientation() const; + virtual void setValue(const String&); + virtual float valueForRange() const; + virtual float maxValueForRange() const; + virtual float minValueForRange() const; + virtual AccessibilityOrientation orientation() const; - protected: - AccessibilitySlider(RenderObject*); +protected: + AccessibilitySlider(RenderObject*); - private: - HTMLInputElement* element() const; - }; +private: + HTMLInputElement* element() const; + virtual bool accessibilityIsIgnored() const; +}; - class AccessibilitySliderThumb : public AccessibilityObject { - - public: - static PassRefPtr<AccessibilitySliderThumb> create(); - virtual ~AccessibilitySliderThumb() { } +class AccessibilitySliderThumb : public AccessibilityObject { + +public: + static PassRefPtr<AccessibilitySliderThumb> create(); + virtual ~AccessibilitySliderThumb() { } - virtual AccessibilityRole roleValue() const { return SliderThumbRole; } - virtual bool accessibilityIsIgnored() const { return false; } + virtual AccessibilityRole roleValue() const { return SliderThumbRole; } - void setParentObject(AccessibilitySlider* slider) { m_parentSlider = slider; } - virtual AccessibilityObject* parentObject() const { return m_parentSlider; } + void setParentObject(AccessibilitySlider* slider) { m_parentSlider = slider; } + virtual AccessibilityObject* parentObject() const { return m_parentSlider; } - virtual IntSize size() const; - virtual IntRect elementRect() const; + virtual IntSize size() const; + virtual IntRect elementRect() const; - private: - AccessibilitySliderThumb(); +private: + AccessibilitySliderThumb(); + virtual bool accessibilityIsIgnored() const { return false; } - AccessibilitySlider* m_parentSlider; - }; + AccessibilitySlider* m_parentSlider; +}; } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTable.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTable.cpp index 928ef2c..aed8867 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTable.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTable.cpp @@ -29,15 +29,15 @@ #include "config.h" #include "AccessibilityTable.h" +#include "AXObjectCache.h" #include "AccessibilityTableCell.h" #include "AccessibilityTableColumn.h" #include "AccessibilityTableHeaderContainer.h" #include "AccessibilityTableRow.h" -#include "AXObjectCache.h" #include "HTMLNames.h" -#include "HTMLTableElement.h" #include "HTMLTableCaptionElement.h" #include "HTMLTableCellElement.h" +#include "HTMLTableElement.h" #include "RenderObject.h" #include "RenderTable.h" #include "RenderTableCell.h" @@ -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); @@ -149,8 +154,8 @@ bool AccessibilityTable::isTableExposableThroughAccessibility() HTMLTableCellElement* cellElement = static_cast<HTMLTableCellElement*>(cellNode); // in this case, the developer explicitly assigned a "data" table attribute - if (!cellElement->headers().isEmpty() || !cellElement->abbr().isEmpty() || - !cellElement->axis().isEmpty() || !cellElement->scope().isEmpty()) + if (!cellElement->headers().isEmpty() || !cellElement->abbr().isEmpty() + || !cellElement->axis().isEmpty() || !cellElement->scope().isEmpty()) return true; RenderStyle* renderStyle = cell->style(); @@ -158,15 +163,15 @@ bool AccessibilityTable::isTableExposableThroughAccessibility() continue; // a cell needs to have matching bordered sides, before it can be considered a bordered cell. - if ((cell->borderTop() > 0 && cell->borderBottom() > 0) || - (cell->borderLeft() > 0 && cell->borderRight() > 0)) + if ((cell->borderTop() > 0 && cell->borderBottom() > 0) + || (cell->borderLeft() > 0 && cell->borderRight() > 0)) borderedCellCount++; // if the cell has a different color from the table and there is cell spacing, // then it is probably a data table cell (spacing and colors take the place of borders) Color cellColor = renderStyle->backgroundColor(); - if (table->hBorderSpacing() > 0 && table->vBorderSpacing() > 0 && - tableBGColor != cellColor && cellColor.alpha() != 1) + if (table->hBorderSpacing() > 0 && table->vBorderSpacing() > 0 + && tableBGColor != cellColor && cellColor.alpha() != 1) backgroundDifferenceCellCount++; // if we've found 10 "good" cells, we don't need to keep searching @@ -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/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTable.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTable.h index b6aa3ca..42edf2a 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTable.h +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTable.h @@ -63,6 +63,7 @@ public: AccessibilityChildrenVector& columns(); AccessibilityChildrenVector& rows(); + virtual bool supportsSelectedRows() { return false; } unsigned columnCount(); unsigned rowCount(); diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableCell.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableCell.cpp index 7674cb8..318c619 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableCell.cpp +++ b/src/3rdparty/webkit/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/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableColumn.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableColumn.cpp index e09d65e..5872706 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableColumn.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableColumn.cpp @@ -29,12 +29,12 @@ #include "config.h" #include "AccessibilityTableColumn.h" -#include "AccessibilityTableCell.h" #include "AXObjectCache.h" +#include "AccessibilityTableCell.h" #include "HTMLNames.h" #include "RenderTable.h" -#include "RenderTableSection.h" #include "RenderTableCell.h" +#include "RenderTableSection.h" using namespace std; @@ -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/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableColumn.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableColumn.h index 6270398..15d300c 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableColumn.h +++ b/src/3rdparty/webkit/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/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp index af9de39..e2da83c 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableHeaderContainer.cpp @@ -29,8 +29,8 @@ #include "config.h" #include "AccessibilityTableHeaderContainer.h" -#include "AccessibilityTable.h" #include "AXObjectCache.h" +#include "AccessibilityTable.h" using namespace std; @@ -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); @@ -79,9 +91,8 @@ void AccessibilityTableHeaderContainer::addChildren() static_cast<AccessibilityTable*>(m_parentTable)->columnHeaders(m_children); unsigned length = m_children.size(); - for (unsigned k = 0; k < length; ++k) { + for (unsigned k = 0; k < length; ++k) m_headerRect.unite(m_children[k]->elementRect()); - } } } // namespace WebCore diff --git a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableHeaderContainer.h b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableHeaderContainer.h index 8a9448a..79521c0 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableHeaderContainer.h +++ b/src/3rdparty/webkit/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/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableRow.cpp b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableRow.cpp index 53b479e..e2a1157 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableRow.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/AccessibilityTableRow.cpp @@ -29,8 +29,8 @@ #include "config.h" #include "AccessibilityTableRow.h" -#include "AccessibilityTableCell.h" #include "AXObjectCache.h" +#include "AccessibilityTableCell.h" #include "HTMLNames.h" #include "HTMLTableRowElement.h" #include "RenderObject.h" @@ -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/src/3rdparty/webkit/WebCore/accessibility/qt/AccessibilityObjectQt.cpp b/src/3rdparty/webkit/WebCore/accessibility/qt/AccessibilityObjectQt.cpp index 756ece3..7232642 100644 --- a/src/3rdparty/webkit/WebCore/accessibility/qt/AccessibilityObjectQt.cpp +++ b/src/3rdparty/webkit/WebCore/accessibility/qt/AccessibilityObjectQt.cpp @@ -20,8 +20,6 @@ #include "config.h" #include "AccessibilityObject.h" -QT_BEGIN_NAMESPACE - #if HAVE(ACCESSIBILITY) namespace WebCore { @@ -31,13 +29,14 @@ bool AccessibilityObject::accessibilityIgnoreAttachment() const return false; } -AccessibilityObjectPlatformInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const +AccessibilityObjectInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const { + if (isMenuListPopup() || isMenuListOption()) + return IgnoreObject; + return DefaultBehavior; } } // namespace WebCore #endif // HAVE(ACCESSIBILITY) - -QT_END_NAMESPACE |