Migrate TextInputPlugin API to TextRange (#21854)

Replaces selection_base() and selection_extent() with selection() and
SetSelection(int, int) with SetSelection(range).

This also adds the following convenience methods to TextRange:
* reversed()
* Contains(size_t position)
* Contains(const TextRange& range)

as well as operator== for use in unit tests. When Flutter migrates to
C++20, we can replace that method with a default declaration.
diff --git a/shell/platform/common/cpp/text_input_model.cc b/shell/platform/common/cpp/text_input_model.cc
index 1ef5b6f3..da0c1fe 100644
--- a/shell/platform/common/cpp/text_input_model.cc
+++ b/shell/platform/common/cpp/text_input_model.cc
@@ -41,12 +41,11 @@
   selection_ = TextRange(0);
 }
 
-bool TextInputModel::SetSelection(size_t base, size_t extent) {
-  size_t max_pos = text_.length();
-  if (base > max_pos || extent > max_pos) {
+bool TextInputModel::SetSelection(const TextRange& range) {
+  if (!text_range().Contains(range)) {
     return false;
   }
-  selection_ = TextRange(base, extent);
+  selection_ = range;
   return true;
 }
 
diff --git a/shell/platform/common/cpp/text_input_model.h b/shell/platform/common/cpp/text_input_model.h
index c5753f8..c49f786 100644
--- a/shell/platform/common/cpp/text_input_model.h
+++ b/shell/platform/common/cpp/text_input_model.h
@@ -27,8 +27,8 @@
 
   // Attempts to set the text selection.
   //
-  // Returns false if the base or extent are out of bounds.
-  bool SetSelection(size_t base, size_t extent);
+  // Returns false if the selection is not within the bounds of the text.
+  bool SetSelection(const TextRange& range);
 
   // Adds a Unicode code point.
   //
@@ -105,11 +105,8 @@
   // GetText().
   int GetCursorOffset() const;
 
-  // The position where the selection starts.
-  int selection_base() const { return selection_.base(); }
-
-  // The position of the cursor.
-  int selection_extent() const { return selection_.extent(); }
+  // The current selection.
+  TextRange selection() const { return selection_; }
 
  private:
   // Deletes the current selection, if any.
@@ -118,6 +115,9 @@
   // reset to the start of the selected range.
   bool DeleteSelected();
 
+  // Returns a range covering the entire text.
+  TextRange text_range() const { return TextRange(0, text_.length()); }
+
   std::u16string text_;
   TextRange selection_ = TextRange(0);
 };
diff --git a/shell/platform/common/cpp/text_input_model_unittests.cc b/shell/platform/common/cpp/text_input_model_unittests.cc
index 86c4771..730f2b9 100644
--- a/shell/platform/common/cpp/text_input_model_unittests.cc
+++ b/shell/platform/common/cpp/text_input_model_unittests.cc
@@ -41,65 +41,58 @@
 TEST(TextInputModel, SetTextResetsSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(3, 3));
-  EXPECT_EQ(model->selection_base(), 3);
-  EXPECT_EQ(model->selection_extent(), 3);
+  EXPECT_TRUE(model->SetSelection(TextRange(3)));
+  EXPECT_EQ(model->selection(), TextRange(3));
   model->SetText("FGHJI");
-  EXPECT_EQ(model->selection_base(), 0);
-  EXPECT_EQ(model->selection_extent(), 0);
+  EXPECT_EQ(model->selection(), TextRange(0));
 }
 
 TEST(TextInputModel, SetSelectionStart) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(0, 0));
-  EXPECT_EQ(model->selection_base(), 0);
-  EXPECT_EQ(model->selection_extent(), 0);
+  EXPECT_TRUE(model->SetSelection(TextRange(0)));
+  EXPECT_EQ(model->selection(), TextRange(0));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, SetSelectionMiddle) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
-  EXPECT_EQ(model->selection_base(), 2);
-  EXPECT_EQ(model->selection_extent(), 2);
+  EXPECT_TRUE(model->SetSelection(TextRange(2)));
+  EXPECT_EQ(model->selection(), TextRange(2));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, SetSelectionEnd) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(5, 5));
-  EXPECT_EQ(model->selection_base(), 5);
-  EXPECT_EQ(model->selection_extent(), 5);
+  EXPECT_TRUE(model->SetSelection(TextRange(5, 5)));
+  EXPECT_EQ(model->selection(), TextRange(5));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, SetSelectionWthExtent) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(1, 4));
-  EXPECT_EQ(model->selection_base(), 1);
-  EXPECT_EQ(model->selection_extent(), 4);
+  EXPECT_TRUE(model->SetSelection(TextRange(1, 4)));
+  EXPECT_EQ(model->selection(), TextRange(1, 4));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, SetSelectionReverseExtent) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(4, 1));
-  EXPECT_EQ(model->selection_base(), 4);
-  EXPECT_EQ(model->selection_extent(), 1);
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 1)));
+  EXPECT_EQ(model->selection(), TextRange(4, 1));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, SetSelectionOutsideString) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_FALSE(model->SetSelection(4, 6));
-  EXPECT_FALSE(model->SetSelection(5, 6));
-  EXPECT_FALSE(model->SetSelection(6, 6));
+  EXPECT_FALSE(model->SetSelection(TextRange(4, 6)));
+  EXPECT_FALSE(model->SetSelection(TextRange(5, 6)));
+  EXPECT_FALSE(model->SetSelection(TextRange(6, 6)));
 }
 
 TEST(TextInputModel, AddCodePoint) {
@@ -109,48 +102,43 @@
   model->AddCodePoint(0x1f604);
   model->AddCodePoint('D');
   model->AddCodePoint('E');
-  EXPECT_EQ(model->selection_base(), 6);
-  EXPECT_EQ(model->selection_extent(), 6);
+  EXPECT_EQ(model->selection(), TextRange(6));
   EXPECT_STREQ(model->GetText().c_str(), "ABπŸ˜„DE");
 }
 
 TEST(TextInputModel, AddCodePointSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(1, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(1, 4)));
   model->AddCodePoint('x');
