@@ -416,13 +416,19 @@ class DomTextMeasurementService extends TextMeasurementService {
416
416
List <EngineLineMetrics > lines;
417
417
if (text != null ) {
418
418
final double lineWidth = maxIntrinsicWidth;
419
+ final double alignOffset = _calculateAlignOffsetForLine (
420
+ paragraph: paragraph,
421
+ lineWidth: lineWidth,
422
+ maxWidth: width,
423
+ );
419
424
lines = < EngineLineMetrics > [
420
425
EngineLineMetrics .withText (
421
426
text,
422
427
startIndex: 0 ,
423
428
endIndex: text.length,
424
429
hardBreak: true ,
425
430
width: lineWidth,
431
+ left: alignOffset,
426
432
lineNumber: 0 ,
427
433
),
428
434
];
@@ -440,6 +446,8 @@ class DomTextMeasurementService extends TextMeasurementService {
440
446
alphabeticBaseline: alphabeticBaseline,
441
447
ideographicBaseline: ideographicBaseline,
442
448
lines: lines,
449
+ textAlign: paragraph._textAlign,
450
+ textDirection: paragraph._textDirection,
443
451
);
444
452
}
445
453
@@ -488,6 +496,8 @@ class DomTextMeasurementService extends TextMeasurementService {
488
496
alphabeticBaseline: alphabeticBaseline,
489
497
ideographicBaseline: ideographicBaseline,
490
498
lines: null ,
499
+ textAlign: paragraph._textAlign,
500
+ textDirection: paragraph._textDirection,
491
501
);
492
502
}
493
503
@@ -546,7 +556,7 @@ class CanvasTextMeasurementService extends TextMeasurementService {
546
556
// TODO(mdebbar): Check if the whole text can fit in a single-line. Then avoid all this ceremony.
547
557
_canvasContext.font = style.cssFontString;
548
558
final LinesCalculator linesCalculator =
549
- LinesCalculator (_canvasContext, text, style , constraints.width);
559
+ LinesCalculator (_canvasContext, paragraph , constraints.width);
550
560
final MinIntrinsicCalculator minIntrinsicCalculator =
551
561
MinIntrinsicCalculator (_canvasContext, text, style);
552
562
final MaxIntrinsicCalculator maxIntrinsicCalculator =
@@ -597,6 +607,8 @@ class CanvasTextMeasurementService extends TextMeasurementService {
597
607
maxIntrinsicWidth: maxIntrinsicCalculator.value,
598
608
width: constraints.width,
599
609
lines: linesCalculator.lines,
610
+ textAlign: paragraph._textAlign,
611
+ textDirection: paragraph._textDirection,
600
612
);
601
613
return result;
602
614
}
@@ -702,16 +714,18 @@ int _excludeTrailing(String text, int start, int end, CharPredicate predicate) {
702
714
/// During the text layout phase, this class splits the lines of text so that it
703
715
/// ends up fitting into the given width constraint.
704
716
///
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.
707
719
class LinesCalculator {
708
- LinesCalculator (this ._canvasContext, this ._text, this ._style , this ._maxWidth);
720
+ LinesCalculator (this ._canvasContext, this ._paragraph , this ._maxWidth);
709
721
710
722
final html.CanvasRenderingContext2D _canvasContext;
711
- final String _text;
712
- final ParagraphGeometricStyle _style;
723
+ final EngineParagraph _paragraph;
713
724
final double _maxWidth;
714
725
726
+ String get _text => _paragraph._plainText;
727
+ ParagraphGeometricStyle get _style => _paragraph._geometricStyle;
728
+
715
729
/// The lines that have been consumed so far.
716
730
List <EngineLineMetrics > lines = < EngineLineMetrics > [];
717
731
@@ -768,12 +782,20 @@ class LinesCalculator {
768
782
start: _lineStart,
769
783
end: chunkEndWithoutSpace,
770
784
);
785
+ final double widthOfResultingLine =
786
+ measureSubstring (_lineStart, breakingPoint) + _ellipsisWidth;
787
+ final double alignOffset = _calculateAlignOffsetForLine (
788
+ paragraph: _paragraph,
789
+ lineWidth: widthOfResultingLine,
790
+ maxWidth: _maxWidth,
791
+ );
771
792
lines.add (EngineLineMetrics .withText (
772
793
_text.substring (_lineStart, breakingPoint) + _style.ellipsis,
773
794
startIndex: _lineStart,
774
795
endIndex: chunkEnd,
775
796
hardBreak: false ,
776
- width: measureSubstring (_lineStart, breakingPoint) + _ellipsisWidth,
797
+ width: widthOfResultingLine,
798
+ left: alignOffset,
777
799
lineNumber: lines.length,
778
800
));
779
801
} else if (isChunkTooLong) {
@@ -826,12 +848,19 @@ class LinesCalculator {
826
848
_whitespacePredicate,
827
849
);
828
850
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
+ );
829
857
final EngineLineMetrics metrics = EngineLineMetrics .withText (
830
858
_text.substring (_lineStart, endWithoutNewlines),
831
859
startIndex: _lineStart,
832
860
endIndex: lineEnd,
833
861
hardBreak: isHardBreak,
834
- width: measureSubstring (_lineStart, endWithoutSpace),
862
+ width: lineWidth,
863
+ left: alignOffset,
835
864
lineNumber: lineNumber,
836
865
);
837
866
lines.add (metrics);
@@ -958,3 +987,30 @@ class MaxIntrinsicCalculator {
958
987
_lastHardLineEnd = hardLineEnd;
959
988
}
960
989
}
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