Implementation
static void applyPositionedChildOffset(
RenderBoxModel parent,
RenderBoxModel child,
) {
RenderLayoutParentData childParentData = child.parentData as RenderLayoutParentData;
Size size = child.boxSize!;
Size parentSize = parent.boxSize!;
RenderStyle parentRenderStyle = parent.renderStyle;
CSSLengthValue parentBorderLeftWidth = parentRenderStyle.effectiveBorderLeftWidth;
CSSLengthValue parentBorderRightWidth = parentRenderStyle.effectiveBorderRightWidth;
CSSLengthValue parentBorderTopWidth = parentRenderStyle.effectiveBorderTopWidth;
CSSLengthValue parentBorderBottomWidth = parentRenderStyle.effectiveBorderBottomWidth;
CSSLengthValue parentPaddingLeft = parentRenderStyle.paddingLeft;
CSSLengthValue parentPaddingTop = parentRenderStyle.paddingTop;
// The containing block of not an inline box is formed by the padding edge of the ancestor.
// Thus the final offset of child need to add the border of parent.
// https://www.w3.org/TR/css-position-3/#def-cb
Size containingBlockSize = Size(
parentSize.width - parentBorderLeftWidth.computedValue - parentBorderRightWidth.computedValue,
parentSize.height - parentBorderTopWidth.computedValue - parentBorderBottomWidth.computedValue);
CSSRenderStyle childRenderStyle = child.renderStyle;
CSSLengthValue left = childRenderStyle.left;
CSSLengthValue right = childRenderStyle.right;
CSSLengthValue top = childRenderStyle.top;
CSSLengthValue bottom = childRenderStyle.bottom;
CSSLengthValue marginLeft = childRenderStyle.marginLeft;
CSSLengthValue marginRight = childRenderStyle.marginRight;
CSSLengthValue marginTop = childRenderStyle.marginTop;
CSSLengthValue marginBottom = childRenderStyle.marginBottom;
// Fix side effects by render portal.
if (child is RenderEventListener && child.child is RenderBoxModel) {
child = child.child as RenderBoxModel;
childParentData = child.parentData as RenderLayoutParentData;
}
// The static position of positioned element is its offset when its position property had been static
// which equals to the position of its placeholder renderBox.
// https://www.w3.org/TR/CSS2/visudet.html#static-position
RenderPositionPlaceholder? ph = child.renderStyle.getSelfPositionPlaceHolder();
Offset staticPositionOffset = _getPlaceholderToParentOffset(ph, parent,
excludeScrollOffset: child.renderStyle.position != CSSPositionType.fixed);
try {
final pTag = parent.renderStyle.target.tagName.toLowerCase();
final cTag = child.renderStyle.target.tagName.toLowerCase();
final phOff = (ph != null && ph.parentData is RenderLayoutParentData)
? (ph.parentData as RenderLayoutParentData).offset
: null;
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => '<$cTag> static from placeholder: raw=${phOff == null ? 'null' : '${phOff.dx.toStringAsFixed(2)},${phOff.dy.toStringAsFixed(2)}'} '
'toParent=${staticPositionOffset.dx.toStringAsFixed(2)},${staticPositionOffset.dy.toStringAsFixed(2)} parent=<$pTag>',
);
} catch (_) {}
// Diagnostics: static-position context snapshot
try {
final cTag = child.renderStyle.target.tagName.toLowerCase();
final dispSpec = child.renderStyle.display.toString().split('.').last;
final dispEff = child.renderStyle.effectiveDisplay.toString().split('.').last;
final posType = child.renderStyle.position.toString().split('.').last;
final phParent = ph == null ? 'null' : ph.parent.runtimeType.toString();
final bool phInIFC = ph != null && ph.parent is RenderFlowLayout && (ph.parent as RenderFlowLayout).establishIFC;
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'context <${cTag}> pos=${posType} disp(spec=${dispSpec}, eff=${dispEff}) '
'parentIsDocRoot=${parent.isDocumentRootBox} phParent=${phParent} phInIFC=${phInIFC}',
);
} catch (_) {}
// Ensure static position accuracy for W3C compliance
// W3C requires static position to represent where element would be in normal flow
Offset adjustedStaticPosition = _ensureAccurateStaticPosition(
staticPositionOffset,
child,
parent,
left,
right,
top,
bottom,
parentBorderLeftWidth,
parentBorderRightWidth,
parentBorderTopWidth,
parentBorderBottomWidth,
parentPaddingLeft,
parentPaddingTop
);
// Inline static-position correction (horizontal): when the placeholder sits inside
// an IFC container (e.g., text followed by abspos inline), align the static X to the
// inline advance within that container's content box so that `left:auto` follows the
// preceding inline content per CSS static-position rules.
// Only apply when the containing block is not the document root. Root cases are handled
// specially below to preserve expected behavior.
if (!parent.isDocumentRootBox && ph != null) {
// Find the nearest ancestor flow container that establishes an IFC.
RenderObject? a = ph.parent;
RenderFlowLayout? flowParent;
while (a != null) {
if (a is RenderFlowLayout && a.establishIFC) {
flowParent = a;
break;
}
a = (a.parent is RenderObject) ? a.parent as RenderObject? : null;
}
if (flowParent != null) {
// Only inline-level hypothetical boxes should use inline advance for static X.
// Use specified display (not effective) to avoid misclassifying inline elements
// that are out-of-flow as block.
final CSSDisplay childDisp = child.renderStyle.display;
final bool childIsBlockLike = (childDisp == CSSDisplay.block || childDisp == CSSDisplay.flex);
// Base content-left inset inside the IFC container
final double contentLeftInset =
flowParent.renderStyle.effectiveBorderLeftWidth.computedValue +
flowParent.renderStyle.paddingLeft.computedValue;
if (!childIsBlockLike) {
// Use IFC-provided inline advance; when unavailable (e.g., empty inline), keep 0.
double inlineAdvance = flowParent.inlineAdvanceBefore(ph);
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'IFC inline advance (non-root inline)=${inlineAdvance.toStringAsFixed(2)}',
);
} catch (_) {}
if (inlineAdvance == 0.0) {
// Fallback: if placeholder is appended after inline content within this IFC container,
// use the paragraph visual max line width as the preceding inline advance.
final bool hasPrecedingInline = _hasInlineContentBeforePlaceholder(flowParent, ph);
if (hasPrecedingInline && flowParent.inlineFormattingContext != null) {
inlineAdvance = flowParent.inlineFormattingContext!.paragraphVisualMaxLineWidth;
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'fallback inline advance by paragraph width =${inlineAdvance.toStringAsFixed(2)}',
);
} catch (_) {}
}
}
// Do not use inline advance when the abspos has percentage width (e.g., width:100%),
// since the horizontal insets equation will use the static position as 'left' and a
// percentage width that fills the containing block; browsers effectively align such
// overlays at the content-left (no inline advance).
final bool widthIsPercentage = child.renderStyle.width.type == CSSLengthType.PERCENTAGE;
final double effAdvance = widthIsPercentage ? 0.0 : inlineAdvance;
// Compute flow content-left in CB space and add inline advance.
final Offset _phToFlow = _getPlaceholderToParentOffset(ph, flowParent, excludeScrollOffset: true);
final double targetX = staticPositionOffset.dx - _phToFlow.dx + contentLeftInset + effAdvance;
adjustedStaticPosition = Offset(targetX, adjustedStaticPosition.dy);
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'adjust static pos by IFC inline advance '
'contentLeft=${contentLeftInset.toStringAsFixed(2)} '
'advance=${effAdvance.toStringAsFixed(2)} '
'→ (${adjustedStaticPosition.dx.toStringAsFixed(2)},${adjustedStaticPosition.dy.toStringAsFixed(2)})',
);
} catch (_) {}
// Vertical: when both top and bottom are auto, align to the IFC container's
// content-top in CB coordinates so the abspos sits at the top of the line box.
if (top.isAuto && bottom.isAuto) {
final double contentTopInset = flowParent.renderStyle.paddingTop.computedValue +
flowParent.renderStyle.effectiveBorderTopWidth.computedValue;
final double targetY = staticPositionOffset.dy - _phToFlow.dy + contentTopInset;
adjustedStaticPosition = Offset(adjustedStaticPosition.dx, targetY);
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'adjust static Y by IFC content-top '
'flowContentTopInCB=${targetY.toStringAsFixed(2)}',
);
} catch (_) {}
}
} else {
// Block-level hypothetical box: anchor to flow content-left in CB space.
if (contentLeftInset != 0.0) {
final Offset _phToFlow = _getPlaceholderToParentOffset(ph, flowParent, excludeScrollOffset: true);
final double targetX = staticPositionOffset.dx - _phToFlow.dx + contentLeftInset;
adjustedStaticPosition = Offset(targetX, adjustedStaticPosition.dy);
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'adjust static pos by IFC content-left for block '
'contentLeft=${contentLeftInset.toStringAsFixed(2)} '
'→ (${adjustedStaticPosition.dx.toStringAsFixed(2)},${adjustedStaticPosition.dy.toStringAsFixed(2)})',
);
} catch (_) {}
}
// Block-level vertical: place below the inline line box height when top/bottom are auto
// AND there is preceding inline content before the placeholder.
if (top.isAuto && bottom.isAuto) {
// Determine preceding inline by structural scan when width sums are unavailable.
final bool hasPrecedingInline = _hasInlineContentBeforePlaceholder(flowParent, ph);
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'non-root IFC block: hasPrecedingInline=${hasPrecedingInline}',
);
} catch (_) {}
if (hasPrecedingInline) {
final InlineFormattingContext? ifc = flowParent.inlineFormattingContext;
if (ifc != null) {
double paraH;
final lines = ifc.paragraphLineMetrics;
if (lines.isNotEmpty) {
paraH = lines.fold<double>(0.0, (sum, lm) => sum + lm.height);
} else {
paraH = ifc.paragraph?.height ?? 0.0;
}
if (paraH != 0.0 && adjustedStaticPosition.dy.abs() < 0.5) {
adjustedStaticPosition = adjustedStaticPosition.translate(0, paraH);
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'adjust static pos by IFC paragraph height for block '
'lines=${lines.length} h=${paraH.toStringAsFixed(2)} '
'→ (${adjustedStaticPosition.dx.toStringAsFixed(2)},${adjustedStaticPosition.dy.toStringAsFixed(2)})',
);
} catch (_) {}
}
}
}
}
}
// Vertical static position for top/bottom auto in IFC:
// Anchor to the IFC container's content top so the abspos aligns with
// the line box where the placeholder sits (top of the first line).
if (top.isAuto && bottom.isAuto) {
final double padTop = flowParent.renderStyle.paddingTop.computedValue;
final double borderTop = flowParent.renderStyle.effectiveBorderTopWidth.computedValue;
final double contentTopInset = padTop + borderTop;
if (contentTopInset != 0.0 && adjustedStaticPosition.dy.abs() < 0.5) {
adjustedStaticPosition = adjustedStaticPosition.translate(0, contentTopInset);
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'adjust static pos by IFC contentTop '
'inset=${contentTopInset.toStringAsFixed(2)} '
'→ (${adjustedStaticPosition.dx.toStringAsFixed(2)},${adjustedStaticPosition.dy.toStringAsFixed(2)})',
);
} catch (_) {}
}
}
}
}
// If the containing block is the document root (<html>) and the placeholder lives
// under the block formatting context of <body>, align the static position vertically
// with the first in-flow block-level child’s collapsed top (ignoring parent collapse).
// This matches browser behavior where the first in-flow child’s top margin effectively
// offsets the visible content from the root. The positioned element’s static position
// should reflect that visual start so the out-of-flow element and the following in-flow
// element align vertically when no insets are specified.
if (parent.isDocumentRootBox && ph != null) {
final RenderObject? phParent = ph.parent;
if (phParent is RenderBoxModel) {
final RenderBoxModel phContainer = phParent;
final RenderStyle cStyle = phContainer.renderStyle;
final bool qualifiesBFC =
cStyle.isLayoutBox() &&
cStyle.effectiveDisplay == CSSDisplay.block &&
(cStyle.effectiveOverflowY == CSSOverflowType.visible || cStyle.effectiveOverflowY == CSSOverflowType.clip) &&
cStyle.paddingTop.computedValue == 0 &&
cStyle.effectiveBorderTopWidth.computedValue == 0;
// Only adjust when placeholder is the first attached child (no previous in-flow block)
final bool isFirstChild = (ph.parentData is RenderLayoutParentData) &&
((ph.parentData as RenderLayoutParentData).previousSibling == null);
if (qualifiesBFC && isFirstChild) {
final RenderBoxModel? firstFlow = _resolveNextInFlowSiblingModel(ph);
if (firstFlow != null) {
final double childTopIgnoringParent = firstFlow.renderStyle.collapsedMarginTopIgnoringParent;
if (childTopIgnoringParent != 0) {
adjustedStaticPosition = adjustedStaticPosition.translate(0, childTopIgnoringParent);
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'adjust static pos by first in-flow child top(${childTopIgnoringParent.toStringAsFixed(2)}) '
'→ (${adjustedStaticPosition.dx.toStringAsFixed(2)},${adjustedStaticPosition.dy.toStringAsFixed(2)})',
);
} catch (_) {}
}
}
}
// Horizontal static-position in IFC under document root: when placeholder lives in an
// inline formatting context (e.g., <div><span>text</span><abspos/></div>) but the containing
// block is <html>, the static X should reflect the inline advance within the IFC container.
// Compute inline advance from the IFC paragraph; if the placeholder is the last child,
// fall back to the paragraph’s visual max line width.
// Use the nearest IFC container up the chain for horizontal inline advance.
RenderFlowLayout? flowParent;
if (phParent is RenderFlowLayout && phParent.establishIFC) {
flowParent = phParent as RenderFlowLayout;
} else {
RenderObject? a = phParent.parent;
while (a != null) {
if (a is RenderFlowLayout && a.establishIFC) {
flowParent = a;
break;
}
a = (a.parent is RenderObject) ? a.parent as RenderObject? : null;
}
}
if (flowParent != null) {
// Base inset: content-left inside the IFC container
final double contentLeftInset =
flowParent.renderStyle.effectiveBorderLeftWidth.computedValue +
flowParent.renderStyle.paddingLeft.computedValue;
// Under document root, honor block-level vs inline-level behavior:
// - Block/flex: anchor to content-left only (x = content-left), no vertical shift.
// - Inline-level: add horizontal inline advance before placeholder.
// Use the specified display for block-vs-inline determination; effectiveDisplay
// is normalized for out-of-flow and may not reflect original block-vs-inline.
final CSSDisplay childDispSpecified = child.renderStyle.display;
final bool childIsBlockLike = (childDispSpecified == CSSDisplay.block || childDispSpecified == CSSDisplay.flex);
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'doc-root IFC path: dispSpecified=${childDispSpecified.toString().split('.').last} '
'blockLike=${childIsBlockLike} contentLeft=${contentLeftInset.toStringAsFixed(2)}',
);
} catch (_) {}
if (childIsBlockLike) {
if (contentLeftInset != 0.0) {
final Offset _phToFlow = _getPlaceholderToParentOffset(ph, flowParent, excludeScrollOffset: true);
final double targetX = staticPositionOffset.dx - _phToFlow.dx + contentLeftInset;
adjustedStaticPosition = Offset(targetX, adjustedStaticPosition.dy);
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'adjust static pos under root by IFC content-left for block '
'contentLeft=${contentLeftInset.toStringAsFixed(2)} '
'→ (${adjustedStaticPosition.dx.toStringAsFixed(2)},${adjustedStaticPosition.dy.toStringAsFixed(2)})',
);
} catch (_) {}
}
// Vertical: if preceded by inline, move to the next line (add paragraph height).
if (top.isAuto && bottom.isAuto) {
final bool hasPrecedingInline = _hasInlineContentBeforePlaceholder(flowParent, ph);
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'doc-root IFC block: hasPrecedingInline=${hasPrecedingInline}',
);
} catch (_) {}
if (hasPrecedingInline) {
final InlineFormattingContext? ifc = flowParent.inlineFormattingContext;
if (ifc != null) {
double paraH;
final lines = ifc.paragraphLineMetrics;
if (lines.isNotEmpty) {
paraH = lines.fold<double>(0.0, (sum, lm) => sum + lm.height);
} else {
paraH = ifc.paragraph?.height ?? 0.0;
}
if (paraH != 0.0) {
adjustedStaticPosition = adjustedStaticPosition.translate(0, paraH);
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'adjust static pos under root by IFC paragraph height for block '
'lines=${lines.length} '
'h=${paraH.toStringAsFixed(2)} '
'→ (${adjustedStaticPosition.dx.toStringAsFixed(2)},${adjustedStaticPosition.dy.toStringAsFixed(2)})',
);
} catch (_) {}
}
}
}
}
} else {
double inlineAdvance = flowParent.inlineAdvanceBefore(ph);
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'inline-level under root: inlineAdvance=${inlineAdvance.toStringAsFixed(2)}',
);
} catch (_) {}
if (inlineAdvance == 0.0) {
final bool hasPrecedingInline = _hasInlineContentBeforePlaceholder(flowParent, ph);
if (hasPrecedingInline && flowParent.inlineFormattingContext != null) {
inlineAdvance = flowParent.inlineFormattingContext!.paragraphVisualMaxLineWidth;
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'fallback inline advance under root by paragraph width =${inlineAdvance.toStringAsFixed(2)}',
);
} catch (_) {}
}
}
final bool widthIsPercentage = child.renderStyle.width.type == CSSLengthType.PERCENTAGE;
final double effAdvance = widthIsPercentage ? 0.0 : inlineAdvance;
final Offset _phToFlow = _getPlaceholderToParentOffset(ph, flowParent, excludeScrollOffset: true);
final double targetX = staticPositionOffset.dx - _phToFlow.dx + contentLeftInset + effAdvance;
adjustedStaticPosition = Offset(targetX, adjustedStaticPosition.dy);
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'adjust static pos under root by IFC inline advance '
'contentLeft=${contentLeftInset.toStringAsFixed(2)} '
'advance=${effAdvance.toStringAsFixed(2)} '
'→ (${adjustedStaticPosition.dx.toStringAsFixed(2)},${adjustedStaticPosition.dy.toStringAsFixed(2)})',
);
} catch (_) {}
}
}
}
}
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.staticPosition,
message: () => 'adjusted static pos = (${adjustedStaticPosition.dx.toStringAsFixed(2)},${adjustedStaticPosition.dy.toStringAsFixed(2)})',
);
} catch (_) {}
// Child renderObject is reparented under its containing block at build time,
// and staticPositionOffset is already measured relative to the containing block.
// No additional ancestor offset adjustment is needed.
Offset ancestorOffset = Offset.zero;
// ScrollTop and scrollLeft will be added to offset of renderBox in the paint stage
// for positioned fixed element.
if (childRenderStyle.position == CSSPositionType.fixed) {
Offset scrollOffset = child.getTotalScrollOffset();
child.additionalPaintOffsetX = scrollOffset.dx;
child.additionalPaintOffsetY = scrollOffset.dy;
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.fixed,
message: () => '<${child.renderStyle.target.tagName.toLowerCase()}>'
' fixed paintOffset=(${scrollOffset.dx.toStringAsFixed(2)},${scrollOffset.dy.toStringAsFixed(2)})',
);
} catch (_) {}
}
// When the parent is a scroll container (overflow on either axis not visible),
// convert positioned offsets to the scrolling content box coordinate space.
// Overflow paint translates children relative to the content edge, so offsets
// computed from the padding edge must exclude border and padding for alignment.
final bool parentIsScrollContainer =
parent.renderStyle.effectiveOverflowX != CSSOverflowType.visible ||
parent.renderStyle.effectiveOverflowY != CSSOverflowType.visible;
// Determine direction for resolving 'auto' horizontal insets: use the
// direction of the element establishing the static-position containing block
// (typically the IFC container hosting the placeholder) when available;
// otherwise fall back to the containing block's direction.
TextDirection _staticContainingDir = parent.renderStyle.direction;
if (ph != null && ph.parent is RenderFlowLayout) {
final RenderFlowLayout flowParent = ph.parent as RenderFlowLayout;
_staticContainingDir = flowParent.renderStyle.direction;
}
// For sticky positioning, the insets act as constraints during scroll, not as
// absolute offsets at layout time. Compute the base (un-stuck) offset from the
// static position by treating both axis insets as auto for layout.
final bool isSticky = childRenderStyle.position == CSSPositionType.sticky;
double x = _computePositionedOffset(
Axis.horizontal,
_staticContainingDir,
false,
parentBorderLeftWidth,
parentPaddingLeft,
containingBlockSize.width,
size.width,
adjustedStaticPosition.dx,
isSticky ? CSSLengthValue.auto : left,
isSticky ? CSSLengthValue.auto : right,
marginLeft,
marginRight,
);
double y = _computePositionedOffset(
Axis.vertical,
parent.renderStyle.direction,
false,
parentBorderTopWidth,
parentPaddingTop,
containingBlockSize.height,
size.height,
adjustedStaticPosition.dy,
isSticky ? CSSLengthValue.auto : top,
isSticky ? CSSLengthValue.auto : bottom,
marginTop,
marginBottom,
);
try {
final dir = parent.renderStyle.direction;
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.offsets,
message: () => 'compute offset for <${child.renderStyle.target.tagName.toLowerCase()}>'
' dir=$dir parentScroll=$parentIsScrollContainer left=${left.cssText()} right=${right.cssText()} '
'top=${top.cssText()} bottom=${bottom.cssText()} → (${x.toStringAsFixed(2)},${y.toStringAsFixed(2)})',
);
} catch (_) {}
final Offset finalOffset = Offset(x, y) - ancestorOffset;
// If this positioned element is wrapped (e.g., by RenderEventListener), ensure
// the wrapper is placed at the positioned offset so its background/border align
// with the child content. The child uses internal offsets relative to the wrapper.
bool placedWrapper = false;
final RenderObject? directParent = child.parent;
if (directParent is RenderEventListener) {
final RenderLayoutParentData pd = directParent.parentData as RenderLayoutParentData;
pd.offset = finalOffset;
placedWrapper = true;
}
if (!placedWrapper) {
childParentData.offset = finalOffset;
}
// Diagnostics: compute instantaneous on-screen right edge and parent bounds to detect overflow.
try {
// Parent padding-right edge in parent's border-box coordinate space.
final double parentPadRightX = parent.boxSize!.width - parentBorderRightWidth.computedValue;
// Child transform translation applied at paint time.
final Matrix4 eff = child.renderStyle.effectiveTransformMatrix;
final Vector3 tr = eff.getTranslation();
final double tx = tr.x;
final double rightEdgeX = finalOffset.dx + tx + size.width;
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.offsets,
message: () => 'bounds check: childRight=${rightEdgeX.toStringAsFixed(2)} '
'parentPadRight=${parentPadRightX.toStringAsFixed(2)} '
'overflowX=${(rightEdgeX - parentPadRightX).toStringAsFixed(2)}',
);
} catch (_) {}
try {
PositionedLayoutLog.log(
impl: PositionedImpl.layout,
feature: PositionedFeature.offsets,
message: () => 'apply offset final=(${finalOffset.dx.toStringAsFixed(2)},${finalOffset.dy.toStringAsFixed(2)}) '
'from x=${x.toStringAsFixed(2)} y=${y.toStringAsFixed(2)} ancestor=(${ancestorOffset.dx.toStringAsFixed(2)},${ancestorOffset.dy.toStringAsFixed(2)})',
);
} catch (_) {}
}