@@ -29,50 +29,58 @@ public override Size GetDesiredSize(double widthConstraint, double heightConstra
2929 layout . LineCount > 1 &&
3030 PlatformView . Ellipsize == null )
3131 {
32- // Capture original line count before narrowing to detect re-wrapping.
33- var originalLineCount = layout . LineCount ;
34-
3532 float maxLineWidth = 0 ;
33+ float maxLineRight = 0 ;
3634 for ( int i = 0 ; i < layout . LineCount ; i ++ )
3735 {
3836 float lineWidth = layout . GetLineWidth ( i ) ;
3937 if ( lineWidth > maxLineWidth )
4038 maxLineWidth = lineWidth ;
39+
40+ // GetLineRight() captures the true visual right edge, including RTL/bidi
41+ // offsets that GetLineWidth() can under-report for non-left-anchored text.
42+ float lineRight = layout . GetLineRight ( i ) ;
43+ if ( lineRight > maxLineRight )
44+ {
45+ maxLineRight = lineRight ;
46+ }
4147 }
4248
4349 if ( maxLineWidth > 0 )
4450 {
51+ // If any line's visual right edge exceeds the computed content width,
52+ // narrowing to that width would clip the text (e.g. RTL/bidi in an RTL
53+ // container). Return the original size without an extra measure pass.
54+ if ( maxLineRight > maxLineWidth )
55+ {
56+ return size ;
57+ }
58+
4559 var actualWidth = Context . FromPixels ( maxLineWidth + PlatformView . PaddingLeft + PlatformView . PaddingRight ) ;
4660 if ( actualWidth < size . Width )
4761 {
48- // Always verify that narrowing doesn't cause the text to re-wrap into more
49- // lines than the original measurement, which would truncate visible text.
50- // This covers both explicit MaxLines constraints and cases where layout
51- // under-reports line widths (e.g. RTL/bidi text in an RTL container).
62+ // When MaxLines is constrained, verify that narrowing doesn't cause the text
63+ // to re-wrap into more lines than MaxLines allows (which would truncate text).
5264 // Re-measure at exactly the pixel width the view will be arranged at.
53- var narrowedPx = ( int ) Context . ToPixels ( actualWidth ) ;
54-
55- // AtMost mirrors how the layout pass constrains width, ensuring the
56- // re-measurement reflects the same wrapping behaviour the view will
57- // experience when arranged at actualWidth.
58- PlatformView . Measure (
59- MeasureSpecMode . AtMost . MakeMeasureSpec ( narrowedPx ) ,
60- MeasureSpecMode . Unspecified . MakeMeasureSpec ( 0 ) ) ;
61-
62- // Fail-safe: if Layout is null after re-measurement we cannot verify
63- // that truncation won't occur, so return the original size.
64- var measuredLayout = PlatformView . Layout ;
65-
66- // Use MaxLines as the limit when explicitly set; otherwise use the
67- // original line count so that any re-wrapping caused by the narrowed
68- // width is detected and the original size is returned instead.
69- var lineLimit = PlatformView . MaxLines != int . MaxValue
70- ? PlatformView . MaxLines
71- : originalLineCount ;
72-
73- if ( measuredLayout is null || measuredLayout . LineCount > lineLimit )
65+ if ( PlatformView . MaxLines != int . MaxValue )
7466 {
75- return size ; // Narrowing causes truncation (or unverifiable); return original size
67+ var narrowedPx = ( int ) Context . ToPixels ( actualWidth ) ;
68+
69+ // AtMost mirrors how the layout pass constrains width, ensuring the
70+ // re-measurement reflects the same wrapping behaviour the view will
71+ // experience when arranged at actualWidth.
72+ PlatformView . Measure (
73+ MeasureSpecMode . AtMost . MakeMeasureSpec ( narrowedPx ) ,
74+ MeasureSpecMode . Unspecified . MakeMeasureSpec ( 0 ) ) ;
75+
76+ // Fail-safe: if Layout is null after re-measurement we cannot verify
77+ // that truncation won't occur, so return the original size.
78+ var measuredLayout = PlatformView . Layout ;
79+
80+ if ( measuredLayout is null || measuredLayout . LineCount > PlatformView . MaxLines )
81+ {
82+ return size ; // Narrowing causes truncation (or unverifiable); return original size
83+ }
7684 }
7785
7886 return new Size ( actualWidth , size . Height ) ;
0 commit comments