getContentSize method
Common layout content size (including flow and flexbox layout) calculation logic
Implementation
Size getContentSize({
required double contentWidth,
required double contentHeight,
}) {
try {
// Keep for future diagnostic hooks (no-op by default).
final tag = renderStyle.target.tagName.toLowerCase();
final disp = renderStyle.effectiveDisplay;
final pType = parent?.runtimeType.toString() ?? 'null';
final _ = '[BoxSize] <$tag> getContentSize in='
'${contentWidth.toStringAsFixed(2)}×${contentHeight.toStringAsFixed(2)} '
'display=$disp parent=$pType';
} catch (_) {}
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.getParentRenderStyle();
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 is CSSRenderStyle)
? parentRenderStyle.writingMode
: CSSWritingMode.horizontalTb;
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;
}