-  EXPECT_EQ(model->selection_base(), 2);
-  EXPECT_EQ(model->selection_extent(), 2);
+  EXPECT_EQ(model->selection(), TextRange(2));
   EXPECT_STREQ(model->GetText().c_str(), "AxE");
 }
 
 TEST(TextInputModel, AddCodePointReverseSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(4, 1));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 1)));
   model->AddCodePoint('x');
-  EXPECT_EQ(model->selection_base(), 2);
-  EXPECT_EQ(model->selection_extent(), 2);
+  EXPECT_EQ(model->selection(), TextRange(2));
   EXPECT_STREQ(model->GetText().c_str(), "AxE");
 }
 
 TEST(TextInputModel, AddCodePointSelectionWideCharacter) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(1, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(1, 4)));
   model->AddCodePoint(0x1f604);
-  EXPECT_EQ(model->selection_base(), 3);
-  EXPECT_EQ(model->selection_extent(), 3);
+  EXPECT_EQ(model->selection(), TextRange(3));
   EXPECT_STREQ(model->GetText().c_str(), "AπŸ˜„E");
 }
 
 TEST(TextInputModel, AddCodePointReverseSelectionWideCharacter) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(4, 1));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 1)));
   model->AddCodePoint(0x1f604);
-  EXPECT_EQ(model->selection_base(), 3);
-  EXPECT_EQ(model->selection_extent(), 3);
+  EXPECT_EQ(model->selection(), TextRange(3));
   EXPECT_STREQ(model->GetText().c_str(), "AπŸ˜„E");
 }
 
@@ -159,498 +147,448 @@
   model->AddText(u"ABCDE");
   model->AddText("πŸ˜„");
   model->AddText("FGHIJ");
-  EXPECT_EQ(model->selection_base(), 12);
-  EXPECT_EQ(model->selection_extent(), 12);
+  EXPECT_EQ(model->selection(), TextRange(12));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDEπŸ˜„FGHIJ");
 }
 
 TEST(TextInputModel, AddTextSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(1, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(1, 4)));
   model->AddText("xy");
-  EXPECT_EQ(model->selection_base(), 3);
-  EXPECT_EQ(model->selection_extent(), 3);
+  EXPECT_EQ(model->selection(), TextRange(3));
   EXPECT_STREQ(model->GetText().c_str(), "AxyE");
 }
 
 TEST(TextInputModel, AddTextReverseSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(4, 1));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 1)));
   model->AddText("xy");
-  EXPECT_EQ(model->selection_base(), 3);
-  EXPECT_EQ(model->selection_extent(), 3);
+  EXPECT_EQ(model->selection(), TextRange(3));
   EXPECT_STREQ(model->GetText().c_str(), "AxyE");
 }
 
 TEST(TextInputModel, AddTextSelectionWideCharacter) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(1, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(1, 4)));
   model->AddText(u"πŸ˜„πŸ™ƒ");
-  EXPECT_EQ(model->selection_base(), 5);
-  EXPECT_EQ(model->selection_extent(), 5);
+  EXPECT_EQ(model->selection(), TextRange(5));
   EXPECT_STREQ(model->GetText().c_str(), "AπŸ˜„πŸ™ƒE");
 }
 
 TEST(TextInputModel, AddTextReverseSelectionWideCharacter) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(4, 1));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 1)));
   model->AddText(u"πŸ˜„πŸ™ƒ");
-  EXPECT_EQ(model->selection_base(), 5);
-  EXPECT_EQ(model->selection_extent(), 5);
+  EXPECT_EQ(model->selection(), TextRange(5));
   EXPECT_STREQ(model->GetText().c_str(), "AπŸ˜„πŸ™ƒE");
 }
 
 TEST(TextInputModel, DeleteStart) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(0, 0));
