blob: 3c976f2ce3962ae1c9b1868ca201e84314db5985 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/actor/ui/dom_node_geometry.h"
#include <absl/container/flat_hash_map.h>
#include "base/metrics/histogram_functions.h"
#include "chrome/common/chrome_features.h"
#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
namespace actor::ui {
namespace {
using base::UmaHistogramEnumeration;
using optimization_guide::proto::ContentAttributes;
using optimization_guide::proto::ContentNode;
using optimization_guide::proto::DocumentIdentifier;
using NodeGeomMap = absl::flat_hash_map<DomNode, ContentAttributes>;
constexpr char kDomNodeResultHistogram[] =
"Actor.DomNodeGeometry.GetDomNodeResult";
void BuildNodeMapInternal(const DocumentIdentifier& doc_id,
const ContentNode& root,
NodeGeomMap& map) {
const auto& content_attributes = root.content_attributes();
if (content_attributes.has_common_ancestor_dom_node_id()) {
DomNode key{.node_id = content_attributes.common_ancestor_dom_node_id(),
.document_identifier = doc_id.serialized_token()};
map.emplace(std::move(key), root.content_attributes());
}
// If the node is an iframe, then use the iframe's doc_id for its children.
// Otherwise use the same doc_id.
const DocumentIdentifier& child_doc_id =
(content_attributes.has_iframe_data() &&
content_attributes.iframe_data().has_frame_data())
? content_attributes.iframe_data().frame_data().document_identifier()
: doc_id;
for (const auto& child : root.children_nodes()) {
BuildNodeMapInternal(child_doc_id, child, map);
}
}
NodeGeomMap BuildNodeMap(const DocumentIdentifier& doc_id,
const ContentNode& root) {
NodeGeomMap map;
BuildNodeMapInternal(doc_id, root, map);
return map;
}
} // namespace
std::optional<gfx::Point> GetDomNodePointFromApc(
const optimization_guide::proto::AnnotatedPageContent& apc,
const DomNode& node) {
if (!features::kGlicActorUiOverlayMagicCursor.Get()) {
// Disabled unless Magic Cursor is on to improve latency.
return std::nullopt;
}
if (!apc.has_main_frame_data() ||
!apc.main_frame_data().has_document_identifier()) {
UmaHistogramEnumeration(kDomNodeResultHistogram,
GetDomNodeResult::kNoApcMainFrameData);
return std::nullopt;
}
NodeGeomMap node_map = BuildNodeMap(
apc.main_frame_data().document_identifier(), apc.root_node());
auto it = node_map.find(node);
if (it == node_map.end()) {
UmaHistogramEnumeration(kDomNodeResultHistogram,
GetDomNodeResult::kNodeNotFoundInApc);
return std::nullopt;
}
const ContentAttributes& attr = it->second;
if (!attr.has_geometry()) {
UmaHistogramEnumeration(kDomNodeResultHistogram,
GetDomNodeResult::kNoGeometry);
return std::nullopt;
}
const auto& geom = attr.geometry();
if (!geom.has_visible_bounding_box()) {
UmaHistogramEnumeration(kDomNodeResultHistogram,
GetDomNodeResult::kOffScreen);
return std::nullopt;
}
const auto& rect = geom.visible_bounding_box();
const int x = rect.x() + rect.width() / 2;
const int y = rect.y() + rect.height() / 2;
UmaHistogramEnumeration(kDomNodeResultHistogram, GetDomNodeResult::kSuccess);
return gfx::Point(x, y);
}
} // namespace actor::ui