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:

committed by
Chromium LUCI CQ

parent
24a02aa913
commit
0e8ac37d77
components/pdf/renderer
pdf_accessibility_tree.ccpdf_accessibility_tree.hpdf_accessibility_tree_browsertest.ccpdf_view_web_plugin_client.ccpdf_view_web_plugin_client.h
content
public
renderer
pdf
third_party/blink
public
renderer
core
accessibility
modules
@ -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,
|
||||
|
Reference in New Issue
Block a user