Unverified Commit 0374542c authored by Tomasz Gucio's avatar Tomasz Gucio Committed by GitHub

Use baseline value to get position in next line (#93129)

parent 52ae102f
......@@ -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());
});
});
},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment