123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ui/accessibility/ax_range.h"
- #include <memory>
- #include <string>
- #include <vector>
- #include "base/memory/raw_ptr.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "ui/accessibility/ax_enums.mojom.h"
- #include "ui/accessibility/ax_node.h"
- #include "ui/accessibility/ax_node_data.h"
- #include "ui/accessibility/ax_node_position.h"
- #include "ui/accessibility/ax_tree.h"
- #include "ui/accessibility/ax_tree_id.h"
- #include "ui/accessibility/ax_tree_update.h"
- #include "ui/accessibility/test_ax_node_helper.h"
- #include "ui/accessibility/test_ax_tree_manager.h"
- namespace ui {
- using TestPositionInstance =
- std::unique_ptr<AXPosition<AXNodePosition, AXNode>>;
- using TestPositionRange = AXRange<AXPosition<AXNodePosition, AXNode>>;
- namespace {
- constexpr AXNodeID ROOT_ID = 1;
- constexpr AXNodeID DIV1_ID = 2;
- constexpr AXNodeID BUTTON_ID = 3;
- constexpr AXNodeID DIV2_ID = 4;
- constexpr AXNodeID CHECK_BOX1_ID = 5;
- constexpr AXNodeID CHECK_BOX2_ID = 6;
- constexpr AXNodeID TEXT_FIELD_ID = 7;
- constexpr AXNodeID STATIC_TEXT1_ID = 8;
- constexpr AXNodeID INLINE_BOX1_ID = 9;
- constexpr AXNodeID LINE_BREAK1_ID = 10;
- constexpr AXNodeID INLINE_BOX_LINE_BREAK1_ID = 11;
- constexpr AXNodeID STATIC_TEXT2_ID = 12;
- constexpr AXNodeID INLINE_BOX2_ID = 13;
- constexpr AXNodeID LINE_BREAK2_ID = 14;
- constexpr AXNodeID INLINE_BOX_LINE_BREAK2_ID = 15;
- constexpr AXNodeID PARAGRAPH_ID = 16;
- constexpr AXNodeID STATIC_TEXT3_ID = 17;
- constexpr AXNodeID INLINE_BOX3_ID = 18;
- constexpr AXNodeID EMPTY_PARAGRAPH_ID = 19;
- class TestAXRangeScreenRectDelegate : public AXRangeRectDelegate {
- public:
- explicit TestAXRangeScreenRectDelegate(TestAXTreeManager* tree_manager)
- : tree_manager_(tree_manager) {}
- virtual ~TestAXRangeScreenRectDelegate() = default;
- TestAXRangeScreenRectDelegate(const TestAXRangeScreenRectDelegate& delegate) =
- delete;
- TestAXRangeScreenRectDelegate& operator=(
- const TestAXRangeScreenRectDelegate& delegate) = delete;
- gfx::Rect GetInnerTextRangeBoundsRect(
- AXTreeID tree_id,
- AXNodeID node_id,
- int start_offset,
- int end_offset,
- const ui::AXClippingBehavior clipping_behavior,
- AXOffscreenResult* offscreen_result) override {
- if (tree_manager_->GetTreeID() != tree_id)
- return gfx::Rect();
- AXNode* node = tree_manager_->GetNodeFromTree(node_id);
- if (!node)
- return gfx::Rect();
- TestAXNodeHelper* wrapper =
- TestAXNodeHelper::GetOrCreate(tree_manager_->GetTree(), node);
- return wrapper->GetInnerTextRangeBoundsRect(
- start_offset, end_offset, AXCoordinateSystem::kScreenDIPs,
- clipping_behavior, offscreen_result);
- }
- gfx::Rect GetBoundsRect(AXTreeID tree_id,
- AXNodeID node_id,
- AXOffscreenResult* offscreen_result) override {
- if (tree_manager_->GetTreeID() != tree_id)
- return gfx::Rect();
- AXNode* node = tree_manager_->GetNodeFromTree(node_id);
- if (!node)
- return gfx::Rect();
- TestAXNodeHelper* wrapper =
- TestAXNodeHelper::GetOrCreate(tree_manager_->GetTree(), node);
- return wrapper->GetBoundsRect(AXCoordinateSystem::kScreenDIPs,
- AXClippingBehavior::kClipped,
- offscreen_result);
- }
- private:
- const raw_ptr<TestAXTreeManager> tree_manager_;
- };
- class AXRangeTest : public ::testing::Test, public TestAXTreeManager {
- public:
- const std::u16string EMPTY = u"";
- const std::u16string NEWLINE = u"\n";
- const std::u16string BUTTON = u"Button";
- const std::u16string LINE_1 = u"Line 1";
- const std::u16string LINE_2 = u"Line 2";
- const std::u16string TEXT_FIELD =
- LINE_1.substr().append(NEWLINE).append(LINE_2).append(NEWLINE);
- const std::u16string AFTER_LINE = u"After";
- const std::u16string ALL_TEXT =
- BUTTON.substr().append(TEXT_FIELD).append(AFTER_LINE);
- AXRangeTest();
- AXRangeTest(const AXRangeTest&) = delete;
- AXRangeTest& operator=(const AXRangeTest&) = delete;
- ~AXRangeTest() override = default;
- protected:
- void SetUp() override;
- AXNodeData root_;
- AXNodeData div1_;
- AXNodeData div2_;
- AXNodeData button_;
- AXNodeData check_box1_;
- AXNodeData check_box2_;
- AXNodeData text_field_;
- AXNodeData line_break1_;
- AXNodeData line_break2_;
- AXNodeData static_text1_;
- AXNodeData static_text2_;
- AXNodeData static_text3_;
- AXNodeData inline_box1_;
- AXNodeData inline_box2_;
- AXNodeData inline_box3_;
- AXNodeData inline_box_line_break1_;
- AXNodeData inline_box_line_break2_;
- AXNodeData paragraph_;
- AXNodeData empty_paragraph_;
- private:
- ScopedAXEmbeddedObjectBehaviorSetter ax_embedded_object_behavior_;
- };
- // These tests use kSuppressCharacter behavior.
- AXRangeTest::AXRangeTest()
- : ax_embedded_object_behavior_(
- AXEmbeddedObjectBehavior::kSuppressCharacter) {}
- void AXRangeTest::SetUp() {
- // Set up the AXTree for the following content:
- // ++1 Role::kDialog
- // ++++2 Role::kGenericContainer
- // ++++++3 Role::kButton, name="Button"
- // ++++++4 Role::kGenericContainer
- // ++++++++5 Role::kCheckBox, name="Checkbox 1"
- // ++++++++6 Role::kCheckBox, name="Checkbox 2"
- // ++++7 Role::kTextField
- // ++++++8 Role::kStaticText, name="Line 1"
- // ++++++++9 Role::kInlineTextBox, name="Line 1"
- // ++++++10 Role::kLineBreak, name="\n"
- // ++++++++11 Role::kInlineTextBox, name="\n"
- // ++++++12 Role::kStaticText, name="Line 2"
- // ++++++++13 Role::kInlineTextBox, name="Line 2"
- // ++++++14 Role::kLineBreak, name="\n"
- // ++++++++15 Role::kInlineTextBox, name="\n"
- // ++++16 Role::kParagraph
- // ++++++17 Role::kStaticText, name="After"
- // ++++++++18 Role::kInlineTextBox, name="After"
- // ++++19 Role::kParagraph, IGNORED
- //
- // [Root]
- // {0, 0, 800, 600}
- //
- // [Button] [Checkbox 1] [Checkbox 2]
- // {20, 20, 100x30}, {120, 20, 30x30} {150, 20, 30x30}
- //
- // [Line 1] [\n]
- // {20, 50, 30x30} {50, 50, 0x30}
- //
- // [Line 2] [\n]
- // {20, 80, 42x30} {62, 80, 0x30}
- //
- // [After]
- // {20, 110, 50x30}
- //
- // [Empty paragraph]
- // {20, 140, 700, 0}
- root_.id = ROOT_ID;
- div1_.id = DIV1_ID;
- div2_.id = DIV2_ID;
- button_.id = BUTTON_ID;
- check_box1_.id = CHECK_BOX1_ID;
- check_box2_.id = CHECK_BOX2_ID;
- text_field_.id = TEXT_FIELD_ID;
- line_break1_.id = LINE_BREAK1_ID;
- line_break2_.id = LINE_BREAK2_ID;
- static_text1_.id = STATIC_TEXT1_ID;
- static_text2_.id = STATIC_TEXT2_ID;
- static_text3_.id = STATIC_TEXT3_ID;
- inline_box1_.id = INLINE_BOX1_ID;
- inline_box2_.id = INLINE_BOX2_ID;
- inline_box3_.id = INLINE_BOX3_ID;
- inline_box_line_break1_.id = INLINE_BOX_LINE_BREAK1_ID;
- inline_box_line_break2_.id = INLINE_BOX_LINE_BREAK2_ID;
- paragraph_.id = PARAGRAPH_ID;
- empty_paragraph_.id = EMPTY_PARAGRAPH_ID;
- root_.role = ax::mojom::Role::kDialog;
- root_.AddState(ax::mojom::State::kFocusable);
- root_.SetName(ALL_TEXT);
- root_.relative_bounds.bounds = gfx::RectF(0, 0, 800, 600);
- div1_.role = ax::mojom::Role::kGenericContainer;
- div1_.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
- div1_.child_ids.push_back(button_.id);
- div1_.child_ids.push_back(div2_.id);
- root_.child_ids.push_back(div1_.id);
- button_.role = ax::mojom::Role::kButton;
- button_.SetHasPopup(ax::mojom::HasPopup::kMenu);
- button_.SetName("Button");
- button_.SetNameFrom(ax::mojom::NameFrom::kValue);
- button_.SetValue("Button");
- button_.relative_bounds.bounds = gfx::RectF(20, 20, 100, 30);
- button_.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
- check_box1_.id);
- div2_.role = ax::mojom::Role::kGenericContainer;
- div2_.child_ids.push_back(check_box1_.id);
- div2_.child_ids.push_back(check_box2_.id);
- check_box1_.role = ax::mojom::Role::kCheckBox;
- check_box1_.SetCheckedState(ax::mojom::CheckedState::kTrue);
- check_box1_.SetName("Checkbox 1");
- check_box1_.relative_bounds.bounds = gfx::RectF(120, 20, 30, 30);
- check_box1_.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId,
- button_.id);
- check_box1_.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
- check_box2_.id);
- check_box2_.role = ax::mojom::Role::kCheckBox;
- check_box2_.SetCheckedState(ax::mojom::CheckedState::kTrue);
- check_box2_.SetName("Checkbox 2");
- check_box2_.relative_bounds.bounds = gfx::RectF(150, 20, 30, 30);
- check_box2_.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId,
- check_box1_.id);
- text_field_.role = ax::mojom::Role::kTextField;
- text_field_.AddState(ax::mojom::State::kEditable);
- text_field_.SetValue(TEXT_FIELD);
- text_field_.AddIntListAttribute(ax::mojom::IntListAttribute::kLineStarts,
- std::vector<int32_t>{0, 7});
- text_field_.child_ids.push_back(static_text1_.id);
- text_field_.child_ids.push_back(line_break1_.id);
- text_field_.child_ids.push_back(static_text2_.id);
- text_field_.child_ids.push_back(line_break2_.id);
- root_.child_ids.push_back(text_field_.id);
- static_text1_.role = ax::mojom::Role::kStaticText;
- static_text1_.AddState(ax::mojom::State::kEditable);
- static_text1_.SetName(LINE_1);
- static_text1_.child_ids.push_back(inline_box1_.id);
- inline_box1_.role = ax::mojom::Role::kInlineTextBox;
- inline_box1_.AddState(ax::mojom::State::kEditable);
- inline_box1_.SetName(LINE_1);
- inline_box1_.relative_bounds.bounds = gfx::RectF(20, 50, 30, 30);
- std::vector<int32_t> character_offsets1;
- // The width of each character is 5px.
- character_offsets1.push_back(25); // "L" {20, 50, 5x30}
- character_offsets1.push_back(30); // "i" {25, 50, 5x30}
- character_offsets1.push_back(35); // "n" {30, 50, 5x30}
- character_offsets1.push_back(40); // "e" {35, 50, 5x30}
- character_offsets1.push_back(45); // " " {40, 50, 5x30}
- character_offsets1.push_back(50); // "1" {45, 50, 5x30}
- inline_box1_.AddIntListAttribute(
- ax::mojom::IntListAttribute::kCharacterOffsets, character_offsets1);
- inline_box1_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts,
- std::vector<int32_t>{0, 5});
- inline_box1_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds,
- std::vector<int32_t>{4, 6});
- inline_box1_.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
- line_break1_.id);
- line_break1_.role = ax::mojom::Role::kLineBreak;
- line_break1_.AddState(ax::mojom::State::kEditable);
- line_break1_.SetName(NEWLINE);
- line_break1_.relative_bounds.bounds = gfx::RectF(50, 50, 0, 30);
- line_break1_.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId,
- inline_box1_.id);
- line_break1_.child_ids.push_back(inline_box_line_break1_.id);
- inline_box_line_break1_.role = ax::mojom::Role::kInlineTextBox;
- inline_box_line_break1_.AddBoolAttribute(
- ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
- inline_box_line_break1_.SetName(NEWLINE);
- inline_box_line_break1_.relative_bounds.bounds = gfx::RectF(50, 50, 0, 30);
- inline_box_line_break1_.AddIntListAttribute(
- ax::mojom::IntListAttribute::kCharacterOffsets, {0});
- inline_box_line_break1_.AddIntListAttribute(
- ax::mojom::IntListAttribute::kWordStarts, std::vector<int32_t>{0});
- inline_box_line_break1_.AddIntListAttribute(
- ax::mojom::IntListAttribute::kWordEnds, std::vector<int32_t>{0});
- static_text2_.role = ax::mojom::Role::kStaticText;
- static_text2_.AddState(ax::mojom::State::kEditable);
- static_text2_.SetName(LINE_2);
- static_text2_.child_ids.push_back(inline_box2_.id);
- inline_box2_.role = ax::mojom::Role::kInlineTextBox;
- inline_box2_.AddState(ax::mojom::State::kEditable);
- inline_box2_.SetName(LINE_2);
- inline_box2_.relative_bounds.bounds = gfx::RectF(20, 80, 42, 30);
- std::vector<int32_t> character_offsets2;
- // The width of each character is 7 px.
- character_offsets2.push_back(27); // "L" {20, 80, 7x30}
- character_offsets2.push_back(34); // "i" {27, 80, 7x30}
- character_offsets2.push_back(41); // "n" {34, 80, 7x30}
- character_offsets2.push_back(48); // "e" {41, 80, 7x30}
- character_offsets2.push_back(55); // " " {48, 80, 7x30}
- character_offsets2.push_back(62); // "2" {55, 80, 7x30}
- inline_box2_.AddIntListAttribute(
- ax::mojom::IntListAttribute::kCharacterOffsets, character_offsets2);
- inline_box2_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts,
- std::vector<int32_t>{0, 5});
- inline_box2_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds,
- std::vector<int32_t>{4, 6});
- inline_box2_.AddIntAttribute(ax::mojom::IntAttribute::kNextOnLineId,
- line_break2_.id);
- line_break2_.role = ax::mojom::Role::kLineBreak;
- line_break2_.AddState(ax::mojom::State::kEditable);
- line_break2_.SetName(NEWLINE);
- line_break2_.relative_bounds.bounds = gfx::RectF(62, 80, 0, 30);
- line_break2_.AddIntAttribute(ax::mojom::IntAttribute::kPreviousOnLineId,
- inline_box2_.id);
- line_break2_.child_ids.push_back(inline_box_line_break2_.id);
- inline_box_line_break2_.role = ax::mojom::Role::kInlineTextBox;
- inline_box_line_break2_.AddBoolAttribute(
- ax::mojom::BoolAttribute::kIsLineBreakingObject, true);
- inline_box_line_break2_.SetName(NEWLINE);
- inline_box_line_break2_.relative_bounds.bounds = gfx::RectF(62, 80, 0, 30);
- inline_box_line_break2_.AddIntListAttribute(
- ax::mojom::IntListAttribute::kCharacterOffsets, {0});
- inline_box_line_break2_.AddIntListAttribute(
- ax::mojom::IntListAttribute::kWordStarts, std::vector<int32_t>{0});
- inline_box_line_break2_.AddIntListAttribute(
- ax::mojom::IntListAttribute::kWordEnds, std::vector<int32_t>{0});
- paragraph_.role = ax::mojom::Role::kParagraph;
- paragraph_.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
- true);
- paragraph_.child_ids.push_back(static_text3_.id);
- root_.child_ids.push_back(paragraph_.id);
- static_text3_.role = ax::mojom::Role::kStaticText;
- static_text3_.SetName(AFTER_LINE);
- static_text3_.child_ids.push_back(inline_box3_.id);
- inline_box3_.role = ax::mojom::Role::kInlineTextBox;
- inline_box3_.SetName(AFTER_LINE);
- inline_box3_.relative_bounds.bounds = gfx::RectF(20, 110, 50, 30);
- std::vector<int32_t> character_offsets3;
- // The width of each character is 10 px.
- character_offsets3.push_back(30); // "A" {20, 110, 10x30}
- character_offsets3.push_back(40); // "f" {30, 110, 10x30}
- character_offsets3.push_back(50); // "t" {40, 110, 10x30}
- character_offsets3.push_back(60); // "e" {50, 110, 10x30}
- character_offsets3.push_back(70); // "r" {60, 110, 10x30}
- inline_box3_.AddIntListAttribute(
- ax::mojom::IntListAttribute::kCharacterOffsets, character_offsets3);
- inline_box3_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordStarts,
- std::vector<int32_t>{0});
- inline_box3_.AddIntListAttribute(ax::mojom::IntListAttribute::kWordEnds,
- std::vector<int32_t>{5});
- empty_paragraph_.role = ax::mojom::Role::kParagraph;
- empty_paragraph_.AddState(ax::mojom::State::kIgnored);
- empty_paragraph_.relative_bounds.bounds = gfx::RectF(20, 140, 700, 0);
- root_.child_ids.push_back(empty_paragraph_.id);
- AXTreeUpdate initial_state;
- initial_state.root_id = 1;
- initial_state.nodes = {root_,
- div1_,
- button_,
- div2_,
- check_box1_,
- check_box2_,
- text_field_,
- static_text1_,
- inline_box1_,
- line_break1_,
- inline_box_line_break1_,
- static_text2_,
- inline_box2_,
- line_break2_,
- inline_box_line_break2_,
- paragraph_,
- static_text3_,
- inline_box3_,
- empty_paragraph_};
- initial_state.has_tree_data = true;
- initial_state.tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
- initial_state.tree_data.title = "Dialog title";
- SetTree(std::make_unique<AXTree>(initial_state));
- }
- } // namespace
- TEST_F(AXRangeTest, RangeOfContents) {
- const AXNode* root = GetNodeFromTree(ROOT_ID);
- const TestPositionRange root_range =
- TestPositionRange::RangeOfContents(*root);
- const AXNode* text_field = GetNodeFromTree(TEXT_FIELD_ID);
- const TestPositionRange text_field_range =
- TestPositionRange::RangeOfContents(*text_field);
- const AXNode* static_text = GetNodeFromTree(STATIC_TEXT1_ID);
- const TestPositionRange static_text_range =
- TestPositionRange::RangeOfContents(*static_text);
- const AXNode* inline_box = GetNodeFromTree(INLINE_BOX1_ID);
- const TestPositionRange inline_box_range =
- TestPositionRange::RangeOfContents(*inline_box);
- EXPECT_TRUE(root_range.anchor()->IsTreePosition());
- EXPECT_EQ(root_range.anchor()->GetAnchor(), root);
- EXPECT_EQ(root_range.anchor()->child_index(), 0);
- EXPECT_TRUE(root_range.focus()->IsTreePosition());
- EXPECT_EQ(root_range.focus()->GetAnchor(), root);
- EXPECT_EQ(root_range.focus()->child_index(), 4);
- EXPECT_TRUE(text_field_range.anchor()->IsTextPosition())
- << "Atomic text fields should be leaf nodes hence we get a text "
- "position.";
- EXPECT_EQ(text_field_range.anchor()->GetAnchor(), text_field);
- EXPECT_EQ(text_field_range.anchor()->text_offset(), 0);
- EXPECT_TRUE(text_field_range.focus()->IsTextPosition())
- << "Atomic text fields should be leaf nodes hence we get a text "
- "position.";
- EXPECT_EQ(text_field_range.focus()->GetAnchor(), text_field);
- EXPECT_EQ(text_field_range.focus()->text_offset(), 14)
- << "Should be length of \"Line 1\\nLine 2\\n\".";
- EXPECT_TRUE(static_text_range.anchor()->IsTextPosition());
- EXPECT_EQ(static_text_range.anchor()->GetAnchor(), static_text);
- EXPECT_EQ(static_text_range.anchor()->text_offset(), 0);
- EXPECT_TRUE(static_text_range.focus()->IsTextPosition());
- EXPECT_EQ(static_text_range.focus()->GetAnchor(), static_text);
- EXPECT_EQ(static_text_range.focus()->text_offset(), 6)
- << "Should be length of \"Line 1\".";
- EXPECT_TRUE(inline_box_range.anchor()->IsTextPosition());
- EXPECT_EQ(inline_box_range.anchor()->GetAnchor(), inline_box);
- EXPECT_EQ(inline_box_range.anchor()->text_offset(), 0);
- EXPECT_TRUE(inline_box_range.focus()->IsTextPosition());
- EXPECT_EQ(inline_box_range.focus()->GetAnchor(), inline_box);
- EXPECT_EQ(inline_box_range.focus()->text_offset(), 6)
- << "Should be length of \"Line 1\".";
- }
- TEST_F(AXRangeTest, EqualityOperators) {
- TestPositionInstance null_position = AXNodePosition::CreateNullPosition();
- TestPositionInstance test_position1 = AXNodePosition::CreateTextPosition(
- GetTreeID(), button_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance test_position2 = AXNodePosition::CreateTextPosition(
- GetTreeID(), text_field_.id, 7 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance test_position3 = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box2_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- // Invalid ranges (with at least one null endpoint).
- TestPositionRange null_position_and_nullptr(null_position->Clone(), nullptr);
- TestPositionRange nullptr_and_test_position(nullptr, test_position1->Clone());
- TestPositionRange test_position_and_null_position(test_position2->Clone(),
- null_position->Clone());
- TestPositionRange test_positions_1_and_2(test_position1->Clone(),
- test_position2->Clone());
- TestPositionRange test_positions_2_and_1(test_position2->Clone(),
- test_position1->Clone());
- TestPositionRange test_positions_1_and_3(test_position1->Clone(),
- test_position3->Clone());
- TestPositionRange test_positions_2_and_3(test_position2->Clone(),
- test_position3->Clone());
- TestPositionRange test_positions_3_and_2(test_position3->Clone(),
- test_position2->Clone());
- EXPECT_EQ(null_position_and_nullptr, nullptr_and_test_position);
- EXPECT_EQ(nullptr_and_test_position, test_position_and_null_position);
- EXPECT_NE(null_position_and_nullptr, test_positions_2_and_1);
- EXPECT_NE(test_positions_2_and_1, test_position_and_null_position);
- EXPECT_EQ(test_positions_1_and_2, test_positions_1_and_2);
- EXPECT_NE(test_positions_2_and_1, test_positions_1_and_2);
- EXPECT_EQ(test_positions_3_and_2, test_positions_2_and_3);
- EXPECT_NE(test_positions_1_and_2, test_positions_2_and_3);
- EXPECT_EQ(test_positions_1_and_2, test_positions_1_and_3);
- }
- TEST_F(AXRangeTest, AsForwardRange) {
- TestPositionRange null_range(AXNodePosition::CreateNullPosition(),
- AXNodePosition::CreateNullPosition());
- null_range = null_range.AsForwardRange();
- EXPECT_TRUE(null_range.IsNull());
- TestPositionInstance tree_position = AXNodePosition::CreateTreePosition(
- GetTreeID(), button_.id, 0 /* child_index */);
- TestPositionInstance text_position1 = AXNodePosition::CreateTextPosition(
- GetTreeID(), line_break1_.id, 1 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance text_position2 = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box2_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionRange tree_to_text_range(text_position1->Clone(),
- tree_position->Clone());
- tree_to_text_range = tree_to_text_range.AsForwardRange();
- EXPECT_EQ(*tree_position, *tree_to_text_range.anchor());
- EXPECT_EQ(*text_position1, *tree_to_text_range.focus());
- TestPositionRange text_to_text_range(text_position2->Clone(),
- text_position1->Clone());
- text_to_text_range = text_to_text_range.AsForwardRange();
- EXPECT_EQ(*text_position1, *text_to_text_range.anchor());
- EXPECT_EQ(*text_position2, *text_to_text_range.focus());
- }
- TEST_F(AXRangeTest, IsCollapsed) {
- TestPositionRange null_range(AXNodePosition::CreateNullPosition(),
- AXNodePosition::CreateNullPosition());
- null_range = null_range.AsForwardRange();
- EXPECT_FALSE(null_range.IsCollapsed());
- TestPositionInstance tree_position1 = AXNodePosition::CreateTreePosition(
- GetTreeID(), text_field_.id, 0 /* child_index */);
- // Since there are no children in inline_box1_, the following is essentially
- // an "after text" position which should not compare as equivalent to the
- // above tree position which is a "before text" position inside the text
- // field.
- TestPositionInstance tree_position2 = AXNodePosition::CreateTreePosition(
- GetTreeID(), inline_box1_.id, 0 /* child_index */);
- TestPositionInstance text_position1 = AXNodePosition::CreateTextPosition(
- GetTreeID(), static_text1_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance text_position2 = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance text_position3 = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box2_.id, 1 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionRange tree_to_null_range(tree_position1->Clone(),
- AXNodePosition::CreateNullPosition());
- EXPECT_TRUE(tree_to_null_range.IsNull());
- EXPECT_FALSE(tree_to_null_range.IsCollapsed());
- TestPositionRange null_to_text_range(AXNodePosition::CreateNullPosition(),
- text_position1->Clone());
- EXPECT_TRUE(null_to_text_range.IsNull());
- EXPECT_FALSE(null_to_text_range.IsCollapsed());
- TestPositionRange tree_to_tree_range(tree_position2->Clone(),
- tree_position1->Clone());
- EXPECT_FALSE(tree_to_tree_range.IsCollapsed());
- // A tree and a text position that essentially point to the same text offset
- // are equivalent, even if they are anchored to a different node.
- TestPositionRange tree_to_text_range(tree_position1->Clone(),
- text_position1->Clone());
- EXPECT_TRUE(tree_to_text_range.IsCollapsed());
- // The following positions are not equivalent since tree_position2 is an
- // "after text" position.
- tree_to_text_range =
- TestPositionRange(tree_position2->Clone(), text_position2->Clone());
- EXPECT_FALSE(tree_to_text_range.IsCollapsed());
- TestPositionRange text_to_text_range(text_position1->Clone(),
- text_position1->Clone());
- EXPECT_TRUE(text_to_text_range.IsCollapsed());
- // Two text positions that essentially point to the same text offset are
- // equivalent, even if they are anchored to a different node.
- text_to_text_range =
- TestPositionRange(text_position1->Clone(), text_position2->Clone());
- EXPECT_TRUE(text_to_text_range.IsCollapsed());
- text_to_text_range =
- TestPositionRange(text_position1->Clone(), text_position3->Clone());
- EXPECT_FALSE(text_to_text_range.IsCollapsed());
- }
- TEST_F(AXRangeTest, BeginAndEndIterators) {
- TestPositionInstance null_position = AXNodePosition::CreateNullPosition();
- TestPositionInstance test_position1 = AXNodePosition::CreateTextPosition(
- GetTreeID(), button_.id, 3 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance test_position2 = AXNodePosition::CreateTextPosition(
- GetTreeID(), check_box1_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance test_position3 = AXNodePosition::CreateTextPosition(
- GetTreeID(), check_box2_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance test_position4 = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionRange nullptr_and_null_position(nullptr, null_position->Clone());
- EXPECT_EQ(TestPositionRange::Iterator(), nullptr_and_null_position.begin());
- EXPECT_EQ(TestPositionRange::Iterator(), nullptr_and_null_position.end());
- TestPositionRange test_position1_and_nullptr(test_position1->Clone(),
- nullptr);
- EXPECT_EQ(TestPositionRange::Iterator(), test_position1_and_nullptr.begin());
- EXPECT_EQ(TestPositionRange::Iterator(), test_position1_and_nullptr.end());
- TestPositionRange null_position_and_test_position2(null_position->Clone(),
- test_position2->Clone());
- EXPECT_EQ(TestPositionRange::Iterator(),
- null_position_and_test_position2.begin());
- EXPECT_EQ(TestPositionRange::Iterator(),
- null_position_and_test_position2.end());
- TestPositionRange test_position1_and_test_position2(test_position1->Clone(),
- test_position2->Clone());
- EXPECT_NE(TestPositionRange::Iterator(test_position1->Clone(),
- test_position4->Clone()),
- test_position1_and_test_position2.begin());
- EXPECT_NE(TestPositionRange::Iterator(test_position1->Clone(),
- test_position3->Clone()),
- test_position1_and_test_position2.begin());
- EXPECT_EQ(TestPositionRange::Iterator(test_position1->Clone(),
- test_position2->Clone()),
- test_position1_and_test_position2.begin());
- EXPECT_EQ(TestPositionRange::Iterator(nullptr, test_position2->Clone()),
- test_position1_and_test_position2.end());
- TestPositionRange test_position3_and_test_position4(test_position3->Clone(),
- test_position4->Clone());
- EXPECT_NE(TestPositionRange::Iterator(test_position1->Clone(),
- test_position4->Clone()),
- test_position3_and_test_position4.begin());
- EXPECT_NE(TestPositionRange::Iterator(test_position2->Clone(),
- test_position4->Clone()),
- test_position3_and_test_position4.begin());
- EXPECT_EQ(TestPositionRange::Iterator(test_position3->Clone(),
- test_position4->Clone()),
- test_position3_and_test_position4.begin());
- EXPECT_NE(TestPositionRange::Iterator(nullptr, test_position2->Clone()),
- test_position3_and_test_position4.end());
- EXPECT_NE(TestPositionRange::Iterator(nullptr, test_position3->Clone()),
- test_position3_and_test_position4.end());
- EXPECT_EQ(TestPositionRange::Iterator(nullptr, test_position4->Clone()),
- test_position3_and_test_position4.end());
- }
- TEST_F(AXRangeTest, LeafTextRangeIteration) {
- TestPositionInstance button_start = AXNodePosition::CreateTextPosition(
- GetTreeID(), button_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance button_middle = AXNodePosition::CreateTextPosition(
- GetTreeID(), button_.id, 3 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance button_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), button_.id, 6 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- // Since a check box is not visible to the text representation, it spans an
- // empty anchor whose start and end positions are the same.
- TestPositionInstance check_box1 = AXNodePosition::CreateTextPosition(
- GetTreeID(), check_box1_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance check_box2 = AXNodePosition::CreateTextPosition(
- GetTreeID(), check_box2_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line1_start = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line1_middle = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 3 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line1_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 6 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line_break1_start = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box_line_break1_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line_break1_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box_line_break1_.id, 1 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line2_start = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box2_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line2_middle = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box2_.id, 3 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line2_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box2_.id, 6 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line_break2_start = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box_line_break2_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line_break2_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box_line_break2_.id, 1 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance after_line_start = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box3_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance after_line_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box3_.id, 5 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance empty_paragraph_start =
- AXNodePosition::CreateTextPosition(GetTreeID(), empty_paragraph_.id,
- 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance empty_paragraph_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), empty_paragraph_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- std::vector<TestPositionRange> expected_ranges;
- auto TestRangeIterator =
- [&expected_ranges](const TestPositionRange& test_range) {
- std::vector<TestPositionRange> actual_ranges;
- for (TestPositionRange leaf_text_range : test_range) {
- EXPECT_TRUE(leaf_text_range.IsLeafTextRange());
- actual_ranges.emplace_back(std::move(leaf_text_range));
- }
- EXPECT_EQ(expected_ranges.size(), actual_ranges.size());
- size_t element_count =
- std::min(expected_ranges.size(), actual_ranges.size());
- for (size_t i = 0; i < element_count; ++i) {
- EXPECT_EQ(expected_ranges[i], actual_ranges[i]);
- EXPECT_EQ(expected_ranges[i].anchor()->GetAnchor(),
- actual_ranges[i].anchor()->GetAnchor());
- }
- };
- // Iterating over a null range; note that expected_ranges is empty.
- TestRangeIterator(TestPositionRange(nullptr, nullptr));
- TestPositionRange non_null_degenerate_range(check_box1->Clone(),
- check_box1->Clone());
- expected_ranges.clear();
- expected_ranges.emplace_back(check_box1->Clone(), check_box1->Clone());
- TestRangeIterator(non_null_degenerate_range);
- TestPositionRange empty_text_forward_range(button_end->Clone(),
- line1_start->Clone());
- TestPositionRange empty_text_backward_range(line1_start->Clone(),
- button_end->Clone());
- expected_ranges.clear();
- expected_ranges.emplace_back(button_end->Clone(), button_end->Clone());
- expected_ranges.emplace_back(check_box1->Clone(), check_box1->Clone());
- expected_ranges.emplace_back(check_box2->Clone(), check_box2->Clone());
- expected_ranges.emplace_back(line1_start->Clone(), line1_start->Clone());
- TestRangeIterator(empty_text_forward_range);
- TestRangeIterator(empty_text_backward_range);
- TestPositionRange entire_anchor_forward_range(button_start->Clone(),
- button_end->Clone());
- TestPositionRange entire_anchor_backward_range(button_end->Clone(),
- button_start->Clone());
- expected_ranges.clear();
- expected_ranges.emplace_back(button_start->Clone(), button_end->Clone());
- TestRangeIterator(entire_anchor_forward_range);
- TestRangeIterator(entire_anchor_backward_range);
- TestPositionRange across_anchors_forward_range(button_middle->Clone(),
- line1_middle->Clone());
- TestPositionRange across_anchors_backward_range(line1_middle->Clone(),
- button_middle->Clone());
- expected_ranges.clear();
- expected_ranges.emplace_back(button_middle->Clone(), button_end->Clone());
- expected_ranges.emplace_back(check_box1->Clone(), check_box1->Clone());
- expected_ranges.emplace_back(check_box2->Clone(), check_box2->Clone());
- expected_ranges.emplace_back(line1_start->Clone(), line1_middle->Clone());
- TestRangeIterator(across_anchors_forward_range);
- TestRangeIterator(across_anchors_backward_range);
- TestPositionRange starting_at_end_position_forward_range(
- line1_end->Clone(), line2_middle->Clone());
- TestPositionRange starting_at_end_position_backward_range(
- line2_middle->Clone(), line1_end->Clone());
- expected_ranges.clear();
- expected_ranges.emplace_back(line1_end->Clone(), line1_end->Clone());
- expected_ranges.emplace_back(line_break1_start->Clone(),
- line_break1_end->Clone());
- expected_ranges.emplace_back(line2_start->Clone(), line2_middle->Clone());
- TestRangeIterator(starting_at_end_position_forward_range);
- TestRangeIterator(starting_at_end_position_backward_range);
- TestPositionRange ending_at_start_position_forward_range(
- line1_middle->Clone(), line2_start->Clone());
- TestPositionRange ending_at_start_position_backward_range(
- line2_start->Clone(), line1_middle->Clone());
- expected_ranges.clear();
- expected_ranges.emplace_back(line1_middle->Clone(), line1_end->Clone());
- expected_ranges.emplace_back(line_break1_start->Clone(),
- line_break1_end->Clone());
- expected_ranges.emplace_back(line2_start->Clone(), line2_start->Clone());
- TestRangeIterator(ending_at_start_position_forward_range);
- TestRangeIterator(ending_at_start_position_backward_range);
- TestPositionInstance range_start = AXNodePosition::CreateTreePosition(
- GetTreeID(), root_.id, 0 /* child_index */);
- TestPositionInstance range_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), root_.id, ALL_TEXT.length() /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionRange entire_test_forward_range(range_start->Clone(),
- range_end->Clone());
- TestPositionRange entire_test_backward_range(range_end->Clone(),
- range_start->Clone());
- expected_ranges.clear();
- expected_ranges.emplace_back(button_start->Clone(), button_end->Clone());
- expected_ranges.emplace_back(check_box1->Clone(), check_box1->Clone());
- expected_ranges.emplace_back(check_box2->Clone(), check_box2->Clone());
- expected_ranges.emplace_back(line1_start->Clone(), line1_end->Clone());
- expected_ranges.emplace_back(line_break1_start->Clone(),
- line_break1_end->Clone());
- expected_ranges.emplace_back(line2_start->Clone(), line2_end->Clone());
- expected_ranges.emplace_back(line_break2_start->Clone(),
- line_break2_end->Clone());
- expected_ranges.emplace_back(after_line_start->Clone(),
- after_line_end->Clone());
- expected_ranges.emplace_back(empty_paragraph_start->Clone(),
- empty_paragraph_end->Clone());
- TestRangeIterator(entire_test_forward_range);
- TestRangeIterator(entire_test_backward_range);
- }
- TEST_F(AXRangeTest, GetTextWithWholeObjects) {
- // Create a range starting from the button object and ending at the last
- // character of the root, i.e. at the last character of the second line in the
- // text field.
- TestPositionInstance start = AXNodePosition::CreateTreePosition(
- GetTreeID(), root_.id, 0 /* child_index */);
- TestPositionInstance end = AXNodePosition::CreateTextPosition(
- GetTreeID(), root_.id, ALL_TEXT.length() /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(end->IsTextPosition());
- TestPositionRange forward_range(start->Clone(), end->Clone());
- EXPECT_EQ(ALL_TEXT, forward_range.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- TestPositionRange backward_range(std::move(end), std::move(start));
- EXPECT_EQ(ALL_TEXT, backward_range.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- // Button
- start = AXNodePosition::CreateTextPosition(
- GetTreeID(), button_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(start->IsTextPosition());
- end = AXNodePosition::CreateTextPosition(
- GetTreeID(), button_.id, BUTTON.length() /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(end->IsTextPosition());
- TestPositionRange button_range(start->Clone(), end->Clone());
- EXPECT_EQ(BUTTON, button_range.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- TestPositionRange button_range_backward(std::move(end), std::move(start));
- EXPECT_EQ(BUTTON, button_range_backward.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- // text_field_
- start = AXNodePosition::CreateTextPosition(
- GetTreeID(), text_field_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- end = AXNodePosition::CreateTextPosition(
- GetTreeID(), text_field_.id, TEXT_FIELD.length() /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(start->IsTextPosition());
- ASSERT_TRUE(end->IsTextPosition());
- TestPositionRange text_field_range(start->Clone(), end->Clone());
- EXPECT_EQ(TEXT_FIELD,
- text_field_range.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- TestPositionRange text_field_range_backward(std::move(end), std::move(start));
- EXPECT_EQ(TEXT_FIELD,
- text_field_range_backward.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- // static_text1_
- start = AXNodePosition::CreateTextPosition(
- GetTreeID(), static_text1_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(start->IsTextPosition());
- end = AXNodePosition::CreateTextPosition(
- GetTreeID(), static_text1_.id, LINE_1.length() /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(end->IsTextPosition());
- TestPositionRange static_text1_range(start->Clone(), end->Clone());
- EXPECT_EQ(LINE_1, static_text1_range.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- TestPositionRange static_text1_range_backward(std::move(end),
- std::move(start));
- EXPECT_EQ(LINE_1, static_text1_range_backward.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- // static_text2_
- start = AXNodePosition::CreateTextPosition(
- GetTreeID(), static_text2_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(start->IsTextPosition());
- end = AXNodePosition::CreateTextPosition(
- GetTreeID(), static_text2_.id, LINE_2.length() /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(end->IsTextPosition());
- TestPositionRange static_text2_range(start->Clone(), end->Clone());
- EXPECT_EQ(LINE_2, static_text2_range.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- TestPositionRange static_text2_range_backward(std::move(end),
- std::move(start));
- EXPECT_EQ(LINE_2, static_text2_range_backward.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- // static_text1_ to static_text2_
- std::u16string text_between_text1_start_and_text2_end =
- LINE_1.substr().append(NEWLINE).append(LINE_2);
- start = AXNodePosition::CreateTextPosition(
- GetTreeID(), static_text1_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(start->IsTextPosition());
- end = AXNodePosition::CreateTextPosition(
- GetTreeID(), static_text2_.id, LINE_2.length() /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(end->IsTextPosition());
- TestPositionRange static_text_range(start->Clone(), end->Clone());
- EXPECT_EQ(text_between_text1_start_and_text2_end,
- static_text_range.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- TestPositionRange static_text_range_backward(std::move(end),
- std::move(start));
- EXPECT_EQ(text_between_text1_start_and_text2_end,
- static_text_range_backward.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- // root_ to static_text2_'s end
- std::u16string text_up_to_text2_end =
- BUTTON.substr(0).append(LINE_1).append(NEWLINE).append(LINE_2);
- start = AXNodePosition::CreateTreePosition(GetTreeID(), root_.id,
- 0 /* child_index */);
- end = AXNodePosition::CreateTextPosition(
- GetTreeID(), static_text2_.id, LINE_2.length() /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(end->IsTextPosition());
- TestPositionRange root_to_static2_text_range(start->Clone(), end->Clone());
- EXPECT_EQ(text_up_to_text2_end,
- root_to_static2_text_range.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- TestPositionRange root_to_static2_text_range_backward(std::move(end),
- std::move(start));
- EXPECT_EQ(text_up_to_text2_end,
- root_to_static2_text_range_backward.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- // root_ to static_text2_'s start
- std::u16string text_up_to_text2_start =
- BUTTON.substr(0).append(LINE_1).append(NEWLINE);
- start = AXNodePosition::CreateTreePosition(GetTreeID(), root_.id,
- 0 /* child_index */);
- end = AXNodePosition::CreateTreePosition(GetTreeID(), static_text2_.id,
- 0 /* child_index */);
- TestPositionRange root_to_static2_tree_range(start->Clone(), end->Clone());
- EXPECT_EQ(text_up_to_text2_start,
- root_to_static2_tree_range.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- TestPositionRange root_to_static2_tree_range_backward(std::move(end),
- std::move(start));
- EXPECT_EQ(text_up_to_text2_start,
- root_to_static2_tree_range_backward.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- }
- TEST_F(AXRangeTest, GetTextWithTextOffsets) {
- std::u16string most_text = BUTTON.substr(2).append(TEXT_FIELD.substr(0, 11));
- // Create a range starting from the button object and ending two characters
- // before the end of the root.
- TestPositionInstance start = AXNodePosition::CreateTextPosition(
- GetTreeID(), button_.id, 2 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(start->IsTextPosition());
- TestPositionInstance end = AXNodePosition::CreateTextPosition(
- GetTreeID(), static_text2_.id, 4 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(end->IsTextPosition());
- TestPositionRange forward_range(start->Clone(), end->Clone());
- EXPECT_EQ(most_text, forward_range.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- TestPositionRange backward_range(std::move(end), std::move(start));
- EXPECT_EQ(most_text, backward_range.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- // root_ to static_text2_'s start with offsets
- std::u16string text_up_to_text2_tree_start =
- BUTTON.substr(0).append(TEXT_FIELD.substr(0, 10));
- start = AXNodePosition::CreateTreePosition(GetTreeID(), root_.id,
- 0 /* child_index */);
- end = AXNodePosition::CreateTextPosition(
- GetTreeID(), static_text2_.id, 3 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(end->IsTextPosition());
- TestPositionRange root_to_static2_tree_range(start->Clone(), end->Clone());
- EXPECT_EQ(text_up_to_text2_tree_start,
- root_to_static2_tree_range.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- TestPositionRange root_to_static2_tree_range_backward(std::move(end),
- std::move(start));
- EXPECT_EQ(text_up_to_text2_tree_start,
- root_to_static2_tree_range_backward.GetText(
- AXTextConcatenationBehavior::kWithoutParagraphBreaks,
- AXEmbeddedObjectBehavior::kSuppressCharacter));
- }
- TEST_F(AXRangeTest, GetTextWithEmptyRanges) {
- // empty string with non-leaf tree position
- TestPositionInstance start = AXNodePosition::CreateTreePosition(
- GetTreeID(), root_.id, 0 /* child_index */);
- TestPositionRange non_leaf_tree_range(start->Clone(), start->Clone());
- EXPECT_EQ(EMPTY, non_leaf_tree_range.GetText());
- // empty string with leaf tree position
- start = AXNodePosition::CreateTreePosition(GetTreeID(), inline_box1_.id,
- 0 /* child_index */);
- TestPositionRange leaf_empty_range(start->Clone(), start->Clone());
- EXPECT_EQ(EMPTY, leaf_empty_range.GetText());
- // empty string with leaf text position and no offset
- start = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionRange leaf_text_no_offset(start->Clone(), start->Clone());
- EXPECT_EQ(EMPTY, leaf_text_no_offset.GetText());
- // empty string with leaf text position with offset
- start = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 3 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionRange leaf_text_offset(start->Clone(), start->Clone());
- EXPECT_EQ(EMPTY, leaf_text_offset.GetText());
- // empty string with non-leaf text with no offset
- start = AXNodePosition::CreateTextPosition(
- GetTreeID(), root_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionRange non_leaf_text_no_offset(start->Clone(), start->Clone());
- EXPECT_EQ(EMPTY, non_leaf_text_no_offset.GetText());
- // empty string with non-leaf text position with offset
- start = AXNodePosition::CreateTextPosition(
- GetTreeID(), root_.id, 3 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionRange non_leaf_text_offset(start->Clone(), start->Clone());
- EXPECT_EQ(EMPTY, non_leaf_text_offset.GetText());
- // empty string with same position between two anchors, but different offsets
- TestPositionInstance after_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), line_break1_.id, 1 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance before_start = AXNodePosition::CreateTextPosition(
- GetTreeID(), static_text2_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionRange same_position_different_anchors_forward(
- after_end->Clone(), before_start->Clone());
- EXPECT_EQ(EMPTY, same_position_different_anchors_forward.GetText());
- TestPositionRange same_position_different_anchors_backward(
- before_start->Clone(), after_end->Clone());
- EXPECT_EQ(EMPTY, same_position_different_anchors_backward.GetText());
- }
- TEST_F(AXRangeTest, GetTextAddingNewlineBetweenParagraphs) {
- // There are three newlines between the button and the text field. The first
- // two are emitted because there are two empty checkboxes following the button
- // on the same line, i.e. two checkboxes without any text contents. Each empty
- // object forms a paragraph boundary, so that such an object will be easily
- // discernible by a screen reader user. The third newline is caused by the
- // fact that the text field is on the next line.
- const std::u16string button_end_to_line1_start =
- NEWLINE.substr().append(NEWLINE).append(NEWLINE);
- TestPositionInstance button_start = AXNodePosition::CreateTextPosition(
- GetTreeID(), button_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance button_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), button_.id, 6 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line1_start = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line1_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 6 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line2_start = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box2_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line2_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box2_.id, 6 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance after_line_start = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box3_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance after_line_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box3_.id, 5 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- auto TestGetTextForRange = [](TestPositionInstance range_start,
- TestPositionInstance range_end,
- const std::u16string& expected_text,
- const size_t expected_appended_newlines_count) {
- TestPositionRange forward_test_range(range_start->Clone(),
- range_end->Clone());
- TestPositionRange backward_test_range(std::move(range_end),
- std::move(range_start));
- size_t appended_newlines_count = 0;
- EXPECT_EQ(expected_text,
- forward_test_range.GetText(
- AXTextConcatenationBehavior::kWithParagraphBreaks,
- g_ax_embedded_object_behavior, -1, false,
- &appended_newlines_count));
- EXPECT_EQ(expected_appended_newlines_count, appended_newlines_count);
- EXPECT_EQ(expected_text,
- backward_test_range.GetText(
- AXTextConcatenationBehavior::kWithParagraphBreaks,
- g_ax_embedded_object_behavior, -1, false,
- &appended_newlines_count));
- EXPECT_EQ(expected_appended_newlines_count, appended_newlines_count);
- };
- std::u16string button_start_to_line1_end =
- BUTTON.substr().append(button_end_to_line1_start).append(LINE_1);
- TestGetTextForRange(button_start->Clone(), line1_end->Clone(),
- button_start_to_line1_end,
- /* expected_appended_newlines_count */ 3);
- std::u16string button_start_to_line1_start =
- BUTTON.substr().append(button_end_to_line1_start);
- TestGetTextForRange(button_start->Clone(), line1_start->Clone(),
- button_start_to_line1_start,
- /* expected_appended_newlines_count */ 3);
- std::u16string button_end_to_line1_end =
- button_end_to_line1_start.substr().append(LINE_1);
- TestGetTextForRange(button_end->Clone(), line1_end->Clone(),
- button_end_to_line1_end,
- /* expected_appended_newlines_count */ 3);
- TestGetTextForRange(button_end->Clone(), line1_start->Clone(),
- button_end_to_line1_start,
- /* expected_appended_newlines_count */ 3);
- std::u16string line2_start_to_after_line_end =
- LINE_2.substr().append(NEWLINE).append(AFTER_LINE);
- TestGetTextForRange(line2_start->Clone(), after_line_end->Clone(),
- line2_start_to_after_line_end, 0);
- std::u16string line2_start_to_after_line_start =
- LINE_2.substr().append(NEWLINE);
- TestGetTextForRange(line2_start->Clone(), after_line_start->Clone(),
- line2_start_to_after_line_start, 0);
- std::u16string line2_end_to_after_line_end =
- NEWLINE.substr().append(AFTER_LINE);
- TestGetTextForRange(line2_end->Clone(), after_line_end->Clone(),
- line2_end_to_after_line_end, 0);
- std::u16string line2_end_to_after_line_start = NEWLINE;
- TestGetTextForRange(line2_end->Clone(), after_line_start->Clone(),
- line2_end_to_after_line_start, 0);
- std::u16string all_text = BUTTON.substr()
- .append(button_end_to_line1_start)
- .append(TEXT_FIELD)
- .append(AFTER_LINE);
- TestPositionInstance start = AXNodePosition::CreateTextPosition(
- GetTreeID(), root_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance end = AXNodePosition::CreateTextPosition(
- GetTreeID(), root_.id, ALL_TEXT.length() /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestGetTextForRange(std::move(start), std::move(end), all_text,
- /* expected_appended_newlines_count */ 3);
- }
- TEST_F(AXRangeTest, GetTextWithMaxCount) {
- TestPositionInstance line1_start = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line2_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box2_.id, 6 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionRange test_range(line1_start->Clone(), line2_end->Clone());
- EXPECT_EQ(
- LINE_1.substr(0, 2),
- test_range.GetText(AXTextConcatenationBehavior::kWithParagraphBreaks,
- g_ax_embedded_object_behavior, 2));
- // Test the case where an appended newline falls right at max_count.
- EXPECT_EQ(
- LINE_1.substr().append(NEWLINE),
- test_range.GetText(AXTextConcatenationBehavior::kWithParagraphBreaks,
- g_ax_embedded_object_behavior, 7));
- // Test passing -1 for max_count.
- EXPECT_EQ(
- LINE_1.substr().append(NEWLINE).append(LINE_2),
- test_range.GetText(AXTextConcatenationBehavior::kWithParagraphBreaks,
- g_ax_embedded_object_behavior, -1));
- }
- TEST_F(AXRangeTest, GetTextWithList) {
- const std::u16string kListMarker1 = u"1. ";
- const std::u16string kListItemContent = u"List item 1";
- const std::u16string kListMarker2 = u"2. ";
- const std::u16string kAfterList = u"After list";
- const std::u16string kAllText = kListMarker1.substr()
- .append(kListItemContent)
- .append(NEWLINE)
- .append(kListMarker2)
- .append(NEWLINE)
- .append(kAfterList);
- // This test expects:
- // "1. List item 1
- // 2.
- // After list"
- // for the following AXTree:
- // ++1 kRootWebArea
- // ++++2 kList
- // ++++++3 kListItem
- // ++++++++4 kListMarker
- // ++++++++++5 kStaticText
- // ++++++++++++6 kInlineTextBox "1. "
- // ++++++++7 kStaticText
- // ++++++++++8 kInlineTextBox "List item 1"
- // ++++++9 kListItem
- // ++++++++10 kListMarker
- // +++++++++++11 kStaticText
- // ++++++++++++++12 kInlineTextBox "2. "
- // ++++13 kStaticText
- // +++++++14 kInlineTextBox "After list"
- AXNodeData root;
- AXNodeData list;
- AXNodeData list_item1;
- AXNodeData list_item2;
- AXNodeData list_marker1;
- AXNodeData list_marker2;
- AXNodeData inline_box1;
- AXNodeData inline_box2;
- AXNodeData inline_box3;
- AXNodeData inline_box4;
- AXNodeData static_text1;
- AXNodeData static_text2;
- AXNodeData static_text3;
- AXNodeData static_text4;
- root.id = 1;
- list.id = 2;
- list_item1.id = 3;
- list_marker1.id = 4;
- static_text1.id = 5;
- inline_box1.id = 6;
- static_text2.id = 7;
- inline_box2.id = 8;
- list_item2.id = 9;
- list_marker2.id = 10;
- static_text3.id = 11;
- inline_box3.id = 12;
- static_text4.id = 13;
- inline_box4.id = 14;
- root.role = ax::mojom::Role::kRootWebArea;
- root.child_ids = {list.id, static_text4.id};
- list.role = ax::mojom::Role::kList;
- list.child_ids = {list_item1.id, list_item2.id};
- list_item1.role = ax::mojom::Role::kListItem;
- list_item1.child_ids = {list_marker1.id, static_text2.id};
- list_item1.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
- true);
- list_marker1.role = ax::mojom::Role::kListMarker;
- list_marker1.child_ids = {static_text1.id};
- static_text1.role = ax::mojom::Role::kStaticText;
- static_text1.SetName(kListMarker1);
- static_text1.child_ids = {inline_box1.id};
- inline_box1.role = ax::mojom::Role::kInlineTextBox;
- inline_box1.SetName(kListMarker1);
- static_text2.role = ax::mojom::Role::kStaticText;
- static_text2.SetName(kListItemContent);
- static_text2.child_ids = {inline_box2.id};
- inline_box2.role = ax::mojom::Role::kInlineTextBox;
- inline_box2.SetName(kListItemContent);
- list_item2.role = ax::mojom::Role::kListItem;
- list_item2.child_ids = {list_marker2.id};
- list_item2.AddBoolAttribute(ax::mojom::BoolAttribute::kIsLineBreakingObject,
- true);
- list_marker2.role = ax::mojom::Role::kListMarker;
- list_marker2.child_ids = {static_text3.id};
- static_text3.role = ax::mojom::Role::kStaticText;
- static_text3.SetName(kListMarker2);
- static_text3.child_ids = {inline_box3.id};
- inline_box3.role = ax::mojom::Role::kInlineTextBox;
- inline_box3.SetName(kListMarker2);
- static_text4.role = ax::mojom::Role::kStaticText;
- static_text4.SetName(kAfterList);
- static_text4.child_ids = {inline_box4.id};
- inline_box4.role = ax::mojom::Role::kInlineTextBox;
- inline_box4.SetName(kAfterList);
- AXTreeUpdate initial_state;
- initial_state.root_id = root.id;
- initial_state.nodes = {root, list, list_item1, list_marker1,
- static_text1, inline_box1, static_text2, inline_box2,
- list_item2, list_marker2, static_text3, inline_box3,
- static_text4, inline_box4};
- initial_state.has_tree_data = true;
- initial_state.tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
- initial_state.tree_data.title = "Dialog title";
- SetTree(std::make_unique<AXTree>(initial_state));
- TestPositionInstance start = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(start->IsTextPosition());
- TestPositionInstance end = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box4.id, 10 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- ASSERT_TRUE(end->IsTextPosition());
- TestPositionRange forward_range(start->Clone(), end->Clone());
- EXPECT_EQ(kAllText, forward_range.GetText(
- AXTextConcatenationBehavior::kWithParagraphBreaks));
- TestPositionRange backward_range(std::move(end), std::move(start));
- EXPECT_EQ(kAllText, backward_range.GetText(
- AXTextConcatenationBehavior::kWithParagraphBreaks));
- }
- TEST_F(AXRangeTest, GetRects) {
- TestAXRangeScreenRectDelegate delegate(this);
- // Setting up ax ranges for testing.
- TestPositionInstance button = AXNodePosition::CreateTextPosition(
- GetTreeID(), button_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance check_box1 = AXNodePosition::CreateTextPosition(
- GetTreeID(), check_box1_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance check_box2 = AXNodePosition::CreateTextPosition(
- GetTreeID(), check_box2_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line1_start = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line1_second_char = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 1 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line1_middle = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 3 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line1_second_to_last_char =
- AXNodePosition::CreateTextPosition(GetTreeID(), inline_box1_.id,
- 5 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line1_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box1_.id, 6 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line2_start = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box2_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line2_second_char = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box2_.id, 1 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line2_middle = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box2_.id, 3 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line2_second_to_last_char =
- AXNodePosition::CreateTextPosition(GetTreeID(), inline_box2_.id,
- 5 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance line2_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), inline_box2_.id, 6 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance empty_paragraph_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), empty_paragraph_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- // Since a button is not visible to the text representation, it spans an
- // empty anchor whose start and end positions are the same.
- TestPositionRange button_range(button->Clone(), button->Clone());
- std::vector<gfx::Rect> expected_screen_rects = {gfx::Rect(20, 20, 100, 30)};
- EXPECT_THAT(button_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Since a check box is not visible to the text representation, it spans an
- // empty anchor whose start and end positions are the same.
- TestPositionRange check_box1_range(check_box1->Clone(), check_box1->Clone());
- expected_screen_rects = {gfx::Rect(120, 20, 30, 30)};
- EXPECT_THAT(check_box1_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding boxes of the button and both checkboxes.
- TestPositionRange button_check_box2_range(button->Clone(),
- check_box2->Clone());
- expected_screen_rects = {gfx::Rect(20, 20, 100, 30),
- gfx::Rect(120, 20, 30, 30),
- gfx::Rect(150, 20, 30, 30)};
- EXPECT_THAT(button_check_box2_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding box of text line 1's degenerate range at its start.
- // 0 1 2 3 4 5
- // |L|i|n|e| |1|
- // ||
- TestPositionRange line1_degenerate_range(line1_start->Clone(),
- line1_start->Clone());
- expected_screen_rects = {gfx::Rect(20, 50, 1, 30)};
- EXPECT_THAT(line1_degenerate_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding box of text line 1, its whole range.
- // 0 1 2 3 4 5
- // |L|i|n|e| |1|
- // |-----------|
- TestPositionRange line1_whole_range(line1_start->Clone(), line1_end->Clone());
- expected_screen_rects = {gfx::Rect(20, 50, 30, 30)};
- EXPECT_THAT(line1_whole_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding box of text line 1, its first half range.
- // 0 1 2 3 4 5
- // |L|i|n|e| |1|
- // |-----|
- TestPositionRange line1_first_half_range(line1_start->Clone(),
- line1_middle->Clone());
- expected_screen_rects = {gfx::Rect(20, 50, 15, 30)};
- EXPECT_THAT(line1_first_half_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding box of text line 1, its second half range.
- // 0 1 2 3 4 5
- // |L|i|n|e| |1|
- // |-----|
- TestPositionRange line1_second_half_range(line1_middle->Clone(),
- line1_end->Clone());
- expected_screen_rects = {gfx::Rect(35, 50, 15, 30)};
- EXPECT_THAT(line1_second_half_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding box of text line 1, its mid range.
- // 0 1 2 3 4 5
- // |L|i|n|e| |1|
- // |-------|
- TestPositionRange line1_mid_range(line1_second_char->Clone(),
- line1_second_to_last_char->Clone());
- expected_screen_rects = {gfx::Rect(25, 50, 20, 30)};
- EXPECT_THAT(line1_mid_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding box of text line 2, its whole range.
- // 0 1 2 3 4 5
- // |L|i|n|e| |2|
- // |-----------|
- TestPositionRange line2_whole_range(line2_start->Clone(), line2_end->Clone());
- expected_screen_rects = {gfx::Rect(20, 80, 42, 30)};
- EXPECT_THAT(line2_whole_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding box of text line 2, its first half range.
- // 0 1 2 3 4 5
- // |L|i|n|e| |2|
- // |-----|
- TestPositionRange line2_first_half_range(line2_start->Clone(),
- line2_middle->Clone());
- expected_screen_rects = {gfx::Rect(20, 80, 21, 30)};
- EXPECT_THAT(line2_first_half_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding box of text line 2, its second half range.
- // 0 1 2 3 4 5
- // |L|i|n|e| |2|
- // |-----|
- TestPositionRange line2_second_half_range(line2_middle->Clone(),
- line2_end->Clone());
- expected_screen_rects = {gfx::Rect(41, 80, 21, 30)};
- EXPECT_THAT(line2_second_half_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding box of text line 2, its mid range.
- // 0 1 2 3 4 5
- // |L|i|n|e| |2|
- // |-------|
- TestPositionRange line2_mid_range(line2_second_char->Clone(),
- line2_second_to_last_char->Clone());
- expected_screen_rects = {gfx::Rect(27, 80, 28, 30)};
- EXPECT_THAT(line2_mid_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding box of degenerate range of text line 2, before its
- // second character.
- // 0 1 2 3 4 5
- // |L|i|n|e| |2|
- // ||
- TestPositionRange line2_degenerate_range(line2_second_char->Clone(),
- line2_second_char->Clone());
- expected_screen_rects = {gfx::Rect(27, 80, 1, 30)};
- EXPECT_THAT(line2_degenerate_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding boxes of text line 1 and line 2, the entire range.
- // |L|i|n|e| |1|\n|L|i|n|e| |2|\n|
- // |--------------------------|
- TestPositionRange line1_line2_whole_range(line1_start->Clone(),
- line2_end->Clone());
- expected_screen_rects = {gfx::Rect(20, 50, 30, 30),
- gfx::Rect(20, 80, 42, 30)};
- EXPECT_THAT(line1_line2_whole_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding boxes of the range that spans from the middle of text
- // line 1 to the middle of text line 2.
- // |L|i|n|e| |1|\n|L|i|n|e| |2|\n|
- // |--------------|
- TestPositionRange line1_line2_mid_range(line1_middle->Clone(),
- line2_middle->Clone());
- expected_screen_rects = {gfx::Rect(35, 50, 15, 30),
- gfx::Rect(20, 80, 21, 30)};
- EXPECT_THAT(line1_line2_mid_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding boxes of the range that spans from the checkbox 2
- // ("invisible" in the text representation) to the middle of text line 2.
- // |[Button][Checkbox 1][Checkbox 2]L|i|n|e| |1|\n|L|i|n|e| |2|\n|A|f|t|e|r<p>
- // |-------------------------------|
- TestPositionRange check_box2_line2_mid_range(check_box2->Clone(),
- line2_middle->Clone());
- expected_screen_rects = {gfx::Rect(150, 20, 30, 30),
- gfx::Rect(20, 50, 30, 30),
- gfx::Rect(20, 80, 21, 30)};
- EXPECT_THAT(check_box2_line2_mid_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Retrieving bounding boxes of the range spanning the entire document.
- // |[Button][Checkbox 1][Checkbox 2]L|i|n|e| |1|\n|L|i|n|e| |2|\n|A|f|t|e|r<p>
- // |-------------------------------------------------------------------------|
- TestPositionRange entire_test_range(button->Clone(),
- empty_paragraph_end->Clone());
- expected_screen_rects = {
- gfx::Rect(20, 20, 100, 30), gfx::Rect(120, 20, 30, 30),
- gfx::Rect(150, 20, 30, 30), gfx::Rect(20, 50, 30, 30),
- gfx::Rect(20, 80, 42, 30), gfx::Rect(20, 110, 50, 30)};
- EXPECT_THAT(entire_test_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- }
- TEST_F(AXRangeTest, GetRectsOffscreen) {
- // Set up root node bounds/viewport size to {0, 50, 800x60}, so that only
- // some text will be onscreen the rest will be offscreen.
- AXNodeData old_root_node_data = GetRootAsAXNode()->data();
- AXNodeData new_root_node_data = old_root_node_data;
- new_root_node_data.relative_bounds.bounds = gfx::RectF(0, 50, 800, 60);
- GetRootAsAXNode()->SetData(new_root_node_data);
- TestAXRangeScreenRectDelegate delegate(this);
- TestPositionInstance button = AXNodePosition::CreateTextPosition(
- GetTreeID(), button_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- TestPositionInstance empty_paragraph_end = AXNodePosition::CreateTextPosition(
- GetTreeID(), empty_paragraph_.id, 0 /* text_offset */,
- ax::mojom::TextAffinity::kDownstream);
- // [Button] [Checkbox 1] [Checkbox 2]
- // {20, 20, 100x30}, {120, 20, 30x30} {150, 20, 30x30}
- // ---
- // [Line 1] [\n] |
- // {20, 50, 30x30} | view port, onscreen
- // | {0, 50, 800x60}
- // [Line 2] [\n] |
- // {20, 80, 42x30} |
- // ---
- // [After]
- // {20, 110, 50x30}
- //
- // [Empty paragraph]
- //
- // Retrieving bounding boxes of the range spanning the entire document.
- // |[Button][Checkbox 1][Checkbox 2]L|i|n|e| |1|\n|L|i|n|e| |2|\n|A|f|t|e|r<P>
- // |-------------------------------------------------------------------------|
- TestPositionRange entire_test_range(button->Clone(),
- empty_paragraph_end->Clone());
- std::vector<gfx::Rect> expected_screen_rects = {gfx::Rect(20, 50, 30, 30),
- gfx::Rect(20, 80, 42, 30)};
- EXPECT_THAT(entire_test_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- // Reset the root node bounds/viewport size back to {0, 0, 800x600}, and
- // verify all elements should be onscreen.
- GetRootAsAXNode()->SetData(old_root_node_data);
- expected_screen_rects = {
- gfx::Rect(20, 20, 100, 30), gfx::Rect(120, 20, 30, 30),
- gfx::Rect(150, 20, 30, 30), gfx::Rect(20, 50, 30, 30),
- gfx::Rect(20, 80, 42, 30), gfx::Rect(20, 110, 50, 30)};
- EXPECT_THAT(entire_test_range.GetRects(&delegate),
- ::testing::ContainerEq(expected_screen_rects));
- }
- } // namespace ui
|