Skip to content

Commit

Permalink
Handle the case of no selection rects (flutter#117419)
Browse files Browse the repository at this point in the history
Fixes an error that can occur when selection contains a partial glyph.
  • Loading branch information
justinmc committed Dec 21, 2022
1 parent 8ff1b6e commit 2931e50
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 2 deletions.
11 changes: 9 additions & 2 deletions packages/flutter/lib/src/widgets/editable_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3266,8 +3266,15 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
rectToReveal = targetOffset.rect;
} else {
final List<Rect> selectionBoxes = renderEditable.getBoxesForSelection(selection);
rectToReveal = selection.baseOffset < selection.extentOffset ?
selectionBoxes.last : selectionBoxes.first;
// selectionBoxes may be empty if, for example, the selection does not
// encompass a full character, like if it only contained part of an
// extended grapheme cluster.
if (selectionBoxes.isEmpty) {
rectToReveal = targetOffset.rect;
} else {
rectToReveal = selection.baseOffset < selection.extentOffset ?
selectionBoxes.last : selectionBoxes.first;
}
}

if (withAnimation) {
Expand Down
44 changes: 44 additions & 0 deletions packages/flutter/test/widgets/editable_text_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14354,6 +14354,50 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async
);
});
});

// Regression test for: https://github.com/flutter/flutter/issues/117418.
testWidgets('can handle the partial selection of a multi-code-unit glyph', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: EditableText(
controller: controller,
showSelectionHandles: true,
autofocus: true,
focusNode: FocusNode(),
style: Typography.material2018().black.titleMedium!,
cursorColor: Colors.blue,
backgroundCursorColor: Colors.grey,
selectionControls: materialTextSelectionControls,
keyboardType: TextInputType.text,
textAlign: TextAlign.right,
minLines: 2,
maxLines: 2,
),
),
);

await tester.enterText(find.byType(EditableText), '12345');
await tester.pumpAndSettle();

final EditableTextState state =
tester.state<EditableTextState>(find.byType(EditableText));
state.userUpdateTextEditingValue(
const TextEditingValue(
// This is an extended grapheme cluster made up of several code units,
// which has length 8. A selection from 0-1 does not fully select it.
text: '👨‍👩‍👦',
selection: TextSelection(
baseOffset: 0,
extentOffset: 1,
),
),
SelectionChangedCause.keyboard,
);

await tester.pumpAndSettle();

expect(tester.takeException(), null);
});
}

class UnsettableController extends TextEditingController {
Expand Down

0 comments on commit 2931e50

Please sign in to comment.