+  EXPECT_TRUE(model->SetSelection(TextRange(0, 0)));
   ASSERT_TRUE(model->Delete());
-  EXPECT_EQ(model->selection_base(), 0);
-  EXPECT_EQ(model->selection_extent(), 0);
+  EXPECT_EQ(model->selection(), TextRange(0));
   EXPECT_STREQ(model->GetText().c_str(), "BCDE");
 }
 
 TEST(TextInputModel, DeleteMiddle) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   ASSERT_TRUE(model->Delete());
-  EXPECT_EQ(model->selection_base(), 2);
-  EXPECT_EQ(model->selection_extent(), 2);
+  EXPECT_EQ(model->selection(), TextRange(2));
   EXPECT_STREQ(model->GetText().c_str(), "ABDE");
 }
 
 TEST(TextInputModel, DeleteEnd) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(5, 5));
+  EXPECT_TRUE(model->SetSelection(TextRange(5, 5)));
   ASSERT_FALSE(model->Delete());
-  EXPECT_EQ(model->selection_base(), 5);
-  EXPECT_EQ(model->selection_extent(), 5);
+  EXPECT_EQ(model->selection(), TextRange(5));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, DeleteWideCharacters) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("πŸ˜„πŸ™ƒπŸ€ͺ🧐");
-  EXPECT_TRUE(model->SetSelection(4, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 4)));
   ASSERT_TRUE(model->Delete());
-  EXPECT_EQ(model->selection_base(), 4);
-  EXPECT_EQ(model->selection_extent(), 4);
+  EXPECT_EQ(model->selection(), TextRange(4));
   EXPECT_STREQ(model->GetText().c_str(), "πŸ˜„πŸ™ƒπŸ§");
 }
 
 TEST(TextInputModel, DeleteSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(1, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(1, 4)));
   ASSERT_TRUE(model->Delete());
-  EXPECT_EQ(model->selection_base(), 1);
-  EXPECT_EQ(model->selection_extent(), 1);
+  EXPECT_EQ(model->selection(), TextRange(1));
   EXPECT_STREQ(model->GetText().c_str(), "AE");
 }
 
 TEST(TextInputModel, DeleteReverseSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(4, 1));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 1)));
   ASSERT_TRUE(model->Delete());
-  EXPECT_EQ(model->selection_base(), 1);
-  EXPECT_EQ(model->selection_extent(), 1);
+  EXPECT_EQ(model->selection(), TextRange(1));
   EXPECT_STREQ(model->GetText().c_str(), "AE");
 }
 
 TEST(TextInputModel, DeleteSurroundingAtCursor) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   EXPECT_TRUE(model->DeleteSurrounding(0, 1));
-  EXPECT_EQ(model->selection_base(), 2);
-  EXPECT_EQ(model->selection_extent(), 2);
+  EXPECT_EQ(model->selection(), TextRange(2));
   EXPECT_STREQ(model->GetText().c_str(), "ABDE");
 }
 
 TEST(TextInputModel, DeleteSurroundingAtCursorAll) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   EXPECT_TRUE(model->DeleteSurrounding(0, 3));
-  EXPECT_EQ(model->selection_base(), 2);
-  EXPECT_EQ(model->selection_extent(), 2);
+  EXPECT_EQ(model->selection(), TextRange(2));
   EXPECT_STREQ(model->GetText().c_str(), "AB");
 }
 
 TEST(TextInputModel, DeleteSurroundingAtCursorGreedy) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   EXPECT_TRUE(model->DeleteSurrounding(0, 4));
-  EXPECT_EQ(model->selection_base(), 2);
-  EXPECT_EQ(model->selection_extent(), 2);
+  EXPECT_EQ(model->selection(), TextRange(2));
   EXPECT_STREQ(model->GetText().c_str(), "AB");
 }
 
 TEST(TextInputModel, DeleteSurroundingBeforeCursor) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   EXPECT_TRUE(model->DeleteSurrounding(-1, 1));
-  EXPECT_EQ(model->selection_base(), 1);
-  EXPECT_EQ(model->selection_extent(), 1);
+  EXPECT_EQ(model->selection(), TextRange(1));
   EXPECT_STREQ(model->GetText().c_str(), "ACDE");
 }
 
 TEST(TextInputModel, DeleteSurroundingBeforeCursorAll) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   EXPECT_TRUE(model->DeleteSurrounding(-2, 2));
-  EXPECT_EQ(model->selection_base(), 0);
-  EXPECT_EQ(model->selection_extent(), 0);
+  EXPECT_EQ(model->selection(), TextRange(0));
   EXPECT_STREQ(model->GetText().c_str(), "CDE");
 }
 
 TEST(TextInputModel, DeleteSurroundingBeforeCursorGreedy) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   EXPECT_TRUE(model->DeleteSurrounding(-3, 3));
