Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 2931e50

Browse files
authored
Handle the case of no selection rects (#117419)
Fixes an error that can occur when selection contains a partial glyph.
1 parent 8ff1b6e commit 2931e50

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

packages/flutter/lib/src/widgets/editable_text.dart

+9-2
Original file line numberDiff line numberDiff line change
@@ -3266,8 +3266,15 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
32663266
rectToReveal = targetOffset.rect;
32673267
} else {
32683268
final List<Rect> selectionBoxes = renderEditable.getBoxesForSelection(selection);
3269-
rectToReveal = selection.baseOffset < selection.extentOffset ?
3270-
selectionBoxes.last : selectionBoxes.first;
3269+
// selectionBoxes may be empty if, for example, the selection does not
3270+
// encompass a full character, like if it only contained part of an
3271+
// extended grapheme cluster.
3272+
if (selectionBoxes.isEmpty) {
3273+
rectToReveal = targetOffset.rect;
3274+
} else {
3275+
rectToReveal = selection.baseOffset < selection.extentOffset ?
3276+
selectionBoxes.last : selectionBoxes.first;
3277+
}
32713278
}
32723279

32733280
if (withAnimation) {

packages/flutter/test/widgets/editable_text_test.dart

+44
Original file line numberDiff line numberDiff line change
@@ -14354,6 +14354,50 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async
1435414354
);
1435514355
});
1435614356
});
14357+
14358+
// Regression test for: https://github.com/flutter/flutter/issues/117418.
14359+
testWidgets('can handle the partial selection of a multi-code-unit glyph', (WidgetTester tester) async {
14360+
await tester.pumpWidget(
14361+
MaterialApp(
14362+
home: EditableText(
14363+
controller: controller,
14364+
showSelectionHandles: true,
14365+
autofocus: true,
14366+
focusNode: FocusNode(),
14367+
style: Typography.material2018().black.titleMedium!,
14368+
cursorColor: Colors.blue,
14369+
backgroundCursorColor: Colors.grey,
14370+
selectionControls: materialTextSelectionControls,
14371+
keyboardType: TextInputType.text,
14372+
textAlign: TextAlign.right,
14373+
minLines: 2,
14374+
maxLines: 2,
14375+
),
14376+
),
14377+
);
14378+
14379+
await tester.enterText(find.byType(EditableText), '12345');
14380+
await tester.pumpAndSettle();
14381+
14382+
final EditableTextState state =
14383+
tester.state<EditableTextState>(find.byType(EditableText));
14384+
state.userUpdateTextEditingValue(
14385+
const TextEditingValue(
14386+
// This is an extended grapheme cluster made up of several code units,
14387+
// which has length 8. A selection from 0-1 does not fully select it.
14388+
text: '👨‍👩‍👦',
14389+
selection: TextSelection(
14390+
baseOffset: 0,
14391+
extentOffset: 1,
14392+
),
14393+
),
14394+
SelectionChangedCause.keyboard,
14395+
);
14396+
14397+
await tester.pumpAndSettle();
14398+
14399+
expect(tester.takeException(), null);
14400+
});
1435714401
}
1435814402

1435914403
class UnsettableController extends TextEditingController {

0 commit comments

Comments
 (0)