getContentSize method
Common layout content size (including flow and flexbox layout) calculation logic
Implementation
Size getContentSize({
required double contentWidth,
required double contentHeight,
}) {
double finalContentWidth = contentWidth;
double finalContentHeight = contentHeight;
// Size which is specified by sizing styles
double? specifiedContentWidth = renderStyle.contentBoxLogicalWidth;
double? specifiedContentHeight = renderStyle.contentBoxLogicalHeight;
// Margin negative will set element which is static && not set width, size bigger
double? marginLeft = renderStyle.marginLeft.computedValue;
double? marginRight = renderStyle.marginRight.computedValue;
double? marginAddSizeLeft = 0;
double? marginAddSizeRight = 0;
if (isNegativeMarginChangeHSize) {
marginAddSizeRight = marginLeft < 0 ? -marginLeft : 0;
marginAddSizeLeft = marginRight < 0 ? -marginRight : 0;
}
// Flex items: when flex-basis is specified (not 'auto'), it overrides the
// main-size property (width/height) for the base size per CSS Flexbox.
// Use the resolved flex-basis as the specified content size on the main axis
// so the item measures to its base size during intrinsic layout.
if (renderStyle.isParentRenderFlexLayout()) {
final CSSRenderStyle? parentRenderStyle =
renderStyle.getAttachedRenderParentRenderStyle();
final CSSLengthValue? flexBasisLV = renderStyle.flexBasis;
final bool isFlexBasisContent =
flexBasisLV?.type == CSSLengthType.CONTENT;
final double? flexBasis = (flexBasisLV == null ||
flexBasisLV == CSSLengthValue.auto ||
isFlexBasisContent)
? null
: flexBasisLV.computedValue;
if (flexBasis != null && parentRenderStyle != null) {
// Determine main-axis orientation with writing-mode awareness.
final CSSWritingMode wm = parentRenderStyle.writingMode;
final bool inlineIsHorizontal = (wm == CSSWritingMode.horizontalTb);
final bool parentRow =
parentRenderStyle.flexDirection == FlexDirection.row ||
parentRenderStyle.flexDirection == FlexDirection.rowReverse;
final bool isMainAxisHorizontal =
parentRow ? inlineIsHorizontal : !inlineIsHorizontal;
final bool isParentMainDefinite = isMainAxisHorizontal
? parentRenderStyle.contentBoxLogicalWidth != null
: parentRenderStyle.contentBoxLogicalHeight != null;
final bool isPctBasis = flexBasisLV!.type == CSSLengthType.PERCENTAGE;
// Follow CSS spec: percentage flex-basis resolves against the flex container's main size;
// if that size is indefinite, the used value is 'content'. In that case, do not override
// the specified content size here—let content determine sizing.
if (isPctBasis && !isParentMainDefinite) {
// Skip overriding specified content size.
} else if (flexBasis > 0) {
// Only apply positive, resolvable flex-basis to content sizing here.
if (isMainAxisHorizontal) {
if (!hasOverrideContentLogicalWidth) {
specifiedContentWidth = _getContentWidth(flexBasis);
}
} else {
if (!hasOverrideContentLogicalHeight) {
specifiedContentHeight = _getContentHeight(flexBasis);
}
}
} else {
// Non-positive flex-basis should not clamp intrinsic content to zero here.
}
}
}
// If an explicit content width is specified via CSS (width/min/max already
// resolved above), it should determine the used content width. Do not
// auto-expand to accommodate measured content here — overflow handling
// should deal with larger content per CSS. Using max() causes blocks inside
// unbounded containers (e.g. horizontal slivers) to incorrectly expand to
// ancestor viewport widths instead of honoring the specified width.
if (specifiedContentWidth != null) {
finalContentWidth = specifiedContentWidth;
}
if (parent is RenderFlexLayout &&
marginAddSizeLeft > 0 &&
marginAddSizeRight > 0 ||
parent is RenderFlowLayout &&
(marginAddSizeRight > 0 || marginAddSizeLeft > 0)) {
finalContentWidth += marginAddSizeLeft;
finalContentWidth += marginAddSizeRight;
}
// Same rule for height: honor the specified content height if provided
// rather than expanding to measured content height here.
if (specifiedContentHeight != null) {
finalContentHeight = specifiedContentHeight;
}
CSSDisplay? effectiveDisplay = renderStyle.effectiveDisplay;
bool isInlineBlock = effectiveDisplay == CSSDisplay.inlineBlock;
bool isNotInline = effectiveDisplay != CSSDisplay.inline;
double? width =
renderStyle.width.isAuto ? null : renderStyle.width.computedValue;
double? height =
renderStyle.height.isAuto ? null : renderStyle.height.computedValue;
double? minWidth =
renderStyle.minWidth.isAuto ? null : renderStyle.minWidth.computedValue;
double? maxWidth =
renderStyle.maxWidth.isNone ? null : renderStyle.maxWidth.computedValue;
double? minHeight = renderStyle.minHeight.isAuto
? null
: renderStyle.minHeight.computedValue;
double? maxHeight = renderStyle.maxHeight.isNone
? null
: renderStyle.maxHeight.computedValue;
// Constrain to min-width or max-width if width not exists.
if (isInlineBlock && maxWidth != null && width == null) {
double maxContentWidth = _getContentWidth(maxWidth);
finalContentWidth = finalContentWidth > maxContentWidth
? maxContentWidth
: finalContentWidth;
} else if (isInlineBlock && minWidth != null && width == null) {
double minContentWidth = _getContentWidth(minWidth);
finalContentWidth = finalContentWidth < minContentWidth
? minContentWidth
: finalContentWidth;
}
// Constrain to min-height or max-height if height not exists.
if (isNotInline && maxHeight != null && height == null) {
double maxContentHeight = _getContentHeight(maxHeight);
finalContentHeight = finalContentHeight > maxContentHeight
? maxContentHeight
: finalContentHeight;
} else if (isNotInline && minHeight != null && height == null) {
double minContentHeight = _getContentHeight(minHeight);
finalContentHeight = finalContentHeight < minContentHeight
? minContentHeight
: finalContentHeight;
}
Size finalContentSize = Size(finalContentWidth, finalContentHeight);
try {
// Keep for future diagnostic hooks (no-op by default).
final tag = renderStyle.target.tagName.toLowerCase();
final paddL = renderStyle.paddingLeft.computedValue;
final paddR = renderStyle.paddingRight.computedValue;
final bordL = renderStyle.effectiveBorderLeftWidth.computedValue;
final bordR = renderStyle.effectiveBorderRightWidth.computedValue;
final _ = '[BoxSize] <$tag> getContentSize out='
'${finalContentSize.width.toStringAsFixed(2)}×${finalContentSize.height.toStringAsFixed(2)} '
'padH=${(paddL + paddR).toStringAsFixed(2)} borderH=${(bordL + bordR).toStringAsFixed(2)}';
} catch (_) {}
return finalContentSize;
}