@@ -88,49 +88,14 @@ .. flowChildren.Select(c => (c, Measure(c, assets, measurer, measurementCache)))
8888 }
8989
9090 bool isRow = stack . Direction is StackDirection . Row ;
91- float containerMain = ResolveMainAxisContainerSize (
91+ float wrapMain = ResolveMainAxisContainerSize (
9292 isRow ? stack . Width : stack . Height ,
93- isRow ? desiredSize ? . Width : desiredSize ? . Height ,
93+ null ,
9494 int . MaxValue ) ;
95- List < List < ( Node Node , Size Size ) > > lines = [ ] ;
96- List < ( Node Node , Size Size ) > currentLine = [ ] ;
97- float currentMain = 0 ;
98- foreach ( ( Node node , Size size ) in items )
99- {
100- float itemMain = isRow ? size . Width : size . Height ;
101- float nextMain = currentLine . Count is 0 ? itemMain : currentMain + stack . Spacing + itemMain ;
102- bool wrapNow = stack . Wrap && currentLine . Count > 0 && nextMain > containerMain ;
103- if ( wrapNow )
104- {
105- lines . Add ( currentLine ) ;
106- currentLine = [ ] ;
107- currentMain = 0 ;
108- }
109-
110- currentLine . Add ( ( node , size ) ) ;
111- currentMain = currentLine . Count is 1 ? itemMain : currentMain + stack . Spacing + itemMain ;
112- }
113-
114- if ( currentLine . Count > 0 )
115- {
116- lines . Add ( currentLine ) ;
117- }
118-
119- List < ( float Main , int Cross ) > lineSize = [ ] ;
120- foreach ( List < ( Node Node , Size Size ) > line in lines )
121- {
122- float lineMain = line . Sum ( i => isRow ? i . Size . Width : i . Size . Height ) ;
123- if ( line . Count > 1 )
124- {
125- lineMain += stack . Spacing * ( line . Count - 1 ) ;
126- }
127-
128- int lineCross = line . Max ( i => isRow ? i . Size . Height : i . Size . Width ) ;
129- lineSize . Add ( ( lineMain , lineCross ) ) ;
130- }
131-
132- float contentMain = lineSize . Max ( l => l . Main ) ;
133- float contentCross = lineSize . Sum ( l => l . Cross ) + Math . Max ( 0 , lines . Count - 1 ) * stack . RunSpacing ;
95+ List < List < ( Node Node , Size Size ) > > lines =
96+ ResolveStackLines ( items , isRow , stack . Wrap , stack . Spacing , wrapMain ) ;
97+ List < ( float Main , int Cross ) > lineSizes = ResolveStackLineSizes ( lines , isRow , stack . Spacing ) ;
98+ ( float contentMain , float contentCross ) = ResolveStackContentSize ( lineSizes , stack . RunSpacing ) ;
13499 float resolvedContainerMain = ResolveMainAxisContainerSize (
135100 isRow ? stack . Width : stack . Height ,
136101 isRow ? desiredSize ? . Width : desiredSize ? . Height ,
@@ -140,17 +105,30 @@ .. flowChildren.Select(c => (c, Measure(c, assets, measurer, measurementCache)))
140105 isRow ? desiredSize ? . Height : desiredSize ? . Width ,
141106 contentCross ) ;
142107
143- float crossCursor = ( isRow ? origin . Y : origin . X ) +
108+ float crossBase = ( isRow ? origin . Y : origin . X ) +
144109 ResolveStartCenterEndOffset ( stack . AlignContent , resolvedContainerCross , contentCross ) ;
110+ int crossCursor = ( int ) Math . Round ( crossBase , MidpointRounding . AwayFromZero ) ;
111+ float runError = crossBase - crossCursor ;
112+ int runSpacingWhole = stack . RunSpacing >= 0
113+ ? ( int ) Math . Floor ( stack . RunSpacing )
114+ : ( int ) Math . Ceiling ( stack . RunSpacing ) ;
115+ float runSpacingFraction = stack . RunSpacing - runSpacingWhole ;
145116 for ( int lineIndex = 0 ; lineIndex < lines . Count ; lineIndex ++ )
146117 {
147118 List < ( Node Node , Size Size ) > line = lines [ lineIndex ] ;
148- ( float lineMain , int lineCross ) = lineSize [ lineIndex ] ;
119+ ( float lineMain , int lineCross ) = lineSizes [ lineIndex ] ;
149120 ( float startMain , float between ) = ResolveMainAxisLayout ( stack . JustifyContent , resolvedContainerMain , lineMain ,
150121 stack . Spacing , line . Count ) ;
151- float mainCursor = startMain ;
152- foreach ( ( Node node , Size size ) in line )
122+ float mainBase = ( isRow ? origin . X : origin . Y ) + startMain ;
123+ int mainCursor = ( int ) Math . Round ( mainBase , MidpointRounding . AwayFromZero ) ;
124+ float gapError = mainBase - mainCursor ;
125+ int betweenWhole = between >= 0
126+ ? ( int ) Math . Floor ( between )
127+ : ( int ) Math . Ceiling ( between ) ;
128+ float betweenFraction = between - betweenWhole ;
129+ for ( int itemIndex = 0 ; itemIndex < line . Count ; itemIndex ++ )
153130 {
131+ ( Node node , Size size ) = line [ itemIndex ] ;
154132 int itemCross = isRow ? size . Height : size . Width ;
155133 int crossOffset = ResolveStartCenterEndOffset ( stack . AlignItems , lineCross , itemCross ) ;
156134 Size ? childDesiredSize = null ;
@@ -159,15 +137,54 @@ .. flowChildren.Select(c => (c, Measure(c, assets, measurer, measurementCache)))
159137 childDesiredSize = isRow ? new ( size . Width , lineCross ) : new ( lineCross , size . Height ) ;
160138 }
161139
162- Point childOrigin = isRow
163- ? new ( ( int ) Math . Round ( origin . X + mainCursor ) , ( int ) Math . Round ( crossCursor + crossOffset ) )
164- : new ( ( int ) Math . Round ( crossCursor + crossOffset ) , ( int ) Math . Round ( origin . Y + mainCursor ) ) ;
140+ float childX = isRow ? mainCursor : crossCursor + crossOffset ;
141+ float childY = isRow ? crossCursor + crossOffset : mainCursor ;
142+ Point childOrigin = new (
143+ ( int ) Math . Round ( childX , MidpointRounding . AwayFromZero ) ,
144+ ( int ) Math . Round ( childY , MidpointRounding . AwayFromZero ) ) ;
165145 RenderNode ( canvas , node , assets , measurer , childOrigin , inheritedOpacity , childDesiredSize , scale ,
166146 resampler , measurementCache ) ;
167- mainCursor += ( isRow ? size . Width : size . Height ) + between ;
147+ if ( itemIndex == line . Count - 1 )
148+ {
149+ continue ;
150+ }
151+
152+ int itemMain = isRow ? size . Width : size . Height ;
153+ int step = itemMain + betweenWhole ;
154+ gapError += betweenFraction ;
155+ if ( gapError >= 1f )
156+ {
157+ step ++ ;
158+ gapError -= 1f ;
159+ }
160+ else if ( gapError <= - 1f )
161+ {
162+ step -- ;
163+ gapError += 1f ;
164+ }
165+
166+ mainCursor += step ;
167+ }
168+
169+ if ( lineIndex == lines . Count - 1 )
170+ {
171+ continue ;
172+ }
173+
174+ int lineStep = lineCross + runSpacingWhole ;
175+ runError += runSpacingFraction ;
176+ if ( runError >= 1f )
177+ {
178+ lineStep ++ ;
179+ runError -= 1f ;
180+ }
181+ else if ( runError <= - 1f )
182+ {
183+ lineStep -- ;
184+ runError += 1f ;
168185 }
169186
170- crossCursor += lineCross + stack . RunSpacing ;
187+ crossCursor += lineStep ;
171188 }
172189 }
173190
@@ -267,7 +284,7 @@ private static void RenderTextNode(Image canvas, TextNode textNode, AssetProvide
267284 float inheritedOpacity )
268285 {
269286 ( FontFamily mainFont , List < FontFamily > fallbacks ) = assets . ResolveFont ( textNode . FontFamily ) ;
270- float scaledFontSize = textNode . FontSize * 72f / 300f ;
287+ float scaledFontSize = textNode . FontSize * 72 / 300 ;
271288 Font font = new ( mainFont , scaledFontSize ) ;
272289 RichTextOptions options = new ( font )
273290 {
@@ -313,12 +330,12 @@ private static string TruncateTextByWidth(string text, string suffix, float maxW
313330 return string . Empty ;
314331 }
315332
316- if ( TextMeasurer . MeasureSize ( text , options ) . Width <= maxWidth )
333+ if ( TextMeasurer . MeasureAdvance ( text , options ) . Width <= maxWidth )
317334 {
318335 return text ;
319336 }
320337
321- if ( TextMeasurer . MeasureSize ( suffix , options ) . Width > maxWidth )
338+ if ( TextMeasurer . MeasureAdvance ( suffix , options ) . Width > maxWidth )
322339 {
323340 return string . Empty ;
324341 }
@@ -330,7 +347,7 @@ private static string TruncateTextByWidth(string text, string suffix, float maxW
330347 {
331348 int mid = ( low + high + 1 ) / 2 ;
332349 string candidate = GetTextElementPrefix ( text , textElementStarts , mid ) + suffix ;
333- if ( TextMeasurer . MeasureSize ( candidate , options ) . Width <= maxWidth )
350+ if ( TextMeasurer . MeasureAdvance ( candidate , options ) . Width <= maxWidth )
334351 {
335352 low = mid ;
336353 continue ;
0 commit comments