Commit a2c23a3b authored by Aaron Leventhal's avatar Aaron Leventhal Committed by Commit Bot

Disallow lifecycle changes in AXObjectCache methods called by DOM/layout

Bug: None
Change-Id: Idb3c060bcaa162c0ba316a797fd59df19a185b5b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2134392
Commit-Queue: Aaron Leventhal <aleventhal@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#756482}
parent 2e3363ad
...@@ -58,6 +58,13 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { ...@@ -58,6 +58,13 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
// block, otherwise returns the node of this layout object. // block, otherwise returns the node of this layout object.
Node* GetNodeOrContainingBlockNode() const; Node* GetNodeOrContainingBlockNode() const;
// DOM and layout tree access.
Node* GetNode() const override;
Document* GetDocument() const override;
LocalFrameView* DocumentFrameView() const override;
Element* AnchorElement() const override;
AtomicString Language() const override;
protected: protected:
LayoutObject* layout_object_; LayoutObject* layout_object_;
...@@ -168,13 +175,6 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject { ...@@ -168,13 +175,6 @@ class MODULES_EXPORT AXLayoutObject : public AXNodeObject {
// Properties of the object's owning document or page. // Properties of the object's owning document or page.
double EstimatedLoadingProgress() const override; double EstimatedLoadingProgress() const override;
// DOM and layout tree access.
Node* GetNode() const override;
Document* GetDocument() const override;
LocalFrameView* DocumentFrameView() const override;
Element* AnchorElement() const override;
AtomicString Language() const override;
// Notifications that this object may have changed. // Notifications that this object may have changed.
void HandleActiveDescendantChanged() override; void HandleActiveDescendantChanged() override;
void HandleAriaExpandedChanged() override; void HandleAriaExpandedChanged() override;
......
...@@ -89,6 +89,21 @@ ...@@ -89,6 +89,21 @@
#include "third_party/blink/renderer/modules/permissions/permission_utils.h" #include "third_party/blink/renderer/modules/permissions/permission_utils.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
// Prevent code that runs during the lifetime of the stack from altering the
// document lifecycle. Usually doc is the same as document_, but it can be
// different when it is a popup document. Because it's harmless to test both
// documents, even if they are the same, the scoped check is initialized for
// both documents.
// clang-format off
#if DCHECK_IS_ON()
#define SCOPED_DISALLOW_LIFECYCLE_TRANSITION(doc) \
DocumentLifecycle::DisallowTransitionScope scoped1((doc).Lifecycle()); \
DocumentLifecycle::DisallowTransitionScope scoped2(document_->Lifecycle())
#else
#define SCOPED_DISALLOW_LIFECYCLE_TRANSITION(doc)
#endif
// clang-format on
namespace blink { namespace blink {
namespace { namespace {
...@@ -939,6 +954,8 @@ void AXObjectCacheImpl::FocusableChangedWithCleanLayout(Element* element) { ...@@ -939,6 +954,8 @@ void AXObjectCacheImpl::FocusableChangedWithCleanLayout(Element* element) {
} }
void AXObjectCacheImpl::DocumentTitleChanged() { void AXObjectCacheImpl::DocumentTitleChanged() {
DocumentLifecycle::DisallowTransitionScope disallow(document_->Lifecycle());
PostNotification(Root(), ax::mojom::Event::kDocumentTitleChanged); PostNotification(Root(), ax::mojom::Event::kDocumentTitleChanged);
} }
...@@ -1034,8 +1051,7 @@ void AXObjectCacheImpl::ProcessDeferredAccessibilityEvents(Document& document) { ...@@ -1034,8 +1051,7 @@ void AXObjectCacheImpl::ProcessDeferredAccessibilityEvents(Document& document) {
} }
void AXObjectCacheImpl::ProcessUpdates(Document& document) { void AXObjectCacheImpl::ProcessUpdates(Document& document) {
// None of the updates should alter the document lifecycle. SCOPED_DISALLOW_LIFECYCLE_TRANSITION(document);
DocumentLifecycle::DisallowTransitionScope disallow(document.Lifecycle());
TreeUpdateCallbackQueue old_tree_update_callback_queue; TreeUpdateCallbackQueue old_tree_update_callback_queue;
tree_update_callback_queue_.swap(old_tree_update_callback_queue); tree_update_callback_queue_.swap(old_tree_update_callback_queue);
...@@ -1165,6 +1181,8 @@ void AXObjectCacheImpl::FireAXEventImmediately( ...@@ -1165,6 +1181,8 @@ void AXObjectCacheImpl::FireAXEventImmediately(
if (layout_object && layout_object->View()) if (layout_object && layout_object->View())
DCHECK(!layout_object->View()->GetLayoutState()); DCHECK(!layout_object->View()->GetLayoutState());
} }
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(*obj->GetDocument());
#endif #endif
PostPlatformNotification(obj, event_type, event_from); PostPlatformNotification(obj, event_type, event_from);
...@@ -1233,6 +1251,8 @@ void AXObjectCacheImpl::ListboxSelectedChildrenChanged( ...@@ -1233,6 +1251,8 @@ void AXObjectCacheImpl::ListboxSelectedChildrenChanged(
} }
void AXObjectCacheImpl::ListboxActiveIndexChanged(HTMLSelectElement* select) { void AXObjectCacheImpl::ListboxActiveIndexChanged(HTMLSelectElement* select) {
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(select->GetDocument());
auto* ax_object = DynamicTo<AXListBox>(Get(select)); auto* ax_object = DynamicTo<AXListBox>(Get(select));
if (!ax_object) if (!ax_object)
return; return;
...@@ -1246,6 +1266,8 @@ void AXObjectCacheImpl::LocationChanged(LayoutObject* layout_object) { ...@@ -1246,6 +1266,8 @@ void AXObjectCacheImpl::LocationChanged(LayoutObject* layout_object) {
void AXObjectCacheImpl::RadiobuttonRemovedFromGroup( void AXObjectCacheImpl::RadiobuttonRemovedFromGroup(
HTMLInputElement* group_member) { HTMLInputElement* group_member) {
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(group_member->GetDocument());
auto* ax_object = DynamicTo<AXRadioInput>(Get(group_member)); auto* ax_object = DynamicTo<AXRadioInput>(Get(group_member));
if (!ax_object) if (!ax_object)
return; return;
...@@ -1272,6 +1294,8 @@ void AXObjectCacheImpl::HandleLayoutComplete(LayoutObject* layout_object) { ...@@ -1272,6 +1294,8 @@ void AXObjectCacheImpl::HandleLayoutComplete(LayoutObject* layout_object) {
if (!layout_object) if (!layout_object)
return; return;
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(layout_object->GetDocument());
modification_count_++; modification_count_++;
// Create the AXObject if it didn't yet exist - that's always safe at the // Create the AXObject if it didn't yet exist - that's always safe at the
...@@ -1300,14 +1324,18 @@ void AXObjectCacheImpl::HandleAriaExpandedChangeWithCleanLayout(Node* node) { ...@@ -1300,14 +1324,18 @@ void AXObjectCacheImpl::HandleAriaExpandedChangeWithCleanLayout(Node* node) {
if (!node) if (!node)
return; return;
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(node->GetDocument());
DCHECK(!node->GetDocument().NeedsLayoutTreeUpdateForNode(*node)); DCHECK(!node->GetDocument().NeedsLayoutTreeUpdateForNode(*node));
if (AXObject* obj = GetOrCreate(node)) if (AXObject* obj = GetOrCreate(node))
obj->HandleAriaExpandedChanged(); obj->HandleAriaExpandedChanged();
} }
void AXObjectCacheImpl::HandleAriaSelectedChangedWithCleanLayout(Node* node) { void AXObjectCacheImpl::HandleAriaSelectedChangedWithCleanLayout(Node* node) {
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(node->GetDocument());
DCHECK(node); DCHECK(node);
DCHECK(!node->GetDocument().NeedsLayoutTreeUpdateForNode(*node)); DCHECK(!document_->NeedsLayoutTreeUpdateForNode(*node));
AXObject* obj = Get(node); AXObject* obj = Get(node);
if (!obj) if (!obj)
return; return;
...@@ -1734,6 +1762,13 @@ void AXObjectCacheImpl::MarkElementDirty(const Element* element, bool subtree) { ...@@ -1734,6 +1762,13 @@ void AXObjectCacheImpl::MarkElementDirty(const Element* element, bool subtree) {
void AXObjectCacheImpl::HandleFocusedUIElementChanged( void AXObjectCacheImpl::HandleFocusedUIElementChanged(
Element* old_focused_element, Element* old_focused_element,
Element* new_focused_element) { Element* new_focused_element) {
#if DCHECK_IS_ON()
// The focus can be in a different document when a popup is open.
Document& focused_doc =
new_focused_element ? new_focused_element->GetDocument() : *document_;
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(focused_doc);
#endif
RemoveValidationMessageObject(); RemoveValidationMessageObject();
if (!new_focused_element) { if (!new_focused_element) {
...@@ -1764,6 +1799,8 @@ void AXObjectCacheImpl::HandleEditableTextContentChanged(Node* node) { ...@@ -1764,6 +1799,8 @@ void AXObjectCacheImpl::HandleEditableTextContentChanged(Node* node) {
if (!node) if (!node)
return; return;
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(node->GetDocument());
AXObject* obj = nullptr; AXObject* obj = nullptr;
// We shouldn't create a new AX object here because we might be in the middle // We shouldn't create a new AX object here because we might be in the middle
// of a layout. // of a layout.
...@@ -1809,37 +1846,46 @@ void AXObjectCacheImpl::HandleUpdateActiveMenuOption(LayoutObject* menu_list, ...@@ -1809,37 +1846,46 @@ void AXObjectCacheImpl::HandleUpdateActiveMenuOption(LayoutObject* menu_list,
if (!ax_object) if (!ax_object)
return; return;
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(*ax_object->GetDocument());
ax_object->DidUpdateActiveOption(option_index); ax_object->DidUpdateActiveOption(option_index);
} }
void AXObjectCacheImpl::DidShowMenuListPopup(LayoutObject* menu_list) { void AXObjectCacheImpl::DidShowMenuListPopup(LayoutObject* menu_list) {
auto* ax_object = DynamicTo<AXMenuList>(Get(menu_list)); SCOPED_DISALLOW_LIFECYCLE_TRANSITION(menu_list->GetDocument());
if (!ax_object)
return;
auto* ax_object = DynamicTo<AXMenuList>(Get(menu_list));
if (ax_object)
ax_object->DidShowPopup(); ax_object->DidShowPopup();
} }
void AXObjectCacheImpl::DidHideMenuListPopup(LayoutObject* menu_list) { void AXObjectCacheImpl::DidHideMenuListPopup(LayoutObject* menu_list) {
auto* ax_object = DynamicTo<AXMenuList>(Get(menu_list)); SCOPED_DISALLOW_LIFECYCLE_TRANSITION(menu_list->GetDocument());
if (!ax_object)
return;
auto* ax_object = DynamicTo<AXMenuList>(Get(menu_list));
if (ax_object)
ax_object->DidHidePopup(); ax_object->DidHidePopup();
} }
void AXObjectCacheImpl::HandleLoadComplete(Document* document) { void AXObjectCacheImpl::HandleLoadComplete(Document* document) {
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(*document);
PostNotification(GetOrCreate(document), ax::mojom::Event::kLoadComplete); PostNotification(GetOrCreate(document), ax::mojom::Event::kLoadComplete);
AddPermissionStatusListener(); AddPermissionStatusListener();
} }
void AXObjectCacheImpl::HandleLayoutComplete(Document* document) { void AXObjectCacheImpl::HandleLayoutComplete(Document* document) {
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(*document);
PostNotification(GetOrCreate(document), ax::mojom::Event::kLayoutComplete); PostNotification(GetOrCreate(document), ax::mojom::Event::kLayoutComplete);
} }
void AXObjectCacheImpl::HandleScrolledToAnchor(const Node* anchor_node) { void AXObjectCacheImpl::HandleScrolledToAnchor(const Node* anchor_node) {
if (!anchor_node) if (!anchor_node)
return; return;
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(anchor_node->GetDocument());
AXObject* obj = GetOrCreate(anchor_node->GetLayoutObject()); AXObject* obj = GetOrCreate(anchor_node->GetLayoutObject());
if (!obj) if (!obj)
return; return;
...@@ -1854,18 +1900,22 @@ void AXObjectCacheImpl::HandleFrameRectsChanged(Document& document) { ...@@ -1854,18 +1900,22 @@ void AXObjectCacheImpl::HandleFrameRectsChanged(Document& document) {
void AXObjectCacheImpl::HandleScrollPositionChanged( void AXObjectCacheImpl::HandleScrollPositionChanged(
LocalFrameView* frame_view) { LocalFrameView* frame_view) {
AXObject* target_ax_object = SCOPED_DISALLOW_LIFECYCLE_TRANSITION(*frame_view->GetFrame().GetDocument());
GetOrCreate(frame_view->GetFrame().GetDocument());
AXObject* target_ax_object = GetOrCreate(document_);
PostNotification(target_ax_object, ax::mojom::Event::kScrollPositionChanged); PostNotification(target_ax_object, ax::mojom::Event::kScrollPositionChanged);
} }
void AXObjectCacheImpl::HandleScrollPositionChanged( void AXObjectCacheImpl::HandleScrollPositionChanged(
LayoutObject* layout_object) { LayoutObject* layout_object) {
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(layout_object->GetDocument());
PostNotification(GetOrCreate(layout_object), PostNotification(GetOrCreate(layout_object),
ax::mojom::Event::kScrollPositionChanged); ax::mojom::Event::kScrollPositionChanged);
} }
const AtomicString& AXObjectCacheImpl::ComputedRoleForNode(Node* node) { const AtomicString& AXObjectCacheImpl::ComputedRoleForNode(Node* node) {
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(node->GetDocument());
AXObject* obj = GetOrCreate(node); AXObject* obj = GetOrCreate(node);
if (!obj) if (!obj)
return AXObject::RoleName(ax::mojom::Role::kUnknown); return AXObject::RoleName(ax::mojom::Role::kUnknown);
...@@ -1873,6 +1923,8 @@ const AtomicString& AXObjectCacheImpl::ComputedRoleForNode(Node* node) { ...@@ -1873,6 +1923,8 @@ const AtomicString& AXObjectCacheImpl::ComputedRoleForNode(Node* node) {
} }
String AXObjectCacheImpl::ComputedNameForNode(Node* node) { String AXObjectCacheImpl::ComputedNameForNode(Node* node) {
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(node->GetDocument());
AXObject* obj = GetOrCreate(node); AXObject* obj = GetOrCreate(node);
if (!obj) if (!obj)
return ""; return "";
...@@ -1881,6 +1933,11 @@ String AXObjectCacheImpl::ComputedNameForNode(Node* node) { ...@@ -1881,6 +1933,11 @@ String AXObjectCacheImpl::ComputedNameForNode(Node* node) {
} }
void AXObjectCacheImpl::OnTouchAccessibilityHover(const IntPoint& location) { void AXObjectCacheImpl::OnTouchAccessibilityHover(const IntPoint& location) {
// TODO(aleventhal) This triggers a DCHECK when running
// content_browsertests --gtest_filter=TouchAccessibility*.TouchExploration*
// DocumentLifecycle::DisallowTransitionScope
// disallow(document_->Lifecycle());
AXObject* hit = Root()->AccessibilityHitTest(location); AXObject* hit = Root()->AccessibilityHitTest(location);
if (hit) { if (hit) {
// Ignore events on a frame or plug-in, because the touch events // Ignore events on a frame or plug-in, because the touch events
...@@ -1897,6 +1954,8 @@ void AXObjectCacheImpl::OnTouchAccessibilityHover(const IntPoint& location) { ...@@ -1897,6 +1954,8 @@ void AXObjectCacheImpl::OnTouchAccessibilityHover(const IntPoint& location) {
void AXObjectCacheImpl::SetCanvasObjectBounds(HTMLCanvasElement* canvas, void AXObjectCacheImpl::SetCanvasObjectBounds(HTMLCanvasElement* canvas,
Element* element, Element* element,
const LayoutRect& rect) { const LayoutRect& rect) {
SCOPED_DISALLOW_LIFECYCLE_TRANSITION(element->GetDocument());
AXObject* obj = GetOrCreate(element); AXObject* obj = GetOrCreate(element);
if (!obj) if (!obj)
return; return;
......
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