AX: Defer RenderListBox selectionChanged event until after layout is done.
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Sep 2017 16:31:56 +0000 (16:31 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Sep 2017 16:31:56 +0000 (16:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=177589
<rdar://problem/34705785>

Reviewed by Chris Fleizach.

Defer AX update when the selection changed event is followed by a layout.

Covered by existing tests.

* accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::remove):
(WebCore::AXObjectCache::performDeferredCacheUpdate):
(WebCore::AXObjectCache::deferSelectedChildrenChangedIfNeeded):
* accessibility/AXObjectCache.h:
(WebCore::AXObjectCache::deferSelectedChildrenChangedIfNeeded):
* rendering/RenderListBox.cpp:
(WebCore::RenderListBox::selectionChanged):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@222612 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/accessibility/AXObjectCache.cpp
Source/WebCore/accessibility/AXObjectCache.h
Source/WebCore/rendering/RenderListBox.cpp

index 1930278..14b0f30 100644 (file)
@@ -1,3 +1,24 @@
+2017-09-28  Zalan Bujtas  <zalan@apple.com>
+
+        AX: Defer RenderListBox selectionChanged event until after layout is done.
+        https://bugs.webkit.org/show_bug.cgi?id=177589
+        <rdar://problem/34705785>
+
+        Reviewed by Chris Fleizach.
+
+        Defer AX update when the selection changed event is followed by a layout.
+
+        Covered by existing tests.
+
+        * accessibility/AXObjectCache.cpp:
+        (WebCore::AXObjectCache::remove):
+        (WebCore::AXObjectCache::performDeferredCacheUpdate):
+        (WebCore::AXObjectCache::deferSelectedChildrenChangedIfNeeded):
+        * accessibility/AXObjectCache.h:
+        (WebCore::AXObjectCache::deferSelectedChildrenChangedIfNeeded):
+        * rendering/RenderListBox.cpp:
+        (WebCore::RenderListBox::selectionChanged):
+
 2017-09-28  Zan Dobersek  <zdobersek@igalia.com>
 
         [Cairo] Remove the cairo_glyph_t complexity from GlyphBuffer
index 5ed862e..2ed49f9 100644 (file)
@@ -719,8 +719,10 @@ void AXObjectCache::remove(Node* node)
     if (!node)
         return;
 
-    if (is<Element>(*node))
+    if (is<Element>(*node)) {
         m_deferredRecomputeIsIgnoredList.remove(downcast<Element>(node));
+        m_deferredSelectedChildredChangedList.remove(downcast<Element>(node));
+    }
     m_deferredTextChangedList.remove(node);
     removeNodeForUse(node);
 
@@ -2781,6 +2783,10 @@ void AXObjectCache::performDeferredCacheUpdate()
             recomputeIsIgnored(renderer);
     }
     m_deferredRecomputeIsIgnoredList.clear();
+    
+    for (auto* selectElement : m_deferredSelectedChildredChangedList)
+        selectedChildrenChanged(selectElement);
+    m_deferredSelectedChildredChangedList.clear();
 }
 
 static bool rendererNeedsDeferredUpdate(RenderObject& renderer)
@@ -2833,6 +2839,19 @@ void AXObjectCache::deferTextChangedIfNeeded(Node* node)
     textChanged(node);
 }
 
+void AXObjectCache::deferSelectedChildrenChangedIfNeeded(Element& selectElement)
+{
+    auto* renderer = selectElement.renderer();
+    if (renderer && renderer->beingDestroyed())
+        return;
+    
+    if (renderer && rendererNeedsDeferredUpdate(*renderer)) {
+        m_deferredSelectedChildredChangedList.add(&selectElement);
+        return;
+    }
+    selectedChildrenChanged(&selectElement);
+}
+
 bool isNodeAriaVisible(Node* node)
 {
     if (!node)
index 788fb74..8dc56bd 100644 (file)
@@ -332,6 +332,7 @@ public:
     void deferRecomputeIsIgnoredIfNeeded(Element*);
     void deferRecomputeIsIgnored(Element*);
     void deferTextChangedIfNeeded(Node*);
+    void deferSelectedChildrenChangedIfNeeded(Element&);
     void performDeferredCacheUpdate();
     
     RefPtr<Range> rangeMatchesTextNearRange(RefPtr<Range>, const String&);
@@ -439,6 +440,7 @@ private:
     AXTextStateChangeIntent m_textSelectionIntent;
     ListHashSet<Element*> m_deferredRecomputeIsIgnoredList;
     ListHashSet<Node*> m_deferredTextChangedList;
+    ListHashSet<Element*> m_deferredSelectedChildredChangedList;
     bool m_isSynchronizingSelection { false };
     bool m_performingDeferredCacheUpdate { false };
 };
@@ -490,6 +492,7 @@ inline void AXObjectCache::childrenChanged(RenderObject*, RenderObject*) { }
 inline void AXObjectCache::deferRecomputeIsIgnoredIfNeeded(Element*) { }
 inline void AXObjectCache::deferRecomputeIsIgnored(Element*) { }
 inline void AXObjectCache::deferTextChangedIfNeeded(Node*) { }
+inline void AXObjectCache::deferSelectedChildrenChangedIfNeeded(Element&) { }
 inline void AXObjectCache::detachWrapper(AccessibilityObject*, AccessibilityDetachmentType) { }
 inline void AXObjectCache::focusAriaModalNodeTimerFired() { }
 inline void AXObjectCache::frameLoadingEventNotification(Frame*, AXLoadingEvent) { }
index 35a8d64..66e0347 100644 (file)
@@ -162,7 +162,7 @@ void RenderListBox::selectionChanged()
     }
     
     if (AXObjectCache* cache = document().existingAXObjectCache())
-        cache->selectedChildrenChanged(this);
+        cache->deferSelectedChildrenChangedIfNeeded(selectElement());
 }
 
 void RenderListBox::layout()