Commit 94eba324 authored by Alice Boxhall's avatar Alice Boxhall Committed by Commit Bot

Process attribute changes in AXObjectCache after layout is clean.

Processing attribute changes can cause AXObjects to get created,
which can cause crashes if layout is not clean.

Also, check that nodes do not need distribution updates before
processing attribute changes.

Bug: 835455
Change-Id: Ibf7a3d0e2d7befe53e43096e6d0414a5623e8885
Reviewed-on: https://chromium-review.googlesource.com/c/1324530
Commit-Queue: Alice Boxhall <aboxhall@chromium.org>
Reviewed-by: default avatarNektarios Paisios <nektar@chromium.org>
Reviewed-by: default avatarKeishi Hattori <keishi@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607134}
parent afd3d04f
...@@ -223,6 +223,8 @@ CORE_EXPORT std::ostream& operator<<(std::ostream&, const QualifiedName&); ...@@ -223,6 +223,8 @@ CORE_EXPORT std::ostream& operator<<(std::ostream&, const QualifiedName&);
} // namespace blink } // namespace blink
WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(blink::QualifiedName);
namespace WTF { namespace WTF {
template <> template <>
......
...@@ -751,7 +751,8 @@ void AXObjectCacheImpl::ChildrenChanged(LayoutObject* layout_object) { ...@@ -751,7 +751,8 @@ void AXObjectCacheImpl::ChildrenChanged(LayoutObject* layout_object) {
Node* node = GetClosestNodeForLayoutObject(layout_object); Node* node = GetClosestNodeForLayoutObject(layout_object);
if (node && node->GetDocument().NeedsLayoutTreeUpdateForNode(*node)) { if (node && (node->GetDocument().NeedsLayoutTreeUpdateForNode(*node) ||
node->NeedsDistributionRecalc())) {
nodes_changed_during_layout_.push_back(node); nodes_changed_during_layout_.push_back(node);
return; return;
} }
...@@ -765,7 +766,8 @@ void AXObjectCacheImpl::ChildrenChanged(AccessibleNode* accessible_node) { ...@@ -765,7 +766,8 @@ void AXObjectCacheImpl::ChildrenChanged(AccessibleNode* accessible_node) {
return; return;
Element* element = accessible_node->element(); Element* element = accessible_node->element();
if (element && if (element &&
element->GetDocument().NeedsLayoutTreeUpdateForNode(*element)) { (element->GetDocument().NeedsLayoutTreeUpdateForNode(*element) ||
element->NeedsDistributionRecalc())) {
nodes_changed_during_layout_.push_back(element); nodes_changed_during_layout_.push_back(element);
return; return;
} }
...@@ -786,16 +788,28 @@ void AXObjectCacheImpl::ChildrenChanged(AXObject* obj, Node* optional_node) { ...@@ -786,16 +788,28 @@ void AXObjectCacheImpl::ChildrenChanged(AXObject* obj, Node* optional_node) {
void AXObjectCacheImpl::ProcessUpdatesAfterLayout(Document& document) { void AXObjectCacheImpl::ProcessUpdatesAfterLayout(Document& document) {
if (document.Lifecycle().GetState() < DocumentLifecycle::kLayoutClean) if (document.Lifecycle().GetState() < DocumentLifecycle::kLayoutClean)
return; return;
VectorOf<Node> old_nodes_changed_during_layout;
HeapVector<Member<Node>> remaining_nodes; nodes_changed_during_layout_.swap(old_nodes_changed_during_layout);
for (auto node : nodes_changed_during_layout_) { for (auto node : old_nodes_changed_during_layout) {
if (node->GetDocument() != document) { if (node->GetDocument() != document) {
remaining_nodes.push_back(node); nodes_changed_during_layout_.push_back(node);
continue; continue;
} }
ChildrenChanged(Get(node), node); ChildrenChanged(Get(node), node);
} }
nodes_changed_during_layout_.swap(remaining_nodes);
AttributesChangedVector old_attributes_changed_during_layout;
attributes_changed_during_layout_.swap(old_attributes_changed_during_layout);
for (auto pair : old_attributes_changed_during_layout) {
auto attribute_name = pair.first;
auto element = pair.second;
if (element->GetDocument() != document) {
attributes_changed_during_layout_.push_back(
std::make_pair(attribute_name, element));
continue;
}
HandleAttributeChanged(attribute_name, element);
}
} }
void AXObjectCacheImpl::NotificationPostTimerFired(TimerBase*) { void AXObjectCacheImpl::NotificationPostTimerFired(TimerBase*) {
...@@ -932,7 +946,7 @@ void AXObjectCacheImpl::HandleLayoutComplete(LayoutObject* layout_object) { ...@@ -932,7 +946,7 @@ void AXObjectCacheImpl::HandleLayoutComplete(LayoutObject* layout_object) {
} }
void AXObjectCacheImpl::HandleClicked(Node* node) { void AXObjectCacheImpl::HandleClicked(Node* node) {
if (AXObject* obj = GetOrCreate(node)) if (AXObject* obj = Get(node))
PostNotification(obj, ax::mojom::Event::kClicked); PostNotification(obj, ax::mojom::Event::kClicked);
} }
...@@ -1027,6 +1041,16 @@ void AXObjectCacheImpl::HandlePossibleRoleChange(Node* node) { ...@@ -1027,6 +1041,16 @@ void AXObjectCacheImpl::HandlePossibleRoleChange(Node* node) {
void AXObjectCacheImpl::HandleAttributeChanged(const QualifiedName& attr_name, void AXObjectCacheImpl::HandleAttributeChanged(const QualifiedName& attr_name,
Element* element) { Element* element) {
if (!element)
return;
if (element->GetDocument().NeedsLayoutTreeUpdateForNode(*element) ||
element->NeedsDistributionRecalc()) {
attributes_changed_during_layout_.push_back(
std::make_pair(attr_name, element));
return;
}
if (attr_name == kRoleAttr || attr_name == kTypeAttr || if (attr_name == kRoleAttr || attr_name == kTypeAttr ||
attr_name == kSizeAttr || attr_name == kAriaHaspopupAttr) attr_name == kSizeAttr || attr_name == kAriaHaspopupAttr)
HandlePossibleRoleChange(element); HandlePossibleRoleChange(element);
...@@ -1421,6 +1445,7 @@ void AXObjectCacheImpl::Trace(blink::Visitor* visitor) { ...@@ -1421,6 +1445,7 @@ void AXObjectCacheImpl::Trace(blink::Visitor* visitor) {
visitor->Trace(objects_); visitor->Trace(objects_);
visitor->Trace(notifications_to_post_); visitor->Trace(notifications_to_post_);
visitor->Trace(nodes_changed_during_layout_); visitor->Trace(nodes_changed_during_layout_);
visitor->Trace(attributes_changed_during_layout_);
AXObjectCache::Trace(visitor); AXObjectCache::Trace(visitor);
} }
......
...@@ -296,7 +296,9 @@ class MODULES_EXPORT AXObjectCacheImpl ...@@ -296,7 +296,9 @@ class MODULES_EXPORT AXObjectCacheImpl
mojom::blink::PermissionServicePtr permission_service_; mojom::blink::PermissionServicePtr permission_service_;
mojo::Binding<mojom::blink::PermissionObserver> permission_observer_binding_; mojo::Binding<mojom::blink::PermissionObserver> permission_observer_binding_;
HeapVector<Member<Node>> nodes_changed_during_layout_; VectorOf<Node> nodes_changed_during_layout_;
typedef VectorOfPairs<QualifiedName, Element> AttributesChangedVector;
AttributesChangedVector attributes_changed_during_layout_;
DISALLOW_COPY_AND_ASSIGN(AXObjectCacheImpl); DISALLOW_COPY_AND_ASSIGN(AXObjectCacheImpl);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment