1 /*
2  * Copyright 2020 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.ui.layout
18 
19 import androidx.compose.ui.graphics.GraphicsLayerScope
20 import androidx.compose.ui.graphics.layer.GraphicsLayer
21 import androidx.compose.ui.node.LookaheadCapablePlaceable
22 import androidx.compose.ui.node.MotionReferencePlacementDelegate
23 import androidx.compose.ui.node.Owner
24 import androidx.compose.ui.unit.Constraints
25 import androidx.compose.ui.unit.IntOffset
26 import androidx.compose.ui.unit.IntSize
27 import androidx.compose.ui.unit.LayoutDirection
28 
29 /**
30  * A [Placeable] corresponds to a child layout that can be positioned by its parent layout. Most
31  * [Placeable]s are the result of a [Measurable.measure] call.
32  *
33  * A `Placeable` should never be stored between measure calls.
34  */
35 abstract class Placeable : Measured {
36     /**
37      * The width, in pixels, of the measured layout, as seen by the parent. This will usually
38      * coincide with the measured width of the layout (aka the `width` value passed into
39      * [MeasureScope.layout]), but can be different if the layout does not respect its incoming
40      * constraints: in these cases the width will be coerced inside the min and max width
41      * constraints - to access the actual width that the layout measured itself to, use
42      * [measuredWidth].
43      */
44     var width: Int = 0
45         private set
46 
47     /**
48      * The height, in pixels, of the measured layout, as seen by the parent. This will usually
49      * coincide with the measured height of the layout (aka the `height` value passed into
50      * [MeasureScope.layout]), but can be different if the layout does not respect its incoming
51      * constraints: in these cases the height will be coerced inside the min and max height
52      * constraints - to access the actual height that the layout measured itself to, use
53      * [measuredHeight].
54      */
55     var height: Int = 0
56         private set
57 
58     /** The measured width of the layout. This might not respect the measurement constraints. */
59     override val measuredWidth: Int
60         get() = measuredSize.width
61 
62     /** The measured height of the layout. This might not respect the measurement constraints. */
63     override val measuredHeight: Int
64         get() = measuredSize.height
65 
66     /** The measured size of this Placeable. This might not respect [measurementConstraints]. */
67     protected var measuredSize: IntSize = IntSize(0, 0)
68         set(value) {
69             if (field != value) {
70                 field = value
71                 onMeasuredSizeChanged()
72             }
73         }
74 
onMeasuredSizeChangednull75     private fun onMeasuredSizeChanged() {
76         width =
77             measuredSize.width.coerceIn(
78                 measurementConstraints.minWidth,
79                 measurementConstraints.maxWidth
80             )
81         height =
82             measuredSize.height.coerceIn(
83                 measurementConstraints.minHeight,
84                 measurementConstraints.maxHeight
85             )
86         apparentToRealOffset =
87             IntOffset((width - measuredSize.width) / 2, (height - measuredSize.height) / 2)
88     }
89 
90     /**
91      * Place a [Placeable] at [position] in its parent's coordinate system.
92      *
93      * @param position position in the parent's coordinate system.
94      * @param zIndex controls the drawing order for the [Placeable]. A [Placeable] with larger
95      *   [zIndex] will be drawn on top of all the children with smaller [zIndex]. When children have
96      *   the same [zIndex] the order in which the items were placed is used.
97      * @param layerBlock when non-null this [Placeable] should be placed with an introduced graphic
98      *   layer. You can configure any layer property available on [GraphicsLayerScope] via this
99      *   block. Also if the [Placeable] will be placed with a new [position] next time only the
100      *   graphic layer will be moved without requiring to redrawn the [Placeable] content.
101      */
placeAtnull102     protected abstract fun placeAt(
103         position: IntOffset,
104         zIndex: Float,
105         layerBlock: (GraphicsLayerScope.() -> Unit)?
106     )
107 
108     /**
109      * Place a [Placeable] at [position] in its parent's coordinate system.
110      *
111      * @param position position in the parent's coordinate system.
112      * @param zIndex controls the drawing order for the [Placeable]. A [Placeable] with larger
113      *   [zIndex] will be drawn on top of all the children with smaller [zIndex]. When children have
114      *   the same [zIndex] the order in which the items were placed is used.
115      * @param layer [GraphicsLayer] to place this placeable with. If the [Placeable] will be placed
116      *   with a new [position] next time only the graphic layer will be moved without requiring to
117      *   redrawn the [Placeable] content.
118      */
119     protected open fun placeAt(position: IntOffset, zIndex: Float, layer: GraphicsLayer) {
120         placeAt(position, zIndex, null)
121     }
122 
123     /** The constraints used for the measurement made to obtain this [Placeable]. */
124     protected var measurementConstraints: Constraints = DefaultConstraints
125         set(value) {
126             if (field != value) {
127                 field = value
128                 onMeasuredSizeChanged()
129             }
130         }
131 
132     /**
133      * The offset to be added to an apparent position assigned to this [Placeable] to make it real.
134      * The real layout will be centered on the space assigned by the parent, which computed the
135      * child's position only seeing its apparent size.
136      */
137     protected var apparentToRealOffset: IntOffset = IntOffset.Zero
138         private set
139 
140     /**
141      * Receiver scope that permits explicit placement of a [Placeable].
142      *
143      * While a [Placeable] may be placed at any time, this explicit receiver scope is used to
144      * discourage placement outside of [MeasureScope.layout] positioning blocks. This permits
145      * Compose UI to perform additional layout optimizations allowing repositioning a [Placeable]
146      * without remeasuring its original [Measurable] if factors contributing to its potential
147      * measurement have not changed. The scope also allows automatic mirroring of children positions
148      * in RTL layout direction contexts using the [placeRelative] methods available in the scope. If
149      * the automatic mirroring is not desired, [place] should be used instead.
150      */
151     // TODO(b/150276678): using the PlacementScope to place outside the layout pass is not working.
152     @PlacementScopeMarker
153     abstract class PlacementScope {
154         /**
155          * Keeps the parent layout node's width to make the automatic mirroring of the position in
156          * RTL environment. If the value is zero, than the [Placeable] will be be placed to the
157          * original position (position will not be mirrored).
158          */
159         protected abstract val parentWidth: Int
160 
161         /**
162          * Keeps the layout direction of the parent of the placeable that is being places using
163          * current [PlacementScope]. Used to support automatic position mirroring for convenient RTL
164          * support in custom layouts.
165          */
166         protected abstract val parentLayoutDirection: LayoutDirection
167 
168         /**
169          * The [LayoutCoordinates] of this layout, if known or `null` if the layout hasn't been
170          * placed yet. [coordinates] will be `null` when determining alignment lines, preventing
171          * alignment lines from depending on absolute coordinates.
172          *
173          * When [coordinates] is `null`, there will always be a follow-up placement call in which
174          * [coordinates] is not-`null`.
175          *
176          * If you read a position from the coordinates during the placement block the block will be
177          * automatically re-executed when the parent layout changes a position. If you don't read it
178          * the placement block execution can be skipped as an optimization.
179          *
180          * @sample androidx.compose.ui.samples.PlacementScopeCoordinatesSample
181          */
182         open val coordinates: LayoutCoordinates?
183             get() = null
184 
185         /**
186          * Returns the value for this [Ruler] or [defaultValue] if it wasn't
187          * [provided][RulerScope.provides]. [Ruler] values are unavailable while calculating
188          * [AlignmentLine]s.
189          *
190          * @sample androidx.compose.ui.samples.RulerConsumerUsage
191          */
currentnull192         open fun Ruler.current(defaultValue: Float): Float = defaultValue
193 
194         /**
195          * Place a [Placeable] at [position] in its parent's coordinate system. If the layout
196          * direction is right-to-left, the given [position] will be horizontally mirrored so that
197          * the position of the [Placeable] implicitly reacts to RTL layout direction contexts. If
198          * this method is used outside the [MeasureScope.layout] positioning block, the automatic
199          * position mirroring will not happen and the [Placeable] will be placed at the given
200          * [position], similar to the [place] method.
201          *
202          * @param position position in the parent's coordinate system.
203          * @param zIndex controls the drawing order for the [Placeable]. A [Placeable] with larger
204          *   [zIndex] will be drawn on top of all the children with smaller [zIndex]. When children
205          *   have the same [zIndex] the order in which the items were placed is used.
206          */
207         fun Placeable.placeRelative(position: IntOffset, zIndex: Float = 0f) =
208             placeAutoMirrored(position, zIndex, null)
209 
210         /**
211          * Place a [Placeable] at [x], [y] in its parent's coordinate system. If the layout
212          * direction is right-to-left, the given position will be horizontally mirrored so that the
213          * position of the [Placeable] implicitly reacts to RTL layout direction contexts. If this
214          * method is used outside the [MeasureScope.layout] positioning block, the automatic
215          * position mirroring will not happen and the [Placeable] will be placed at the given
216          * position, similar to the [place] method.
217          *
218          * @param x x coordinate in the parent's coordinate system.
219          * @param y y coordinate in the parent's coordinate system.
220          * @param zIndex controls the drawing order for the [Placeable]. A [Placeable] with larger
221          *   [zIndex] will be drawn on top of all the children with smaller [zIndex]. When children
222          *   have the same [zIndex] the order in which the items were placed is used.
223          */
224         fun Placeable.placeRelative(x: Int, y: Int, zIndex: Float = 0f) =
225             placeAutoMirrored(IntOffset(x, y), zIndex, null)
226 
227         /**
228          * Place a [Placeable] at [x], [y] in its parent's coordinate system. Unlike
229          * [placeRelative], the given position will not implicitly react in RTL layout direction
230          * contexts.
231          *
232          * @param x x coordinate in the parent's coordinate system.
233          * @param y y coordinate in the parent's coordinate system.
234          * @param zIndex controls the drawing order for the [Placeable]. A [Placeable] with larger
235          *   [zIndex] will be drawn on top of all the children with smaller [zIndex]. When children
236          *   have the same [zIndex] the order in which the items were placed is used.
237          */
238         fun Placeable.place(x: Int, y: Int, zIndex: Float = 0f) =
239             placeApparentToRealOffset(IntOffset(x, y), zIndex, null)
240 
241         /**
242          * Place a [Placeable] at [position] in its parent's coordinate system. Unlike
243          * [placeRelative], the given [position] will not implicitly react in RTL layout direction
244          * contexts.
245          *
246          * @param position position in the parent's coordinate system.
247          * @param zIndex controls the drawing order for the [Placeable]. A [Placeable] with larger
248          *   [zIndex] will be drawn on top of all the children with smaller [zIndex]. When children
249          *   have the same [zIndex] the order in which the items were placed is used.
250          */
251         fun Placeable.place(position: IntOffset, zIndex: Float = 0f) =
252             placeApparentToRealOffset(position, zIndex, null)
253 
254         /**
255          * Place a [Placeable] at [position] in its parent's coordinate system with an introduced
256          * graphic layer. If the layout direction is right-to-left, the given [position] will be
257          * horizontally mirrored so that the position of the [Placeable] implicitly reacts to RTL
258          * layout direction contexts. If this method is used outside the [MeasureScope.layout]
259          * positioning block, the automatic position mirroring will not happen and the [Placeable]
260          * will be placed at the given [position], similar to the [place] method.
261          *
262          * @param position position in the parent's coordinate system.
263          * @param zIndex controls the drawing order for the [Placeable]. A [Placeable] with larger
264          *   [zIndex] will be drawn on top of all the children with smaller [zIndex]. When children
265          *   have the same [zIndex] the order in which the items were placed is used.
266          * @param layerBlock You can configure any layer property available on [GraphicsLayerScope]
267          *   via this block. If the [Placeable] will be placed with a new [position] next time only
268          *   the graphic layer will be moved without requiring to redrawn the [Placeable] content.
269          */
270         fun Placeable.placeRelativeWithLayer(
271             position: IntOffset,
272             zIndex: Float = 0f,
273             layerBlock: GraphicsLayerScope.() -> Unit = DefaultLayerBlock
274         ) = placeAutoMirrored(position, zIndex, layerBlock)
275 
276         /**
277          * Place a [Placeable] at [x], [y] in its parent's coordinate system with an introduced
278          * graphic layer. If the layout direction is right-to-left, the given position will be
279          * horizontally mirrored so that the position of the [Placeable] implicitly reacts to RTL
280          * layout direction contexts. If this method is used outside the [MeasureScope.layout]
281          * positioning block, the automatic position mirroring will not happen and the [Placeable]
282          * will be placed at the given position, similar to the [place] method.
283          *
284          * @param x x coordinate in the parent's coordinate system.
285          * @param y y coordinate in the parent's coordinate system.
286          * @param zIndex controls the drawing order for the [Placeable]. A [Placeable] with larger
287          *   [zIndex] will be drawn on top of all the children with smaller [zIndex]. When children
288          *   have the same [zIndex] the order in which the items were placed is used.
289          * @param layerBlock You can configure any layer property available on [GraphicsLayerScope]
290          *   via this block. If the [Placeable] will be placed with a new [x] or [y] next time only
291          *   the graphic layer will be moved without requiring to redrawn the [Placeable] content.
292          */
293         fun Placeable.placeRelativeWithLayer(
294             x: Int,
295             y: Int,
296             zIndex: Float = 0f,
297             layerBlock: GraphicsLayerScope.() -> Unit = DefaultLayerBlock
298         ) = placeAutoMirrored(IntOffset(x, y), zIndex, layerBlock)
299 
300         /**
301          * Place a [Placeable] at [x], [y] in its parent's coordinate system with an introduced
302          * graphic layer. Unlike [placeRelative], the given position will not implicitly react in
303          * RTL layout direction contexts.
304          *
305          * @param x x coordinate in the parent's coordinate system.
306          * @param y y coordinate in the parent's coordinate system.
307          * @param zIndex controls the drawing order for the [Placeable]. A [Placeable] with larger
308          *   [zIndex] will be drawn on top of all the children with smaller [zIndex]. When children
309          *   have the same [zIndex] the order in which the items were placed is used.
310          * @param layerBlock You can configure any layer property available on [GraphicsLayerScope]
311          *   via this block. If the [Placeable] will be placed with a new [x] or [y] next time only
312          *   the graphic layer will be moved without requiring to redrawn the [Placeable] content.
313          */
314         fun Placeable.placeWithLayer(
315             x: Int,
316             y: Int,
317             zIndex: Float = 0f,
318             layerBlock: GraphicsLayerScope.() -> Unit = DefaultLayerBlock
319         ) = placeApparentToRealOffset(IntOffset(x, y), zIndex, layerBlock)
320 
321         /**
322          * Place a [Placeable] at [position] in its parent's coordinate system with an introduced
323          * graphic layer. Unlike [placeRelative], the given [position] will not implicitly react in
324          * RTL layout direction contexts.
325          *
326          * @param position position in the parent's coordinate system.
327          * @param zIndex controls the drawing order for the [Placeable]. A [Placeable] with larger
328          *   [zIndex] will be drawn on top of all the children with smaller [zIndex]. When children
329          *   have the same [zIndex] the order in which the items were placed is used.
330          * @param layerBlock You can configure any layer property available on [GraphicsLayerScope]
331          *   via this block. If the [Placeable] will be placed with a new [position] next time only
332          *   the graphic layer will be moved without requiring to redrawn the [Placeable] content.
333          */
334         fun Placeable.placeWithLayer(
335             position: IntOffset,
336             zIndex: Float = 0f,
337             layerBlock: GraphicsLayerScope.() -> Unit = DefaultLayerBlock
338         ) = placeApparentToRealOffset(position, zIndex, layerBlock)
339 
340         /**
341          * Place a [Placeable] at [x], [y] in its parent's coordinate system with an introduced
342          * graphic layer. Unlike [placeRelative], the given position will not implicitly react in
343          * RTL layout direction contexts.
344          *
345          * @param x x coordinate in the parent's coordinate system.
346          * @param y y coordinate in the parent's coordinate system.
347          * @param zIndex controls the drawing order for the [Placeable]. A [Placeable] with larger
348          *   [zIndex] will be drawn on top of all the children with smaller [zIndex]. When children
349          *   have the same [zIndex] the order in which the items were placed is used.
350          * @param layer [GraphicsLayer] to place this placeable with. If the [Placeable] will be
351          *   placed with a new [x] or [y] next time only the graphic layer will be moved without
352          *   requiring to redrawn the [Placeable] content.
353          */
354         fun Placeable.placeWithLayer(
355             x: Int,
356             y: Int,
357             layer: GraphicsLayer,
358             zIndex: Float = 0f,
359         ) = placeApparentToRealOffset(IntOffset(x, y), zIndex, layer)
360 
361         /**
362          * Place a [Placeable] at [position] in its parent's coordinate system with an introduced
363          * graphic layer. Unlike [placeRelative], the given [position] will not implicitly react in
364          * RTL layout direction contexts.
365          *
366          * @param position position in the parent's coordinate system.
367          * @param zIndex controls the drawing order for the [Placeable]. A [Placeable] with larger
368          *   [zIndex] will be drawn on top of all the children with smaller [zIndex]. When children
369          *   have the same [zIndex] the order in which the items were placed is used.
370          * @param layer [GraphicsLayer] to place this placeable with. If the [Placeable] will be
371          *   placed with a new [position] next time only the graphic layer will be moved without
372          *   requiring to redrawn the [Placeable] content.
373          */
374         fun Placeable.placeWithLayer(
375             position: IntOffset,
376             layer: GraphicsLayer,
377             zIndex: Float = 0f,
378         ) = placeApparentToRealOffset(position, zIndex, layer)
379 
380         /**
381          * Place a [Placeable] at [x], [y] in its parent's coordinate system with an introduced
382          * graphic layer. If the layout direction is right-to-left, the given position will be
383          * horizontally mirrored so that the position of the [Placeable] implicitly reacts to RTL
384          * layout direction contexts. If this method is used outside the [MeasureScope.layout]
385          * positioning block, the automatic position mirroring will not happen and the [Placeable]
386          * will be placed at the given position, similar to the [place] method.
387          *
388          * @param x x coordinate in the parent's coordinate system.
389          * @param y y coordinate in the parent's coordinate system.
390          * @param zIndex controls the drawing order for the [Placeable]. A [Placeable] with larger
391          *   [zIndex] will be drawn on top of all the children with smaller [zIndex]. When children
392          *   have the same [zIndex] the order in which the items were placed is used.
393          * @param layer [GraphicsLayer] to place this placeable with. If the [Placeable] will be
394          *   placed with a new [x] or [y] next time only the graphic layer will be moved without
395          *   requiring to redrawn the [Placeable] content.
396          */
397         fun Placeable.placeRelativeWithLayer(
398             x: Int,
399             y: Int,
400             layer: GraphicsLayer,
401             zIndex: Float = 0f
402         ) = placeAutoMirrored(IntOffset(x, y), zIndex, layer)
403 
404         /**
405          * Place a [Placeable] at [position] in its parent's coordinate system with an introduced
406          * graphic layer. If the layout direction is right-to-left, the given [position] will be
407          * horizontally mirrored so that the position of the [Placeable] implicitly reacts to RTL
408          * layout direction contexts. If this method is used outside the [MeasureScope.layout]
409          * positioning block, the automatic position mirroring will not happen and the [Placeable]
410          * will be placed at the given [position], similar to the [place] method.
411          *
412          * @param position position in the parent's coordinate system.
413          * @param zIndex controls the drawing order for the [Placeable]. A [Placeable] with larger
414          *   [zIndex] will be drawn on top of all the children with smaller [zIndex]. When children
415          *   have the same [zIndex] the order in which the items were placed is used.
416          * @param layer [GraphicsLayer] to place this placeable with. If the [Placeable] will be
417          *   placed with a new [position] next time only the graphic layer will be moved without
418          *   requiring to redrawn the [Placeable] content.
419          */
420         fun Placeable.placeRelativeWithLayer(
421             position: IntOffset,
422             layer: GraphicsLayer,
423             zIndex: Float = 0f
424         ) = placeAutoMirrored(position, zIndex, layer)
425 
426         @Suppress("NOTHING_TO_INLINE")
427         internal inline fun Placeable.placeAutoMirrored(
428             position: IntOffset,
429             zIndex: Float,
430             noinline layerBlock: (GraphicsLayerScope.() -> Unit)?
431         ) {
432             if (parentLayoutDirection == LayoutDirection.Ltr || parentWidth == 0) {
433                 placeApparentToRealOffset(position, zIndex, layerBlock)
434             } else {
435                 placeApparentToRealOffset(
436                     IntOffset((parentWidth - width - position.x), position.y),
437                     zIndex,
438                     layerBlock
439                 )
440             }
441         }
442 
443         @Suppress("NOTHING_TO_INLINE")
placeAutoMirrorednull444         internal inline fun Placeable.placeAutoMirrored(
445             position: IntOffset,
446             zIndex: Float,
447             layer: GraphicsLayer
448         ) {
449             if (parentLayoutDirection == LayoutDirection.Ltr || parentWidth == 0) {
450                 placeApparentToRealOffset(position, zIndex, layer)
451             } else {
452                 placeApparentToRealOffset(
453                     IntOffset((parentWidth - width - position.x), position.y),
454                     zIndex,
455                     layer
456                 )
457             }
458         }
459 
460         @Suppress("NOTHING_TO_INLINE")
placeApparentToRealOffsetnull461         internal inline fun Placeable.placeApparentToRealOffset(
462             position: IntOffset,
463             zIndex: Float,
464             noinline layerBlock: (GraphicsLayerScope.() -> Unit)?,
465         ) {
466             handleMotionFrameOfReferencePlacement()
467             placeAt(position + apparentToRealOffset, zIndex, layerBlock)
468         }
469 
470         @Suppress("NOTHING_TO_INLINE")
placeApparentToRealOffsetnull471         internal inline fun Placeable.placeApparentToRealOffset(
472             position: IntOffset,
473             zIndex: Float,
474             layer: GraphicsLayer
475         ) {
476             handleMotionFrameOfReferencePlacement()
477             placeAt(position + apparentToRealOffset, zIndex, layer)
478         }
479 
480         /**
481          * Internal indicator to know when to tag [Placeable] as placed on the same frame of
482          * reference.
483          */
484         private var motionFrameOfReferencePlacement: Boolean = false
485 
486         /**
487          * Placement done under [block], will have their [Placeable] placed on the same frame of
488          * reference as the current layout.
489          *
490          * In [LayoutCoordinates], this means that the offset introduced under [block] may be
491          * excluded when calculating positions by passing `includeMotionFrameOfReference = false` in
492          * [LayoutCoordinates.localPositionOf].
493          *
494          * Excluding the position set by certain layouts can be helpful to trigger lookahead based
495          * animation when intended. The typical case are layouts that change frequently due to a
496          * provided value, like [scroll][androidx.compose.foundation.verticalScroll].
497          */
withMotionFrameOfReferencePlacementnull498         fun withMotionFrameOfReferencePlacement(block: PlacementScope.() -> Unit) {
499             motionFrameOfReferencePlacement = true
500             block()
501             motionFrameOfReferencePlacement = false
502         }
503 
504         /**
505          * Updates the [MotionReferencePlacementDelegate.isPlacedUnderMotionFrameOfReference] flag
506          * when called a [Placeable] is placed under [withMotionFrameOfReferencePlacement].
507          *
508          * Note that the Main/Lookahead pass delegate are expected to propagate the flag to the
509          * proper [LookaheadCapablePlaceable].
510          */
handleMotionFrameOfReferencePlacementnull511         private fun Placeable.handleMotionFrameOfReferencePlacement() {
512             if (this is MotionReferencePlacementDelegate) {
513                 updatePlacedUnderMotionFrameOfReference(
514                     this@PlacementScope.motionFrameOfReferencePlacement
515                 )
516             }
517         }
518     }
519 }
520 
521 /** Block on [GraphicsLayerScope] which applies the default layer parameters. */
<lambda>null522 private val DefaultLayerBlock: GraphicsLayerScope.() -> Unit = {}
523 
524 private val DefaultConstraints = Constraints()
525 
PlacementScopenull526 internal fun PlacementScope(
527     lookaheadCapablePlaceable: LookaheadCapablePlaceable
528 ): Placeable.PlacementScope = LookaheadCapablePlacementScope(lookaheadCapablePlaceable)
529 
530 internal fun PlacementScope(owner: Owner): Placeable.PlacementScope = OuterPlacementScope(owner)
531 
532 /** PlacementScope used by almost all parts of Compose. */
533 private class LookaheadCapablePlacementScope(private val within: LookaheadCapablePlaceable) :
534     Placeable.PlacementScope() {
535     override val parentWidth: Int
536         get() = within.measuredWidth
537 
538     override val parentLayoutDirection: LayoutDirection
539         get() = within.layoutDirection
540 
541     override val coordinates: LayoutCoordinates?
542         get() {
543             val coords = if (within.isPlacingForAlignment) null else within.coordinates
544             // if coordinates are not null we will only set this flag when the inner
545             // coordinate values are read. see NodeCoordinator.onCoordinatesUsed()
546             if (coords == null) {
547                 within.layoutNode.layoutDelegate.onCoordinatesUsed()
548             }
549             return coords
550         }
551 
552     override fun Ruler.current(defaultValue: Float): Float =
553         within.findRulerValue(this, defaultValue)
554 }
555 
556 /** The PlacementScope that is used at the root of the compose layout hierarchy. */
557 private class OuterPlacementScope(val owner: Owner) : Placeable.PlacementScope() {
558     override val parentWidth: Int
559         get() = owner.root.width
560 
561     override val parentLayoutDirection: LayoutDirection
562         get() = owner.layoutDirection
563 
564     override val coordinates: LayoutCoordinates
565         get() = owner.root.outerCoordinator
566 }
567