0

Add a new struct to AIPageContent, InteractionInfo.

Bug: 392668105
Change-Id: I33b50e74e07c74a1007706595258915620f758dc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6217967
Reviewed-by: Alex Gough <ajgo@chromium.org>
Commit-Queue: Abigail Klein <abigailbklein@google.com>
Cr-Commit-Position: refs/heads/main@{#1417088}
This commit is contained in:
Abigail Klein
2025-02-06 16:48:11 -08:00
committed by Chromium LUCI CQ
parent bc69f9633e
commit b3a265d8ee
8 changed files with 359 additions and 35 deletions
components/optimization_guide/content/browser
third_party/blink

@ -95,8 +95,6 @@ void ConvertGeometry(const blink::mojom::AIPageContentGeometry& mojom_geometry,
proto_geometry->mutable_visible_bounding_box());
proto_geometry->set_is_fixed_or_sticky_position(
mojom_geometry.is_fixed_or_sticky_position);
proto_geometry->set_scrolls_overflow_x(mojom_geometry.scrolls_overflow_x);
proto_geometry->set_scrolls_overflow_y(mojom_geometry.scrolls_overflow_y);
}
optimization_guide::proto::TextSize ConvertTextSize(

@ -438,8 +438,6 @@ TEST(PageContentProtoUtilTest, ConvertGeometry) {
text_node->content_attributes->geometry->visible_bounding_box =
gfx::Rect(11, 21, 31, 41);
text_node->content_attributes->geometry->is_fixed_or_sticky_position = true;
text_node->content_attributes->geometry->scrolls_overflow_x = true;
text_node->content_attributes->geometry->scrolls_overflow_y = true;
root_content->root_node->children_nodes.emplace_back(std::move(text_node));
proto::AnnotatedPageContent proto;
@ -462,8 +460,6 @@ TEST(PageContentProtoUtilTest, ConvertGeometry) {
EXPECT_EQ(geometry.visible_bounding_box().width(), 31);
EXPECT_EQ(geometry.visible_bounding_box().height(), 41);
EXPECT_TRUE(geometry.is_fixed_or_sticky_position());
EXPECT_TRUE(geometry.scrolls_overflow_x());
EXPECT_TRUE(geometry.scrolls_overflow_y());
}
TEST(PageContentProtoUtilTest, ConvertAnnotatedRoles) {

@ -10,6 +10,9 @@ import "ui/gfx/geometry/mojom/geometry.mojom";
import "url/mojom/origin.mojom";
import "url/mojom/url.mojom";
[EnableIfNot=is_android]
import "ui/base/cursor/mojom/cursor_type.mojom";
// This is a mojom representation of the corresponding AnnotatedPageContent
// proto.
// See components/optimization_guide/proto/features/common_quality_data.proto
@ -66,12 +69,45 @@ struct AIPageContentGeometry {
// Whether the content node is fixed or sticky position. This may suggest
// that the node is a header, footer, or sidebar.
bool is_fixed_or_sticky_position;
};
struct AIPageContentInteractionInfo {
// Whether the content node can scroll in the x direction.
bool scrolls_overflow_x;
// Whether the content node can scroll in the y direction.
bool scrolls_overflow_y;
// Whether the content node is selectable.
bool is_selectable;
// Whether the content node is editable; i.e. whether the user can type into
// it. This refers to the text actually being editable, not whether the
// content node is a text field.
bool is_editable;
// Whether the content node can be resized. This is relevant for scroll
// containers and iframes which have the CSS resize behavior.
bool can_resize_horizontal;
bool can_resize_vertical;
// Whether the content node is focusable.
bool is_focusable;
// Whether the content node is focused.
bool is_focused;
// Whether the content node is draggable.
bool is_draggable;
// Whether the content node is clickable. This checks for whether the node is
// a clickable control (e.g. form control elements) or has activation
// behavior. It also checks for whether the node has a click handler.
bool is_clickable;
// The cursor type for the content node.
[EnableIfNot=is_android]
ui.mojom.CursorType cursor_type;
};
enum AIPageContentTextSize {
@ -204,6 +240,9 @@ struct AIPageContentAttributes {
// Geometry of the common_ancestor_dom_node_id.
AIPageContentGeometry? geometry;
// Interaction information for the common_ancestor_dom_node_id.
AIPageContentInteractionInfo? interaction_info;
// Only set if attribute_type is kText.
AIPageContentTextInfo? text_info;

@ -7065,6 +7065,32 @@ bool Element::IsMouseFocusable(UpdateBehavior update_behavior) const {
return true;
}
bool Element::IsMaybeClickable() {
if (IsClickableControl(this)) {
return true;
}
if (HasActivationBehavior()) {
return true;
}
if (HasJSBasedEventListeners(event_type_names::kClick) ||
HasJSBasedEventListeners(event_type_names::kKeydown) ||
HasJSBasedEventListeners(event_type_names::kKeypress) ||
HasJSBasedEventListeners(event_type_names::kKeyup) ||
HasJSBasedEventListeners(event_type_names::kMouseover) ||
HasJSBasedEventListeners(event_type_names::kMouseenter)) {
return true;
}
if (HasEventListeners(event_type_names::kClick) ||
HasEventListeners(event_type_names::kKeydown) ||
HasEventListeners(event_type_names::kKeypress) ||
HasEventListeners(event_type_names::kKeyup) ||
HasEventListeners(event_type_names::kMouseover) ||
HasEventListeners(event_type_names::kMouseenter)) {
return true;
}
return false;
}
bool Element::IsFocusable(UpdateBehavior update_behavior) const {
return IsFocusableState(update_behavior) != FocusableState::kNotFocusable;
}

@ -1035,6 +1035,14 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
kAssertNoLayoutUpdates,
};
// Whether the element is clickable. This checks for whether the node is
// a clickable control (e.g. form control elements) or has activation
// behavior. It also checks for whether the node has a click handler.
// Note: this should not be taken as a guarantee that the element is
// clickable; this is used as a heuristic to determine whether the element
// is likely to be clickable.
bool IsMaybeClickable();
// Focusability logic:
// IsFocusable: true if the element can be focused via element.focus().
// IsMouseFocusable: true if clicking on the element will focus it.

@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/display_lock/display_lock_document_state.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
@ -37,6 +38,10 @@
#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
#include "ui/gfx/geometry/rect_conversions.h"
#if !BUILDFLAG(IS_ANDROID)
#include "ui/base/cursor/mojom/cursor_type.mojom-blink.h"
#endif // !BUILDFLAG(IS_ANDROID)
namespace blink {
namespace {
@ -61,6 +66,94 @@ bool IsHeadingTag(const HTMLElement& element) {
element.HasTagName(html_names::kH6Tag);
}
#if !BUILDFLAG(IS_ANDROID)
ui::mojom::blink::CursorType GetCursorType(const ComputedStyle& style,
bool is_selectable) {
const auto& cursor = style.Cursor();
const auto& iBeamCursor = style.IsHorizontalWritingMode()
? ui::mojom::blink::CursorType::kIBeam
: ui::mojom::blink::CursorType::kVerticalText;
switch (cursor) {
case ECursor::kNone:
return ui::mojom::blink::CursorType::kNone;
case ECursor::kCopy:
return ui::mojom::blink::CursorType::kCopy;
case ECursor::kAuto:
if (is_selectable) {
return iBeamCursor;
}
return ui::mojom::blink::CursorType::kPointer;
case ECursor::kCrosshair:
return ui::mojom::blink::CursorType::kCross;
case ECursor::kDefault:
return ui::mojom::blink::CursorType::kPointer;
case ECursor::kPointer:
return ui::mojom::blink::CursorType::kPointer;
case ECursor::kMove:
return ui::mojom::blink::CursorType::kMove;
case ECursor::kVerticalText:
return ui::mojom::blink::CursorType::kVerticalText;
case ECursor::kCell:
return ui::mojom::blink::CursorType::kCell;
case ECursor::kContextMenu:
return ui::mojom::blink::CursorType::kContextMenu;
case ECursor::kAlias:
return ui::mojom::blink::CursorType::kAlias;
case ECursor::kProgress:
return ui::mojom::blink::CursorType::kProgress;
case ECursor::kNoDrop:
return ui::mojom::blink::CursorType::kNoDrop;
case ECursor::kNotAllowed:
return ui::mojom::blink::CursorType::kNotAllowed;
case ECursor::kZoomIn:
return ui::mojom::blink::CursorType::kZoomIn;
case ECursor::kZoomOut:
return ui::mojom::blink::CursorType::kZoomOut;
case ECursor::kEResize:
return ui::mojom::blink::CursorType::kEastResize;
case ECursor::kNeResize:
return ui::mojom::blink::CursorType::kNorthEastResize;
case ECursor::kNwResize:
return ui::mojom::blink::CursorType::kNorthWestResize;
case ECursor::kNResize:
return ui::mojom::blink::CursorType::kNorthResize;
case ECursor::kSeResize:
return ui::mojom::blink::CursorType::kSouthEastResize;
case ECursor::kSwResize:
return ui::mojom::blink::CursorType::kSouthWestResize;
case ECursor::kSResize:
return ui::mojom::blink::CursorType::kSouthResize;
case ECursor::kWResize:
return ui::mojom::blink::CursorType::kWestResize;
case ECursor::kEwResize:
return ui::mojom::blink::CursorType::kEastWestResize;
case ECursor::kNsResize:
return ui::mojom::blink::CursorType::kNorthSouthResize;
case ECursor::kNeswResize:
return ui::mojom::blink::CursorType::kNorthEastSouthWestResize;
case ECursor::kNwseResize:
return ui::mojom::blink::CursorType::kNorthWestSouthEastResize;
case ECursor::kColResize:
return ui::mojom::blink::CursorType::kColumnResize;
case ECursor::kRowResize:
return ui::mojom::blink::CursorType::kRowResize;
case ECursor::kText:
return iBeamCursor;
case ECursor::kWait:
return ui::mojom::blink::CursorType::kWait;
case ECursor::kHelp:
return ui::mojom::blink::CursorType::kHelp;
case ECursor::kAllScroll:
return ui::mojom::blink::CursorType::kMove;
case ECursor::kGrab:
return ui::mojom::blink::CursorType::kGrab;
case ECursor::kGrabbing:
return ui::mojom::blink::CursorType::kGrabbing;
}
NOTREACHED();
}
#endif // !BUILDFLAG(IS_ANDROID)
mojom::blink::AIPageContentAnchorRel GetAnchorRel(const AtomicString& rel) {
if (rel == "noopener") {
return mojom::blink::AIPageContentAnchorRel::kRelationNoOpener;
@ -773,7 +866,8 @@ AIPageContentAgent::ContentBuilder::MaybeGenerateContentNode(
auto content_node = mojom::blink::AIPageContentNode::New();
content_node->content_attributes =
mojom::blink::AIPageContentAttributes::New();
auto& attributes = *content_node->content_attributes;
mojom::blink::AIPageContentAttributes& attributes =
*content_node->content_attributes;
AddAnnotatedRoles(object, attributes.annotated_roles);
// Set the attribute type and add any special attributes if the attribute type
@ -853,6 +947,8 @@ AIPageContentAgent::ContentBuilder::MaybeGenerateContentNode(
AddNodeGeometry(object, attributes);
AddNodeInteractionInfo(object, attributes);
return content_node;
}
@ -875,7 +971,7 @@ void AIPageContentAgent::ContentBuilder::AddNodeGeometry(
}
attributes.geometry = mojom::blink::AIPageContentGeometry::New();
auto& geometry = *attributes.geometry;
mojom::blink::AIPageContentGeometry& geometry = *attributes.geometry;
geometry.outer_bounding_box =
object.AbsoluteBoundingBoxRect(kMapCoordinatesFlags);
@ -889,8 +985,45 @@ void AIPageContentAgent::ContentBuilder::AddNodeGeometry(
geometry.is_fixed_or_sticky_position =
object.Style()->GetPosition() == EPosition::kFixed ||
object.Style()->GetPosition() == EPosition::kSticky;
geometry.scrolls_overflow_x = object.Style()->ScrollsOverflowX();
geometry.scrolls_overflow_y = object.Style()->ScrollsOverflowY();
}
void AIPageContentAgent::ContentBuilder::AddNodeInteractionInfo(
const LayoutObject& object,
mojom::blink::AIPageContentAttributes& attributes) const {
attributes.interaction_info =
mojom::blink::AIPageContentInteractionInfo::New();
mojom::blink::AIPageContentInteractionInfo& interaction_info =
*attributes.interaction_info;
const ComputedStyle& style = *object.Style();
interaction_info.scrolls_overflow_x = style.ScrollsOverflowX();
interaction_info.scrolls_overflow_y = style.ScrollsOverflowY();
bool is_selectable = object.IsSelectable();
interaction_info.is_selectable = is_selectable;
#if !BUILDFLAG(IS_ANDROID)
interaction_info.cursor_type = GetCursorType(style, is_selectable);
#endif // !BUILDFLAG(IS_ANDROID)
if (auto* node = object.GetNode()) {
interaction_info.is_editable = IsEditable(*node);
}
if (auto* box = DynamicTo<LayoutBox>(object)) {
if (box->CanResize()) {
EResize resize = style.UsedResize();
interaction_info.can_resize_vertical =
resize == EResize::kVertical || resize == EResize::kBoth;
interaction_info.can_resize_horizontal =
resize == EResize::kHorizontal || resize == EResize::kBoth;
}
}
if (auto* element = DynamicTo<HTMLElement>(object.GetNode())) {
interaction_info.is_focusable = element->IsFocusable();
interaction_info.is_focused = element->IsFocused();
interaction_info.is_draggable = element->draggable();
interaction_info.is_clickable = element->IsMaybeClickable();
}
}
} // namespace blink

@ -88,6 +88,9 @@ class MODULES_EXPORT AIPageContentAgent final
void AddNodeGeometry(
const LayoutObject& object,
mojom::blink::AIPageContentAttributes& attributes) const;
void AddNodeInteractionInfo(
const LayoutObject& object,
mojom::blink::AIPageContentAttributes& attributes) const;
const raw_ref<const mojom::blink::AIPageContentOptions> options_;
};

@ -42,7 +42,7 @@ class AIPageContentAgentTest : public testing::Test {
~AIPageContentAgentTest() override = default;
void SetUp() override {
helper_.Initialize();
helper_.InitializeWithSettings(&UpdateWebSettings);
helper_.Resize(kWindowSize);
ASSERT_TRUE(helper_.LocalMainFrame());
}
@ -246,6 +246,11 @@ class AIPageContentAgentTest : public testing::Test {
const mojom::blink::AIPageContentOptions default_options_;
test::TaskEnvironment task_environment_;
frame_test_helpers::WebViewHelper helper_;
private:
static void UpdateWebSettings(WebSettings* settings) {
settings->SetTextAreasAreResizable(true);
}
};
TEST_F(AIPageContentAgentTest, Basic) {
@ -1073,8 +1078,10 @@ TEST_F(AIPageContentAgentTest, FixedPosition) {
CheckContainerNode(fixed_element);
EXPECT_TRUE(
fixed_element.content_attributes->geometry->is_fixed_or_sticky_position);
EXPECT_FALSE(fixed_element.content_attributes->geometry->scrolls_overflow_x);
EXPECT_FALSE(fixed_element.content_attributes->geometry->scrolls_overflow_y);
EXPECT_FALSE(
fixed_element.content_attributes->interaction_info->scrolls_overflow_x);
EXPECT_FALSE(
fixed_element.content_attributes->interaction_info->scrolls_overflow_y);
CheckTextNode(*fixed_element.children_nodes[0],
"This element stays in place when the page is scrolled.");
@ -1082,16 +1089,20 @@ TEST_F(AIPageContentAgentTest, FixedPosition) {
CheckContainerNode(sticky_element);
EXPECT_TRUE(
sticky_element.content_attributes->geometry->is_fixed_or_sticky_position);
EXPECT_FALSE(sticky_element.content_attributes->geometry->scrolls_overflow_x);
EXPECT_FALSE(sticky_element.content_attributes->geometry->scrolls_overflow_y);
EXPECT_FALSE(
sticky_element.content_attributes->interaction_info->scrolls_overflow_x);
EXPECT_FALSE(
sticky_element.content_attributes->interaction_info->scrolls_overflow_y);
CheckTextNode(*sticky_element.children_nodes[0],
"This element stays in place when the page is scrolled.");
const auto& normal_element = *root.children_nodes[2];
EXPECT_FALSE(
normal_element.content_attributes->geometry->is_fixed_or_sticky_position);
EXPECT_FALSE(normal_element.content_attributes->geometry->scrolls_overflow_x);
EXPECT_FALSE(normal_element.content_attributes->geometry->scrolls_overflow_y);
EXPECT_FALSE(
normal_element.content_attributes->interaction_info->scrolls_overflow_x);
EXPECT_FALSE(
normal_element.content_attributes->interaction_info->scrolls_overflow_y);
CheckTextNode(normal_element,
"This element flows naturally with the document.");
}
@ -1157,17 +1168,17 @@ TEST_F(AIPageContentAgentTest, ScrollContainer) {
const auto& root = *content->root_node;
ASSERT_EQ(root.children_nodes.size(), 4u);
EXPECT_TRUE(root.content_attributes->geometry->scrolls_overflow_x);
EXPECT_TRUE(root.content_attributes->geometry->scrolls_overflow_y);
EXPECT_TRUE(root.content_attributes->interaction_info->scrolls_overflow_x);
EXPECT_TRUE(root.content_attributes->interaction_info->scrolls_overflow_y);
const auto& scrollable_x_element = *root.children_nodes[0];
CheckContainerNode(scrollable_x_element);
EXPECT_FALSE(scrollable_x_element.content_attributes->geometry
->is_fixed_or_sticky_position);
EXPECT_TRUE(
scrollable_x_element.content_attributes->geometry->scrolls_overflow_x);
EXPECT_FALSE(
scrollable_x_element.content_attributes->geometry->scrolls_overflow_y);
EXPECT_TRUE(scrollable_x_element.content_attributes->interaction_info
->scrolls_overflow_x);
EXPECT_FALSE(scrollable_x_element.content_attributes->interaction_info
->scrolls_overflow_y);
CheckTextNode(
*scrollable_x_element.children_nodes[0],
"ABCDEFGHIJKLMOPQRSTUVWXYZABCDEFGHIJKLMOPQRSTUVWXYZABCDEFGHIJKLMOPQRSTUVW"
@ -1178,10 +1189,10 @@ TEST_F(AIPageContentAgentTest, ScrollContainer) {
CheckContainerNode(scrollable_y_element);
EXPECT_FALSE(scrollable_y_element.content_attributes->geometry
->is_fixed_or_sticky_position);
EXPECT_FALSE(
scrollable_y_element.content_attributes->geometry->scrolls_overflow_x);
EXPECT_TRUE(
scrollable_y_element.content_attributes->geometry->scrolls_overflow_y);
EXPECT_FALSE(scrollable_y_element.content_attributes->interaction_info
->scrolls_overflow_x);
EXPECT_TRUE(scrollable_y_element.content_attributes->interaction_info
->scrolls_overflow_y);
CheckTextNode(*scrollable_y_element.children_nodes[0],
"Some long text to make it scrollable. Some long text to make "
"it scrollable. Some long text to make it scrollable. Some "
@ -1191,10 +1202,10 @@ TEST_F(AIPageContentAgentTest, ScrollContainer) {
CheckContainerNode(auto_scroll_x_element);
EXPECT_FALSE(auto_scroll_x_element.content_attributes->geometry
->is_fixed_or_sticky_position);
EXPECT_TRUE(
auto_scroll_x_element.content_attributes->geometry->scrolls_overflow_x);
EXPECT_FALSE(
auto_scroll_x_element.content_attributes->geometry->scrolls_overflow_y);
EXPECT_TRUE(auto_scroll_x_element.content_attributes->interaction_info
->scrolls_overflow_x);
EXPECT_FALSE(auto_scroll_x_element.content_attributes->interaction_info
->scrolls_overflow_y);
CheckTextNode(
*auto_scroll_x_element.children_nodes[0],
"ABCDEFGHIJKLMOPQRSTUVWXYZABCDEFGHIJKLMOPQRSTUVWXYZABCDEFGHIJKLMOPQRSTUVW"
@ -1205,10 +1216,10 @@ TEST_F(AIPageContentAgentTest, ScrollContainer) {
CheckContainerNode(auto_scroll_y_element);
EXPECT_FALSE(auto_scroll_y_element.content_attributes->geometry
->is_fixed_or_sticky_position);
EXPECT_FALSE(
auto_scroll_y_element.content_attributes->geometry->scrolls_overflow_x);
EXPECT_TRUE(
auto_scroll_y_element.content_attributes->geometry->scrolls_overflow_y);
EXPECT_FALSE(auto_scroll_y_element.content_attributes->interaction_info
->scrolls_overflow_x);
EXPECT_TRUE(auto_scroll_y_element.content_attributes->interaction_info
->scrolls_overflow_y);
CheckTextNode(*auto_scroll_y_element.children_nodes[0],
"Some long text to make it scrollable. Some long text to make "
"it scrollable. Some long text to make it scrollable. Some "
@ -1896,5 +1907,115 @@ TEST_F(AIPageContentAgentTest, FormWithRadio) {
CheckTextNode(*form.children_nodes[3], "I have a car");
}
TEST_F(AIPageContentAgentTest, InteractiveElements) {
frame_test_helpers::LoadHTMLString(
helper_.LocalMainFrame(),
"<body>"
" <style>"
" div {"
" resize: both;"
" overflow: auto;"
" border: 1px solid black;"
" width: 200px;"
" }"
" </style>"
" <textarea>text</textarea>"
" <button>button</button>"
" <div>resize</div>"
"</body>",
url_test_helpers::ToKURL("http://foobar.com"));
auto content = GetAIPageContent();
ASSERT_TRUE(content);
ASSERT_TRUE(content->root_node);
const auto& root = *content->root_node;
EXPECT_EQ(root.children_nodes.size(), 3u);
const auto& text_area = *root.children_nodes[0];
CheckFormControlNode(text_area, mojom::blink::FormControlType::kTextArea);
EXPECT_TRUE(text_area.content_attributes->interaction_info->is_selectable);
EXPECT_FALSE(text_area.content_attributes->interaction_info->is_editable);
EXPECT_TRUE(text_area.content_attributes->interaction_info->is_focusable);
EXPECT_FALSE(text_area.content_attributes->interaction_info->is_focused);
EXPECT_FALSE(text_area.content_attributes->interaction_info->is_draggable);
EXPECT_TRUE(text_area.content_attributes->interaction_info->is_clickable);
EXPECT_TRUE(
text_area.content_attributes->interaction_info->can_resize_vertical);
EXPECT_TRUE(
text_area.content_attributes->interaction_info->can_resize_horizontal);
EXPECT_EQ(text_area.children_nodes.size(), 1u);
const auto& text_area_text = *text_area.children_nodes[0];
CheckTextNode(text_area_text, "text");
EXPECT_TRUE(
text_area_text.content_attributes->interaction_info->is_selectable);
EXPECT_TRUE(text_area_text.content_attributes->interaction_info->is_editable);
EXPECT_FALSE(
text_area_text.content_attributes->interaction_info->is_focusable);
EXPECT_FALSE(text_area_text.content_attributes->interaction_info->is_focused);
EXPECT_FALSE(
text_area_text.content_attributes->interaction_info->is_draggable);
EXPECT_FALSE(
text_area_text.content_attributes->interaction_info->is_clickable);
EXPECT_FALSE(
text_area_text.content_attributes->interaction_info->can_resize_vertical);
EXPECT_FALSE(text_area_text.content_attributes->interaction_info
->can_resize_horizontal);
const auto& button = *root.children_nodes[1];
CheckFormControlNode(button, mojom::blink::FormControlType::kButtonSubmit);
EXPECT_TRUE(button.content_attributes->interaction_info->is_selectable);
EXPECT_FALSE(button.content_attributes->interaction_info->is_editable);
EXPECT_TRUE(button.content_attributes->interaction_info->is_focusable);
EXPECT_FALSE(button.content_attributes->interaction_info->is_focused);
EXPECT_FALSE(button.content_attributes->interaction_info->is_draggable);
EXPECT_TRUE(button.content_attributes->interaction_info->is_clickable);
EXPECT_FALSE(
button.content_attributes->interaction_info->can_resize_vertical);
EXPECT_FALSE(
button.content_attributes->interaction_info->can_resize_horizontal);
EXPECT_EQ(button.children_nodes.size(), 1u);
const auto& button_text = *button.children_nodes[0];
CheckTextNode(button_text, "button");
EXPECT_TRUE(button_text.content_attributes->interaction_info->is_selectable);
EXPECT_FALSE(button_text.content_attributes->interaction_info->is_editable);
EXPECT_FALSE(button_text.content_attributes->interaction_info->is_focusable);
EXPECT_FALSE(button_text.content_attributes->interaction_info->is_focused);
EXPECT_FALSE(button_text.content_attributes->interaction_info->is_draggable);
EXPECT_FALSE(button_text.content_attributes->interaction_info->is_clickable);
EXPECT_FALSE(
button_text.content_attributes->interaction_info->can_resize_vertical);
EXPECT_FALSE(
button_text.content_attributes->interaction_info->can_resize_horizontal);
const auto& resize = *root.children_nodes[2];
CheckContainerNode(resize);
EXPECT_TRUE(resize.content_attributes->interaction_info->is_selectable);
EXPECT_FALSE(resize.content_attributes->interaction_info->is_editable);
EXPECT_FALSE(resize.content_attributes->interaction_info->is_focusable);
EXPECT_FALSE(resize.content_attributes->interaction_info->is_focused);
EXPECT_FALSE(resize.content_attributes->interaction_info->is_draggable);
EXPECT_FALSE(resize.content_attributes->interaction_info->is_clickable);
EXPECT_TRUE(resize.content_attributes->interaction_info->can_resize_vertical);
EXPECT_TRUE(
resize.content_attributes->interaction_info->can_resize_horizontal);
EXPECT_EQ(resize.children_nodes.size(), 1u);
const auto& resize_text = *resize.children_nodes[0];
CheckTextNode(resize_text, "resize");
EXPECT_TRUE(resize_text.content_attributes->interaction_info->is_selectable);
EXPECT_FALSE(resize_text.content_attributes->interaction_info->is_editable);
EXPECT_FALSE(resize_text.content_attributes->interaction_info->is_focusable);
EXPECT_FALSE(resize_text.content_attributes->interaction_info->is_focused);
EXPECT_FALSE(resize_text.content_attributes->interaction_info->is_draggable);
EXPECT_FALSE(resize_text.content_attributes->interaction_info->is_clickable);
EXPECT_FALSE(
resize_text.content_attributes->interaction_info->can_resize_vertical);
EXPECT_FALSE(
resize_text.content_attributes->interaction_info->can_resize_horizontal);
}
} // namespace
} // namespace blink