-  EXPECT_EQ(model->selection_base(), 0);
-  EXPECT_EQ(model->selection_extent(), 0);
+  EXPECT_EQ(model->selection(), TextRange(0));
   EXPECT_STREQ(model->GetText().c_str(), "CDE");
 }
 
 TEST(TextInputModel, DeleteSurroundingAfterCursor) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   EXPECT_TRUE(model->DeleteSurrounding(1, 1));
-  EXPECT_EQ(model->selection_base(), 2);
-  EXPECT_EQ(model->selection_extent(), 2);
+  EXPECT_EQ(model->selection(), TextRange(2));
   EXPECT_STREQ(model->GetText().c_str(), "ABCE");
 }
 
 TEST(TextInputModel, DeleteSurroundingAfterCursorAll) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   EXPECT_TRUE(model->DeleteSurrounding(1, 2));
-  EXPECT_EQ(model->selection_base(), 2);
-  EXPECT_EQ(model->selection_extent(), 2);
+  EXPECT_EQ(model->selection(), TextRange(2));
   EXPECT_STREQ(model->GetText().c_str(), "ABC");
 }
 
 TEST(TextInputModel, DeleteSurroundingAfterCursorGreedy) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   EXPECT_TRUE(model->DeleteSurrounding(1, 3));
-  EXPECT_EQ(model->selection_base(), 2);
-  EXPECT_EQ(model->selection_extent(), 2);
+  EXPECT_EQ(model->selection(), TextRange(2));
   EXPECT_STREQ(model->GetText().c_str(), "ABC");
 }
 
 TEST(TextInputModel, DeleteSurroundingSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 3));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 3)));
   EXPECT_TRUE(model->DeleteSurrounding(0, 1));
-  EXPECT_EQ(model->selection_base(), 3);
-  EXPECT_EQ(model->selection_extent(), 3);
+  EXPECT_EQ(model->selection(), TextRange(3));
   EXPECT_STREQ(model->GetText().c_str(), "ABCE");
 }
 
 TEST(TextInputModel, DeleteSurroundingReverseSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(4, 3));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 3)));
   EXPECT_TRUE(model->DeleteSurrounding(0, 1));
-  EXPECT_EQ(model->selection_base(), 3);
-  EXPECT_EQ(model->selection_extent(), 3);
+  EXPECT_EQ(model->selection(), TextRange(3));
   EXPECT_STREQ(model->GetText().c_str(), "ABCE");
 }
 
 TEST(TextInputModel, BackspaceStart) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(0, 0));
+  EXPECT_TRUE(model->SetSelection(TextRange(0, 0)));
   ASSERT_FALSE(model->Backspace());
-  EXPECT_EQ(model->selection_base(), 0);
-  EXPECT_EQ(model->selection_extent(), 0);
+  EXPECT_EQ(model->selection(), TextRange(0));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, BackspaceMiddle) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   ASSERT_TRUE(model->Backspace());
-  EXPECT_EQ(model->selection_base(), 1);
-  EXPECT_EQ(model->selection_extent(), 1);
+  EXPECT_EQ(model->selection(), TextRange(1));
   EXPECT_STREQ(model->GetText().c_str(), "ACDE");
 }
 
 TEST(TextInputModel, BackspaceEnd) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(5, 5));
+  EXPECT_TRUE(model->SetSelection(TextRange(5, 5)));
   ASSERT_TRUE(model->Backspace());
-  EXPECT_EQ(model->selection_base(), 4);
-  EXPECT_EQ(model->selection_extent(), 4);
+  EXPECT_EQ(model->selection(), TextRange(4));
   EXPECT_STREQ(model->GetText().c_str(), "ABCD");
 }
 
 TEST(TextInputModel, BackspaceWideCharacters) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("πŸ˜„πŸ™ƒπŸ€ͺ🧐");
-  EXPECT_TRUE(model->SetSelection(4, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 4)));
   ASSERT_TRUE(model->Backspace());
-  EXPECT_EQ(model->selection_base(), 2);
-  EXPECT_EQ(model->selection_extent(), 2);
+  EXPECT_EQ(model->selection(), TextRange(2));
   EXPECT_STREQ(model->GetText().c_str(), "πŸ˜„πŸ€ͺ🧐");
 }
 
 TEST(TextInputModel, BackspaceSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(1, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(1, 4)));
   ASSERT_TRUE(model->Delete());
-  EXPECT_EQ(model->selection_base(), 1);
-  EXPECT_EQ(model->selection_extent(), 1);
+  EXPECT_EQ(model->selection(), TextRange(1));
   EXPECT_STREQ(model->GetText().c_str(), "AE");
 }
 
 TEST(TextInputModel, BackspaceReverseSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(4, 1));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 1)));
   ASSERT_TRUE(model->Delete());
-  EXPECT_EQ(model->selection_base(), 1);
-  EXPECT_EQ(model->selection_extent(), 1);
+  EXPECT_EQ(model->selection(), TextRange(1));
   EXPECT_STREQ(model->GetText().c_str(), "AE");
 }
 
 TEST(TextInputModel, MoveCursorForwardStart) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(0, 0));
