Changeset 131915 in webkit
- Timestamp:
- Oct 19, 2012 10:16:19 AM (12 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r131910 r131915 1 2012-10-19 Chris Fleizach <cfleizach@apple.com> 2 3 AX: aria-hidden=false does not work as expected 4 https://bugs.webkit.org/show_bug.cgi?id=98787 5 6 Reviewed by Beth Dakin. 7 8 * accessibility/aria-hidden-negates-no-visibility.html: Added. 9 * platform/mac/accessibility/aria-hidden-negates-no-visibility-expected.txt: Added. 10 1 11 2012-10-19 Shinya Kawanaka <shinyak@chromium.org> 2 12 -
trunk/LayoutTests/platform/chromium/TestExpectations
r131908 r131915 1425 1425 1426 1426 webkit.org/b/73912 accessibility/aria-checkbox-sends-notification.html [ Failure Pass ] 1427 webkit.org/b/98787 accessibility/aria-hidden-negates-no-visibility.html [ Skip ] 1427 1428 1428 1429 # ----------------------------------------------------------------- -
trunk/Source/WebCore/ChangeLog
r131914 r131915 1 2012-10-19 Chris Fleizach <cfleizach@apple.com> 2 3 AX: aria-hidden=false does not work as expected 4 https://bugs.webkit.org/show_bug.cgi?id=98787 5 6 Reviewed by Beth Dakin. 7 8 ARIA requires that aria-hidden=false override an element's native visibility and include that 9 node in the AX hierarchy. 10 11 To accomplish this we have to allow invisible items to be included, as well as items that 12 have no renderers associated with them. 13 14 Test: accessibility/aria-hidden-negates-no-visibility.html 15 16 * accessibility/AXObjectCache.cpp: 17 (WebCore::AXObjectCache::getOrCreate): 18 * accessibility/AccessibilityARIAGrid.cpp: 19 (WebCore::AccessibilityARIAGrid::addTableCellChild): 20 (WebCore::AccessibilityARIAGrid::addChildren): 21 * accessibility/AccessibilityARIAGrid.h: 22 (AccessibilityARIAGrid): 23 * accessibility/AccessibilityNodeObject.cpp: 24 (WebCore): 25 (WebCore::AccessibilityNodeObject::boundingBoxRect): 26 (WebCore::AccessibilityNodeObject::insertChild): 27 (WebCore::AccessibilityNodeObject::addChild): 28 (WebCore::AccessibilityNodeObject::addChildren): 29 (WebCore::AccessibilityNodeObject::textUnderElement): 30 * accessibility/AccessibilityNodeObject.h: 31 (AccessibilityNodeObject): 32 * accessibility/AccessibilityObject.cpp: 33 (WebCore::AccessibilityObject::textIteratorBehaviorForTextRange): 34 (WebCore): 35 * accessibility/AccessibilityObject.h: 36 (AccessibilityObject): 37 (WebCore::AccessibilityObject::addChild): 38 (WebCore::AccessibilityObject::insertChild): 39 * accessibility/AccessibilityRenderObject.cpp: 40 (WebCore): 41 (WebCore::AccessibilityRenderObject::accessibilityIsIgnoredBase): 42 (WebCore::AccessibilityRenderObject::addHiddenChildren): 43 (WebCore::AccessibilityRenderObject::addChildren): 44 * accessibility/AccessibilityRenderObject.h: 45 (AccessibilityRenderObject): 46 1 47 2012-10-19 Tommy Widenflycht <tommyw@google.com> 2 48 -
trunk/Source/WebCore/accessibility/AXObjectCache.cpp
r130612 r131915 317 317 return getOrCreate(node->renderer()); 318 318 319 if (!node->parentElement()) 320 return 0; 321 319 322 // It's only allowed to create an AccessibilityObject from a Node if it's in a canvas subtree. 320 if (!node->parentElement() || !node->parentElement()->isInCanvasSubtree()) 323 // Or if it's a hidden element, but we still want to expose it because of other ARIA attributes. 324 bool inCanvasSubtree = node->parentElement()->isInCanvasSubtree(); 325 bool isHidden = !node->renderer() && isNodeAriaVisible(node); 326 if (!inCanvasSubtree && !isHidden) 321 327 return 0; 322 328 … … 784 790 return axObject && axObject->isTextControl(); 785 791 } 792 793 bool isNodeAriaVisible(Node* node) 794 { 795 if (!node) 796 return false; 797 798 if (!node->isElementNode()) 799 return false; 800 801 return equalIgnoringCase(toElement(node)->getAttribute(aria_hiddenAttr), "false"); 802 } 786 803 787 804 } // namespace WebCore -
trunk/Source/WebCore/accessibility/AXObjectCache.h
r128570 r131915 209 209 210 210 bool nodeHasRole(Node*, const String& role); 211 211 // This will let you know if aria-hidden was explicitly set to false. 212 bool isNodeAriaVisible(Node*); 213 212 214 #if !HAVE(ACCESSIBILITY) 213 215 inline AXObjectCache::AXObjectCache(const Document* doc) : m_document(const_cast<Document*>(doc)), m_notificationPostTimer(this, 0) { } -
trunk/Source/WebCore/accessibility/AccessibilityARIAGrid.cpp
r123428 r131915 67 67 } 68 68 69 bool AccessibilityARIAGrid::add Child(AccessibilityObject* child, HashSet<AccessibilityObject*>& appendedRows, unsigned& columnCount)69 bool AccessibilityARIAGrid::addTableCellChild(AccessibilityObject* child, HashSet<AccessibilityObject*>& appendedRows, unsigned& columnCount) 70 70 { 71 71 if (!child || !child->isTableRow() || child->ariaRoleAttribute() != RowRole) … … 115 115 for (RefPtr<AccessibilityObject> child = firstChild(); child; child = child->nextSibling()) { 116 116 117 if (!add Child(child.get(), appendedRows, columnCount)) {117 if (!addTableCellChild(child.get(), appendedRows, columnCount)) { 118 118 119 119 // in case the render tree doesn't match the expected ARIA hierarchy, look at the children … … 126 126 size_t length = children.size(); 127 127 for (size_t i = 0; i < length; ++i) 128 add Child(children[i].get(), appendedRows, columnCount);128 addTableCellChild(children[i].get(), appendedRows, columnCount); 129 129 } 130 130 } -
trunk/Source/WebCore/accessibility/AccessibilityARIAGrid.h
r124582 r131915 59 59 virtual bool isMultiSelectable() const { return true; } 60 60 61 bool add Child(AccessibilityObject*, HashSet<AccessibilityObject*>& appendedRows, unsigned& columnCount);61 bool addTableCellChild(AccessibilityObject*, HashSet<AccessibilityObject*>& appendedRows, unsigned& columnCount); 62 62 }; 63 63 -
trunk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp
r131905 r131915 223 223 return boundingBoxRect(); 224 224 } 225 226 LayoutRect AccessibilityNodeObject::boundingBoxRect() const 227 { 228 // AccessibilityNodeObjects have no mechanism yet to return a size or position. 229 // For now, let's return the position of the ancestor that does have a position, 230 // and make it the width of that parent, and about the height of a line of text, so that it's clear the object is a child of the parent. 231 232 LayoutRect boundingBox; 233 234 for (AccessibilityObject* positionProvider = parentObject(); positionProvider; positionProvider = positionProvider->parentObject()) { 235 if (positionProvider->isAccessibilityRenderObject()) { 236 LayoutRect parentRect = positionProvider->elementRect(); 237 boundingBox.setSize(LayoutSize(parentRect.width(), FractionalLayoutUnit(std::min(10.0f, parentRect.height().toFloat())))); 238 boundingBox.setLocation(parentRect.location()); 239 break; 240 } 241 } 242 243 return boundingBox; 244 } 225 245 226 246 void AccessibilityNodeObject::setNode(Node* node) … … 285 305 } 286 306 307 void AccessibilityNodeObject::insertChild(AccessibilityObject* child, unsigned index) 308 { 309 if (!child) 310 return; 311 312 // If the parent is asking for this child's children, then either it's the first time (and clearing is a no-op), 313 // or its visibility has changed. In the latter case, this child may have a stale child cached. 314 // This can prevent aria-hidden changes from working correctly. Hence, whenever a parent is getting children, ensure data is not stale. 315 child->clearChildren(); 316 317 if (child->accessibilityIsIgnored()) { 318 AccessibilityChildrenVector children = child->children(); 319 size_t length = children.size(); 320 for (size_t i = 0; i < length; ++i) 321 m_children.insert(index + i, children[i]); 322 } else { 323 ASSERT(child->parentObject() == this); 324 m_children.insert(index, child); 325 } 326 } 327 328 void AccessibilityNodeObject::addChild(AccessibilityObject* child) 329 { 330 insertChild(child, m_children.size()); 331 } 332 287 333 void AccessibilityNodeObject::addChildren() 288 334 { … … 300 346 return; 301 347 302 for (Node* child = m_node->firstChild(); child; child = child->nextSibling()) { 303 RefPtr<AccessibilityObject> obj = axObjectCache()->getOrCreate(child); 304 obj->clearChildren(); 305 if (obj->accessibilityIsIgnored()) { 306 AccessibilityChildrenVector children = obj->children(); 307 size_t length = children.size(); 308 for (size_t i = 0; i < length; ++i) 309 m_children.append(children[i]); 310 } else { 311 ASSERT(obj->parentObject() == this); 312 m_children.append(obj); 313 } 314 } 348 for (Node* child = m_node->firstChild(); child; child = child->nextSibling()) 349 addChild(axObjectCache()->getOrCreate(child)); 315 350 } 316 351 … … 1401 1436 if (node->isElementNode()) 1402 1437 return toElement(node)->innerText(); 1403 1438 else if (node->isTextNode()) 1439 return toText(node)->wholeText(); 1440 1404 1441 return String(); 1405 1442 } -
trunk/Source/WebCore/accessibility/AccessibilityNodeObject.h
r131905 r131915 159 159 virtual AccessibilityRole determineAccessibilityRole(); 160 160 virtual void addChildren(); 161 virtual void addChild(AccessibilityObject*); 162 virtual void insertChild(AccessibilityObject*, unsigned index); 163 161 164 virtual bool canHaveChildren() const; 162 165 virtual bool accessibilityIsIgnored() const; … … 175 178 String accessibilityDescriptionForElements(Vector<Element*> &elements) const; 176 179 void elementsFromAttribute(Vector<Element*>& elements, const QualifiedName&) const; 180 virtual LayoutRect boundingBoxRect() const; 177 181 String ariaDescribedByAttribute() const; 178 182 -
trunk/Source/WebCore/accessibility/AccessibilityObject.cpp
r128748 r131915 1777 1777 } 1778 1778 1779 TextIteratorBehavior AccessibilityObject::textIteratorBehaviorForTextRange() const 1780 { 1781 TextIteratorBehavior behavior = TextIteratorIgnoresStyleVisibility; 1782 1783 #if PLATFORM(GTK) 1784 // We need to emit replaced elements for GTK, and present 1785 // them with the 'object replacement character' (0xFFFC). 1786 behavior = static_cast<TextIteratorBehavior>(behavior | TextIteratorEmitsObjectReplacementCharacters); 1787 #endif 1788 1789 return behavior; 1790 } 1791 1779 1792 AccessibilityRole AccessibilityObject::buttonRoleType() const 1780 1793 { -
trunk/Source/WebCore/accessibility/AccessibilityObject.h
r131905 r131915 34 34 #include "FractionalLayoutRect.h" 35 35 #include "LayoutTypes.h" 36 #include "TextIterator.h" 36 37 #include "VisiblePosition.h" 37 38 #include "VisibleSelection.h" … … 574 575 static IntRect boundingBoxForQuads(RenderObject*, const Vector<FloatQuad>&); 575 576 577 TextIteratorBehavior textIteratorBehaviorForTextRange() const; 576 578 virtual PlainTextRange selectedTextRange() const { return PlainTextRange(); } 577 579 unsigned selectionStart() const { return selectedTextRange().start; } … … 613 615 const AccessibilityChildrenVector& children(); 614 616 virtual void addChildren() { } 617 virtual void addChild(AccessibilityObject*) { } 618 virtual void insertChild(AccessibilityObject*, unsigned) { } 619 615 620 virtual bool canHaveChildren() const { return true; } 616 621 virtual bool hasChildren() const { return m_haveChildren; } -
trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
r131908 r131915 80 80 #include "Text.h" 81 81 #include "TextControlInnerElements.h" 82 #include "TextIterator.h"83 82 #include "htmlediting.h" 84 83 #include "visible_units.h" … … 598 597 599 598 return String(); 600 }601 602 static TextIteratorBehavior textIteratorBehaviorForTextRange()603 {604 TextIteratorBehavior behavior = TextIteratorIgnoresStyleVisibility;605 606 #if PLATFORM(GTK)607 // We need to emit replaced elements for GTK, and present608 // them with the 'object replacement character' (0xFFFC).609 behavior = static_cast<TextIteratorBehavior>(behavior | TextIteratorEmitsObjectReplacementCharacters);610 #endif611 612 return behavior;613 599 } 614 600 … … 1036 1022 // The following cases can apply to any element that's a subclass of AccessibilityRenderObject. 1037 1023 1038 // Ignore invisible elements. 1039 if (!m_renderer || m_renderer->style()->visibility() != VISIBLE) 1024 if (!m_renderer) 1040 1025 return IgnoreObject; 1041 1026 1027 if (m_renderer->style()->visibility() != VISIBLE) { 1028 // aria-hidden is meant to override visibility as the determinant in AX hierarchy inclusion. 1029 if (equalIgnoringCase(getAttribute(aria_hiddenAttr), "false")) 1030 return DefaultBehavior; 1031 1032 return IgnoreObject; 1033 } 1034 1042 1035 // Anything marked as aria-hidden or a child of something aria-hidden must be hidden. 1043 1036 if (ariaIsHidden()) … … 2652 2645 #endif 2653 2646 2647 // Hidden children are those that are not rendered or visible, but are specifically marked as aria-hidden=false, 2648 // meaning that they should be exposed to the AX hierarchy. 2649 void AccessibilityRenderObject::addHiddenChildren() 2650 { 2651 Node* node = this->node(); 2652 if (!node) 2653 return; 2654 2655 // First do a quick run through to determine if we have any hidden nodes (most often we will not). 2656 // If we do have hidden nodes, we need to determine where to insert them so they match DOM order as close as possible. 2657 bool shouldInsertHiddenNodes = false; 2658 for (Node* child = node->firstChild(); child; child = child->nextSibling()) { 2659 if (!child->renderer() && isNodeAriaVisible(child)) { 2660 shouldInsertHiddenNodes = true; 2661 break; 2662 } 2663 } 2664 2665 if (!shouldInsertHiddenNodes) 2666 return; 2667 2668 // Iterate through all of the children, including those that may have already been added, and 2669 // try to insert hidden nodes in the correct place in the DOM order. 2670 unsigned insertionIndex = 0; 2671 for (Node* child = node->firstChild(); child; child = child->nextSibling()) { 2672 if (child->renderer()) { 2673 // Find out where the last render sibling is located within m_children. 2674 AccessibilityObject* childObject = axObjectCache()->get(child->renderer()); 2675 if (childObject && childObject->accessibilityIsIgnored()) { 2676 AccessibilityChildrenVector children = childObject->children(); 2677 if (children.size()) 2678 childObject = children.last().get(); 2679 else 2680 childObject = 0; 2681 } 2682 2683 if (childObject) 2684 insertionIndex = m_children.find(childObject) + 1; 2685 continue; 2686 } 2687 2688 if (!isNodeAriaVisible(child)) 2689 continue; 2690 2691 unsigned previousSize = m_children.size(); 2692 if (insertionIndex > previousSize) 2693 insertionIndex = previousSize; 2694 2695 insertChild(axObjectCache()->getOrCreate(child), insertionIndex); 2696 insertionIndex += (m_children.size() - previousSize); 2697 } 2698 } 2699 2654 2700 void AccessibilityRenderObject::addChildren() 2655 2701 { … … 2663 2709 return; 2664 2710 2665 // add all unignored acc children 2666 for (RefPtr<AccessibilityObject> obj = firstChild(); obj; obj = obj->nextSibling()) { 2667 // If the parent is asking for this child's children, then either it's the first time (and clearing is a no-op), 2668 // or its visibility has changed. In the latter case, this child may have a stale child cached. 2669 // This can prevent aria-hidden changes from working correctly. Hence, whenever a parent is getting children, ensure data is not stale. 2670 obj->clearChildren(); 2671 2672 if (obj->accessibilityIsIgnored()) { 2673 AccessibilityChildrenVector children = obj->children(); 2674 unsigned length = children.size(); 2675 for (unsigned i = 0; i < length; ++i) 2676 m_children.append(children[i]); 2677 } else { 2678 ASSERT(obj->parentObject() == this); 2679 m_children.append(obj); 2680 } 2681 } 2682 2711 for (RefPtr<AccessibilityObject> obj = firstChild(); obj; obj = obj->nextSibling()) 2712 addChild(obj.get()); 2713 2714 addHiddenChildren(); 2683 2715 addAttachmentChildren(); 2684 2716 addImageMapChildren(); -
trunk/Source/WebCore/accessibility/AccessibilityRenderObject.h
r131905 r131915 247 247 // This returns true if it's focusable but it's not content editable and it's not a control or ARIA control. 248 248 249 void addHiddenChildren(); 249 250 void addTextFieldChildren(); 250 251 void addImageMapChildren();
Note: See TracChangeset
for help on using the changeset viewer.