mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
fix getFullHeightForCaret when strut is disabled. (#154039)
Fixes https://github.com/flutter/flutter/issues/150638
This commit is contained in:
parent
418fa9d626
commit
b4c9a226cd
@ -371,6 +371,7 @@ class _TextLayout {
|
||||
|
||||
final double baseline = lineMetrics.baseline;
|
||||
final double dx;
|
||||
final double height;
|
||||
late final ui.GlyphInfo? lastGlyph = _paragraph.getGlyphInfoAt(rawString.length - 1);
|
||||
// TODO(LongCatIsLooong): handle the case where maxLine is set to non-null
|
||||
// and the last line ends with trailing whitespaces.
|
||||
@ -381,13 +382,15 @@ class _TextLayout {
|
||||
TextDirection.ltr => glyphBounds.right,
|
||||
TextDirection.rtl => glyphBounds.left,
|
||||
};
|
||||
height = glyphBounds.height;
|
||||
} else {
|
||||
dx = switch (writingDirection) {
|
||||
TextDirection.ltr => lineMetrics.left + lineMetrics.width,
|
||||
TextDirection.rtl => lineMetrics.left,
|
||||
};
|
||||
height = lineMetrics.height;
|
||||
}
|
||||
return _LineCaretMetrics(offset: Offset(dx, baseline), writingDirection: writingDirection);
|
||||
return _LineCaretMetrics(offset: Offset(dx, baseline), writingDirection: writingDirection, height: height);
|
||||
}
|
||||
|
||||
double _contentWidthFor(double minWidth, double maxWidth, TextWidthBasis widthBasis) {
|
||||
@ -501,8 +504,8 @@ class _TextPainterLayoutCacheWithOffset {
|
||||
/// The _CaretMetrics for carets located in a non-empty paragraph. Such carets
|
||||
/// are anchored to the trailing edge or the leading edge of a glyph, or a
|
||||
/// ligature component.
|
||||
final class _LineCaretMetrics {
|
||||
const _LineCaretMetrics({required this.offset, required this.writingDirection});
|
||||
class _LineCaretMetrics {
|
||||
const _LineCaretMetrics({required this.offset, required this.writingDirection, required this.height});
|
||||
/// The offset from the top left corner of the paragraph to the caret's top
|
||||
/// start location.
|
||||
final Offset offset;
|
||||
@ -512,10 +515,13 @@ final class _LineCaretMetrics {
|
||||
/// right of [offset].
|
||||
final TextDirection writingDirection;
|
||||
|
||||
/// The recommended height of the caret.
|
||||
final double height;
|
||||
|
||||
_LineCaretMetrics shift(Offset offset) {
|
||||
return offset == Offset.zero
|
||||
? this
|
||||
: _LineCaretMetrics(offset: offset + this.offset, writingDirection: writingDirection);
|
||||
: _LineCaretMetrics(offset: offset + this.offset, writingDirection: writingDirection, height: height);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1367,6 +1373,16 @@ class TextPainter {
|
||||
///
|
||||
/// Valid only after [layout] has been called.
|
||||
double getFullHeightForCaret(TextPosition position, Rect caretPrototype) {
|
||||
// The if condition is derived from
|
||||
// https://github.com/google/skia/blob/0086a17e0d4cc676cf88cae671ba5ee967eb7241/modules/skparagraph/src/TextLine.cpp#L1244-L1246
|
||||
// which is set here:
|
||||
// https://github.com/flutter/engine/blob/a821b8790c9fd0e095013cd5bd1f20273bc1ee47/third_party/txt/src/skia/paragraph_builder_skia.cc#L134
|
||||
if (strutStyle == null || strutStyle == StrutStyle.disabled || strutStyle?.fontSize == 0.0) {
|
||||
final double? heightFromCaretMetrics = _computeCaretMetrics(position)?.height;
|
||||
if (heightFromCaretMetrics != null) {
|
||||
return heightFromCaretMetrics;
|
||||
}
|
||||
}
|
||||
final TextBox textBox = _getOrCreateLayoutTemplate().getBoxesForRange(0, 1, boxHeightStyle: ui.BoxHeightStyle.strut).single;
|
||||
return textBox.toRect().height;
|
||||
}
|
||||
@ -1450,7 +1466,8 @@ class TextPainter {
|
||||
|
||||
if (glyphInfo == null) {
|
||||
// If the glyph isn't laid out, then the position points to a character
|
||||
// that is not laid out. Use the EOT caret.
|
||||
// that is not laid out (the part of text is invisible due to maxLines or
|
||||
// infinite paragraph x offset). Use the EOT caret.
|
||||
// TODO(LongCatIsLooong): assert when an invalid position is given.
|
||||
final ui.Paragraph template = _getOrCreateLayoutTemplate();
|
||||
assert(template.numberOfLines == 1);
|
||||
@ -1487,6 +1504,7 @@ class TextPainter {
|
||||
metrics = _LineCaretMetrics(
|
||||
offset: Offset(anchorToLeft ? box.left : box.right, box.top),
|
||||
writingDirection: box.direction,
|
||||
height: box.bottom - box.top,
|
||||
);
|
||||
} else {
|
||||
// Fall back to glyphInfo. This should only happen when using the HTML renderer.
|
||||
@ -1499,6 +1517,7 @@ class TextPainter {
|
||||
metrics = _LineCaretMetrics(
|
||||
offset: Offset(dx, graphemeBounds.top),
|
||||
writingDirection: glyphInfo.writingDirection,
|
||||
height: graphemeBounds.height,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -857,6 +857,28 @@ void main() {
|
||||
expect(caretOffset.dy, 0.0);
|
||||
painter.dispose();
|
||||
});
|
||||
|
||||
test('caret height reflects run height if strut is disabled', () {
|
||||
const TextSpan span = TextSpan(text: 'M', style: TextStyle(fontSize: 128), children: <InlineSpan>[
|
||||
TextSpan(text: 'M', style: TextStyle(fontSize: 32)),
|
||||
TextSpan(text: 'M', style: TextStyle(fontSize: 64)),
|
||||
]);
|
||||
final TextPainter painter = TextPainter()
|
||||
..textDirection = TextDirection.ltr
|
||||
..text = span
|
||||
..layout();
|
||||
|
||||
expect(painter.getFullHeightForCaret(const TextPosition(offset: 0, affinity: ui.TextAffinity.upstream), Rect.zero), 128.0);
|
||||
expect(painter.getFullHeightForCaret(const TextPosition(offset: 0), Rect.zero), 128.0);
|
||||
expect(painter.getFullHeightForCaret(const TextPosition(offset: 1, affinity: ui.TextAffinity.upstream), Rect.zero), 128.0);
|
||||
expect(painter.getFullHeightForCaret(const TextPosition(offset: 1), Rect.zero), 32.0);
|
||||
expect(painter.getFullHeightForCaret(const TextPosition(offset: 2, affinity: ui.TextAffinity.upstream), Rect.zero), 32.0);
|
||||
expect(painter.getFullHeightForCaret(const TextPosition(offset: 2), Rect.zero), 64.0);
|
||||
expect(painter.getFullHeightForCaret(const TextPosition(offset: 3, affinity: ui.TextAffinity.upstream), Rect.zero), 64.0);
|
||||
expect(painter.getFullHeightForCaret(const TextPosition(offset: 3), Rect.zero), 128.0);
|
||||
|
||||
painter.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
test('TextPainter error test', () {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user