Changeset 229553 in webkit
- Timestamp:
- Mar 12, 2018 2:59:28 PM (6 years ago)
- Location:
- branches/safari-605-branch
- Files:
-
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/safari-605-branch/LayoutTests/ChangeLog
r229047 r229553 1 2018-03-11 Jason Marcell <jmarcell@apple.com> 2 3 Cherry-pick r228279. rdar://problem/38154561 4 5 2018-02-08 Chris Fleizach <cfleizach@apple.com> 6 7 AX: Defer attribute computation until needed. 8 https://bugs.webkit.org/show_bug.cgi?id=182386 9 <rdar://problem/37115277> 10 11 Reviewed by Zalan Bujtas. 12 13 Update tests to reflect new world of delayed attribute handling for accessibility. 14 15 * accessibility/canvas-fallback-content.html: 16 Make test async so attributes can be checked after deferred handling. 17 * accessibility/mac/aria-expanded-notifications.html: 18 Access elements through AX tree so attribute changes generate notifications. 19 * accessibility/mac/aria-listbox-selectedchildren-change.html: 20 Make test async so attributes can be checked after deferred handling. 21 * accessibility/mac/aria-menu-item-selected-notification.html: 22 Access menu item through AX tree so attribute changes generate notifications. 23 * accessibility/mac/aria-modal-auto-focus.html: 24 Access buttons after delay so attributes have time to be deferred. 25 * accessibility/mac/element-busy-changed.html: 26 Process second attribute change after delay so we generate two notifications. 27 * accessibility/mac/expanded-notification.html: 28 Set attributes after a delay so they generate individual notifications. 29 * accessibility/notification-listeners.html: 30 Access elements through AX tree so attribute changes generate notifications. 31 1 32 2018-02-26 Ryan Haddad <ryanhaddad@apple.com> 2 33 -
branches/safari-605-branch/LayoutTests/accessibility/canvas-fallback-content.html
r201216 r229553 41 41 42 42 if (window.testRunner && window.accessibilityController) { 43 window.jsTestIsAsync = true; 43 44 window.testRunner.dumpAsText(); 44 45 … … 81 82 // Check that the role is updated when the element changes. 82 83 document.getElementById('focusable1').setAttribute('role', 'button'); 83 check("focusable1", "AXRole: AXButton"); 84 setTimeout(function() { 85 check("focusable1", "AXRole: AXButton"); 86 }, 1); 87 84 88 document.getElementById('focusable2').setAttribute('role', 'button'); 85 check("focusable2", "AXRole: AXButton"); 89 setTimeout(function() { 90 check("focusable2", "AXRole: AXButton"); 91 finishJSTest(); 92 }, 1); 86 93 } 87 94 -
branches/safari-605-branch/LayoutTests/accessibility/mac/aria-expanded-notifications.html
r217171 r229553 59 59 shouldBe("addedNotification", "true"); 60 60 61 accessibilityController.accessibleElementById("tree0"); 62 accessibilityController.accessibleElementById("tree0_item0"); 63 61 64 // the first aria-expanded should generate row count, row collapsed. 62 65 document.getElementById("tree0_item0").setAttribute("aria-expanded", "false"); -
branches/safari-605-branch/LayoutTests/accessibility/mac/aria-listbox-selectedchildren-change.html
r217171 r229553 6 6 <body id="body"> 7 7 8 <div role="group"tabindex=0 id="listbox" role="listbox">8 <div tabindex=0 id="listbox" role="listbox"> 9 9 <div id="option1" role="option" aria-selected="true">Option</div> 10 10 <div id="option2" role="option">Option</div> … … 36 36 jsTestIsAsync = true; 37 37 38 document.getElementById("listbox").focus(); 39 listbox = window.accessibilityController.focusedElement; 38 listbox = accessibilityController.accessibleElementById("listbox"); 40 39 41 40 var addedNotification = window.accessibilityController.addNotificationListener(ariaCallback); … … 44 43 // These should each trigger a notification that the selected children changed. 45 44 document.getElementById("option2").setAttribute("aria-selected", "true"); 46 document.getElementById("option2").setAttribute("aria-selected", "false"); 45 setTimeout(function() { 46 document.getElementById("option2").setAttribute("aria-selected", "false"); 47 }, 1); 47 48 } 48 49 -
branches/safari-605-branch/LayoutTests/accessibility/mac/aria-menu-item-selected-notification.html
r187799 r229553 40 40 41 41 var addedNotification = accessibilityController.addNotificationListener(ariaCallback); 42 accessibilityController. rootElement;42 accessibilityController.accessibleElementById("menu"); 43 43 44 44 shouldBe("addedNotification", "true"); -
branches/safari-605-branch/LayoutTests/accessibility/mac/aria-modal-auto-focus.html
r210265 r229553 51 51 // 2. Click the new button, dialog2 shows and focus should move to the close button. 52 52 document.getElementById("new").click(); 53 closeBtn = accessibilityController.accessibleElementById("close");54 53 setTimeout(function(){ 54 closeBtn = accessibilityController.accessibleElementById("close"); 55 55 shouldBeTrue("closeBtn.isFocused"); 56 56 57 57 // 3. Click the close button, dialog2 closes and focus should go back to the 58 58 // first focusable child of dialog1. 59 59 document.getElementById("close").click(); 60 okBtn = accessibilityController.accessibleElementById("ok");61 60 setTimeout(function(){ 61 okBtn = accessibilityController.accessibleElementById("ok"); 62 62 shouldBeTrue("okBtn.isFocused"); 63 63 finishJSTest(); 64 }, 50);65 }, 50);66 }, 50);64 }, 100); 65 }, 100); 66 }, 100); 67 67 } 68 68 -
branches/safari-605-branch/LayoutTests/accessibility/mac/element-busy-changed.html
r187799 r229553 34 34 var busyElement = document.getElementById("body"); 35 35 busyElement.setAttribute("aria-busy", "true"); 36 busyElement.setAttribute("aria-busy", "false"); 36 37 setTimeout(function() { 38 busyElement.setAttribute("aria-busy", "false"); 39 }, 1); 37 40 } 38 41 </script> -
branches/safari-605-branch/LayoutTests/accessibility/mac/expanded-notification.html
r187799 r229553 39 39 40 40 var addedNotification = accessibilityController.addNotificationListener(ariaCallback); 41 debug("Initial expanded status: " + accessibilityController.accessibleElementById("button").isExpanded); 41 var button = accessibilityController.accessibleElementById("button"); 42 debug("Initial expanded status: " + button.isExpanded); 43 44 document.getElementById("button").setAttribute("aria-expanded", "true"); 42 45 43 46 setTimeout(function() { 44 document.getElementById("button").setAttribute("aria-expanded", "true"); 45 setTimeout(function() { 46 document.getElementById("button").setAttribute("aria-expanded", "false"); 47 }, 10); 47 document.getElementById("button").setAttribute("aria-expanded", "false"); 48 48 }, 10); 49 49 } -
branches/safari-605-branch/LayoutTests/accessibility/notification-listeners.html
r211573 r229553 46 46 } 47 47 48 // Ensure these elements exist in the AX tree otherwise notifications won't be generated. 49 accessibilityController.accessibleElementById("select"); 50 accessibilityController.accessibleElementById("slider"); 51 48 52 // This should trigger a "invalid status changed" notification on the select. 49 53 document.getElementById("select").setAttribute("aria-invalid", "true"); -
branches/safari-605-branch/Source/WebCore/ChangeLog
r229035 r229553 1 2018-03-11 Jason Marcell <jmarcell@apple.com> 2 3 Cherry-pick r228279. rdar://problem/38154561 4 5 2018-02-08 Chris Fleizach <cfleizach@apple.com> 6 7 AX: Defer attribute computation until needed. 8 https://bugs.webkit.org/show_bug.cgi?id=182386 9 <rdar://problem/37115277> 10 11 Reviewed by Zalan Bujtas. 12 13 Accessibility is doing too much work when handling attribute changes. Here's how we can improve this: 14 1) Defer attribute changes while the tree is dirty (and coalesce them). 15 2) Don't create AXObjects when an attribute changes unnecessarily. If no client has requested an ax object, it's likely no work needs to be done 16 (with the exception of a few attributes like aria-modal) 17 3) Stop calculating the entire accessible ARIA label when trying to decide if an element should be ignored. That's generally wasteful and the 18 consequence of including more AX elements in the tree is very minimal. 19 20 * accessibility/AXObjectCache.cpp: 21 (WebCore::rendererNeedsDeferredUpdate): 22 (WebCore::nodeAndRendererAreValid): 23 (WebCore::AXObjectCache::remove): 24 (WebCore::AXObjectCache::handleAriaExpandedChange): 25 (WebCore::AXObjectCache::handleAriaRoleChanged): 26 (WebCore::AXObjectCache::deferAttributeChangeIfNeeded): 27 (WebCore::AXObjectCache::shouldProcessAttributeChange): 28 (WebCore::AXObjectCache::handleAttributeChange): 29 (WebCore::AXObjectCache::prepareForDocumentDestruction): 30 (WebCore::AXObjectCache::performDeferredCacheUpdate): 31 (WebCore::AXObjectCache::deferRecomputeIsIgnoredIfNeeded): 32 (WebCore::AXObjectCache::deferRecomputeIsIgnored): 33 (WebCore::AXObjectCache::deferTextChangedIfNeeded): 34 (WebCore::AXObjectCache::deferSelectedChildrenChangedIfNeeded): 35 (WebCore::AXObjectCache::handleAttributeChanged): Deleted. 36 * accessibility/AXObjectCache.h: 37 (WebCore::AXObjectCache::deferAttributeChangeIfNeeded): 38 (WebCore::AXObjectCache::handleAttributeChanged): Deleted. 39 * accessibility/AccessibilityNodeObject.cpp: 40 (WebCore::AccessibilityNodeObject::hasAttributesRequiredForInclusion const): 41 * accessibility/AccessibleNode.cpp: 42 (WebCore::AccessibleNode::notifyAttributeChanged): 43 * dom/Element.cpp: 44 (WebCore::Element::attributeChanged): 45 1 46 2018-02-26 Jason Marcell <jmarcell@apple.com> 2 47 -
branches/safari-605-branch/Source/WebCore/accessibility/AXObjectCache.cpp
r227884 r229553 121 121 static const Seconds accessibilityLiveRegionChangedNotificationInterval { 20_ms }; 122 122 static const Seconds accessibilityFocusModalNodeNotificationInterval { 50_ms }; 123 123 124 static bool rendererNeedsDeferredUpdate(const RenderObject& renderer) 125 { 126 ASSERT(!renderer.beingDestroyed()); 127 auto& document = renderer.document(); 128 return renderer.needsLayout() || document.needsStyleRecalc() || document.inRenderTreeUpdate() || (document.view() && document.view()->layoutContext().isInRenderTreeLayout()); 129 } 130 131 static bool nodeAndRendererAreValid(Node* node) 132 { 133 if (!node) 134 return false; 135 136 auto* renderer = node->renderer(); 137 return renderer && !renderer->beingDestroyed(); 138 } 139 124 140 AccessibilityObjectInclusion AXComputedObjectAttributeCache::getIgnored(AXID id) const 125 141 { … … 724 740 m_deferredSelectedChildredChangedList.remove(downcast<Element>(&node)); 725 741 m_deferredTextFormControlValue.remove(downcast<Element>(&node)); 742 m_deferredAttributeChange.remove(downcast<Element>(&node)); 726 743 } 727 744 m_deferredTextChangedList.remove(&node); … … 1403 1420 void AXObjectCache::handleAriaExpandedChange(Node* node) 1404 1421 { 1405 if (AccessibilityObject* obj = get OrCreate(node))1422 if (AccessibilityObject* obj = get(node)) 1406 1423 obj->handleAriaExpandedChanged(); 1407 1424 } … … 1417 1434 stopCachingComputedObjectAttributes(); 1418 1435 1419 if (AccessibilityObject* obj = getOrCreate(node)) { 1436 // Don't make an AX object unless it's needed 1437 if (AccessibilityObject* obj = get(node)) { 1420 1438 obj->updateAccessibilityRole(); 1421 1439 obj->notifyIfIgnoredValueChanged(); … … 1423 1441 } 1424 1442 1425 void AXObjectCache::handleAttributeChanged(const QualifiedName& attrName, Element* element) 1426 { 1443 void AXObjectCache::deferAttributeChangeIfNeeded(const QualifiedName& attrName, Element* element) 1444 { 1445 if (nodeAndRendererAreValid(element) && rendererNeedsDeferredUpdate(*element->renderer())) 1446 m_deferredAttributeChange.add(element, attrName); 1447 else 1448 handleAttributeChange(attrName, element); 1449 } 1450 1451 bool AXObjectCache::shouldProcessAttributeChange(const QualifiedName& attrName, Element* element) 1452 { 1453 if (!element) 1454 return false; 1455 1456 // aria-modal ends up affecting sub-trees that are being shown/hidden so it's likely that 1457 // an AT would not have accessed this node yet. 1458 if (attrName == aria_modalAttr) 1459 return true; 1460 1461 // If an AXObject has yet to be created, then there's no need to process attribute changes. 1462 // Some of these notifications are processed on the parent, so allow that to proceed as well 1463 if (get(element) || get(element->parentNode())) 1464 return true; 1465 1466 return false; 1467 } 1468 1469 void AXObjectCache::handleAttributeChange(const QualifiedName& attrName, Element* element) 1470 { 1471 if (!shouldProcessAttributeChange(attrName, element)) 1472 return; 1473 1427 1474 if (attrName == roleAttr) 1428 1475 handleAriaRoleChanged(element); 1429 1476 else if (attrName == altAttr || attrName == titleAttr) 1430 deferTextChangedIfNeeded(element);1477 textChanged(element); 1431 1478 else if (attrName == forAttr && is<HTMLLabelElement>(*element)) 1432 1479 labelChanged(element); … … 1442 1489 postNotification(element, AXObjectCache::AXValueChanged); 1443 1490 else if (attrName == aria_labelAttr || attrName == aria_labeledbyAttr || attrName == aria_labelledbyAttr) 1444 deferTextChangedIfNeeded(element);1491 textChanged(element); 1445 1492 else if (attrName == aria_checkedAttr) 1446 1493 checkedStateChanged(element); … … 2761 2808 filterListForRemoval(m_deferredSelectedChildredChangedList, document, nodesToRemove); 2762 2809 filterMapForRemoval(m_deferredTextFormControlValue, document, nodesToRemove); 2810 filterMapForRemoval(m_deferredAttributeChange, document, nodesToRemove); 2763 2811 2764 2812 for (auto* node : nodesToRemove) … … 2800 2848 } 2801 2849 m_deferredTextFormControlValue.clear(); 2802 } 2803 2804 static bool rendererNeedsDeferredUpdate(RenderObject& renderer) 2805 { 2806 ASSERT(!renderer.beingDestroyed()); 2807 auto& document = renderer.document(); 2808 return renderer.needsLayout() || document.needsStyleRecalc() || document.inRenderTreeUpdate() || (document.view() && document.view()->layoutContext().isInRenderTreeLayout()); 2809 } 2810 2850 2851 for (auto& deferredAttributeChangeContext : m_deferredAttributeChange) 2852 handleAttributeChange(deferredAttributeChangeContext.value, deferredAttributeChangeContext.key); 2853 m_deferredAttributeChange.clear(); 2854 } 2855 2811 2856 void AXObjectCache::deferRecomputeIsIgnoredIfNeeded(Element* element) 2812 2857 { 2813 if (!element) 2814 return; 2815 2816 auto* renderer = element->renderer(); 2817 if (!renderer || renderer->beingDestroyed()) 2818 return; 2819 2820 if (rendererNeedsDeferredUpdate(*renderer)) { 2858 if (!nodeAndRendererAreValid(element)) 2859 return; 2860 2861 if (rendererNeedsDeferredUpdate(*element->renderer())) { 2821 2862 m_deferredRecomputeIsIgnoredList.add(element); 2822 2863 return; 2823 2864 } 2824 recomputeIsIgnored( renderer);2865 recomputeIsIgnored(element->renderer()); 2825 2866 } 2826 2867 2827 2868 void AXObjectCache::deferRecomputeIsIgnored(Element* element) 2828 2869 { 2829 if (!element) 2830 return; 2831 2832 if (element->renderer() && element->renderer()->beingDestroyed()) 2870 if (!nodeAndRendererAreValid(element)) 2833 2871 return; 2834 2872 … … 2838 2876 void AXObjectCache::deferTextChangedIfNeeded(Node* node) 2839 2877 { 2840 if (!node) 2841 return; 2842 2843 auto* renderer = node->renderer(); 2844 if (renderer && renderer->beingDestroyed()) 2845 return; 2846 2847 if (renderer && rendererNeedsDeferredUpdate(*renderer)) { 2878 if (!nodeAndRendererAreValid(node)) 2879 return; 2880 2881 if (rendererNeedsDeferredUpdate(*node->renderer())) { 2848 2882 m_deferredTextChangedList.add(node); 2849 2883 return; … … 2854 2888 void AXObjectCache::deferSelectedChildrenChangedIfNeeded(Element& selectElement) 2855 2889 { 2856 auto* renderer = selectElement.renderer(); 2857 if (renderer && renderer->beingDestroyed()) 2858 return; 2859 2860 if (renderer && rendererNeedsDeferredUpdate(*renderer)) { 2890 if (!nodeAndRendererAreValid(&selectElement)) 2891 return; 2892 2893 if (rendererNeedsDeferredUpdate(*selectElement.renderer())) { 2861 2894 m_deferredSelectedChildredChangedList.add(&selectElement); 2862 2895 return; -
branches/safari-605-branch/Source/WebCore/accessibility/AXObjectCache.h
r225855 r229553 186 186 Node* modalNode(); 187 187 188 void handleAttributeChanged(const QualifiedName& attrName, Element*);188 void deferAttributeChangeIfNeeded(const QualifiedName&, Element*); 189 189 void recomputeIsIgnored(RenderObject* renderer); 190 190 … … 410 410 void handleLiveRegionCreated(Node*); 411 411 void handleMenuItemSelected(Node*); 412 void handleAttributeChange(const QualifiedName&, Element*); 413 bool shouldProcessAttributeChange(const QualifiedName&, Element*); 412 414 413 415 // aria-modal related … … 447 449 ListHashSet<Element*> m_deferredSelectedChildredChangedList; 448 450 HashMap<Element*, String> m_deferredTextFormControlValue; 451 HashMap<Element*, QualifiedName> m_deferredAttributeChange; 449 452 bool m_isSynchronizingSelection { false }; 450 453 bool m_performingDeferredCacheUpdate { false }; … … 508 511 inline void AXObjectCache::handleModalChange(Node*) { } 509 512 inline void AXObjectCache::handleAriaRoleChanged(Node*) { } 510 inline void AXObjectCache::handleAttributeChanged(const QualifiedName&, Element*) { } 513 inline void AXObjectCache::deferAttributeChangeIfNeeded(const QualifiedName&, Element*) { } 514 inline void AXObjectCache::handleAttributeChange(const QualifiedName&, Element*) { } 515 inline bool AXObjectCache::shouldProcessAttributeChange(const QualifiedName&, Element*) { return false; } 511 516 inline void AXObjectCache::handleFocusedUIElementChanged(Node*, Node*) { } 512 517 inline void AXObjectCache::handleScrollbarUpdate(ScrollView*) { } -
branches/safari-605-branch/Source/WebCore/accessibility/AccessibilityNodeObject.cpp
r225680 r229553 2018 2018 return true; 2019 2019 2020 if (!ariaAccessibilityDescription().isEmpty()) 2020 // Avoid calculating the actual description here, which is expensive. 2021 // This means there might be more accessible elements in the tree if the labelledBy points to invalid elements, but that shouldn't cause any real problems. 2022 if (getAttribute(aria_labelledbyAttr).length() || getAttribute(aria_labeledbyAttr).length() || getAttribute(aria_labelAttr).length()) 2021 2023 return true; 2022 2024 -
branches/safari-605-branch/Source/WebCore/accessibility/AccessibleNode.cpp
r225511 r229553 380 380 { 381 381 if (AXObjectCache* cache = m_ownerElement.document().axObjectCache()) 382 cache-> handleAttributeChanged(name, &m_ownerElement);382 cache->deferAttributeChangeIfNeeded(name, &m_ownerElement); 383 383 } 384 384 -
branches/safari-605-branch/Source/WebCore/dom/Element.cpp
r227306 r229553 1390 1390 1391 1391 if (AXObjectCache* cache = document().existingAXObjectCache()) 1392 cache-> handleAttributeChanged(name, this);1392 cache->deferAttributeChangeIfNeeded(name, this); 1393 1393 } 1394 1394
Note: See TracChangeset
for help on using the changeset viewer.