1 /*
<lambda>null2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.compose.foundation.layout
18 
19 import androidx.compose.foundation.layout.LayoutOrientation.Horizontal
20 import androidx.compose.foundation.layout.LayoutOrientation.Vertical
21 import androidx.compose.runtime.Immutable
22 import androidx.compose.runtime.Stable
23 import androidx.compose.ui.Alignment
24 import androidx.compose.ui.Modifier
25 import androidx.compose.ui.layout.AlignmentLine
26 import androidx.compose.ui.layout.IntrinsicMeasurable
27 import androidx.compose.ui.layout.Measured
28 import androidx.compose.ui.layout.Placeable
29 import androidx.compose.ui.node.ModifierNodeElement
30 import androidx.compose.ui.node.ParentDataModifierNode
31 import androidx.compose.ui.platform.InspectorInfo
32 import androidx.compose.ui.unit.Constraints
33 import androidx.compose.ui.unit.Density
34 import androidx.compose.ui.unit.LayoutDirection
35 import androidx.compose.ui.util.fastForEach
36 import androidx.compose.ui.util.fastRoundToInt
37 import kotlin.jvm.JvmInline
38 import kotlin.math.max
39 import kotlin.math.min
40 
41 /** [Row] will be [Horizontal], [Column] is [Vertical]. */
42 internal enum class LayoutOrientation {
43     Horizontal,
44     Vertical
45 }
46 
47 /** Used to specify the alignment of a layout's children, in cross axis direction. */
48 @Immutable
49 internal sealed class CrossAxisAlignment {
50     /**
51      * Aligns to [size]. If this is a vertical alignment, [layoutDirection] should be
52      * [LayoutDirection.Ltr].
53      *
54      * @param size The remaining space (total size - content size) in the container.
55      * @param layoutDirection The layout direction of the content if horizontal or
56      *   [LayoutDirection.Ltr] if vertical.
57      * @param placeable The item being aligned.
58      * @param beforeCrossAxisAlignmentLine The space before the cross-axis alignment line if an
59      *   alignment line is being used or 0 if no alignment line is being used.
60      */
alignnull61     internal abstract fun align(
62         size: Int,
63         layoutDirection: LayoutDirection,
64         placeable: Placeable,
65         beforeCrossAxisAlignmentLine: Int
66     ): Int
67 
68     /** Returns `true` if this is [Relative]. */
69     internal open val isRelative: Boolean
70         get() = false
71 
72     /**
73      * Returns the alignment line position relative to the left/top of the space or `null` if this
74      * alignment doesn't rely on alignment lines.
75      */
76     internal open fun calculateAlignmentLinePosition(placeable: Placeable): Int? = null
77 
78     companion object {
79         /** Place children such that their center is in the middle of the cross axis. */
80         @Stable val Center: CrossAxisAlignment = CenterCrossAxisAlignment
81 
82         /**
83          * Place children such that their start edge is aligned to the start edge of the cross
84          * axis. TODO(popam): Consider rtl directionality.
85          */
86         @Stable val Start: CrossAxisAlignment = StartCrossAxisAlignment
87 
88         /**
89          * Place children such that their end edge is aligned to the end edge of the cross
90          * axis. TODO(popam): Consider rtl directionality.
91          */
92         @Stable val End: CrossAxisAlignment = EndCrossAxisAlignment
93 
94         /** Align children by their baseline. */
95         fun AlignmentLine(alignmentLine: AlignmentLine): CrossAxisAlignment =
96             AlignmentLineCrossAxisAlignment(AlignmentLineProvider.Value(alignmentLine))
97 
98         /**
99          * Align children relative to their siblings using the alignment line provided as a
100          * parameter using [AlignmentLineProvider].
101          */
102         internal fun Relative(alignmentLineProvider: AlignmentLineProvider): CrossAxisAlignment =
103             AlignmentLineCrossAxisAlignment(alignmentLineProvider)
104 
105         /** Align children with vertical alignment. */
106         internal fun vertical(vertical: Alignment.Vertical): CrossAxisAlignment =
107             VerticalCrossAxisAlignment(vertical)
108 
109         /** Align children with horizontal alignment. */
110         internal fun horizontal(horizontal: Alignment.Horizontal): CrossAxisAlignment =
111             HorizontalCrossAxisAlignment(horizontal)
112     }
113 
114     private object CenterCrossAxisAlignment : CrossAxisAlignment() {
alignnull115         override fun align(
116             size: Int,
117             layoutDirection: LayoutDirection,
118             placeable: Placeable,
119             beforeCrossAxisAlignmentLine: Int
120         ): Int {
121             return size / 2
122         }
123     }
124 
125     private object StartCrossAxisAlignment : CrossAxisAlignment() {
alignnull126         override fun align(
127             size: Int,
128             layoutDirection: LayoutDirection,
129             placeable: Placeable,
130             beforeCrossAxisAlignmentLine: Int
131         ): Int {
132             return if (layoutDirection == LayoutDirection.Ltr) 0 else size
133         }
134     }
135 
136     private object EndCrossAxisAlignment : CrossAxisAlignment() {
alignnull137         override fun align(
138             size: Int,
139             layoutDirection: LayoutDirection,
140             placeable: Placeable,
141             beforeCrossAxisAlignmentLine: Int
142         ): Int {
143             return if (layoutDirection == LayoutDirection.Ltr) size else 0
144         }
145     }
146 
147     private class AlignmentLineCrossAxisAlignment(
148         val alignmentLineProvider: AlignmentLineProvider
149     ) : CrossAxisAlignment() {
150         override val isRelative: Boolean
151             get() = true
152 
calculateAlignmentLinePositionnull153         override fun calculateAlignmentLinePosition(placeable: Placeable): Int {
154             return alignmentLineProvider.calculateAlignmentLinePosition(placeable)
155         }
156 
alignnull157         override fun align(
158             size: Int,
159             layoutDirection: LayoutDirection,
160             placeable: Placeable,
161             beforeCrossAxisAlignmentLine: Int
162         ): Int {
163             val alignmentLinePosition =
164                 alignmentLineProvider.calculateAlignmentLinePosition(placeable)
165             return if (alignmentLinePosition != AlignmentLine.Unspecified) {
166                 val line = beforeCrossAxisAlignmentLine - alignmentLinePosition
167                 if (layoutDirection == LayoutDirection.Rtl) {
168                     size - line
169                 } else {
170                     line
171                 }
172             } else {
173                 0
174             }
175         }
176     }
177 
178     private data class VerticalCrossAxisAlignment(val vertical: Alignment.Vertical) :
179         CrossAxisAlignment() {
alignnull180         override fun align(
181             size: Int,
182             layoutDirection: LayoutDirection,
183             placeable: Placeable,
184             beforeCrossAxisAlignmentLine: Int
185         ): Int {
186             return vertical.align(0, size)
187         }
188     }
189 
190     private data class HorizontalCrossAxisAlignment(val horizontal: Alignment.Horizontal) :
191         CrossAxisAlignment() {
alignnull192         override fun align(
193             size: Int,
194             layoutDirection: LayoutDirection,
195             placeable: Placeable,
196             beforeCrossAxisAlignmentLine: Int
197         ): Int {
198             return horizontal.align(0, size, layoutDirection)
199         }
200     }
201 }
202 
203 /**
204  * Box [Constraints], but which abstract away width and height in favor of main axis and cross axis.
205  */
206 @JvmInline
207 internal value class OrientationIndependentConstraints
208 private constructor(private val value: Constraints) {
209     inline val mainAxisMin: Int
210         get() = value.minWidth
211 
212     inline val mainAxisMax: Int
213         get() = value.maxWidth
214 
215     inline val crossAxisMin: Int
216         get() = value.minHeight
217 
218     inline val crossAxisMax: Int
219         get() = value.maxHeight
220 
221     constructor(
222         mainAxisMin: Int,
223         mainAxisMax: Int,
224         crossAxisMin: Int,
225         crossAxisMax: Int
226     ) : this(
227         Constraints(
228             minWidth = mainAxisMin,
229             maxWidth = mainAxisMax,
230             minHeight = crossAxisMin,
231             maxHeight = crossAxisMax
232         )
233     )
234 
235     constructor(
236         c: Constraints,
237         orientation: LayoutOrientation
238     ) : this(
239         if (orientation === Horizontal) c.minWidth else c.minHeight,
240         if (orientation === Horizontal) c.maxWidth else c.maxHeight,
241         if (orientation === Horizontal) c.minHeight else c.minWidth,
242         if (orientation === Horizontal) c.maxHeight else c.maxWidth
243     )
244 
245     // Creates a new instance with the same main axis constraints and maximum tight cross axis.
stretchCrossAxisnull246     fun stretchCrossAxis() =
247         OrientationIndependentConstraints(
248             mainAxisMin,
249             mainAxisMax,
250             if (crossAxisMax != Constraints.Infinity) crossAxisMax else crossAxisMin,
251             crossAxisMax
252         )
253 
254     // Given an orientation, resolves the current instance to traditional constraints.
255     fun toBoxConstraints(orientation: LayoutOrientation) =
256         if (orientation === Horizontal) {
257             Constraints(mainAxisMin, mainAxisMax, crossAxisMin, crossAxisMax)
258         } else {
259             Constraints(crossAxisMin, crossAxisMax, mainAxisMin, mainAxisMax)
260         }
261 
262     // Given an orientation, resolves the max width constraint this instance represents.
maxWidthnull263     fun maxWidth(orientation: LayoutOrientation) =
264         if (orientation === Horizontal) {
265             mainAxisMax
266         } else {
267             crossAxisMax
268         }
269 
270     // Given an orientation, resolves the max height constraint this instance represents.
maxHeightnull271     fun maxHeight(orientation: LayoutOrientation) =
272         if (orientation === Horizontal) {
273             crossAxisMax
274         } else {
275             mainAxisMax
276         }
277 
copynull278     fun copy(
279         mainAxisMin: Int = this.mainAxisMin,
280         mainAxisMax: Int = this.mainAxisMax,
281         crossAxisMin: Int = this.crossAxisMin,
282         crossAxisMax: Int = this.crossAxisMax
283     ): OrientationIndependentConstraints =
284         OrientationIndependentConstraints(mainAxisMin, mainAxisMax, crossAxisMin, crossAxisMax)
285 }
286 
287 internal val IntrinsicMeasurable.rowColumnParentData: RowColumnParentData?
288     get() = parentData as? RowColumnParentData
289 
290 internal val Placeable.rowColumnParentData: RowColumnParentData?
291     get() = parentData as? RowColumnParentData
292 
293 internal val RowColumnParentData?.weight: Float
294     get() = this?.weight ?: 0f
295 
296 internal val RowColumnParentData?.fill: Boolean
297     get() = this?.fill ?: true
298 
299 internal val RowColumnParentData?.crossAxisAlignment: CrossAxisAlignment?
300     get() = this?.crossAxisAlignment
301 
302 internal val RowColumnParentData?.isRelative: Boolean
303     get() = this.crossAxisAlignment?.isRelative ?: false
304 
305 internal object IntrinsicMeasureBlocks {
306     fun HorizontalMinWidth(
307         measurables: List<IntrinsicMeasurable>,
308         availableHeight: Int,
309         mainAxisSpacing: Int
310     ): Int {
311         return intrinsicMainAxisSize(
312             measurables,
313             { h -> minIntrinsicWidth(h) },
314             availableHeight,
315             mainAxisSpacing,
316         )
317     }
318 
319     fun VerticalMinWidth(
320         measurables: List<IntrinsicMeasurable>,
321         availableHeight: Int,
322         mainAxisSpacing: Int
323     ): Int {
324         return intrinsicCrossAxisSize(
325             measurables,
326             { w -> maxIntrinsicHeight(w) },
327             { h -> minIntrinsicWidth(h) },
328             availableHeight,
329             mainAxisSpacing,
330         )
331     }
332 
333     fun HorizontalMinHeight(
334         measurables: List<IntrinsicMeasurable>,
335         availableWidth: Int,
336         mainAxisSpacing: Int
337     ): Int {
338         return intrinsicCrossAxisSize(
339             measurables,
340             { h -> maxIntrinsicWidth(h) },
341             { w -> minIntrinsicHeight(w) },
342             availableWidth,
343             mainAxisSpacing,
344         )
345     }
346 
347     fun VerticalMinHeight(
348         measurables: List<IntrinsicMeasurable>,
349         availableWidth: Int,
350         mainAxisSpacing: Int
351     ): Int {
352         return intrinsicMainAxisSize(
353             measurables,
354             { w -> minIntrinsicHeight(w) },
355             availableWidth,
356             mainAxisSpacing,
357         )
358     }
359 
360     fun HorizontalMaxWidth(
361         measurables: List<IntrinsicMeasurable>,
362         availableHeight: Int,
363         mainAxisSpacing: Int
364     ): Int {
365         return intrinsicMainAxisSize(
366             measurables,
367             { h -> maxIntrinsicWidth(h) },
368             availableHeight,
369             mainAxisSpacing,
370         )
371     }
372 
373     fun VerticalMaxWidth(
374         measurables: List<IntrinsicMeasurable>,
375         availableHeight: Int,
376         mainAxisSpacing: Int
377     ): Int {
378         return intrinsicCrossAxisSize(
379             measurables,
380             { w -> maxIntrinsicHeight(w) },
381             { h -> maxIntrinsicWidth(h) },
382             availableHeight,
383             mainAxisSpacing,
384         )
385     }
386 
387     fun HorizontalMaxHeight(
388         measurables: List<IntrinsicMeasurable>,
389         availableWidth: Int,
390         mainAxisSpacing: Int
391     ): Int {
392         return intrinsicCrossAxisSize(
393             measurables,
394             { h -> maxIntrinsicWidth(h) },
395             { w -> maxIntrinsicHeight(w) },
396             availableWidth,
397             mainAxisSpacing,
398         )
399     }
400 
401     fun VerticalMaxHeight(
402         measurables: List<IntrinsicMeasurable>,
403         availableWidth: Int,
404         mainAxisSpacing: Int
405     ): Int {
406         return intrinsicMainAxisSize(
407             measurables,
408             { w -> maxIntrinsicHeight(w) },
409             availableWidth,
410             mainAxisSpacing,
411         )
412     }
413 }
414 
intrinsicMainAxisSizenull415 private inline fun intrinsicMainAxisSize(
416     children: List<IntrinsicMeasurable>,
417     mainAxisSize: IntrinsicMeasurable.(Int) -> Int,
418     crossAxisAvailable: Int,
419     mainAxisSpacing: Int
420 ): Int {
421     if (children.isEmpty()) return 0
422     var weightUnitSpace = 0
423     var fixedSpace = 0
424     var totalWeight = 0f
425     children.fastForEach { child ->
426         val weight = child.rowColumnParentData.weight
427         val size = child.mainAxisSize(crossAxisAvailable)
428         if (weight == 0f) {
429             fixedSpace += size
430         } else if (weight > 0f) {
431             totalWeight += weight
432             weightUnitSpace = max(weightUnitSpace, (size / weight).fastRoundToInt())
433         }
434     }
435     return (weightUnitSpace * totalWeight).fastRoundToInt() +
436         fixedSpace +
437         (children.size - 1) * mainAxisSpacing
438 }
439 
intrinsicCrossAxisSizenull440 private inline fun intrinsicCrossAxisSize(
441     children: List<IntrinsicMeasurable>,
442     mainAxisSize: IntrinsicMeasurable.(Int) -> Int,
443     crossAxisSize: IntrinsicMeasurable.(Int) -> Int,
444     mainAxisAvailable: Int,
445     mainAxisSpacing: Int
446 ): Int {
447     if (children.isEmpty()) return 0
448     var fixedSpace = min((children.size - 1) * mainAxisSpacing, mainAxisAvailable)
449     var crossAxisMax = 0
450     var totalWeight = 0f
451     children.fastForEach { child ->
452         val weight = child.rowColumnParentData.weight
453         if (weight == 0f) {
454             // Ask the child how much main axis space it wants to occupy. This cannot be more
455             // than the remaining available space.
456             val remaining =
457                 if (mainAxisAvailable == Constraints.Infinity) Constraints.Infinity
458                 else mainAxisAvailable - fixedSpace
459             val mainAxisSpace = min(child.mainAxisSize(Constraints.Infinity), remaining)
460             fixedSpace += mainAxisSpace
461             // Now that the assigned main axis space is known, ask about the cross axis space.
462             crossAxisMax = max(crossAxisMax, child.crossAxisSize(mainAxisSpace))
463         } else if (weight > 0f) {
464             totalWeight += weight
465         }
466     }
467 
468     // For weighted children, calculate how much main axis space weight=1 would represent.
469     val weightUnitSpace =
470         if (totalWeight == 0f) {
471             0
472         } else if (mainAxisAvailable == Constraints.Infinity) {
473             Constraints.Infinity
474         } else {
475             (max(mainAxisAvailable - fixedSpace, 0) / totalWeight).fastRoundToInt()
476         }
477 
478     children.fastForEach { child ->
479         val weight = child.rowColumnParentData.weight
480         // Now the main axis for weighted children is known, so ask about the cross axis space.
481         if (weight > 0f) {
482             crossAxisMax =
483                 max(
484                     crossAxisMax,
485                     child.crossAxisSize(
486                         if (weightUnitSpace != Constraints.Infinity) {
487                             (weightUnitSpace * weight).fastRoundToInt()
488                         } else {
489                             Constraints.Infinity
490                         }
491                     )
492                 )
493         }
494     }
495     return crossAxisMax
496 }
497 
498 internal class LayoutWeightElement(
499     val weight: Float,
500     val fill: Boolean,
501 ) : ModifierNodeElement<LayoutWeightNode>() {
createnull502     override fun create(): LayoutWeightNode {
503         return LayoutWeightNode(weight, fill)
504     }
505 
updatenull506     override fun update(node: LayoutWeightNode) {
507         node.weight = weight
508         node.fill = fill
509     }
510 
inspectablePropertiesnull511     override fun InspectorInfo.inspectableProperties() {
512         name = "weight"
513         value = weight
514         properties["weight"] = weight
515         properties["fill"] = fill
516     }
517 
hashCodenull518     override fun hashCode(): Int {
519         var result = weight.hashCode()
520         result = 31 * result + fill.hashCode()
521         return result
522     }
523 
equalsnull524     override fun equals(other: Any?): Boolean {
525         if (this === other) return true
526         val otherModifier = other as? LayoutWeightElement ?: return false
527         return weight == otherModifier.weight && fill == otherModifier.fill
528     }
529 }
530 
531 internal class LayoutWeightNode(
532     var weight: Float,
533     var fill: Boolean,
534 ) : ParentDataModifierNode, Modifier.Node() {
modifyParentDatanull535     override fun Density.modifyParentData(parentData: Any?) =
536         ((parentData as? RowColumnParentData) ?: RowColumnParentData()).also {
537             it.weight = weight
538             it.fill = fill
539         }
540 }
541 
542 internal class WithAlignmentLineBlockElement(val block: (Measured) -> Int) :
543     ModifierNodeElement<SiblingsAlignedNode.WithAlignmentLineBlockNode>() {
createnull544     override fun create(): SiblingsAlignedNode.WithAlignmentLineBlockNode {
545         return SiblingsAlignedNode.WithAlignmentLineBlockNode(block)
546     }
547 
updatenull548     override fun update(node: SiblingsAlignedNode.WithAlignmentLineBlockNode) {
549         node.block = block
550     }
551 
equalsnull552     override fun equals(other: Any?): Boolean {
553         if (this === other) return true
554         val otherModifier = other as? WithAlignmentLineBlockElement ?: return false
555         return block === otherModifier.block
556     }
557 
hashCodenull558     override fun hashCode(): Int = block.hashCode()
559 
560     override fun InspectorInfo.inspectableProperties() {
561         name = "alignBy"
562         value = block
563     }
564 }
565 
566 internal class WithAlignmentLineElement(val alignmentLine: AlignmentLine) :
567     ModifierNodeElement<SiblingsAlignedNode.WithAlignmentLineNode>() {
createnull568     override fun create(): SiblingsAlignedNode.WithAlignmentLineNode {
569         return SiblingsAlignedNode.WithAlignmentLineNode(alignmentLine)
570     }
571 
updatenull572     override fun update(node: SiblingsAlignedNode.WithAlignmentLineNode) {
573         node.alignmentLine = alignmentLine
574     }
575 
inspectablePropertiesnull576     override fun InspectorInfo.inspectableProperties() {
577         name = "alignBy"
578         value = alignmentLine
579     }
580 
hashCodenull581     override fun hashCode(): Int = alignmentLine.hashCode()
582 
583     override fun equals(other: Any?): Boolean {
584         if (this === other) return true
585         val otherModifier = other as? WithAlignmentLineElement ?: return false
586         return alignmentLine == otherModifier.alignmentLine
587     }
588 }
589 
590 internal sealed class SiblingsAlignedNode : ParentDataModifierNode, Modifier.Node() {
modifyParentDatanull591     abstract override fun Density.modifyParentData(parentData: Any?): Any?
592 
593     internal class WithAlignmentLineBlockNode(
594         var block: (Measured) -> Int,
595     ) : SiblingsAlignedNode() {
596         override fun Density.modifyParentData(parentData: Any?): Any {
597             return ((parentData as? RowColumnParentData) ?: RowColumnParentData()).also {
598                 it.crossAxisAlignment =
599                     CrossAxisAlignment.Relative(AlignmentLineProvider.Block(block))
600             }
601         }
602     }
603 
604     internal class WithAlignmentLineNode(
605         var alignmentLine: AlignmentLine,
606     ) : SiblingsAlignedNode() {
modifyParentDatanull607         override fun Density.modifyParentData(parentData: Any?): Any {
608             return ((parentData as? RowColumnParentData) ?: RowColumnParentData()).also {
609                 it.crossAxisAlignment =
610                     CrossAxisAlignment.Relative(AlignmentLineProvider.Value(alignmentLine))
611             }
612         }
613     }
614 }
615 
616 internal class HorizontalAlignElement(val horizontal: Alignment.Horizontal) :
617     ModifierNodeElement<HorizontalAlignNode>() {
createnull618     override fun create(): HorizontalAlignNode {
619         return HorizontalAlignNode(horizontal)
620     }
621 
updatenull622     override fun update(node: HorizontalAlignNode) {
623         node.horizontal = horizontal
624     }
625 
inspectablePropertiesnull626     override fun InspectorInfo.inspectableProperties() {
627         name = "align"
628         value = horizontal
629     }
630 
hashCodenull631     override fun hashCode(): Int = horizontal.hashCode()
632 
633     override fun equals(other: Any?): Boolean {
634         if (this === other) return true
635         val otherModifier = other as? HorizontalAlignElement ?: return false
636         return horizontal == otherModifier.horizontal
637     }
638 }
639 
640 internal class HorizontalAlignNode(var horizontal: Alignment.Horizontal) :
641     ParentDataModifierNode, Modifier.Node() {
modifyParentDatanull642     override fun Density.modifyParentData(parentData: Any?): RowColumnParentData {
643         return ((parentData as? RowColumnParentData) ?: RowColumnParentData()).also {
644             it.crossAxisAlignment = CrossAxisAlignment.horizontal(horizontal)
645         }
646     }
647 }
648 
649 internal class VerticalAlignElement(
650     val alignment: Alignment.Vertical,
651 ) : ModifierNodeElement<VerticalAlignNode>() {
createnull652     override fun create(): VerticalAlignNode {
653         return VerticalAlignNode(alignment)
654     }
655 
updatenull656     override fun update(node: VerticalAlignNode) {
657         node.vertical = alignment
658     }
659 
inspectablePropertiesnull660     override fun InspectorInfo.inspectableProperties() {
661         name = "align"
662         value = alignment
663     }
664 
hashCodenull665     override fun hashCode(): Int = alignment.hashCode()
666 
667     override fun equals(other: Any?): Boolean {
668         if (this === other) return true
669         val otherModifier = other as? VerticalAlignElement ?: return false
670         return alignment == otherModifier.alignment
671     }
672 }
673 
674 internal class VerticalAlignNode(var vertical: Alignment.Vertical) :
675     ParentDataModifierNode, Modifier.Node() {
modifyParentDatanull676     override fun Density.modifyParentData(parentData: Any?): RowColumnParentData {
677         return ((parentData as? RowColumnParentData) ?: RowColumnParentData()).also {
678             it.crossAxisAlignment = CrossAxisAlignment.vertical(vertical)
679         }
680     }
681 }
682 
683 /** Parent data associated with children. */
684 internal data class RowColumnParentData(
685     var weight: Float = 0f,
686     var fill: Boolean = true,
687     var crossAxisAlignment: CrossAxisAlignment? = null,
688     var flowLayoutData: FlowLayoutData? = null,
689 )
690 
691 /** Provides the alignment line. */
692 internal sealed class AlignmentLineProvider {
calculateAlignmentLinePositionnull693     abstract fun calculateAlignmentLinePosition(placeable: Placeable): Int
694 
695     data class Block(val lineProviderBlock: (Measured) -> Int) : AlignmentLineProvider() {
696         override fun calculateAlignmentLinePosition(placeable: Placeable): Int {
697             return lineProviderBlock(placeable)
698         }
699     }
700 
701     data class Value(val alignmentLine: AlignmentLine) : AlignmentLineProvider() {
calculateAlignmentLinePositionnull702         override fun calculateAlignmentLinePosition(placeable: Placeable): Int {
703             return placeable[alignmentLine]
704         }
705     }
706 }
707