computeContentBoxLogicalWidth method
void
computeContentBoxLogicalWidth()
Implementation
void computeContentBoxLogicalWidth() {
// RenderBoxModel current = renderBoxModel!;
RenderStyle renderStyle = this;
double? logicalWidth;
CSSDisplay? effectiveDisplay = renderStyle.effectiveDisplay;
// Special handling for absolutely/fixed positioned non-replaced elements.
// Follow CSS abs-non-replaced width algorithm:
// - If width is auto and both left and right are auto: keep width as auto (shrink-to-fit in layout).
// - If width is auto and both left and right are not auto: solve width from containing block padding box.
if ((renderStyle.position == CSSPositionType.absolute || renderStyle.position == CSSPositionType.fixed) &&
!renderStyle.isSelfRenderReplaced()) {
if (renderStyle.width.isNotAuto) {
logicalWidth = renderStyle.width.computedValue;
} else if (renderStyle.left.isNotAuto && renderStyle.right.isNotAuto) {
// https://www.w3.org/TR/css-position-3/#abs-non-replaced-width
if (renderStyle.isParentRenderBoxModel()) {
RenderStyle parentRenderStyle = renderStyle.getParentRenderStyle()!;
if (parentRenderStyle.paddingBoxLogicalWidth != null) {
// Width of positioned element should subtract its horizontal margin.
logicalWidth = (parentRenderStyle.paddingBoxLogicalWidth!) -
renderStyle.left.computedValue -
renderStyle.right.computedValue -
renderStyle.marginLeft.computedValue -
renderStyle.marginRight.computedValue;
}
} else {
logicalWidth = null;
}
}
}
// Width applies to all elements except non-replaced inline elements.
// https://drafts.csswg.org/css-sizing-3/#propdef-width
if (effectiveDisplay == CSSDisplay.inline && !renderStyle.isSelfRenderReplaced()) {
_contentBoxLogicalWidth = null;
return;
} else if (effectiveDisplay == CSSDisplay.block ||
effectiveDisplay == CSSDisplay.flex ||
effectiveDisplay == CSSDisplay.grid) {
CSSRenderStyle? parentStyle = renderStyle.getParentRenderStyle();
if (logicalWidth == null && renderStyle.width.isNotAuto) {
logicalWidth = renderStyle.width.computedValue;
} else if (logicalWidth == null && aspectRatio != null && renderStyle.height.isNotAuto) {
// Prefer aspect-ratio when height is definite and width is auto.
double contentH = renderStyle.height.computedValue - renderStyle.border.vertical - renderStyle.padding.vertical;
contentH = math.max(0, contentH);
final double contentW = contentH * aspectRatio!;
logicalWidth = contentW + renderStyle.border.horizontal + renderStyle.padding.horizontal;
} else if (logicalWidth == null && renderStyle.isSelfHTMLElement()) {
// Avoid defaulting to the viewport width when this element participates
// in an inline-block shrink-to-fit context. Children of an inline-block
// with auto width must not assume a definite containing block width; doing so
// causes percentage widths (e.g., 100%) to immediately resolve to the viewport
// and force the inline-block to expand to the full line width. Instead, keep
// width auto here so the child can measure intrinsically and the parent can
// shrink-wrap to its contents.
final CSSRenderStyle? p = renderStyle.getParentRenderStyle();
final bool parentInlineBlockAuto = p != null &&
p.effectiveDisplay == CSSDisplay.inlineBlock && p.width.isAuto;
if (!parentInlineBlockAuto) {
logicalWidth = target.ownerView.viewport!.boxSize!.width;
}
} else if (logicalWidth == null && (renderStyle.isSelfRouterLinkElement() && getCurrentViewportBox() is! RootRenderViewportBox)) {
logicalWidth = getCurrentViewportBox()!.boxSize!.width;
} else if (logicalWidth == null && parentStyle != null) {
// Resolve whether the direct parent is a flex item (its render box's parent is a flex container).
// Determine if our direct parent is a flex item: i.e., the parent's parent is a flex container.
final bool parentIsFlexItem = parentStyle.isParentRenderFlexLayout();
// Whether THIS element is a flex item (its own parent is a flex container).
// When true, width:auto must not be stretched to the parent’s width in the main axis;
// the flex base size is content-based per CSS Flexbox §9.2.
final bool thisIsFlexItem = this.isParentRenderFlexLayout();
// Case A: inside a flex item — stretch block-level auto width to the flex item's measured width.
// For WebF widget elements (custom elements backed by Flutter widgets), only use the
// direct constraints exposed via `WebFWidgetElementChild` instead of inferring from
// the RenderWidget's own content constraints, which can vary by adapter implementation.
if (parentIsFlexItem && !thisIsFlexItem &&
!renderStyle.isSelfRenderReplaced() &&
renderStyle.position != CSSPositionType.absolute &&
renderStyle.position != CSSPositionType.fixed) {
if (parentStyle.isSelfRenderWidget()) {
RenderWidgetElementChild? childWrapper = target.attachedRenderer?.findWidgetElementChild();
double? maxConstraintWidth;
try {
maxConstraintWidth = childWrapper?.constraints.maxWidth;
} catch (_) {}
if (childWrapper != null && maxConstraintWidth != null) {
logicalWidth = maxConstraintWidth;
}
// If there is no WebFWidgetElementChild (or no constraints yet),
// fall through and let the parent (flex) constraints logic handle it.
} else {
final RenderBoxModel? parentBox = parentStyle.attachedRenderBoxModel;
final BoxConstraints? pcc = parentBox?.contentConstraints;
if (pcc != null && pcc.hasBoundedWidth && pcc.maxWidth.isFinite) {
logicalWidth = pcc.maxWidth - renderStyle.margin.horizontal;
}
}
// Case B: normal flow (not inside a flex item) — find the nearest non-inline ancestor
// and adopt its content box logical width or bounded content constraints.
} else if (!parentIsFlexItem &&
!renderStyle.isSelfRenderReplaced() &&
renderStyle.position != CSSPositionType.absolute &&
renderStyle.position != CSSPositionType.fixed &&
!renderStyle.isParentRenderFlexLayout()) {
RenderStyle? ancestorRenderStyle = _findAncestorWithNoDisplayInline();
// Should ignore renderStyle of display inline when searching for ancestors to stretch width.
if (ancestorRenderStyle != null) {
RenderWidgetElementChild? childWrapper = target.attachedRenderer?.findWidgetElementChild();
double? maxConstraintWidth;
try {
maxConstraintWidth = childWrapper?.constraints.maxWidth;
} catch (_) {}
if (ancestorRenderStyle.isSelfRenderWidget() && childWrapper != null && maxConstraintWidth != null) {
logicalWidth = maxConstraintWidth;
} else {
logicalWidth = ancestorRenderStyle.contentBoxLogicalWidth;
}
// No fallback to unrelated ancestors for flex scenarios here; if ancestor is a
// flex item but has no bounded width yet, defer stretching (leave null).
// Should subtract horizontal margin of own from its parent content width.
if (logicalWidth != null) {
logicalWidth -= renderStyle.margin.horizontal;
}
}
}
}
} else if (effectiveDisplay == CSSDisplay.inlineBlock ||
effectiveDisplay == CSSDisplay.inlineFlex ||
effectiveDisplay == CSSDisplay.inlineGrid ||
effectiveDisplay == CSSDisplay.inline) {
if (logicalWidth == null && renderStyle.width.isNotAuto) {
logicalWidth = renderStyle.width.computedValue;
}
}
// Get width by aspect ratio if width is auto.
if (logicalWidth == null && aspectRatio != null) {
// If a definite height is specified, prefer converting via the preferred aspect-ratio.
if (renderStyle.height.isNotAuto) {
double contentH = renderStyle.height.computedValue - renderStyle.border.vertical - renderStyle.padding.vertical;
contentH = math.max(0, contentH);
final double contentW = contentH * aspectRatio!;
logicalWidth = contentW + renderStyle.border.horizontal + renderStyle.padding.horizontal;
}
// Fallback for replaced/intrinsic scenarios.
logicalWidth ??= renderStyle.getWidthByAspectRatio();
}
// Constrain width by min-width and max-width.
if (renderStyle.minWidth.isNotAuto) {
double minWidth = renderStyle.minWidth.computedValue;
if (logicalWidth != null && logicalWidth < minWidth) {
logicalWidth = minWidth;
}
}
if (renderStyle.maxWidth.isNotNone) {
double maxWidth = renderStyle.maxWidth.computedValue;
if (logicalWidth != null && logicalWidth > maxWidth) {
logicalWidth = maxWidth;
}
}
double? logicalContentWidth;
// Subtract padding and border width to get content width.
if (logicalWidth != null) {
logicalContentWidth = logicalWidth - renderStyle.border.horizontal - renderStyle.padding.horizontal;
// Logical width may be smaller than its border and padding width,
// in this case, content width will be negative which is illegal.
logicalContentWidth = math.max(0, logicalContentWidth);
}
_contentBoxLogicalWidth = logicalContentWidth;
}