0

Reland: [pdf-a11y]: reduce dependencies between RenderAccessibility and PdfAccessibilityTree

This is mostly the same base change with an addition to
AXObjectCacheImpl::AddDirtyObjectToSerializationQueue.

On the test flake, despite adding dirty objects, Blink a11y never re-serialized. It looks as though, depending on when exactly PdfAccessibilityTree adds the dirty object, it may fall into post lifecycle hooks, leading to no further scheduled updates.

> Original change's description:
> > [pdf-a11y]: reduce dependencies between RenderAccessibility and PdfAccessibilityTree
> >
> > Sparked by the insight that PdfAccessibilityTree has access directly to
> > the WebPluginContainer on initialization (slightly after construction).
> >
> > Simplifications result.
> >
> > R=aleventhal@chromium.org
> >
> > Bug: 324124958
> > Test: cq
> > Change-Id: I588d1bbd6f99806666fd34394db5cf54db092e93
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5263060
> > Reviewed-by: Aaron Leventhal <aleventhal@chromium.org>
> > Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
> > Commit-Queue: David Tseng <dtseng@chromium.org>
> > Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
> > Reviewed-by: Lei Zhang <thestig@chromium.org>
> > Cr-Commit-Position: refs/heads/main@{#1258225}
> >
>
> Bug: 324124958
> Change-Id: Ic4551f5c1864620864140d5294643db63552840c
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5281142
> Owners-Override: Christian Dullweber <dullweber@chromium.org>
> Reviewed-by: Christian Dullweber <dullweber@chromium.org>
> Commit-Queue: Christian Dullweber <dullweber@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#1258403}

Bug: 324124958
Change-Id: I0101c30c0d3c56de5f227fe73fe8822f335357c0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5282435
Commit-Queue: David Tseng <dtseng@chromium.org>
Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1261779}
This commit is contained in:
David Tseng
2024-02-16 18:35:38 +00:00
committed by Chromium LUCI CQ
parent 24a02aa913
commit 0e8ac37d77
21 changed files with 172 additions and 165 deletions