+  EXPECT_TRUE(model->SetSelection(TextRange(0, 0)));
   EXPECT_TRUE(model->MoveCursorForward());
-  EXPECT_EQ(model->selection_base(), 1);
-  EXPECT_EQ(model->selection_extent(), 1);
+  EXPECT_EQ(model->selection(), TextRange(1));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorForwardMiddle) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   EXPECT_TRUE(model->MoveCursorForward());
-  EXPECT_EQ(model->selection_base(), 3);
-  EXPECT_EQ(model->selection_extent(), 3);
+  EXPECT_EQ(model->selection(), TextRange(3));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorForwardEnd) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(5, 5));
+  EXPECT_TRUE(model->SetSelection(TextRange(5, 5)));
   EXPECT_FALSE(model->MoveCursorForward());
-  EXPECT_EQ(model->selection_base(), 5);
-  EXPECT_EQ(model->selection_extent(), 5);
+  EXPECT_EQ(model->selection(), TextRange(5));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorForwardWideCharacters) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("πŸ˜„πŸ™ƒπŸ€ͺ🧐");
-  EXPECT_TRUE(model->SetSelection(4, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 4)));
   ASSERT_TRUE(model->MoveCursorForward());
-  EXPECT_EQ(model->selection_base(), 6);
-  EXPECT_EQ(model->selection_extent(), 6);
+  EXPECT_EQ(model->selection(), TextRange(6));
   EXPECT_STREQ(model->GetText().c_str(), "πŸ˜„πŸ™ƒπŸ€ͺ🧐");
 }
 
 TEST(TextInputModel, MoveCursorForwardSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(1, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(1, 4)));
   EXPECT_TRUE(model->MoveCursorForward());
-  EXPECT_EQ(model->selection_base(), 4);
-  EXPECT_EQ(model->selection_extent(), 4);
+  EXPECT_EQ(model->selection(), TextRange(4));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorForwardReverseSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(4, 1));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 1)));
   EXPECT_TRUE(model->MoveCursorForward());
-  EXPECT_EQ(model->selection_base(), 4);
-  EXPECT_EQ(model->selection_extent(), 4);
+  EXPECT_EQ(model->selection(), TextRange(4));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorBackStart) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(0, 0));
+  EXPECT_TRUE(model->SetSelection(TextRange(0, 0)));
   EXPECT_FALSE(model->MoveCursorBack());
-  EXPECT_EQ(model->selection_base(), 0);
-  EXPECT_EQ(model->selection_extent(), 0);
+  EXPECT_EQ(model->selection(), TextRange(0));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorBackMiddle) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   EXPECT_TRUE(model->MoveCursorBack());
-  EXPECT_EQ(model->selection_base(), 1);
-  EXPECT_EQ(model->selection_extent(), 1);
+  EXPECT_EQ(model->selection(), TextRange(1));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorBackEnd) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(5, 5));
+  EXPECT_TRUE(model->SetSelection(TextRange(5, 5)));
   EXPECT_TRUE(model->MoveCursorBack());
-  EXPECT_EQ(model->selection_base(), 4);
-  EXPECT_EQ(model->selection_extent(), 4);
+  EXPECT_EQ(model->selection(), TextRange(4));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorBackWideCharacters) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("πŸ˜„πŸ™ƒπŸ€ͺ🧐");
-  EXPECT_TRUE(model->SetSelection(4, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 4)));
   ASSERT_TRUE(model->MoveCursorBack());
-  EXPECT_EQ(model->selection_base(), 2);
-  EXPECT_EQ(model->selection_extent(), 2);
+  EXPECT_EQ(model->selection(), TextRange(2));
   EXPECT_STREQ(model->GetText().c_str(), "πŸ˜„πŸ™ƒπŸ€ͺ🧐");
 }
 
 TEST(TextInputModel, MoveCursorBackSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(1, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(1, 4)));
   EXPECT_TRUE(model->MoveCursorBack());
-  EXPECT_EQ(model->selection_base(), 1);
-  EXPECT_EQ(model->selection_extent(), 1);
+  EXPECT_EQ(model->selection(), TextRange(1));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorBackReverseSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(4, 1));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 1)));
   EXPECT_TRUE(model->MoveCursorBack());
-  EXPECT_EQ(model->selection_base(), 1);
-  EXPECT_EQ(model->selection_extent(), 1);
+  EXPECT_EQ(model->selection(), TextRange(1));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorToBeginningStart) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(0, 0));
+  EXPECT_TRUE(model->SetSelection(TextRange(0, 0)));
   EXPECT_FALSE(model->MoveCursorToBeginning());
