Use baseline value to get position in next line (#93129)
This commit is contained in:
parent
52ae102f18
commit
0374542cc5
@ -161,16 +161,6 @@ class VerticalCaretMovementRun extends BidirectionalIterator<TextPosition> {
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
// Computes the vertical distance from the `from` line's bottom to the `to`
|
||||
// lines top.
|
||||
double _lineDistance(int from, int to) {
|
||||
double lineHeight = 0;
|
||||
for (int index = from + 1; index < to; index += 1) {
|
||||
lineHeight += _lineMetrics[index].height;
|
||||
}
|
||||
return lineHeight;
|
||||
}
|
||||
|
||||
final Map<int, MapEntry<Offset, TextPosition>> _positionCache = <int, MapEntry<Offset, TextPosition>>{};
|
||||
|
||||
MapEntry<Offset, TextPosition> _getTextPositionForLine(int lineNumber) {
|
||||
@ -181,11 +171,8 @@ class VerticalCaretMovementRun extends BidirectionalIterator<TextPosition> {
|
||||
return cachedPosition;
|
||||
}
|
||||
assert(lineNumber != _currentLine);
|
||||
final double distanceY = lineNumber > _currentLine
|
||||
? _lineMetrics[_currentLine].descent + _lineMetrics[lineNumber].ascent + _lineDistance(_currentLine, lineNumber)
|
||||
: - _lineMetrics[_currentLine].ascent - _lineMetrics[lineNumber].descent - _lineDistance(lineNumber, _currentLine);
|
||||
|
||||
final Offset newOffset = _currentOffset.translate(0, distanceY);
|
||||
final Offset newOffset = Offset(_currentOffset.dx, _lineMetrics[lineNumber].baseline);
|
||||
final TextPosition closestPosition = _editable._textPainter.getPositionForOffset(newOffset);
|
||||
final MapEntry<Offset, TextPosition> position = MapEntry<Offset, TextPosition>(newOffset, closestPosition);
|
||||
_positionCache[lineNumber] = position;
|
||||
@ -2418,17 +2405,16 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin,
|
||||
// TODO(LongCatIsLooong): include line boundaries information in
|
||||
// ui.LineMetrics, then we can get rid of this.
|
||||
final Offset offset = _textPainter.getOffsetForCaret(startPosition, Rect.zero);
|
||||
int line = 0;
|
||||
double accumulatedHeight = 0;
|
||||
for (final ui.LineMetrics lineMetrics in metrics) {
|
||||
if (accumulatedHeight + lineMetrics.height > offset.dy) {
|
||||
return MapEntry<int, Offset>(line, Offset(offset.dx, lineMetrics.baseline));
|
||||
if (lineMetrics.baseline + lineMetrics.descent > offset.dy) {
|
||||
return MapEntry<int, Offset>(lineMetrics.lineNumber, Offset(offset.dx, lineMetrics.baseline));
|
||||
}
|
||||
line += 1;
|
||||
accumulatedHeight += lineMetrics.height;
|
||||
}
|
||||
assert(false, 'unable to find the line for $startPosition');
|
||||
return MapEntry<int, Offset>(math.max(0, metrics.length - 1), Offset(offset.dx, accumulatedHeight));
|
||||
return MapEntry<int, Offset>(
|
||||
math.max(0, metrics.length - 1),
|
||||
Offset(offset.dx, metrics.isNotEmpty ? metrics.last.baseline + metrics.last.descent : 0.0),
|
||||
);
|
||||
}
|
||||
|
||||
/// Starts a [VerticalCaretMovementRun] at the given location in the text, for
|
||||
|
@ -57,7 +57,12 @@ void main() {
|
||||
final TextEditingController controller = TextEditingController(text: testText);
|
||||
|
||||
final FocusNode focusNode = FocusNode();
|
||||
Widget buildEditableText({ TextAlign textAlign = TextAlign.left, bool readOnly = false, bool obscured = false }) {
|
||||
Widget buildEditableText({
|
||||
TextAlign textAlign = TextAlign.left,
|
||||
bool readOnly = false,
|
||||
bool obscured = false,
|
||||
TextStyle style = const TextStyle(fontSize: 10.0),
|
||||
}) {
|
||||
return MaterialApp(
|
||||
home: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
@ -69,7 +74,7 @@ void main() {
|
||||
showSelectionHandles: true,
|
||||
autofocus: true,
|
||||
focusNode: focusNode,
|
||||
style: const TextStyle(fontSize: 10),
|
||||
style: style,
|
||||
textScaleFactor: 1,
|
||||
// Avoid the cursor from taking up width.
|
||||
cursorWidth: 0,
|
||||
@ -1593,6 +1598,32 @@ void main() {
|
||||
offset: 3, // Would have been 4 if the run wasn't interrupted.
|
||||
));
|
||||
}, variant: TargetPlatformVariant.all());
|
||||
|
||||
testWidgets('long run with fractional text height', (WidgetTester tester) async {
|
||||
controller.text = "${'źdźbło\n' * 49}źdźbło";
|
||||
controller.selection = const TextSelection.collapsed(offset: 2);
|
||||
await tester.pumpWidget(buildEditableText(style: const TextStyle(fontSize: 13.0, height: 1.17)));
|
||||
|
||||
for (int i = 1; i <= 49; i++) {
|
||||
await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowDown));
|
||||
await tester.pump();
|
||||
expect(
|
||||
controller.selection,
|
||||
TextSelection.collapsed(offset: 2 + i * 7),
|
||||
reason: 'line $i',
|
||||
);
|
||||
}
|
||||
|
||||
for (int i = 49; i >= 1; i--) {
|
||||
await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowUp));
|
||||
await tester.pump();
|
||||
expect(
|
||||
controller.selection,
|
||||
TextSelection.collapsed(offset: 2 + (i - 1) * 7),
|
||||
reason: 'line $i',
|
||||
);
|
||||
}
|
||||
}, variant: TargetPlatformVariant.all());
|
||||
});
|
||||
});
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user