@@ -416,13 +416,19 @@ class DomTextMeasurementService extends TextMeasurementService {
416416 List <EngineLineMetrics > lines;
417417 if (text != null ) {
418418 final double lineWidth = maxIntrinsicWidth;
419+ final double alignOffset = _calculateAlignOffsetForLine (
420+ paragraph: paragraph,
421+ lineWidth: lineWidth,
422+ maxWidth: width,
423+ );
419424 lines = < EngineLineMetrics > [
420425 EngineLineMetrics .withText (
421426 text,
422427 startIndex: 0 ,
423428 endIndex: text.length,
424429 hardBreak: true ,
425430 width: lineWidth,
431+ left: alignOffset,
426432 lineNumber: 0 ,
427433 ),
428434 ];
@@ -440,6 +446,8 @@ class DomTextMeasurementService extends TextMeasurementService {
440446 alphabeticBaseline: alphabeticBaseline,
441447 ideographicBaseline: ideographicBaseline,
442448 lines: lines,
449+ textAlign: paragraph._textAlign,
450+ textDirection: paragraph._textDirection,
443451 );
444452 }
445453
@@ -488,6 +496,8 @@ class DomTextMeasurementService extends TextMeasurementService {
488496 alphabeticBaseline: alphabeticBaseline,
489497 ideographicBaseline: ideographicBaseline,
490498 lines: null ,
499+ textAlign: paragraph._textAlign,
500+ textDirection: paragraph._textDirection,
491501 );
492502 }
493503
@@ -546,7 +556,7 @@ class CanvasTextMeasurementService extends TextMeasurementService {
546556 // TODO(mdebbar): Check if the whole text can fit in a single-line. Then avoid all this ceremony.
547557 _canvasContext.font = style.cssFontString;
548558 final LinesCalculator linesCalculator =
549- LinesCalculator (_canvasContext, text, style , constraints.width);
559+ LinesCalculator (_canvasContext, paragraph , constraints.width);
550560 final MinIntrinsicCalculator minIntrinsicCalculator =
551561 MinIntrinsicCalculator (_canvasContext, text, style);
552562 final MaxIntrinsicCalculator maxIntrinsicCalculator =
@@ -597,6 +607,8 @@ class CanvasTextMeasurementService extends TextMeasurementService {
597607 maxIntrinsicWidth: maxIntrinsicCalculator.value,
598608 width: constraints.width,
599609 lines: linesCalculator.lines,
610+ textAlign: paragraph._textAlign,
611+ textDirection: paragraph._textDirection,
600612 );
601613 return result;
602614 }
@@ -702,16 +714,18 @@ int _excludeTrailing(String text, int start, int end, CharPredicate predicate) {
702714/// During the text layout phase, this class splits the lines of text so that it
703715/// ends up fitting into the given width constraint.
704716///
705- /// It mimicks the Flutter engine's behavior when it comes to handling ellipsis
706- /// and max lines.
717+ /// It implements the Flutter engine's behavior when it comes to handling
718+ /// ellipsis and max lines.
707719class LinesCalculator {
708- LinesCalculator (this ._canvasContext, this ._text, this ._style , this ._maxWidth);
720+ LinesCalculator (this ._canvasContext, this ._paragraph , this ._maxWidth);
709721
710722 final html.CanvasRenderingContext2D _canvasContext;
711- final String _text;
712- final ParagraphGeometricStyle _style;
723+ final EngineParagraph _paragraph;
713724 final double _maxWidth;
714725
726+ String get _text => _paragraph._plainText;
727+ ParagraphGeometricStyle get _style => _paragraph._geometricStyle;
728+
715729 /// The lines that have been consumed so far.
716730 List <EngineLineMetrics > lines = < EngineLineMetrics > [];
717731
@@ -768,12 +782,20 @@ class LinesCalculator {
768782 start: _lineStart,
769783 end: chunkEndWithoutSpace,
770784 );
785+ final double widthOfResultingLine =
786+ measureSubstring (_lineStart, breakingPoint) + _ellipsisWidth;
787+ final double alignOffset = _calculateAlignOffsetForLine (
788+ paragraph: _paragraph,
789+ lineWidth: widthOfResultingLine,
790+ maxWidth: _maxWidth,
791+ );
771792 lines.add (EngineLineMetrics .withText (
772793 _text.substring (_lineStart, breakingPoint) + _style.ellipsis,
773794 startIndex: _lineStart,
774795 endIndex: chunkEnd,
775796 hardBreak: false ,
776- width: measureSubstring (_lineStart, breakingPoint) + _ellipsisWidth,
797+ width: widthOfResultingLine,
798+ left: alignOffset,
777799 lineNumber: lines.length,
778800 ));
779801 } else if (isChunkTooLong) {
@@ -826,12 +848,19 @@ class LinesCalculator {
826848 _whitespacePredicate,
827849 );
828850 final int lineNumber = lines.length;
851+ final double lineWidth = measureSubstring (_lineStart, endWithoutSpace);
852+ final double alignOffset = _calculateAlignOffsetForLine (
853+ paragraph: _paragraph,
854+ lineWidth: lineWidth,
855+ maxWidth: _maxWidth,
856+ );
829857 final EngineLineMetrics metrics = EngineLineMetrics .withText (
830858 _text.substring (_lineStart, endWithoutNewlines),
831859 startIndex: _lineStart,
832860 endIndex: lineEnd,
833861 hardBreak: isHardBreak,
834- width: measureSubstring (_lineStart, endWithoutSpace),
862+ width: lineWidth,
863+ left: alignOffset,
835864 lineNumber: lineNumber,
836865 );
837866 lines.add (metrics);
@@ -958,3 +987,30 @@ class MaxIntrinsicCalculator {
958987 _lastHardLineEnd = hardLineEnd;
959988 }
960989}
990+
991+ /// Calculates the offset necessary for the given line to be correctly aligned.
992+ double _calculateAlignOffsetForLine ({
993+ @required EngineParagraph paragraph,
994+ @required double lineWidth,
995+ @required double maxWidth,
996+ }) {
997+ final double emptySpace = maxWidth - lineWidth;
998+ // WARNING: the [paragraph] may not be laid out yet at this point. This
999+ // function must not use layout metrics, such as [paragraph.height].
1000+ switch (paragraph._textAlign) {
1001+ case ui.TextAlign .center:
1002+ return emptySpace / 2.0 ;
1003+ case ui.TextAlign .right:
1004+ return emptySpace;
1005+ case ui.TextAlign .start:
1006+ return paragraph._textDirection == ui.TextDirection .rtl
1007+ ? emptySpace
1008+ : 0.0 ;
1009+ case ui.TextAlign .end:
1010+ return paragraph._textDirection == ui.TextDirection .rtl
1011+ ? 0.0
1012+ : emptySpace;
1013+ default :
1014+ return 0.0 ;
1015+ }
1016+ }
0 commit comments