Changeset 191931 in webkit
- Timestamp:
- Nov 2, 2015 5:52:38 PM (8 years ago)
- Location:
- trunk
- Files:
-
- 4 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r191928 r191931 1 2015-11-02 Nan Wang <n_wang@apple.com> 2 3 AX: Add support for ARIA 1.1 attribute 'aria-modal' for dialog and alertdialog 4 https://bugs.webkit.org/show_bug.cgi?id=138566 5 6 Reviewed by Chris Fleizach. 7 8 * accessibility/aria-modal-expected.txt: Added. 9 * accessibility/aria-modal-multiple-dialogs-expected.txt: Added. 10 * accessibility/aria-modal-multiple-dialogs.html: Added. 11 * accessibility/aria-modal.html: Added. 12 1 13 2015-11-02 Brady Eidson <beidson@apple.com> 2 14 -
trunk/Source/WebCore/ChangeLog
r191928 r191931 1 2015-11-02 Nan Wang <n_wang@apple.com> 2 3 AX: Add support for ARIA 1.1 attribute 'aria-modal' for dialog and alertdialog 4 https://bugs.webkit.org/show_bug.cgi?id=138566 5 6 Reviewed by Chris Fleizach. 7 8 Added support for aria-modal attribute on dialog/alertdialog roles. 9 When modal dialog is displayed, all other contents will be unaccessible. 10 11 Tests: accessibility/aria-modal-multiple-dialogs.html 12 accessibility/aria-modal.html 13 14 * accessibility/AXObjectCache.cpp: 15 (WebCore::AXObjectCache::AXObjectCache): 16 (WebCore::AXObjectCache::~AXObjectCache): 17 (WebCore::AXObjectCache::findAriaModalNodes): 18 (WebCore::AXObjectCache::updateCurrentAriaModalNode): 19 (WebCore::AXObjectCache::isNodeVisible): 20 (WebCore::AXObjectCache::ariaModalNode): 21 (WebCore::AXObjectCache::focusedImageMapUIElement): 22 (WebCore::AXObjectCache::remove): 23 (WebCore::AXObjectCache::handleAttributeChanged): 24 (WebCore::AXObjectCache::handleAriaModalChange): 25 (WebCore::AXObjectCache::labelChanged): 26 * accessibility/AXObjectCache.h: 27 (WebCore::AXObjectCache::handleActiveDescendantChanged): 28 (WebCore::AXObjectCache::handleAriaExpandedChange): 29 (WebCore::AXObjectCache::handleAriaRoleChanged): 30 (WebCore::AXObjectCache::handleAriaModalChange): 31 (WebCore::AXObjectCache::handleFocusedUIElementChanged): 32 (WebCore::AXObjectCache::handleScrollbarUpdate): 33 (WebCore::AXObjectCache::handleAttributeChanged): 34 * accessibility/AccessibilityObject.cpp: 35 (WebCore::AccessibilityObject::ariaCurrentState): 36 (WebCore::AccessibilityObject::isAriaModalDescendant): 37 (WebCore::AccessibilityObject::ignoredFromARIAModalPresence): 38 (WebCore::AccessibilityObject::hasTagName): 39 (WebCore::AccessibilityObject::defaultObjectInclusion): 40 * accessibility/AccessibilityObject.h: 41 * html/HTMLAttributeNames.in: 42 1 43 2015-11-02 Brady Eidson <beidson@apple.com> 2 44 -
trunk/Source/WebCore/accessibility/AXObjectCache.cpp
r191327 r191931 143 143 , m_passwordNotificationPostTimer(*this, &AXObjectCache::passwordNotificationPostTimerFired) 144 144 , m_liveRegionChangedPostTimer(*this, &AXObjectCache::liveRegionChangedNotificationPostTimerFired) 145 { 145 , m_currentAriaModalNode(nullptr) 146 { 147 findAriaModalNodes(); 146 148 } 147 149 … … 156 158 removeAXID(object.get()); 157 159 } 160 } 161 162 void AXObjectCache::findAriaModalNodes() 163 { 164 // Traverse the DOM tree to look for the aria-modal=true nodes. 165 for (Element* element = ElementTraversal::firstWithin(document().rootNode()); element; element = ElementTraversal::nextIncludingPseudo(*element)) { 166 167 // Must have dialog or alertdialog role 168 if (!nodeHasRole(element, "dialog") && !nodeHasRole(element, "alertdialog")) 169 continue; 170 if (!equalIgnoringCase(element->fastGetAttribute(aria_modalAttr), "true")) 171 continue; 172 173 m_ariaModalNodesSet.add(element); 174 } 175 176 // Set the current valid aria-modal node if possible. 177 updateCurrentAriaModalNode(); 178 } 179 180 void AXObjectCache::updateCurrentAriaModalNode() 181 { 182 // There might be multiple nodes with aria-modal=true set. 183 // We use this function to pick the one we want. 184 m_currentAriaModalNode = nullptr; 185 if (m_ariaModalNodesSet.isEmpty()) 186 return; 187 188 // We only care about the nodes which are visible. 189 ListHashSet<RefPtr<Node>> visibleNodes; 190 for (auto& object : m_ariaModalNodesSet) { 191 if (isNodeVisible(object)) 192 visibleNodes.add(object); 193 } 194 195 if (visibleNodes.isEmpty()) 196 return; 197 198 // If any of the node are keyboard focused, we want to pick that. 199 Node* focusedNode = document().focusedElement(); 200 for (auto& object : visibleNodes) { 201 if (focusedNode != nullptr && focusedNode->isDescendantOf(object.get())) { 202 m_currentAriaModalNode = object.get(); 203 break; 204 } 205 } 206 207 // If none of the nodes are focused, we want to pick the last dialog in the DOM. 208 if (!m_currentAriaModalNode) 209 m_currentAriaModalNode = visibleNodes.last().get(); 210 } 211 212 bool AXObjectCache::isNodeVisible(Node* node) const 213 { 214 if (!is<Element>(node)) 215 return false; 216 217 RenderObject* renderer = node->renderer(); 218 if (!renderer) 219 return false; 220 const RenderStyle& style = renderer->style(); 221 if (style.display() == NONE || style.visibility() != VISIBLE) 222 return false; 223 224 // We also need to consider aria hidden status. 225 if (!isNodeAriaVisible(node)) 226 return false; 227 228 return true; 229 } 230 231 Node* AXObjectCache::ariaModalNode() 232 { 233 // This function returns the valid aria modal node. 234 if (m_ariaModalNodesSet.isEmpty()) 235 return nullptr; 236 237 // Check the current valid aria modal node first. 238 // Usually when one dialog sets aria-modal=true, that dialog is the one we want. 239 if (isNodeVisible(m_currentAriaModalNode)) 240 return m_currentAriaModalNode; 241 242 // Recompute the valid aria modal node when m_currentAriaModalNode is null or hidden. 243 updateCurrentAriaModalNode(); 244 return isNodeVisible(m_currentAriaModalNode) ? m_currentAriaModalNode : nullptr; 158 245 } 159 246 … … 572 659 m_nodeObjectMapping.remove(node); 573 660 661 // Cleanup for aria modal nodes. 662 if (m_currentAriaModalNode == node) 663 m_currentAriaModalNode = nullptr; 664 if (m_ariaModalNodesSet.contains(node)) 665 m_ariaModalNodesSet.remove(node); 666 574 667 if (node->renderer()) { 575 668 remove(node->renderer()); … … 1249 1342 else if (attrName == aria_invalidAttr) 1250 1343 postNotification(element, AXObjectCache::AXInvalidStatusChanged); 1344 else if (attrName == aria_modalAttr) 1345 handleAriaModalChange(element); 1251 1346 else 1252 1347 postNotification(element, AXObjectCache::AXAriaAttributeChanged); 1348 } 1349 1350 void AXObjectCache::handleAriaModalChange(Node* node) 1351 { 1352 if (!is<Element>(node)) 1353 return; 1354 1355 if (!nodeHasRole(node, "dialog") && !nodeHasRole(node, "alertdialog")) 1356 return; 1357 1358 stopCachingComputedObjectAttributes(); 1359 if (equalIgnoringCase(downcast<Element>(*node).fastGetAttribute(aria_modalAttr), "true")) { 1360 // Add the newly modified node to the modal nodes set, and set it to be the current valid aria modal node. 1361 // We will recompute the current valid aria modal node in ariaModalNode() when this node is not visible. 1362 m_ariaModalNodesSet.add(node); 1363 m_currentAriaModalNode = node; 1364 } else { 1365 // Remove the node from the modal nodes set. There might be other visible modal nodes, so we recompute here. 1366 m_ariaModalNodesSet.remove(node); 1367 updateCurrentAriaModalNode(); 1368 } 1369 startCachingComputedObjectAttributesUntilTreeMutates(); 1253 1370 } 1254 1371 -
trunk/Source/WebCore/accessibility/AXObjectCache.h
r187278 r191931 129 129 void handleAriaExpandedChange(Node*); 130 130 void handleScrollbarUpdate(ScrollView*); 131 132 void handleAriaModalChange(Node*); 133 Node* ariaModalNode(); 131 134 132 135 void handleAttributeChanged(const QualifiedName& attrName, Element*); … … 272 275 void handleLiveRegionCreated(Node*); 273 276 void handleMenuItemSelected(Node*); 277 278 // aria-modal related 279 void findAriaModalNodes(); 280 void updateCurrentAriaModalNode(); 281 bool isNodeVisible(Node*) const; 274 282 275 283 Document& m_document; … … 294 302 Timer m_liveRegionChangedPostTimer; 295 303 ListHashSet<RefPtr<AccessibilityObject>> m_liveRegionObjectsSet; 304 305 Node* m_currentAriaModalNode; 306 ListHashSet<Node*> m_ariaModalNodesSet; 296 307 297 308 AXTextStateChangeIntent m_textSelectionIntent; … … 349 360 inline void AXObjectCache::handleAriaExpandedChange(Node*) { } 350 361 inline void AXObjectCache::handleAriaRoleChanged(Node*) { } 362 inline void AXObjectCache::handleAriaModalChange(Node*) { } 351 363 inline void AXObjectCache::handleFocusedUIElementChanged(Node*, Node*) { } 352 364 inline void AXObjectCache::handleScrollbarUpdate(ScrollView*) { } -
trunk/Source/WebCore/accessibility/AccessibilityObject.cpp
r190833 r191931 36 36 #include "DOMTokenList.h" 37 37 #include "Editor.h" 38 #include "ElementIterator.h" 38 39 #include "EventHandler.h" 39 40 #include "FloatRect.h" … … 1845 1846 // Any value not included in the list of allowed values should be treated as "true". 1846 1847 return ARIACurrentTrue; 1848 } 1849 1850 bool AccessibilityObject::isAriaModalDescendant(Node* ariaModalNode) const 1851 { 1852 if (!ariaModalNode || !this->element()) 1853 return false; 1854 1855 if (this->element() == ariaModalNode) 1856 return true; 1857 1858 // ARIA 1.1 aria-modal, indicates whether an element is modal when displayed. 1859 // For the decendants of the modal object, they should also be considered as aria-modal=true. 1860 for (auto& ancestor : elementAncestors(this->element())) { 1861 if (&ancestor == ariaModalNode) 1862 return true; 1863 } 1864 return false; 1865 } 1866 1867 bool AccessibilityObject::ignoredFromARIAModalPresence() const 1868 { 1869 // We shouldn't ignore the top node. 1870 if (!node() || !node()->parentNode()) 1871 return false; 1872 1873 AXObjectCache* cache = axObjectCache(); 1874 if (!cache) 1875 return false; 1876 1877 // ariaModalNode is the current displayed modal dialog. 1878 Node* ariaModalNode = cache->ariaModalNode(); 1879 if (!ariaModalNode) 1880 return false; 1881 1882 // We only want to ignore the objects within the same frame as the modal dialog. 1883 if (ariaModalNode->document().frame() != this->frame()) 1884 return false; 1885 1886 return !isAriaModalDescendant(ariaModalNode); 1847 1887 } 1848 1888 … … 2787 2827 return IgnoreObject; 2788 2828 2829 if (ignoredFromARIAModalPresence()) 2830 return IgnoreObject; 2831 2789 2832 if (isPresentationalChildOfAriaRole()) 2790 2833 return IgnoreObject; -
trunk/Source/WebCore/accessibility/AccessibilityObject.h
r190833 r191931 632 632 AccessibilityARIACurrentState ariaCurrentState() const; 633 633 634 // This function checks if the object should be ignored when there's a modal dialog displayed. 635 bool ignoredFromARIAModalPresence() const; 636 bool isAriaModalDescendant(Node*) const; 637 634 638 bool supportsARIASetSize() const; 635 639 bool supportsARIAPosInSet() const; -
trunk/Source/WebCore/html/HTMLAttributeNames.in
r190833 r191931 38 38 aria-level 39 39 aria-live 40 aria-modal 40 41 aria-multiline 41 42 aria-multiselectable
Note: See TracChangeset
for help on using the changeset viewer.