-  EXPECT_EQ(model->selection_base(), 0);
-  EXPECT_EQ(model->selection_extent(), 0);
+  EXPECT_EQ(model->selection(), TextRange(0));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorToBeginningMiddle) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   EXPECT_TRUE(model->MoveCursorToBeginning());
-  EXPECT_EQ(model->selection_base(), 0);
-  EXPECT_EQ(model->selection_extent(), 0);
+  EXPECT_EQ(model->selection(), TextRange(0));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorToBeginningEnd) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(5, 5));
+  EXPECT_TRUE(model->SetSelection(TextRange(5, 5)));
   EXPECT_TRUE(model->MoveCursorToBeginning());
-  EXPECT_EQ(model->selection_base(), 0);
-  EXPECT_EQ(model->selection_extent(), 0);
+  EXPECT_EQ(model->selection(), TextRange(0));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorToBeginningSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(1, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(1, 4)));
   EXPECT_TRUE(model->MoveCursorToBeginning());
-  EXPECT_EQ(model->selection_base(), 0);
-  EXPECT_EQ(model->selection_extent(), 0);
+  EXPECT_EQ(model->selection(), TextRange(0));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorToBeginningReverseSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(4, 1));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 1)));
   EXPECT_TRUE(model->MoveCursorToBeginning());
-  EXPECT_EQ(model->selection_base(), 0);
-  EXPECT_EQ(model->selection_extent(), 0);
+  EXPECT_EQ(model->selection(), TextRange(0));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorToEndStart) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(0, 0));
+  EXPECT_TRUE(model->SetSelection(TextRange(0, 0)));
   EXPECT_TRUE(model->MoveCursorToEnd());
-  EXPECT_EQ(model->selection_base(), 5);
-  EXPECT_EQ(model->selection_extent(), 5);
+  EXPECT_EQ(model->selection(), TextRange(5));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorToEndMiddle) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(2, 2));
+  EXPECT_TRUE(model->SetSelection(TextRange(2, 2)));
   EXPECT_TRUE(model->MoveCursorToEnd());
-  EXPECT_EQ(model->selection_base(), 5);
-  EXPECT_EQ(model->selection_extent(), 5);
+  EXPECT_EQ(model->selection(), TextRange(5));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorToEndEnd) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(5, 5));
+  EXPECT_TRUE(model->SetSelection(TextRange(5, 5)));
   EXPECT_FALSE(model->MoveCursorToEnd());
-  EXPECT_EQ(model->selection_base(), 5);
-  EXPECT_EQ(model->selection_extent(), 5);
+  EXPECT_EQ(model->selection(), TextRange(5));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorToEndSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(1, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(1, 4)));
   EXPECT_TRUE(model->MoveCursorToEnd());
-  EXPECT_EQ(model->selection_base(), 5);
-  EXPECT_EQ(model->selection_extent(), 5);
+  EXPECT_EQ(model->selection(), TextRange(5));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
 TEST(TextInputModel, MoveCursorToEndReverseSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(4, 1));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 1)));
   EXPECT_TRUE(model->MoveCursorToEnd());
-  EXPECT_EQ(model->selection_base(), 5);
-  EXPECT_EQ(model->selection_extent(), 5);
+  EXPECT_EQ(model->selection(), TextRange(5));
   EXPECT_STREQ(model->GetText().c_str(), "ABCDE");
 }
 
@@ -658,7 +596,7 @@
   auto model = std::make_unique<TextInputModel>();
   // These characters take 1, 2, 3 and 4 bytes in UTF-8.
   model->SetText("$¢€πˆ");
-  EXPECT_TRUE(model->SetSelection(0, 0));
+  EXPECT_TRUE(model->SetSelection(TextRange(0, 0)));
   EXPECT_EQ(model->GetCursorOffset(), 0);
   EXPECT_TRUE(model->MoveCursorForward());
   EXPECT_EQ(model->GetCursorOffset(), 1);
@@ -673,14 +611,14 @@
 TEST(TextInputModel, GetCursorOffsetSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(1, 4));
+  EXPECT_TRUE(model->SetSelection(TextRange(1, 4)));
   EXPECT_EQ(model->GetCursorOffset(), 4);
 }
 
 TEST(TextInputModel, GetCursorOffsetReverseSelection) {
   auto model = std::make_unique<TextInputModel>();
   model->SetText("ABCDE");
-  EXPECT_TRUE(model->SetSelection(4, 1));
+  EXPECT_TRUE(model->SetSelection(TextRange(4, 1)));
   EXPECT_EQ(model->GetCursorOffset(), 1);
 }
 
diff --git a/shell/platform/common/cpp/text_range.h b/shell/platform/common/cpp/text_range.h
index 6524a26..60482da 100644
--- a/shell/platform/common/cpp/text_range.h
+++ b/shell/platform/common/cpp/text_range.h
@@ -47,6 +47,23 @@
   // Returns true if the range is of length 0.
   bool collapsed() const { return base_ == extent_; }
 
