Commit 8ea90796 authored by Dominic Mazzoni's avatar Dominic Mazzoni Committed by Commit Bot

Add class for snapshotting the accessibility tree.

For exporting tagged PDFs, we need the ability to
take a snapshot of the accessibility tree for a
RenderFrame, and to have the accessibility context
stay alive long enough that IDs in the snapshot,
and IDs sent to the printing system, are consistent.

We already had code to do AX tree snapshotting,
so this patch is just some refactoring to make it
a class instead, and to have it return a public
type rather than a content-specific type.

This will be used in the follow-up change that
implements support for tagged PDFs:
http://crrev.com/c/1970742

Bug: 607777
Change-Id: I5163561c2cabcb2dd3579ce9d7a2de8ac96106d4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1970579
Commit-Queue: Dominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarJohn Abd-El-Malek <jam@chromium.org>
Reviewed-by: default avatarAaron Leventhal <aleventhal@chromium.org>
Cr-Commit-Position: refs/heads/master@{#727483}
parent 10ebfb7d
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/web/web_navigation_policy.h" #include "third_party/blink/public/web/web_navigation_policy.h"
#include "ui/accessibility/ax_mode.h" #include "ui/accessibility/ax_mode.h"
#include "ui/accessibility/ax_tree_update.h"
namespace blink { namespace blink {
class AssociatedInterfaceProvider; class AssociatedInterfaceProvider;
...@@ -67,6 +68,21 @@ struct ContextMenuParams; ...@@ -67,6 +68,21 @@ struct ContextMenuParams;
struct WebPluginInfo; struct WebPluginInfo;
struct WebPreferences; struct WebPreferences;
// A class that takes a snapshot of the accessibility tree. Accessibility
// support in Blink is enabled for the lifetime of this object, which can
// be useful if you need consistent IDs between multiple snapshots.
class AXTreeSnapshotter {
public:
AXTreeSnapshotter() = default;
// Return in |accessibility_tree| a snapshot of the accessibility tree
// for the frame with the given accessibility mode. If |max_node_count|
// is nonzero, return no more than that many nodes.
virtual void Snapshot(ui::AXMode ax_mode,
size_t max_node_count,
ui::AXTreeUpdate* accessibility_tree) = 0;
virtual ~AXTreeSnapshotter() = default;
};
// This interface wraps functionality, which is specific to frames, such as // This interface wraps functionality, which is specific to frames, such as
// navigation. It provides communication with a corresponding RenderFrameHost // navigation. It provides communication with a corresponding RenderFrameHost
// in the browser process. // in the browser process.
...@@ -116,6 +132,9 @@ class CONTENT_EXPORT RenderFrame : public IPC::Listener, ...@@ -116,6 +132,9 @@ class CONTENT_EXPORT RenderFrame : public IPC::Listener,
// Return the RenderAccessibility associated with this frame. // Return the RenderAccessibility associated with this frame.
virtual RenderAccessibility* GetRenderAccessibility() = 0; virtual RenderAccessibility* GetRenderAccessibility() = 0;
// Return an object that can take a snapshot of the accessibility tree.
virtual std::unique_ptr<AXTreeSnapshotter> CreateAXTreeSnapshotter() = 0;
// Get the routing ID of the frame. // Get the routing ID of the frame.
virtual int GetRoutingID() = 0; virtual int GetRoutingID() = 0;
......
...@@ -91,38 +91,66 @@ namespace content { ...@@ -91,38 +91,66 @@ namespace content {
// usage. // usage.
const size_t kMaxSnapshotNodeCount = 5000; const size_t kMaxSnapshotNodeCount = 5000;
// static AXTreeSnapshotterImpl::AXTreeSnapshotterImpl(RenderFrameImpl* render_frame)
void RenderAccessibilityImpl::SnapshotAccessibilityTree( : render_frame_(render_frame) {
RenderFrameImpl* render_frame, DCHECK(render_frame->GetWebFrame());
AXContentTreeUpdate* response, blink::WebDocument document_ = render_frame->GetWebFrame()->GetDocument();
ui::AXMode ax_mode) { context_ = std::make_unique<WebAXContext>(document_);
TRACE_EVENT0("accessibility", }
"RenderAccessibilityImpl::SnapshotAccessibilityTree");
DCHECK(render_frame); AXTreeSnapshotterImpl::~AXTreeSnapshotterImpl() = default;
DCHECK(response);
if (!render_frame->GetWebFrame()) void AXTreeSnapshotterImpl::Snapshot(ui::AXMode ax_mode,
return; size_t max_node_count,
ui::AXTreeUpdate* response) {
// Get a snapshot of the accessibility tree as an AXContentNodeData.
AXContentTreeUpdate content_tree;
SnapshotContentTree(ax_mode, max_node_count, &content_tree);
// As a sanity check, node_id_to_clear and event_from should be uninitialized
// if this is a full tree snapshot. They'd only be set to something if
// this was indeed a partial update to the tree (which we don't want).
DCHECK_EQ(0, content_tree.node_id_to_clear);
DCHECK_EQ(ax::mojom::EventFrom::kNone, content_tree.event_from);
// We now have a complete serialization of the accessibility tree, but it
// includes a few fields we don't want to export outside of content/,
// so copy it into a more generic ui::AXTreeUpdate instead.
response->root_id = content_tree.root_id;
response->nodes.resize(content_tree.nodes.size());
response->node_id_to_clear = content_tree.node_id_to_clear;
response->event_from = content_tree.event_from;
// AXNodeData is a superclass of AXContentNodeData, so we can convert
// just by assigning.
response->nodes.assign(content_tree.nodes.begin(), content_tree.nodes.end());
}
WebDocument document = render_frame->GetWebFrame()->GetDocument(); void AXTreeSnapshotterImpl::SnapshotContentTree(ui::AXMode ax_mode,
WebAXContext context(document); size_t max_node_count,
WebAXObject root = context.Root(); AXContentTreeUpdate* response) {
WebAXObject root = context_->Root();
if (!root.UpdateLayoutAndCheckValidity()) if (!root.UpdateLayoutAndCheckValidity())
return; return;
BlinkAXTreeSource tree_source(render_frame, ax_mode);
BlinkAXTreeSource tree_source(render_frame_, ax_mode);
tree_source.SetRoot(root); tree_source.SetRoot(root);
ScopedFreezeBlinkAXTreeSource freeze(&tree_source); ScopedFreezeBlinkAXTreeSource freeze(&tree_source);
BlinkAXTreeSerializer serializer(&tree_source);
serializer.set_max_node_count(kMaxSnapshotNodeCount);
if (serializer.SerializeChanges(context.Root(), response)) // The serializer returns an AXContentTreeUpdate, which can store a complete
// or a partial accessibility tree. AXTreeSerializer is stateful, but the
// first time you serialize from a brand-new tree you're guaranteed to get a
// complete tree.
BlinkAXTreeSerializer serializer(&tree_source);
if (max_node_count)
serializer.set_max_node_count(max_node_count);
if (serializer.SerializeChanges(root, response))
return; return;
// It's possible for the page to fail to serialize the first time due to // It's possible for the page to fail to serialize the first time due to
// aria-owns rearranging the page while it's being scanned. Try a second // aria-owns rearranging the page while it's being scanned. Try a second
// time. // time.
*response = AXContentTreeUpdate(); *response = AXContentTreeUpdate();
if (serializer.SerializeChanges(context.Root(), response)) if (serializer.SerializeChanges(root, response))
return; return;
// It failed again. Clear the response object because it might have errors. // It failed again. Clear the response object because it might have errors.
...@@ -130,6 +158,22 @@ void RenderAccessibilityImpl::SnapshotAccessibilityTree( ...@@ -130,6 +158,22 @@ void RenderAccessibilityImpl::SnapshotAccessibilityTree(
LOG(WARNING) << "Unable to serialize accessibility tree."; LOG(WARNING) << "Unable to serialize accessibility tree.";
} }
// static
void RenderAccessibilityImpl::SnapshotAccessibilityTree(
RenderFrameImpl* render_frame,
AXContentTreeUpdate* response,
ui::AXMode ax_mode) {
TRACE_EVENT0("accessibility",
"RenderAccessibilityImpl::SnapshotAccessibilityTree");
DCHECK(render_frame);
DCHECK(response);
if (!render_frame->GetWebFrame())
return;
AXTreeSnapshotterImpl snapshotter(render_frame);
snapshotter.SnapshotContentTree(ax_mode, kMaxSnapshotNodeCount, response);
}
RenderAccessibilityImpl::RenderAccessibilityImpl(RenderFrameImpl* render_frame, RenderAccessibilityImpl::RenderAccessibilityImpl(RenderFrameImpl* render_frame,
ui::AXMode mode) ui::AXMode mode)
: RenderFrameObserver(render_frame), : RenderFrameObserver(render_frame),
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "content/public/renderer/plugin_ax_tree_source.h" #include "content/public/renderer/plugin_ax_tree_source.h"
#include "content/public/renderer/render_accessibility.h" #include "content/public/renderer/render_accessibility.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_frame_observer.h"
#include "content/renderer/accessibility/blink_ax_tree_source.h" #include "content/renderer/accessibility/blink_ax_tree_source.h"
#include "third_party/blink/public/mojom/renderer_preference_watcher.mojom.h" #include "third_party/blink/public/mojom/renderer_preference_watcher.mojom.h"
...@@ -39,6 +40,33 @@ namespace content { ...@@ -39,6 +40,33 @@ namespace content {
class AXImageAnnotator; class AXImageAnnotator;
class RenderFrameImpl; class RenderFrameImpl;
using BlinkAXTreeSerializer = ui::
AXTreeSerializer<blink::WebAXObject, AXContentNodeData, AXContentTreeData>;
class AXTreeSnapshotterImpl : public AXTreeSnapshotter {
public:
explicit AXTreeSnapshotterImpl(RenderFrameImpl* render_frame);
~AXTreeSnapshotterImpl() override;
// AXTreeSnapshotter implementation.
void Snapshot(ui::AXMode ax_mode,
size_t max_node_count,
ui::AXTreeUpdate* accessibility_tree) override;
// Same as above, but returns in |accessibility_tree| a AXContentTreeUpdate
// with content-specific metadata, instead of an AXTreeUpdate.
void SnapshotContentTree(ui::AXMode ax_mode,
size_t max_node_count,
AXContentTreeUpdate* accessibility_tree);
private:
RenderFrameImpl* render_frame_;
std::unique_ptr<blink::WebAXContext> context_;
AXTreeSnapshotterImpl(const AXTreeSnapshotterImpl&) = delete;
AXTreeSnapshotterImpl& operator=(const AXTreeSnapshotterImpl&) = delete;
};
// The browser process implements native accessibility APIs, allowing // The browser process implements native accessibility APIs, allowing
// assistive technology (e.g., screen readers, magnifiers) to access and // assistive technology (e.g., screen readers, magnifiers) to access and
// control the web contents with high-level APIs. These APIs are also used // control the web contents with high-level APIs. These APIs are also used
...@@ -201,10 +229,6 @@ class CONTENT_EXPORT RenderAccessibilityImpl ...@@ -201,10 +229,6 @@ class CONTENT_EXPORT RenderAccessibilityImpl
BlinkAXTreeSource tree_source_; BlinkAXTreeSource tree_source_;
// The serializer that sends accessibility messages to the browser process. // The serializer that sends accessibility messages to the browser process.
using BlinkAXTreeSerializer =
ui::AXTreeSerializer<blink::WebAXObject,
AXContentNodeData,
AXContentTreeData>;
BlinkAXTreeSerializer serializer_; BlinkAXTreeSerializer serializer_;
using PluginAXTreeSerializer = ui::AXTreeSerializer<const ui::AXNode*, using PluginAXTreeSerializer = ui::AXTreeSerializer<const ui::AXNode*,
......
...@@ -2913,6 +2913,10 @@ RenderAccessibility* RenderFrameImpl::GetRenderAccessibility() { ...@@ -2913,6 +2913,10 @@ RenderAccessibility* RenderFrameImpl::GetRenderAccessibility() {
return render_accessibility_; return render_accessibility_;
} }
std::unique_ptr<AXTreeSnapshotter> RenderFrameImpl::CreateAXTreeSnapshotter() {
return std::make_unique<AXTreeSnapshotterImpl>(this);
}
int RenderFrameImpl::GetRoutingID() { int RenderFrameImpl::GetRoutingID() {
return routing_id_; return routing_id_;
} }
......
...@@ -434,6 +434,7 @@ class CONTENT_EXPORT RenderFrameImpl ...@@ -434,6 +434,7 @@ class CONTENT_EXPORT RenderFrameImpl
// RenderFrame implementation: // RenderFrame implementation:
RenderView* GetRenderView() override; RenderView* GetRenderView() override;
RenderAccessibility* GetRenderAccessibility() override; RenderAccessibility* GetRenderAccessibility() override;
std::unique_ptr<AXTreeSnapshotter> CreateAXTreeSnapshotter() override;
int GetRoutingID() override; int GetRoutingID() override;
blink::WebLocalFrame* GetWebFrame() override; blink::WebLocalFrame* GetWebFrame() override;
const WebPreferences& GetWebkitPreferences() override; const WebPreferences& GetWebkitPreferences() override;
......
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