Correct text selection pivot points (#71756)
diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart
index f162a7a..ce888fd 100644
--- a/packages/flutter/lib/src/rendering/editable.dart
+++ b/packages/flutter/lib/src/rendering/editable.dart
@@ -678,6 +678,8 @@
newSelection = newSelection.copyWith(extentOffset: textSelection.extentOffset);
}
} else {
+ // The directional arrows move the TextSelection.extentOffset, while the
+ // base remains fixed.
if (rightArrow && newSelection.extentOffset < _plainText.length) {
int nextExtent;
if (!shift && !wordModifier && !lineModifier && newSelection.start != newSelection.end) {
@@ -1849,6 +1851,9 @@
}
/// Select text between the global positions [from] and [to].
+ ///
+ /// [from] corresponds to the [TextSelection.baseOffset], and [to] corresponds
+ /// to the [TextSelection.extentOffset].
void selectPositionAt({ required Offset from, Offset? to, required SelectionChangedCause cause }) {
assert(cause != null);
assert(from != null);
@@ -1861,12 +1866,8 @@
? null
: _textPainter.getPositionForOffset(globalToLocal(to - _paintOffset));
- int baseOffset = fromPosition.offset;
- int extentOffset = fromPosition.offset;
- if (toPosition != null) {
- baseOffset = math.min(fromPosition.offset, toPosition.offset);
- extentOffset = math.max(fromPosition.offset, toPosition.offset);
- }
+ final int baseOffset = fromPosition.offset;
+ final int extentOffset = toPosition?.offset ?? fromPosition.offset;
final TextSelection newSelection = TextSelection(
baseOffset: baseOffset,
diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart
index 917b6e5..6e9f924 100644
--- a/packages/flutter/test/material/text_field_test.dart
+++ b/packages/flutter/test/material/text_field_test.dart
@@ -1458,8 +1458,8 @@
await gesture.up();
await tester.pumpAndSettle();
- expect(controller.selection.baseOffset, testValue.indexOf('e'));
- expect(controller.selection.extentOffset, testValue.indexOf('g'));
+ expect(controller.selection.baseOffset, testValue.indexOf('g'));
+ expect(controller.selection.extentOffset, testValue.indexOf('e'));
});
testWidgets('Slow mouse dragging also selects text', (WidgetTester tester) async {
diff --git a/packages/flutter/test/rendering/editable_test.dart b/packages/flutter/test/rendering/editable_test.dart
index 742fed2..748c97b 100644
--- a/packages/flutter/test/rendering/editable_test.dart
+++ b/packages/flutter/test/rendering/editable_test.dart
@@ -570,8 +570,8 @@
pumpFrame();
expect(currentSelection.isCollapsed, isFalse);
- expect(currentSelection.baseOffset, 1);
- expect(currentSelection.extentOffset, 3);
+ expect(currentSelection.baseOffset, 3);
+ expect(currentSelection.extentOffset, 1);
});
test('selection does not flicker as user is dragging', () {
@@ -1006,7 +1006,79 @@
await simulateKeyUpEvent(LogicalKeyboardKey.arrowLeft);
expect(currentSelection.isCollapsed, true);
expect(currentSelection.baseOffset, 2);
+ }, skip: isBrowser); // https://github.com/flutter/flutter/issues/58068
+ test('arrow keys with selection text and shift', () async {
+ final TextSelectionDelegate delegate = FakeEditableTextState();
+ final ViewportOffset viewportOffset = ViewportOffset.zero();
+ late TextSelection currentSelection;
+ final RenderEditable editable = RenderEditable(
+ backgroundCursorColor: Colors.grey,
+ selectionColor: Colors.black,
+ textDirection: TextDirection.ltr,
+ cursorColor: Colors.red,
+ offset: viewportOffset,
+ textSelectionDelegate: delegate,
+ onSelectionChanged: (TextSelection selection, RenderEditable renderObject, SelectionChangedCause cause) {
+ currentSelection = selection;
+ },
+ startHandleLayerLink: LayerLink(),
+ endHandleLayerLink: LayerLink(),
+ text: const TextSpan(
+ text: '012345', // Thumbs up
+ style: TextStyle(height: 1.0, fontSize: 10.0, fontFamily: 'Ahem'),
+ ),
+ selection: const TextSelection.collapsed(
+ offset: 0,
+ ),
+ );
+
+ layout(editable);
+ editable.hasFocus = true;
+
+ editable.selection = const TextSelection(baseOffset: 2, extentOffset: 4);
+ pumpFrame();
+
+ await simulateKeyDownEvent(LogicalKeyboardKey.shift);
+ await simulateKeyDownEvent(LogicalKeyboardKey.arrowRight);
+ await simulateKeyUpEvent(LogicalKeyboardKey.arrowRight);
+ await simulateKeyUpEvent(LogicalKeyboardKey.shift);
+ expect(currentSelection.isCollapsed, false);
+ expect(currentSelection.baseOffset, 2);
+ expect(currentSelection.extentOffset, 5);
+
+ editable.selection = const TextSelection(baseOffset: 4, extentOffset: 2);
+ pumpFrame();
+
+ await simulateKeyDownEvent(LogicalKeyboardKey.shift);
+ await simulateKeyDownEvent(LogicalKeyboardKey.arrowRight);
+ await simulateKeyUpEvent(LogicalKeyboardKey.arrowRight);
+ await simulateKeyUpEvent(LogicalKeyboardKey.shift);
+ expect(currentSelection.isCollapsed, false);
+ expect(currentSelection.baseOffset, 4);
+ expect(currentSelection.extentOffset, 3);
+
+ editable.selection = const TextSelection(baseOffset: 2, extentOffset: 4);
+ pumpFrame();
+
+ await simulateKeyDownEvent(LogicalKeyboardKey.shift);
+ await simulateKeyDownEvent(LogicalKeyboardKey.arrowLeft);
+ await simulateKeyUpEvent(LogicalKeyboardKey.arrowLeft);
+ await simulateKeyUpEvent(LogicalKeyboardKey.shift);
+ expect(currentSelection.isCollapsed, false);
+ expect(currentSelection.baseOffset, 2);
+ expect(currentSelection.extentOffset, 3);
+
+ editable.selection = const TextSelection(baseOffset: 4, extentOffset: 2);
+ pumpFrame();
+
+ await simulateKeyDownEvent(LogicalKeyboardKey.shift);
+ await simulateKeyDownEvent(LogicalKeyboardKey.arrowLeft);
+ await simulateKeyUpEvent(LogicalKeyboardKey.arrowLeft);
+ await simulateKeyUpEvent(LogicalKeyboardKey.shift);
+ expect(currentSelection.isCollapsed, false);
+ expect(currentSelection.baseOffset, 4);
+ expect(currentSelection.extentOffset, 1);
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/58068
group('delete', () {
diff --git a/packages/flutter/test/widgets/selectable_text_test.dart b/packages/flutter/test/widgets/selectable_text_test.dart
index bb8b198..7d2cd13 100644
--- a/packages/flutter/test/widgets/selectable_text_test.dart
+++ b/packages/flutter/test/widgets/selectable_text_test.dart
@@ -765,8 +765,8 @@
await gesture.up();
await tester.pumpAndSettle();
- expect(controller.selection.baseOffset, 5);
- expect(controller.selection.extentOffset, 8);
+ expect(controller.selection.baseOffset, 8);
+ expect(controller.selection.extentOffset, 5);
});
testWidgets('Slow mouse dragging also selects text', (WidgetTester tester) async {