+  // Returns true if the base is greater than the extent.
+  bool reversed() const { return base_ > extent_; }
+
+  // Returns true if |position| is contained within the range.
+  bool Contains(size_t position) const {
+    return position >= start() && position <= end();
+  }
+
+  // Returns true if |range| is contained within the range.
+  bool Contains(const TextRange& range) const {
+    return range.start() >= start() && range.end() <= end();
+  }
+
+  bool operator==(const TextRange& other) const {
+    return base_ == other.base_ && extent_ == other.extent_;
+  }
+
  private:
   size_t base_;
   size_t extent_;
diff --git a/shell/platform/common/cpp/text_range_unittests.cc b/shell/platform/common/cpp/text_range_unittests.cc
index cdeff77..8fcf8fe 100644
--- a/shell/platform/common/cpp/text_range_unittests.cc
+++ b/shell/platform/common/cpp/text_range_unittests.cc
@@ -50,4 +50,123 @@
   EXPECT_FALSE(range.collapsed());
 }
 
+TEST(TextRange, ContainsPreStartPosition) {
+  TextRange range(2, 6);
+  EXPECT_FALSE(range.Contains(1));
+}
+
+TEST(TextRange, ContainsStartPosition) {
+  TextRange range(2, 6);
+  EXPECT_TRUE(range.Contains(2));
+}
+
+TEST(TextRange, ContainsMiddlePosition) {
+  TextRange range(2, 6);
+  EXPECT_TRUE(range.Contains(3));
+  EXPECT_TRUE(range.Contains(4));
+}
+
+TEST(TextRange, ContainsEndPosition) {
+  TextRange range(2, 6);
+  EXPECT_TRUE(range.Contains(6));
+}
+
+TEST(TextRange, ContainsPostEndPosition) {
+  TextRange range(2, 6);
+  EXPECT_FALSE(range.Contains(7));
+}
+
+TEST(TextRange, ContainsPreStartPositionReversed) {
+  TextRange range(6, 2);
+  EXPECT_FALSE(range.Contains(1));
+}
+
+TEST(TextRange, ContainsStartPositionReversed) {
+  TextRange range(6, 2);
+  EXPECT_TRUE(range.Contains(2));
+}
+
+TEST(TextRange, ContainsMiddlePositionReversed) {
+  TextRange range(6, 2);
+  EXPECT_TRUE(range.Contains(3));
+  EXPECT_TRUE(range.Contains(4));
+}
+
+TEST(TextRange, ContainsEndPositionReversed) {
+  TextRange range(6, 2);
+  EXPECT_TRUE(range.Contains(6));
+}
+
+TEST(TextRange, ContainsPostEndPositionReversed) {
+  TextRange range(6, 2);
+  EXPECT_FALSE(range.Contains(7));
+}
+
+TEST(TextRange, ContainsRangePreStartPosition) {
+  TextRange range(2, 6);
+  EXPECT_FALSE(range.Contains(TextRange(0, 1)));
+}
+
+TEST(TextRange, ContainsRangeStartPosition) {
+  TextRange range(2, 6);
+  EXPECT_TRUE(range.Contains(TextRange(2)));
+}
+
+TEST(TextRange, ContainsRangeMiddlePosition) {
+  TextRange range(2, 6);
+  EXPECT_TRUE(range.Contains(TextRange(3, 4)));
+  EXPECT_TRUE(range.Contains(TextRange(4, 5)));
+}
+
+TEST(TextRange, ContainsRangeEndPosition) {
+  TextRange range(2, 6);
+  EXPECT_TRUE(range.Contains(TextRange(6)));
+}
+
+TEST(TextRange, ContainsRangePostEndPosition) {
+  TextRange range(2, 6);
+  EXPECT_FALSE(range.Contains(TextRange(6, 7)));
+}
+
+TEST(TextRange, ContainsRangePreStartPositionReversed) {
+  TextRange range(6, 2);
+  EXPECT_FALSE(range.Contains(TextRange(0, 1)));
+}
+
+TEST(TextRange, ContainsRangeStartPositionReversed) {
+  TextRange range(6, 2);
+  EXPECT_TRUE(range.Contains(TextRange(2)));
+}
+
+TEST(TextRange, ContainsRangeMiddlePositionReversed) {
+  TextRange range(6, 2);
+  EXPECT_TRUE(range.Contains(TextRange(3, 4)));
+  EXPECT_TRUE(range.Contains(TextRange(4, 5)));
+}
+
+TEST(TextRange, ContainsRangeEndPositionReversed) {
+  TextRange range(6, 2);
+  EXPECT_TRUE(range.Contains(TextRange(5)));
+}
+
+TEST(TextRange, ContainsRangePostEndPositionReversed) {
+  TextRange range(6, 2);
+  EXPECT_FALSE(range.Contains(TextRange(6, 7)));
+}
+
+TEST(TextRange, ReversedForwardRange) {
+  TextRange range(2, 6);
+  EXPECT_FALSE(range.reversed());
+}
+
+TEST(TextRange, ReversedCollapsedRange) {
+  TextRange range(2, 2);
+  EXPECT_FALSE(range.reversed());
+}
+
+TEST(TextRange, ReversedReversedRange) {
+  TextRange range(6, 2);
+  EXPECT_TRUE(range.reversed());
+}
+
 }  // namespace flutter
