#include "content/renderer/accessibility/annotations/ax_main_node_annotator.h"
#include <utility>
#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
#include "third_party/blink/public/platform/browser_interface_broker_proxy.h"
namespace content {
using blink::WebAXObject;
using blink::WebDocument;
namespace {
const char kHistogramsName[] =
"Accessibility.MainNodeAnnotations.AnnotationResult";
enum class MainNodeAnnotationResult {
kSuccess = 0,
kInvalid = 1,
kDuplicate = 2,
kMaxValue = kDuplicate,
};
}
AXMainNodeAnnotator::AXMainNodeAnnotator(
RenderAccessibilityImpl* const render_accessibility)
: render_accessibility_(render_accessibility) {
CHECK(render_accessibility_);
}
AXMainNodeAnnotator::~AXMainNodeAnnotator() = default;
void AXMainNodeAnnotator::EnableAnnotations() {
annotator_enabled_ = true;
}
void AXMainNodeAnnotator::CancelAnnotations() {
if (render_accessibility_->GetAccessibilityMode().has_mode(
GetAXModeToEnableAnnotations())) {
return;
}
annotator_enabled_ = false;
annotator_remote_.reset();
}
uint32_t AXMainNodeAnnotator::GetAXModeToEnableAnnotations() {
return ui::AXMode::kAnnotateMainNode;
}
bool AXMainNodeAnnotator::HasAXActionToEnableAnnotations() {
return false;
}
ax::mojom::Action AXMainNodeAnnotator::GetAXActionToEnableAnnotations() {
NOTREACHED();
}
void AXMainNodeAnnotator::Annotate(const WebDocument& document,
ui::AXTreeUpdate* update,
bool load_complete) {
if (main_node_id_ != ui::kInvalidAXNodeID) {
for (ui::AXNodeData& node : update->nodes) {
if (node.id != main_node_id_) {
continue;
}
node.role = ax::mojom::Role::kMain;
return;
}
return;
}
if (!load_complete) {
return;
}
ComputeAuthorStatus(update);
if (author_status_ == AXMainNodeAnnotatorAuthorStatus::kAuthorProvidedMain) {
return;
}
CHECK_EQ(author_status_,
AXMainNodeAnnotatorAuthorStatus::kAuthorDidNotProvideMain);
if (!annotator_enabled_) {
return;
}
if (!annotator_remote_.is_bound() || !annotator_remote_.is_connected()) {
if (!render_accessibility_->render_frame()) {
return;
}
mojo::PendingRemote<screen_ai::mojom::Screen2xMainContentExtractor>
annotator;
render_accessibility_->render_frame()
->GetBrowserInterfaceBroker()
.GetInterface(annotator.InitWithNewPipeAndPassReceiver());
annotator_remote_.Bind(std::move(annotator));
annotator_remote_.reset_on_disconnect();
annotator_remote_->SetClientType(
screen_ai::mojom::MceClientType::kMainNode);
}
annotator_remote_->ExtractMainNode(
*update, base::BindOnce(&AXMainNodeAnnotator::ProcessScreen2xResult,
weak_ptr_factory_.GetWeakPtr(), document));
}
void AXMainNodeAnnotator::ProcessScreen2xResult(const WebDocument& document,
ui::AXNodeID main_node_id) {
if (main_node_id == ui::kInvalidAXNodeID) {
base::UmaHistogramEnumeration(kHistogramsName,
MainNodeAnnotationResult::kInvalid);
return;
}
if (main_node_id_ != ui::kInvalidAXNodeID) {
base::UmaHistogramEnumeration(kHistogramsName,
MainNodeAnnotationResult::kDuplicate);
return;
}
WebAXObject object = WebAXObject::FromWebDocumentByID(document, main_node_id);
if (!object.IsIncludedInTree()) {
base::UmaHistogramEnumeration(kHistogramsName,
MainNodeAnnotationResult::kInvalid);
return;
}
main_node_id_ = main_node_id;
render_accessibility_->MarkWebAXObjectDirty(object);
base::UmaHistogramEnumeration(kHistogramsName,
MainNodeAnnotationResult::kSuccess);
}
void AXMainNodeAnnotator::ComputeAuthorStatus(ui::AXTreeUpdate* update) {
if (author_status_ != AXMainNodeAnnotatorAuthorStatus::kUnconfirmed) {
return;
}
for (ui::AXNodeData& node : update->nodes) {
if (node.role == ax::mojom::Role::kMain) {
author_status_ = AXMainNodeAnnotatorAuthorStatus::kAuthorProvidedMain;
return;
}
}
author_status_ = AXMainNodeAnnotatorAuthorStatus::kAuthorDidNotProvideMain;
}
void AXMainNodeAnnotator::BindAnnotatorForTesting(
mojo::PendingRemote<screen_ai::mojom::Screen2xMainContentExtractor>
annotator) {
annotator_remote_.Bind(std::move(annotator));
annotator_enabled_ = true;
}
}