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