Commit 21acf223 authored by Jason Simmons's avatar Jason Simmons Committed by GitHub

Use the engine's TextOverflow API to implement ellipsizing (#6104)

Fixes https://github.com/flutter/flutter/issues/4478
parent 88d9cbaa
...@@ -33,8 +33,9 @@ class TextPainter { ...@@ -33,8 +33,9 @@ class TextPainter {
TextPainter({ TextPainter({
TextSpan text, TextSpan text,
TextAlign textAlign, TextAlign textAlign,
double textScaleFactor: 1.0 double textScaleFactor: 1.0,
}) : _text = text, _textAlign = textAlign, _textScaleFactor = textScaleFactor { String ellipsis,
}) : _text = text, _textAlign = textAlign, _textScaleFactor = textScaleFactor, _ellipsis = ellipsis {
assert(text == null || text.debugAssertIsValid()); assert(text == null || text.debugAssertIsValid());
assert(textScaleFactor != null); assert(textScaleFactor != null);
} }
...@@ -80,6 +81,21 @@ class TextPainter { ...@@ -80,6 +81,21 @@ class TextPainter {
_needsLayout = true; _needsLayout = true;
} }
/// The string used to ellipsize overflowing text. Setting this to a nonempty
/// string will cause this string to be substituted for the remaining text
/// if the text can not fit within the specificed maximum width.
String get ellipsis => _ellipsis;
String _ellipsis;
set ellipsis(String value) {
assert(value == null || value.isNotEmpty);
if (_ellipsis == value)
return;
_ellipsis = value;
_paragraph = null;
_needsLayout = true;
}
// Unfortunately, using full precision floating point here causes bad layouts // Unfortunately, using full precision floating point here causes bad layouts
// because floating point math isn't associative. If we add and subtract // because floating point math isn't associative. If we add and subtract
// padding, for example, we'll get different values when we estimate sizes and // padding, for example, we'll get different values when we estimate sizes and
...@@ -162,7 +178,11 @@ class TextPainter { ...@@ -162,7 +178,11 @@ class TextPainter {
if (_paragraph == null) { if (_paragraph == null) {
ui.ParagraphBuilder builder = new ui.ParagraphBuilder(); ui.ParagraphBuilder builder = new ui.ParagraphBuilder();
_text.build(builder, textScaleFactor: textScaleFactor); _text.build(builder, textScaleFactor: textScaleFactor);
ui.ParagraphStyle paragraphStyle = _text.style?.getParagraphStyle(textAlign: textAlign, textScaleFactor: textScaleFactor); ui.ParagraphStyle paragraphStyle = _text.style?.getParagraphStyle(
textAlign: textAlign,
textScaleFactor: textScaleFactor,
ellipsis: _ellipsis,
);
paragraphStyle ??= new ui.ParagraphStyle(); paragraphStyle ??= new ui.ParagraphStyle();
_paragraph = builder.build(paragraphStyle); _paragraph = builder.build(paragraphStyle);
} }
......
...@@ -229,14 +229,19 @@ class TextStyle { ...@@ -229,14 +229,19 @@ class TextStyle {
} }
/// The style information for paragraphs, encoded for use by `dart:ui`. /// The style information for paragraphs, encoded for use by `dart:ui`.
ui.ParagraphStyle getParagraphStyle({ TextAlign textAlign, double textScaleFactor: 1.0 }) { ui.ParagraphStyle getParagraphStyle({
TextAlign textAlign,
double textScaleFactor: 1.0,
String ellipsis,
}) {
return new ui.ParagraphStyle( return new ui.ParagraphStyle(
textAlign: textAlign, textAlign: textAlign,
fontWeight: fontWeight, fontWeight: fontWeight,
fontStyle: fontStyle, fontStyle: fontStyle,
fontFamily: fontFamily, fontFamily: fontFamily,
fontSize: fontSize == null ? null : fontSize * textScaleFactor, fontSize: fontSize == null ? null : fontSize * textScaleFactor,
lineHeight: height lineHeight: height,
ellipsis: ellipsis,
); );
} }
......
...@@ -22,6 +22,8 @@ enum TextOverflow { ...@@ -22,6 +22,8 @@ enum TextOverflow {
ellipsis, ellipsis,
} }
const String _kEllipsis = '\u2026';
/// A render object that displays a paragraph of text /// A render object that displays a paragraph of text
class RenderParagraph extends RenderBox { class RenderParagraph extends RenderBox {
/// Creates a paragraph render object. /// Creates a paragraph render object.
...@@ -34,7 +36,12 @@ class RenderParagraph extends RenderBox { ...@@ -34,7 +36,12 @@ class RenderParagraph extends RenderBox {
double textScaleFactor: 1.0 double textScaleFactor: 1.0
}) : _softWrap = softWrap, }) : _softWrap = softWrap,
_overflow = overflow, _overflow = overflow,
_textPainter = new TextPainter(text: text, textAlign: textAlign, textScaleFactor: textScaleFactor) { _textPainter = new TextPainter(
text: text,
textAlign: textAlign,
textScaleFactor: textScaleFactor,
ellipsis: overflow == TextOverflow.ellipsis ? _kEllipsis : null,
) {
assert(text != null); assert(text != null);
assert(text.debugAssertIsValid()); assert(text.debugAssertIsValid());
assert(softWrap != null); assert(softWrap != null);
...@@ -51,7 +58,6 @@ class RenderParagraph extends RenderBox { ...@@ -51,7 +58,6 @@ class RenderParagraph extends RenderBox {
if (_textPainter.text == value) if (_textPainter.text == value)
return; return;
_textPainter.text = value; _textPainter.text = value;
_overflowPainter = null;
_overflowShader = null; _overflowShader = null;
markNeedsLayout(); markNeedsLayout();
} }
...@@ -86,6 +92,7 @@ class RenderParagraph extends RenderBox { ...@@ -86,6 +92,7 @@ class RenderParagraph extends RenderBox {
if (_overflow == value) if (_overflow == value)
return; return;
_overflow = value; _overflow = value;
_textPainter.ellipsis = value == TextOverflow.ellipsis ? _kEllipsis : null;
markNeedsPaint(); markNeedsPaint();
} }
...@@ -99,13 +106,13 @@ class RenderParagraph extends RenderBox { ...@@ -99,13 +106,13 @@ class RenderParagraph extends RenderBox {
if (_textPainter.textScaleFactor == value) if (_textPainter.textScaleFactor == value)
return; return;
_textPainter.textScaleFactor = value; _textPainter.textScaleFactor = value;
_overflowPainter = null;
_overflowShader = null; _overflowShader = null;
markNeedsLayout(); markNeedsLayout();
} }
void _layoutText({ double minWidth: 0.0, double maxWidth: double.INFINITY }) { void _layoutText({ double minWidth: 0.0, double maxWidth: double.INFINITY }) {
_textPainter.layout(minWidth: minWidth, maxWidth: _softWrap ? maxWidth : double.INFINITY); bool wrap = _softWrap || _overflow == TextOverflow.ellipsis;
_textPainter.layout(minWidth: minWidth, maxWidth: wrap ? maxWidth : double.INFINITY);
} }
@override @override
...@@ -160,7 +167,6 @@ class RenderParagraph extends RenderBox { ...@@ -160,7 +167,6 @@ class RenderParagraph extends RenderBox {
} }
bool _hasVisualOverflow = false; bool _hasVisualOverflow = false;
TextPainter _overflowPainter;
ui.Shader _overflowShader; ui.Shader _overflowShader;
@override @override
...@@ -182,20 +188,16 @@ class RenderParagraph extends RenderBox { ...@@ -182,20 +188,16 @@ class RenderParagraph extends RenderBox {
if (didOverflowWidth) { if (didOverflowWidth) {
switch (_overflow) { switch (_overflow) {
case TextOverflow.clip: case TextOverflow.clip:
_overflowPainter = null; case TextOverflow.ellipsis:
_overflowShader = null; _overflowShader = null;
break; break;
case TextOverflow.fade: case TextOverflow.fade:
case TextOverflow.ellipsis: TextPainter fadeWidthPainter = new TextPainter(
_overflowPainter ??= new TextPainter(
text: new TextSpan(style: _textPainter.text.style, text: '\u2026'), text: new TextSpan(style: _textPainter.text.style, text: '\u2026'),
textScaleFactor: textScaleFactor textScaleFactor: textScaleFactor
)..layout(); )..layout();
final double overflowUnit = _overflowPainter.width; final double fadeEnd = size.width;
double fadeEnd = size.width; final double fadeStart = fadeEnd - fadeWidthPainter.width;
if (_overflow == TextOverflow.ellipsis)
fadeEnd -= overflowUnit / 2.0;
final double fadeStart = fadeEnd - _overflowPainter.width;
// TODO(abarth): This shader has an LTR bias. // TODO(abarth): This shader has an LTR bias.
_overflowShader = new ui.Gradient.linear( _overflowShader = new ui.Gradient.linear(
<Point>[new Point(fadeStart, 0.0), new Point(fadeEnd, 0.0)], <Point>[new Point(fadeStart, 0.0), new Point(fadeEnd, 0.0)],
...@@ -204,7 +206,6 @@ class RenderParagraph extends RenderBox { ...@@ -204,7 +206,6 @@ class RenderParagraph extends RenderBox {
break; break;
} }
} else { } else {
_overflowPainter = null;
_overflowShader = null; _overflowShader = null;
} }
} }
...@@ -225,7 +226,7 @@ class RenderParagraph extends RenderBox { ...@@ -225,7 +226,7 @@ class RenderParagraph extends RenderBox {
final Canvas canvas = context.canvas; final Canvas canvas = context.canvas;
if (_hasVisualOverflow) { if (_hasVisualOverflow) {
final Rect bounds = offset & size; final Rect bounds = offset & size;
if (_overflowPainter != null) if (_overflowShader != null)
canvas.saveLayer(bounds, new Paint()); canvas.saveLayer(bounds, new Paint());
else else
canvas.save(); canvas.save();
...@@ -239,11 +240,6 @@ class RenderParagraph extends RenderBox { ...@@ -239,11 +240,6 @@ class RenderParagraph extends RenderBox {
..transferMode = TransferMode.modulate ..transferMode = TransferMode.modulate
..shader = _overflowShader; ..shader = _overflowShader;
canvas.drawRect(Point.origin & size, paint); canvas.drawRect(Point.origin & size, paint);
if (_overflow == TextOverflow.ellipsis) {
// TODO(abarth): This paint offset has an LTR bias.
Offset ellipseOffset = new Offset(size.width - _overflowPainter.width, 0.0);
_overflowPainter.paint(canvas, ellipseOffset);
}
} }
canvas.restore(); canvas.restore();
} }
......
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