Commit cae06dfe authored by Aaron Leventhal's avatar Aaron Leventhal Committed by Chromium LUCI CQ

Reland: wait until safe time to create root accessibility object

It is only safe to create an accessibility object when a document's
style has been computed and layout is clean.

Previously, tests failed because an extra kLoadComplete event
was sometimes fired for the initial empty document, before navigating
to the actual data: url with the test's contents. The extra event
only seems to occur in ChromeOS debug builds.

Bug: 1156939
Change-Id: I95f4afdb5471a98ed87fb1cf8e8a208e5ebfc453
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2611559Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarAaron Leventhal <aleventhal@chromium.org>
Commit-Queue: Aaron Leventhal <aleventhal@chromium.org>
Auto-Submit: Aaron Leventhal <aleventhal@chromium.org>
Cr-Commit-Position: refs/heads/master@{#842329}
parent f1a9be90
...@@ -265,14 +265,9 @@ void RenderAccessibilityImpl::AccessibilityModeChanged(const ui::AXMode& mode) { ...@@ -265,14 +265,9 @@ void RenderAccessibilityImpl::AccessibilityModeChanged(const ui::AXMode& mode) {
if (!document.IsNull()) { if (!document.IsNull()) {
StartOrStopLabelingImages(old_mode, mode); StartOrStopLabelingImages(old_mode, mode);
// If there are any events in flight, |HandleAXEvent| will refuse to process needs_initial_ax_tree_root_ = true;
// our new event. event_schedule_mode_ = EventScheduleMode::kProcessEventsImmediately;
pending_events_.clear(); ScheduleSendPendingAccessibilityEvents();
auto root_object = WebAXObject::FromWebDocument(document, false);
ax::mojom::Event event = root_object.IsLoaded()
? ax::mojom::Event::kLoadComplete
: ax::mojom::Event::kLayoutComplete;
HandleAXEvent(ui::AXEvent(root_object.AxID(), event));
} }
} }
...@@ -476,11 +471,11 @@ void RenderAccessibilityImpl::Reset(int32_t reset_token) { ...@@ -476,11 +471,11 @@ void RenderAccessibilityImpl::Reset(int32_t reset_token) {
if (!document.IsNull()) { if (!document.IsNull()) {
// Tree-only mode gets used by the automation extension API which requires a // Tree-only mode gets used by the automation extension API which requires a
// load complete event to invoke listener callbacks. // load complete event to invoke listener callbacks.
auto root_object = WebAXObject::FromWebDocument(document, false); // SendPendingAccessibilityEvents() will fire the load complete event
ax::mojom::Event event = root_object.IsLoaded() // if the page is loaded.
? ax::mojom::Event::kLoadComplete needs_initial_ax_tree_root_ = true;
: ax::mojom::Event::kLayoutComplete; event_schedule_mode_ = EventScheduleMode::kProcessEventsImmediately;
HandleAXEvent(ui::AXEvent(root_object.AxID(), event)); ScheduleSendPendingAccessibilityEvents();
} }
} }
...@@ -797,10 +792,20 @@ void RenderAccessibilityImpl::SendPendingAccessibilityEvents() { ...@@ -797,10 +792,20 @@ void RenderAccessibilityImpl::SendPendingAccessibilityEvents() {
// complete for the entire document, in order to initialize the browser's // complete for the entire document, in order to initialize the browser's
// cached accessibility tree. // cached accessibility tree.
needs_initial_ax_tree_root_ = false; needs_initial_ax_tree_root_ = false;
auto obj = WebAXObject::FromWebDocument(document); auto root_obj = WebAXObject::FromWebDocument(document);
// Always fire layout complete for a new root object.
pending_events_.insert( pending_events_.insert(
pending_events_.begin(), pending_events_.begin(),
ui::AXEvent(obj.AxID(), ax::mojom::Event::kLayoutComplete)); ui::AXEvent(root_obj.AxID(), ax::mojom::Event::kLayoutComplete));
// If loaded and has some content, insert load complete at the top, so that
// screen readers are informed a new document is ready.
if (root_obj.IsLoaded() && !document.Body().IsNull() &&
!document.Body().FirstChild().IsNull()) {
pending_events_.insert(
pending_events_.begin(),
ui::AXEvent(root_obj.AxID(), ax::mojom::Event::kLoadComplete));
}
} }
if (pending_events_.empty() && dirty_objects_.empty()) { if (pending_events_.empty() && dirty_objects_.empty()) {
...@@ -834,8 +839,8 @@ void RenderAccessibilityImpl::SendPendingAccessibilityEvents() { ...@@ -834,8 +839,8 @@ void RenderAccessibilityImpl::SendPendingAccessibilityEvents() {
// location changes. // location changes.
bool need_to_send_location_changes = false; bool need_to_send_location_changes = false;
// If there's a load complete message, we need to change the event schedule // Keep track of load complete messages. When a load completes, it's a good
// mode. // time to inject a stylesheet for image annotation debugging.
bool had_load_complete_messages = false; bool had_load_complete_messages = false;
ScopedFreezeBlinkAXTreeSource freeze(tree_source_.get()); ScopedFreezeBlinkAXTreeSource freeze(tree_source_.get());
......
...@@ -81,9 +81,7 @@ class WebAXObject { ...@@ -81,9 +81,7 @@ class WebAXObject {
BLINK_EXPORT bool operator>(const WebAXObject& other) const; BLINK_EXPORT bool operator>(const WebAXObject& other) const;
BLINK_EXPORT bool operator>=(const WebAXObject& other) const; BLINK_EXPORT bool operator>=(const WebAXObject& other) const;
BLINK_EXPORT static WebAXObject FromWebNode(const WebNode&); BLINK_EXPORT static WebAXObject FromWebNode(const WebNode&);
BLINK_EXPORT static WebAXObject FromWebDocument( BLINK_EXPORT static WebAXObject FromWebDocument(const WebDocument&);
const WebDocument&,
bool update_layout_if_necessary = true);
BLINK_EXPORT static WebAXObject FromWebDocumentByID(const WebDocument&, int); BLINK_EXPORT static WebAXObject FromWebDocumentByID(const WebDocument&, int);
BLINK_EXPORT static WebAXObject FromWebDocumentFocused( BLINK_EXPORT static WebAXObject FromWebDocumentFocused(
const WebDocument&, const WebDocument&,
......
...@@ -1443,12 +1443,9 @@ WebAXObject WebAXObject::FromWebNode(const WebNode& web_node) { ...@@ -1443,12 +1443,9 @@ WebAXObject WebAXObject::FromWebNode(const WebNode& web_node) {
} }
// static // static
WebAXObject WebAXObject::FromWebDocument(const WebDocument& web_document, WebAXObject WebAXObject::FromWebDocument(const WebDocument& web_document) {
bool update_layout_if_necessary) { if (!MaybeUpdateLayoutAndCheckValidity(web_document))
if (update_layout_if_necessary &&
!MaybeUpdateLayoutAndCheckValidity(web_document)) {
return WebAXObject(); return WebAXObject();
}
const Document* document = web_document.ConstUnwrap<Document>(); const Document* document = web_document.ConstUnwrap<Document>();
auto* cache = To<AXObjectCacheImpl>(document->ExistingAXObjectCache()); auto* cache = To<AXObjectCacheImpl>(document->ExistingAXObjectCache());
return cache ? WebAXObject(cache->GetOrCreate(document->GetLayoutView())) return cache ? WebAXObject(cache->GetOrCreate(document->GetLayoutView()))
......
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