@ -8,6 +8,7 @@
#include <iterator>
#include <utility>
#include "base/check_is_test.h"
#include "base/containers/cxx20_erase.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
@ -31,7 +32,12 @@
#include "pdf/pdf_accessibility_image_fetcher.h"
#include "pdf/pdf_features.h"
#include "third_party/blink/public/strings/grit/blink_accessibility_strings.h"
#include "third_party/blink/public/web/web_ax_object.h"
#include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_plugin_container.h"
#include "ui/accessibility/accessibility_features.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_mode.h"
#include "ui/accessibility/ax_node_id_forward.h"
@ -1564,11 +1570,13 @@ class PdfAccessibilityTreeBuilder {
PdfAccessibilityTree::PdfAccessibilityTree(
content::RenderFrame* render_frame,
chrome_pdf::PdfAccessibilityActionHandler* action_handler,
chrome_pdf::PdfAccessibilityImageFetcher* image_fetcher)
chrome_pdf::PdfAccessibilityImageFetcher* image_fetcher,
blink::WebPluginContainer* plugin_container)
: content::RenderFrameObserver(render_frame),
render_frame_(render_frame),
action_handler_(action_handler),
image_fetcher_(image_fetcher) {
image_fetcher_(image_fetcher),
plugin_container_(plugin_container) {
DCHECK(render_frame);
DCHECK(action_handler_);
DCHECK(image_fetcher_);
@ -1759,7 +1767,7 @@ void PdfAccessibilityTree::DoSetAccessibilityViewportInfo(
root_data.relative_bounds.transform = MakeTransformFromViewInfo();
root->SetData(root_data);
UpdateAXTreeDataFromSelection();
render_accessibility->OnPluginRootNodeUpdated();
MarkPluginContainerDirty();
}
}
@ -1829,7 +1837,7 @@ void PdfAccessibilityTree::DoSetAccessibilityDocInfo(
}
#endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
render_accessibility->SetPluginTreeSource(this);
MarkPluginContainerDirty();
}
void PdfAccessibilityTree::SetAccessibilityPageInfo(
@ -1969,7 +1977,13 @@ void PdfAccessibilityTree::UnserializeNodes() {
LOG(FATAL) << tree_.error();
UpdateAXTreeDataFromSelection();
// TODO(accessibility): this call *re-creates* the serializer in
// RenderAccessibilityImpl. In order to use the serializer there as intended,
// we should supply a list of dirty objects to invalidate on the serializer
// instead of re-creating the entire serializer.
render_accessibility->SetPluginTreeSource(this);
MarkPluginContainerDirty();
nodes_.clear();
if (!sent_metrics_once_) {
@ -2130,7 +2144,7 @@ void PdfAccessibilityTree::SetOcrCompleteStatus() {
if (!tree_.Unserialize(update)) {
LOG(FATAL) << tree_.error();
}
render_accessibility->SetPluginTreeSource(this);
MarkPluginContainerDirty();
}
#endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
@ -2168,7 +2182,7 @@ void PdfAccessibilityTree::ResetStatusNodeAttributes() {
if (!tree_.Unserialize(update)) {
LOG(FATAL) << tree_.error();
}
render_accessibility->SetPluginTreeSource(this);
MarkPluginContainerDirty();
}
void PdfAccessibilityTree::UpdateAXTreeDataFromSelection() {
@ -2365,7 +2379,22 @@ std::unique_ptr<ui::AXActionTarget> PdfAccessibilityTree::CreateActionTarget(
return std::make_unique<PdfAXActionTarget>(target_node, this);
}
blink::WebPluginContainer* PdfAccessibilityTree::GetPluginContainer() {
return plugin_container_;
}
void PdfAccessibilityTree::AccessibilityModeChanged(const ui::AXMode& mode) {
auto* render_accessibility = GetRenderAccessibility();
if (mode.is_mode_off()) {
if (render_accessibility) {
render_accessibility->SetPluginTreeSource(nullptr);
}
return;
}
CHECK(render_accessibility);
render_accessibility->SetPluginTreeSource(this);
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
if (!mode.has_mode(ui::AXMode::kPDFOcr)) {
if (ocr_service_) {
@ -2542,7 +2571,7 @@ void PdfAccessibilityTree::OnOcrDataReceived(
// PDF accessibility tree is available now, so it may be necessary to add a
// postamble page after the last OCRed page.
AddPostamblePageIfNeeded(ocr_requests.back().page_node_id);
render_accessibility->SetPluginTreeSource(this);
MarkPluginContainerDirty();
} else {
// PDF accessibility tree is not yet available. If all pages are OCRed
// before PDF content is being loaded into the accessibility tree, update
@ -2571,11 +2600,24 @@ void PdfAccessibilityTree::CreateOcrService() {
bool PdfAccessibilityTree::ShowContextMenu() {
content::RenderAccessibility* render_accessibility =
GetRenderAccessibilityIfEnabled();
if (!render_accessibility)
if (!render_accessibility) {
return false;
}
render_accessibility->ShowPluginContextMenu();
return true;
// Might be nullptr within tests.
if (!plugin_container_) {
CHECK_IS_TEST();
return false;
}
const blink::WebAXObject& obj =
blink::WebAXObject::FromWebNode(plugin_container_->GetElement());
if (obj.IsNull()) {
return false;
}
ui::AXActionData action_data;
action_data.action = ax::mojom::Action::kShowContextMenu;
return obj.PerformAction(action_data);
}
bool PdfAccessibilityTree::SetChildTree(const ui::AXNodeID& target_node_id,
@ -2601,7 +2643,7 @@ bool PdfAccessibilityTree::SetChildTree(const ui::AXNodeID& target_node_id,
tree_update.root_id = doc_node_->id;
tree_update.nodes = {target_node_data};
CHECK(tree_.Unserialize(tree_update)) << tree_.error();
render_accessibility->SetPluginTreeSource(this);
MarkPluginContainerDirty();
return true;
}
@ -2645,4 +2687,22 @@ void PdfAccessibilityTree::MaybeHandleAccessibilityChange(
}
}
void PdfAccessibilityTree::MarkPluginContainerDirty() {
// Might be nullptr within tests.
if (!plugin_container_) {
CHECK_IS_TEST();
return;
}
const blink::WebAXObject& obj =
blink::WebAXObject::FromWebNode(plugin_container_->GetElement());
if (obj.IsDetached()) {
return;
}
obj.AddDirtyObjectToSerializationQueue(ax::mojom::EventFrom::kNone,
ax::mojom::Action::kNone,
std::vector<ui::AXEventIntent>());
}
} // namespace pdf

@ -33,6 +33,10 @@
#include "ui/accessibility/ax_node_data.h"
#endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
namespace blink {
class WebPluginContainer;
} // namespace blink
namespace chrome_pdf {
class PdfAccessibilityActionHandler;
@ -171,7 +175,8 @@ class PdfAccessibilityTree : public content::PluginAXTreeSource,
PdfAccessibilityTree(
content::RenderFrame* render_frame,
chrome_pdf::PdfAccessibilityActionHandler* action_handler,
chrome_pdf::PdfAccessibilityImageFetcher* image_fetcher);
chrome_pdf::PdfAccessibilityImageFetcher* image_fetcher,
blink::WebPluginContainer* plugin_container);
~PdfAccessibilityTree() override;
static bool IsDataFromPluginValid(
@ -230,6 +235,7 @@ class PdfAccessibilityTree : public content::PluginAXTreeSource,
ui::AXNodeData* out_data) const override;
std::unique_ptr<ui::AXActionTarget> CreateActionTarget(
const ui::AXNode& target_node) override;
blink::WebPluginContainer* GetPluginContainer() override;
// content::RenderFrameObserver:
void AccessibilityModeChanged(const ui::AXMode& mode) override;
@ -331,6 +337,10 @@ class PdfAccessibilityTree : public content::PluginAXTreeSource,
// is true, even if the accessibility state is `AccessibilityState::kLoaded`.
void MaybeHandleAccessibilityChange(bool always_load_or_reload_accessibility);
// Marks the plugin container dirty to ensure serialization of the PDF
// contents.
void MarkPluginContainerDirty();
// Returns a weak pointer for an instance of this class.
base::WeakPtr<PdfAccessibilityTree> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
@ -349,6 +359,8 @@ class PdfAccessibilityTree : public content::PluginAXTreeSource,
action_handler_;
const raw_ptr<chrome_pdf::PdfAccessibilityImageFetcher, ExperimentalRenderer>
image_fetcher_;
const raw_ptr<blink::WebPluginContainer, ExperimentalRenderer>
plugin_container_;
// `zoom_` signifies the zoom level set in for the browser content.
// `scale_` signifies the scale level set by user. Scale is applied

@ -26,7 +26,6 @@
#include "pdf/pdf_accessibility_image_fetcher.h"
#include "pdf/pdf_features.h"
#include "third_party/blink/public/strings/grit/blink_accessibility_strings.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/public/web/web_view.h"
#include "ui/accessibility/ax_action_data.h"
@ -298,7 +297,10 @@ class TestPdfAccessibilityTree : public PdfAccessibilityTree {
content::RenderFrame* render_frame,
chrome_pdf::PdfAccessibilityActionHandler* action_handler,
chrome_pdf::PdfAccessibilityImageFetcher* image_fetcher)
: PdfAccessibilityTree(render_frame, action_handler, image_fetcher) {}
: PdfAccessibilityTree(render_frame,
action_handler,
image_fetcher,
/*plugincontainer=*/nullptr) {}
~TestPdfAccessibilityTree() override = default;
TestPdfAccessibilityTree(const TestPdfAccessibilityTree&) = delete;
@ -2244,9 +2246,9 @@ TEST_F(PdfAccessibilityTreeTest, TestSelectionActionDataConversion) {
// Verify selection offsets in tree data.
ui::AXTreeData tree_data;
pdf_accessibility_tree_->GetTreeData(&tree_data);
EXPECT_EQ(10, tree_data.sel_anchor_object_id);
EXPECT_EQ(static_text_nodes1[0]->id(), tree_data.sel_anchor_object_id);
EXPECT_EQ(0, tree_data.sel_anchor_offset);
EXPECT_EQ(10, tree_data.sel_focus_object_id);
EXPECT_EQ(static_text_nodes1[0]->id(), tree_data.sel_focus_object_id);
EXPECT_EQ(0, tree_data.sel_focus_offset);
pdf_anchor_action_target =
@ -2306,7 +2308,9 @@ TEST_F(PdfAccessibilityTreeTest, TestShowContextMenuAction) {
{
ui::AXActionData action_data;
action_data.action = ax::mojom::Action::kShowContextMenu;
EXPECT_TRUE(pdf_action_target->PerformAction(action_data));
// This renderer is not actually attached to a real plugin.
EXPECT_FALSE(pdf_action_target->PerformAction(action_data));
}
}

@ -262,9 +262,10 @@ void PdfViewWebPluginClient::RecordComputedAction(const std::string& action) {
std::unique_ptr<chrome_pdf::PdfAccessibilityDataHandler>
PdfViewWebPluginClient::CreateAccessibilityDataHandler(
chrome_pdf::PdfAccessibilityActionHandler* action_handler,
chrome_pdf::PdfAccessibilityImageFetcher* image_fetcher) {
return std::make_unique<PdfAccessibilityTree>(render_frame_, action_handler,
image_fetcher);
chrome_pdf::PdfAccessibilityImageFetcher* image_fetcher,
blink::WebPluginContainer* plugin_container) {
return std::make_unique<PdfAccessibilityTree>(
render_frame_, action_handler, image_fetcher, plugin_container);
}
} // namespace pdf

@ -81,7 +81,8 @@ class PdfViewWebPluginClient : public chrome_pdf::PdfViewWebPlugin::Client {
std::unique_ptr<chrome_pdf::PdfAccessibilityDataHandler>
CreateAccessibilityDataHandler(
chrome_pdf::PdfAccessibilityActionHandler* action_handler,
chrome_pdf::PdfAccessibilityImageFetcher* image_fetcher) override;
chrome_pdf::PdfAccessibilityImageFetcher* image_fetcher,
blink::WebPluginContainer* plugin_element) override;
private:
blink::WebLocalFrame* GetFrame() const;

@ -11,12 +11,18 @@
#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/ax_tree_source.h"
namespace blink {
class WebPluginContainer;
}
namespace content {
class PluginAXTreeSource : public ui::AXTreeSource<const ui::AXNode*> {
public:
virtual std::unique_ptr<ui::AXActionTarget> CreateActionTarget(
const ui::AXNode& target_node) = 0;
virtual blink::WebPluginContainer* GetPluginContainer() = 0;
};
} // namespace content

@ -34,8 +34,6 @@ class CONTENT_EXPORT RenderAccessibility {
// reference to it, due to its large object size (128 bytes).
virtual ui::AXTreeID GetTreeIDForPluginHost() const = 0;
virtual void SetPluginTreeSource(PluginAXTreeSource* source) = 0;
virtual void ShowPluginContextMenu() = 0;
virtual void OnPluginRootNodeUpdated() = 0;
virtual void RecordInaccessiblePdfUkm() = 0;

@ -41,8 +41,8 @@
#include "third_party/blink/public/web/web_disallow_transition_scope.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_input_element.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_page_popup.h"
#include "third_party/blink/public/web/web_plugin_container.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/public/web/web_view.h"
#include "ui/accessibility/accessibility_features.h"
@ -59,7 +59,6 @@ using blink::WebAXContext;
using blink::WebAXObject;
using blink::WebDocument;
using blink::WebElement;
using blink::WebLocalFrame;
using blink::WebNode;
using blink::WebSettings;
using blink::WebView;
@ -485,42 +484,6 @@ void RenderAccessibilityImpl::SetPluginTreeSource(
plugin_tree_source_ = plugin_tree_source;
plugin_serializer_ =
std::make_unique<PluginAXTreeSerializer>(plugin_tree_source_);
OnPluginRootNodeUpdated();
}
void RenderAccessibilityImpl::OnPluginRootNodeUpdated() {
// Search the accessibility tree for plugin's root object and post a
// children changed notification on it to force it to update the
// plugin accessibility tree.
WebAXObject obj = GetPluginRoot();
if (obj.IsNull())
return;
MarkWebAXObjectDirty(obj);
// Schedule an update immediately whenever the PDF root in PDF accessibility
// tree changes. It is needed to ensure that changes (e.g. bounds) in PDF
// accessibility tree are serialized.
ScheduleImmediateAXUpdate();
}
void RenderAccessibilityImpl::ShowPluginContextMenu() {
// Search the accessibility tree for plugin's root object and invoke
// ShowContextMenu() on it to show context menu for plugin.
WebAXObject obj = GetPluginRoot();
if (obj.IsNull())
return;
const WebDocument& document = GetMainDocument();
if (document.IsNull())
return;
std::unique_ptr<ui::AXActionTarget> target =
AXActionTargetFactory::CreateFromNodeId(document, plugin_tree_source_,
obj.AxID());
ui::AXActionData action_data;
action_data.action = ax::mojom::Action::kShowContextMenu;
target->PerformAction(action_data);
}
WebDocument RenderAccessibilityImpl::GetMainDocument() const {
@ -555,8 +518,9 @@ bool RenderAccessibilityImpl::SerializeUpdatesAndEvents(
DCHECK(ax_context_);
DCHECK(!accessibility_mode_.is_mode_off());
ax_context_->SerializeDirtyObjectsAndEvents(
!!plugin_tree_source_, updates, events, had_end_of_test_event,
had_load_complete_messages, need_to_send_location_changes);
plugin_tree_source_ ? plugin_tree_source_->GetPluginContainer() : nullptr,
updates, events, had_end_of_test_event, had_load_complete_messages,
need_to_send_location_changes, mark_plugin_subtree_dirty);
for (auto& update : updates) {
if (update.node_id_to_clear > 0) {
@ -789,9 +753,11 @@ void RenderAccessibilityImpl::AddPluginTreeToUpdate(
if (mark_plugin_subtree_dirty) {
plugin_serializer_->Reset();
}
const auto& obj = blink::WebAXObject::FromWebNode(
plugin_tree_source_->GetPluginContainer()->GetElement());
int ax_id = obj.AxID();
for (ui::AXNodeData& node : update->nodes) {
if (node.role == ax::mojom::Role::kEmbeddedObject) {
if (node.id == ax_id) {
const ui::AXNode* root = plugin_tree_source_->GetRoot();
node.child_ids.push_back(root->id());
@ -823,13 +789,6 @@ blink::WebDocument RenderAccessibilityImpl::GetPopupDocument() {
return WebDocument();
}
blink::WebAXObject RenderAccessibilityImpl::GetPluginRoot() {
if (!ax_context_)
return WebAXObject();
ax_context_->UpdateAXForAllDocuments();
return ax_context_->GetPluginRoot();
}
WebAXObject RenderAccessibilityImpl::ComputeRoot() {
DCHECK(render_frame_);
DCHECK(render_frame_->GetWebFrame());

@ -101,8 +101,6 @@ class CONTENT_EXPORT RenderAccessibilityImpl : public RenderAccessibility,
ui::AXMode GetAXMode() const override;
ui::AXTreeID GetTreeIDForPluginHost() const override;
void SetPluginTreeSource(PluginAXTreeSource* source) override;
void OnPluginRootNodeUpdated() override;
void ShowPluginContextMenu() override;
void RecordInaccessiblePdfUkm() override;
// RenderFrameObserver implementation.
@ -198,10 +196,6 @@ class CONTENT_EXPORT RenderAccessibilityImpl : public RenderAccessibility,
// Returns the document for the active popup if any.
blink::WebDocument GetPopupDocument();
// Searches the accessibility tree for plugin's root object and returns it.
// Returns an empty WebAXObject if no root object is present.
blink::WebAXObject GetPluginRoot();
blink::WebAXObject ComputeRoot();
// Sends the URL-keyed metrics for the maximum amount of time spent in

@ -602,6 +602,7 @@ class MockPluginAccessibilityTreeSource : public content::PluginAXTreeSource {
}
bool GetActionTargetCalled() { return action_target_called_; }
void ResetActionTargetCalled() { action_target_called_ = false; }
blink::WebPluginContainer* GetPluginContainer() override { return nullptr; }
private:
std::unique_ptr<ui::AXTree> ax_tree_;

@ -274,7 +274,8 @@ std::unique_ptr<PDFiumEngine> PdfViewWebPlugin::Client::CreateEngine(
std::unique_ptr<PdfAccessibilityDataHandler>
PdfViewWebPlugin::Client::CreateAccessibilityDataHandler(
PdfAccessibilityActionHandler* action_handler,
PdfAccessibilityImageFetcher* image_fetcher) {
PdfAccessibilityImageFetcher* image_fetcher,
blink::WebPluginContainer* plugin_container) {
return nullptr;
}
@ -284,9 +285,7 @@ PdfViewWebPlugin::PdfViewWebPlugin(
const blink::WebPluginParams& params)
: client_(std::move(client)),
pdf_service_(std::move(pdf_service)),
initial_params_(params),
pdf_accessibility_data_handler_(
client_->CreateAccessibilityDataHandler(this, this)) {
initial_params_(params) {
DCHECK(pdf_service_);
pdf_service_->SetListener(listener_receiver_.BindNewPipeAndPassRemote());
}
@ -296,12 +295,18 @@ PdfViewWebPlugin::~PdfViewWebPlugin() = default;
bool PdfViewWebPlugin::Initialize(blink::WebPluginContainer* container) {
DCHECK(container);
client_->SetPluginContainer(container);
DCHECK_EQ(container->Plugin(), this);
pdf_accessibility_data_handler_ =
client_->CreateAccessibilityDataHandler(this, this, container);
return InitializeCommon();
}
bool PdfViewWebPlugin::InitializeForTesting() {
pdf_accessibility_data_handler_ =
client_->CreateAccessibilityDataHandler(this, this, nullptr);
return InitializeCommon();
}

@ -225,7 +225,8 @@ class PdfViewWebPlugin final : public PDFEngine::Client,
virtual std::unique_ptr<PdfAccessibilityDataHandler>
CreateAccessibilityDataHandler(
PdfAccessibilityActionHandler* action_handler,
PdfAccessibilityImageFetcher* image_fetcher);
PdfAccessibilityImageFetcher* image_fetcher,
blink::WebPluginContainer* plugin_container);
};
PdfViewWebPlugin(std::unique_ptr<Client> client,
@ -766,8 +767,7 @@ class PdfViewWebPlugin final : public PDFEngine::Client,
std::unique_ptr<UrlLoader> form_loader_;
// Handler for accessibility data updates.
std::unique_ptr<PdfAccessibilityDataHandler> const
pdf_accessibility_data_handler_;
std::unique_ptr<PdfAccessibilityDataHandler> pdf_accessibility_data_handler_;
// The URL currently under the cursor.
std::string link_under_cursor_;

@ -312,7 +312,9 @@ class FakePdfViewWebPluginClient : public PdfViewWebPlugin::Client {
MOCK_METHOD(std::unique_ptr<PdfAccessibilityDataHandler>,
CreateAccessibilityDataHandler,
(PdfAccessibilityActionHandler*, PdfAccessibilityImageFetcher*),
(PdfAccessibilityActionHandler*,
PdfAccessibilityImageFetcher*,
blink::WebPluginContainer*),
(override));
};

@ -59,10 +59,6 @@ class BLINK_EXPORT WebAXContext {
// via mojo to the browser process.
void SerializeLocationChanges(uint32_t reset_token) const;
// Searches the accessibility tree for plugin's root object and returns it.
// Returns an empty WebAXObject if no root object is present.
WebAXObject GetPluginRoot();
bool SerializeEntireTree(
size_t max_node_count,
base::TimeDelta timeout,
@ -73,12 +69,13 @@ class BLINK_EXPORT WebAXContext {
// the last serialization) into |updates|. (Heuristically) skips
// serializing dirty nodes whose AX id is in |already_serialized_ids|, and
// adds serialized dirty objects into |already_serialized_ids|.
void SerializeDirtyObjectsAndEvents(bool has_plugin_tree_source,
void SerializeDirtyObjectsAndEvents(WebPluginContainer* plugin_container,
std::vector<ui::AXTreeUpdate>& updates,
std::vector<ui::AXEvent>& events,
bool& had_end_of_test_event,
bool& had_load_complete_messages,
bool& need_to_send_location_changes);
bool& need_to_send_location_changes,
bool& mark_plugin_subtree_dirty);
// Returns a vector of the images found in |updates|.
void GetImagesToAnnotate(ui::AXTreeUpdate& updates,

@ -57,6 +57,7 @@ class HTMLOptionElement;
class HTMLFrameOwnerElement;
class HTMLSelectElement;
struct PhysicalRect;
class WebPluginContainer;
class CORE_EXPORT AXObjectCache : public GarbageCollected<AXObjectCache> {
public:
@ -226,8 +227,6 @@ class CORE_EXPORT AXObjectCache : public GarbageCollected<AXObjectCache> {
virtual void SerializeLocationChanges(uint32_t reset_token) = 0;
virtual AXObject* GetPluginRoot() = 0;
// Serialize entire tree, returning true if successful.
virtual bool SerializeEntireTree(
size_t max_node_count,
@ -265,12 +264,13 @@ class CORE_EXPORT AXObjectCache : public GarbageCollected<AXObjectCache> {
const std::vector<ui::AXEventIntent>& event_intents) = 0;
virtual void SerializeDirtyObjectsAndEvents(
bool has_plugin_tree_source,
WebPluginContainer* plugin_container,
std::vector<ui::AXTreeUpdate>& updates,
std::vector<ui::AXEvent>& events,
bool& had_end_of_test_event,
bool& had_load_complete_messages,
bool& need_to_send_location_changes) = 0;
bool& need_to_send_location_changes,
bool& mark_plugin_subtree_dirty) = 0;
// Returns a vector of the images found in |updates|.
virtual void GetImagesToAnnotate(ui::AXTreeUpdate& updates,

@ -41,6 +41,7 @@
#include "third_party/blink/public/mojom/render_accessibility.mojom-blink.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/web/web_local_frame_client.h"
#include "third_party/blink/public/web/web_plugin_container.h"
#include "third_party/blink/renderer/core/accessibility/scoped_blink_ax_event_intent.h"
#include "third_party/blink/renderer/core/aom/accessible_node.h"
#include "third_party/blink/renderer/core/aom/computed_accessible_node.h"
@ -5134,15 +5135,22 @@ void AXObjectCacheImpl::AddDirtyObjectToSerializationQueue(
// SerializeDirtyObjectsAndEvents().
dirty_objects_.push_back(
AXDirtyObject::Create(obj, event_from, event_from_action, event_intents));
// ensure there is a document lifecycle update scheduled for plugin
// containers.
if (obj->GetElement() && DynamicTo<HTMLPlugInElement>(obj->GetElement())) {
ScheduleImmediateSerialization();
}
}
void AXObjectCacheImpl::SerializeDirtyObjectsAndEvents(
bool has_plugin_tree_source,
WebPluginContainer* plugin_container,
std::vector<ui::AXTreeUpdate>& updates,
std::vector<ui::AXEvent>& events,
bool& had_end_of_test_event,
bool& had_load_complete_messages,
bool& need_to_send_location_changes) {
bool& need_to_send_location_changes,
bool& should_reset_plugin_serializer) {
HashSet<int32_t> already_serialized_ids;
int redundant_serialization_count = 0;
@ -5191,9 +5199,15 @@ void AXObjectCacheImpl::SerializeDirtyObjectsAndEvents(
// If there's a plugin, force the tree data to be generated in every
// message so the plugin can merge its own tree data changes.
if (has_plugin_tree_source)
if (plugin_container) {
update.has_tree_data = true;
if (!ax_tree_serializer_->IsInClientTree(
Get(plugin_container->GetElement()))) {
should_reset_plugin_serializer = true;
}
}
bool success = ax_tree_serializer_->SerializeChanges(obj, &update);
DCHECK(success);

@ -502,15 +502,6 @@ class MODULES_EXPORT AXObjectCacheImpl
// called, it will only retrieve objects that have changed since now.
void SerializeLocationChanges(uint32_t reset_token) override;
// Searches the accessibility tree for plugin's root object and returns it.
// Returns an empty WebAXObject if no root object is present.
AXObject* GetPluginRoot() override {
ax_tree_source_->Freeze();
AXObject* result = ax_tree_source_->GetPluginRoot();
ax_tree_source_->Thaw();
return result;
}
bool SerializeEntireTree(
size_t max_node_count,
base::TimeDelta timeout,
@ -526,13 +517,13 @@ class MODULES_EXPORT AXObjectCacheImpl
ax::mojom::blink::Action::kNone,
const std::vector<ui::AXEventIntent>& event_intents = {}) override;
void SerializeDirtyObjectsAndEvents(
bool has_plugin_tree_source,
std::vector<ui::AXTreeUpdate>& updates,
std::vector<ui::AXEvent>& events,
bool& had_end_of_test_event,
bool& had_load_complete_messages,
bool& need_to_send_location_changes) override;
void SerializeDirtyObjectsAndEvents(WebPluginContainer* plugin_container,
std::vector<ui::AXTreeUpdate>& updates,
std::vector<ui::AXEvent>& events,
bool& had_end_of_test_event,
bool& had_load_complete_messages,
bool& need_to_send_location_changes,
bool& mark_plugin_subtree_dirty) override;
void GetImagesToAnnotate(ui::AXTreeUpdate& updates,
std::vector<ui::AXNodeData*>& nodes) override;

@ -114,16 +114,18 @@ TEST_F(AccessibilityTest, HistogramTest) {
}
{
blink::WebPluginContainer* plugin_container = nullptr;
std::vector<ui::AXTreeUpdate> updates;
std::vector<ui::AXEvent> events;
bool has_plugin_tree_source = false;
bool had_end_of_test_event = true;
bool had_load_complete_messages = true;
bool need_to_send_location_changes = false;
bool mark_plugin_subtree_dirty = false;
ScopedFreezeAXCache freeze(cache);
cache.SerializeDirtyObjectsAndEvents(
has_plugin_tree_source, updates, events, had_end_of_test_event,
had_load_complete_messages, need_to_send_location_changes);
plugin_container, updates, events, had_end_of_test_event,
had_load_complete_messages, need_to_send_location_changes,
mark_plugin_subtree_dirty);
histogram_tester.ExpectTotalCount(
"Accessibility.Performance.AXObjectCacheImpl.Snapshot", 1);
histogram_tester.ExpectTotalCount(

@ -409,37 +409,4 @@ void BlinkAXTreeSource::Trace(Visitor* visitor) const {
visitor->Trace(focus_);
}
AXObject* BlinkAXTreeSource::GetPluginRoot() {
AXObject* root = GetRoot();
HeapDeque<Member<AXObject>> objs_to_explore;
objs_to_explore.push_back(root);
while (objs_to_explore.size()) {
AXObject* obj = objs_to_explore.front();
objs_to_explore.pop_front();
Node* node = obj->GetNode();
if (node && node->IsElementNode()) {
Element* element = To<Element>(node);
if (element->IsHTMLWithTagName("embed")) {
return obj;
}
}
// Explore children of this object.
CacheChildrenIfNeeded(obj);
auto num_children = GetChildCount(obj);
for (size_t i = 0; i < num_children; i++) {
auto* child = ChildAt(obj, i);
if (!child) {
continue;
}
objs_to_explore.push_back(child);
}
ClearChildCache(obj);
}
return nullptr;
}
} // namespace blink

@ -76,8 +76,6 @@ class MODULES_EXPORT BlinkAXTreeSource
void Trace(Visitor*) const;
AXObject* GetPluginRoot();
void Freeze();
void Thaw();

@ -63,13 +63,6 @@ void WebAXContext::SerializeLocationChanges(uint32_t reset_token) const {
private_->GetAXObjectCache().SerializeLocationChanges(reset_token);
}
WebAXObject WebAXContext::GetPluginRoot() {
if (!HasActiveDocument()) {
return WebAXObject();
}
return WebAXObject(private_->GetAXObjectCache().GetPluginRoot());
}
bool WebAXContext::SerializeEntireTree(
size_t max_node_count,
base::TimeDelta timeout,
@ -87,18 +80,20 @@ bool WebAXContext::SerializeEntireTree(
}
void WebAXContext::SerializeDirtyObjectsAndEvents(
bool has_plugin_tree_source,
WebPluginContainer* plugin_container,
std::vector<ui::AXTreeUpdate>& updates,
std::vector<ui::AXEvent>& events,
bool& had_end_of_test_event,
bool& had_load_complete_messages,
bool& need_to_send_location_changes) {
bool& need_to_send_location_changes,
bool& mark_plugin_subtree_dirty) {
CHECK(HasActiveDocument());
ScopedFreezeAXCache freeze(private_->GetAXObjectCache());
private_->GetAXObjectCache().SerializeDirtyObjectsAndEvents(
has_plugin_tree_source, updates, events, had_end_of_test_event,
had_load_complete_messages, need_to_send_location_changes);
plugin_container, updates, events, had_end_of_test_event,
had_load_complete_messages, need_to_send_location_changes,
mark_plugin_subtree_dirty);
}
void WebAXContext::GetImagesToAnnotate(ui::AXTreeUpdate& updates,