diff --git a/shell/platform/glfw/text_input_plugin.cc b/shell/platform/glfw/text_input_plugin.cc
index 7a7a88f..7ebc29e 100644
--- a/shell/platform/glfw/text_input_plugin.cc
+++ b/shell/platform/glfw/text_input_plugin.cc
@@ -195,7 +195,7 @@
       base = extent = 0;
     }
     active_model_->SetText(text->value.GetString());
-    active_model_->SetSelection(base, extent);
+    active_model_->SetSelection(TextRange(base, extent));
   } else {
     result->NotImplemented();
     return;
@@ -210,14 +210,14 @@
   auto& allocator = args->GetAllocator();
   args->PushBack(client_id_, allocator);
 
+  TextRange selection = model.selection();
   rapidjson::Value editing_state(rapidjson::kObjectType);
   editing_state.AddMember(kComposingBaseKey, -1, allocator);
   editing_state.AddMember(kComposingExtentKey, -1, allocator);
   editing_state.AddMember(kSelectionAffinityKey, kAffinityDownstream,
                           allocator);
-  editing_state.AddMember(kSelectionBaseKey, model.selection_base(), allocator);
-  editing_state.AddMember(kSelectionExtentKey, model.selection_extent(),
-                          allocator);
+  editing_state.AddMember(kSelectionBaseKey, selection.base(), allocator);
+  editing_state.AddMember(kSelectionExtentKey, selection.extent(), allocator);
   editing_state.AddMember(kSelectionIsDirectionalKey, false, allocator);
   editing_state.AddMember(
       kTextKey, rapidjson::Value(model.GetText(), allocator).Move(), allocator);
diff --git a/shell/platform/linux/fl_text_input_plugin.cc b/shell/platform/linux/fl_text_input_plugin.cc
index ae9ed10..11dc848 100644
--- a/shell/platform/linux/fl_text_input_plugin.cc
+++ b/shell/platform/linux/fl_text_input_plugin.cc
@@ -90,15 +90,14 @@
   fl_value_append_take(args, fl_value_new_int(self->client_id));
   g_autoptr(FlValue) value = fl_value_new_map();
 
+  TextRange selection = self->text_model->selection();
   fl_value_set_string_take(
       value, kTextKey,
       fl_value_new_string(self->text_model->GetText().c_str()));
-  fl_value_set_string_take(
-      value, kSelectionBaseKey,
-      fl_value_new_int(self->text_model->selection_base()));
-  fl_value_set_string_take(
-      value, kSelectionExtentKey,
-      fl_value_new_int(self->text_model->selection_extent()));
+  fl_value_set_string_take(value, kSelectionBaseKey,
+                           fl_value_new_int(selection.base()));
+  fl_value_set_string_take(value, kSelectionExtentKey,
+                           fl_value_new_int(selection.extent()));
 
   // The following keys are not implemented and set to default values.
   fl_value_set_string_take(value, kSelectionAffinityKey,
@@ -219,7 +218,7 @@
   }
 
   self->text_model->SetText(text);
-  self->text_model->SetSelection(selection_base, selection_extent);
+  self->text_model->SetSelection(TextRange(selection_base, selection_extent));
 
   return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr));
 }
diff --git a/shell/platform/windows/text_input_plugin.cc b/shell/platform/windows/text_input_plugin.cc
index 1687664..e69caf5 100644
--- a/shell/platform/windows/text_input_plugin.cc
+++ b/shell/platform/windows/text_input_plugin.cc
@@ -196,7 +196,7 @@
       base = extent = 0;
     }
     active_model_->SetText(text->value.GetString());
-    active_model_->SetSelection(base, extent);
+    active_model_->SetSelection(TextRange(base, extent));
   } else {
     result->NotImplemented();
     return;
@@ -211,14 +211,14 @@
   auto& allocator = args->GetAllocator();
   args->PushBack(client_id_, allocator);
 
+  TextRange selection = model.selection();
   rapidjson::Value editing_state(rapidjson::kObjectType);
   editing_state.AddMember(kComposingBaseKey, -1, allocator);
   editing_state.AddMember(kComposingExtentKey, -1, allocator);
   editing_state.AddMember(kSelectionAffinityKey, kAffinityDownstream,
                           allocator);
-  editing_state.AddMember(kSelectionBaseKey, model.selection_base(), allocator);
-  editing_state.AddMember(kSelectionExtentKey, model.selection_extent(),
-                          allocator);
+  editing_state.AddMember(kSelectionBaseKey, selection.base(), allocator);
+  editing_state.AddMember(kSelectionExtentKey, selection.extent(), allocator);
   editing_state.AddMember(kSelectionIsDirectionalKey, false, allocator);
   editing_state.AddMember(
       kTextKey, rapidjson::Value(model.GetText(), allocator).Move(), allocator);