computedValue property
double
get
computedValue
Implementation
double get computedValue {
switch (type) {
case CSSLengthType.PX:
_computedValue = value;
break;
case CSSLengthType.EM:
// Font size of the parent, in the case of typographical properties like font-size,
// and font size of the element itself, in the case of other properties like width.
if (propertyName == FONT_SIZE) {
// If root element set fontSize as em unit.
if (renderStyle!.parent == null) {
_computedValue = value! * 16;
} else {
_computedValue = value! * renderStyle!.parent!.fontSize.computedValue;
}
} else {
_computedValue = value! * renderStyle!.fontSize.computedValue;
}
break;
case CSSLengthType.REM:
// If root element set fontSize as rem unit.
if (renderStyle!.parent == null) {
_computedValue = value! * 16;
} else {
// Font rem is calculated against the root element's font size.
_computedValue = value! * renderStyle!.rootFontSize;
}
break;
case CSSLengthType.VH:
_computedValue = value! * renderStyle!.viewportSize.height;
break;
case CSSLengthType.VW:
_computedValue = value! * renderStyle!.viewportSize.width;
break;
// 1% of viewport's smaller (vw or vh) dimension.
// If the height of the viewport is less than its width, 1vmin will be equivalent to 1vh.
// If the width of the viewport is less than it’s height, 1vmin is equvialent to 1vw.
case CSSLengthType.VMIN:
_computedValue = value! * renderStyle!.viewportSize.shortestSide;
break;
case CSSLengthType.VMAX:
_computedValue = value! * renderStyle!.viewportSize.longestSide;
break;
case CSSLengthType.PERCENTAGE:
CSSPositionType positionType = renderStyle!.position;
bool isPositioned = positionType == CSSPositionType.absolute ||
positionType == CSSPositionType.fixed;
RenderBoxModel? renderBoxModel = renderStyle!.renderBoxModel;
// Should access the renderStyle of renderBoxModel parent but not renderStyle parent
// cause the element of renderStyle parent may not equal to containing block.
RenderStyle? parentRenderStyle;
if (renderBoxModel?.parent is RenderBoxModel) {
RenderBoxModel parentRenderBoxModel = renderBoxModel?.parent as RenderBoxModel;
// Get the renderStyle of outer scrolling box cause the renderStyle of scrolling
// content box is only a fraction of the complete renderStyle.
parentRenderStyle = parentRenderBoxModel.isScrollingContentBox
? (parentRenderBoxModel.parent as RenderBoxModel).renderStyle
: parentRenderBoxModel.renderStyle;
}
// Percentage relative width priority: logical width > renderer width
double? parentPaddingBoxWidth =
parentRenderStyle?.paddingBoxLogicalWidth
?? parentRenderStyle?.paddingBoxWidth;
double? parentContentBoxWidth =
parentRenderStyle?.contentBoxLogicalWidth
?? parentRenderStyle?.contentBoxWidth;
// Percentage relative height priority: logical height > renderer height
double? parentPaddingBoxHeight =
parentRenderStyle?.paddingBoxLogicalHeight
?? parentRenderStyle?.paddingBoxHeight;
double? parentContentBoxHeight =
parentRenderStyle?.contentBoxLogicalHeight
?? parentRenderStyle?.contentBoxHeight;
// Positioned element is positioned relative to the padding box of its containing block
// while the others relative to the content box.
double? relativeParentWidth = isPositioned
? parentPaddingBoxWidth
: parentContentBoxWidth;
double? relativeParentHeight = isPositioned
? parentPaddingBoxHeight
: parentContentBoxHeight;
switch (propertyName) {
case FONT_SIZE:
// Relative to the parent font size.
if (renderStyle!.parent == null) {
_computedValue = value! * 16;
} else {
_computedValue = value! * renderStyle!.parent!.fontSize.computedValue;
}
break;
case LINE_HEIGHT:
// Relative to the font size of the element itself.
_computedValue = value! * renderStyle!.fontSize.computedValue;
break;
case WIDTH:
case MIN_WIDTH:
case MAX_WIDTH:
if (relativeParentWidth != null) {
_computedValue = value! * relativeParentWidth;
} else {
// Mark parent to relayout to get renderer width of parent.
if (renderBoxModel != null) {
renderBoxModel.markParentNeedsRelayout();
}
_computedValue = double.infinity;
}
break;
case HEIGHT:
case MIN_HEIGHT:
case MAX_HEIGHT:
// The percentage of height is calculated with respect to the height of the generated box's containing block.
// If the height of the containing block is not specified explicitly (i.e., it depends on content height),
// and this element is not absolutely positioned, the value computes to 'auto'.
// https://www.w3.org/TR/CSS2/visudet.html#propdef-height
// There are two exceptions when percentage height is resolved against actual render height of parent:
// 1. positioned element
// 2. parent is flex item
RenderStyle? grandParentRenderStyle = parentRenderStyle?.parent;
bool isGrandParentFlexLayout = grandParentRenderStyle?.display == CSSDisplay.flex ||
grandParentRenderStyle?.display == CSSDisplay.inlineFlex;
// The percentage height of positioned element and flex item resolves against the rendered height
// of parent, mark parent as needs relayout if rendered height is not ready yet.
if (isPositioned || isGrandParentFlexLayout) {
if (relativeParentHeight != null) {
_computedValue = value! * relativeParentHeight;
} else {
// Mark parent to relayout to get renderer height of parent.
if (renderBoxModel != null) {
renderBoxModel.markParentNeedsRelayout();
}
_computedValue = double.infinity;
}
} else {
double? relativeParentHeight = parentRenderStyle?.contentBoxLogicalHeight;
if (relativeParentHeight != null) {
_computedValue = value! * relativeParentHeight;
} else {
// Resolves height as auto if parent has no height specified.
_computedValue = double.infinity;
}
}
break;
case PADDING_TOP:
case PADDING_RIGHT:
case PADDING_BOTTOM:
case PADDING_LEFT:
case MARGIN_LEFT:
case MARGIN_RIGHT:
case MARGIN_TOP:
case MARGIN_BOTTOM:
// https://www.w3.org/TR/css-box-3/#padding-physical
// Percentage refer to logical width of containing block
if (relativeParentWidth != null) {
_computedValue = value! * relativeParentWidth;
} else {
// Mark parent to relayout to get renderer height of parent.
if (renderBoxModel != null) {
renderBoxModel.markParentNeedsRelayout();
}
_computedValue = 0;
}
break;
case FLEX_BASIS:
// Flex-basis computation is called in RenderFlexLayout which
// will ensure parent exists.
RenderStyle parentRenderStyle = renderStyle!.parent!;
double? mainContentSize = parentRenderStyle.flexDirection == FlexDirection.row ?
parentRenderStyle.contentBoxLogicalWidth :
parentRenderStyle.contentBoxLogicalHeight;
if (mainContentSize != null) {
_computedValue = mainContentSize * value!;
} else {
// @TODO: Not supported when parent has no logical main size.
_computedValue = 0;
}
// Refer to the flex container's inner main size.
break;
// https://www.w3.org/TR/css-position-3/#valdef-top-percentage
// The inset is a percentage relative to the containing block’s size in the corresponding
// axis (e.g. width for left or right, height for top and bottom). For sticky positioned boxes,
// the inset is instead relative to the relevant scrollport’s size. Negative values are allowed.
case TOP:
case BOTTOM:
// Offset of positioned element starts from the edge of padding box of containing block.
if (parentPaddingBoxHeight != null) {
_computedValue = value! * parentPaddingBoxHeight;
} else {
// Mark parent to relayout to get renderer height of parent.
if (renderBoxModel != null) {
renderBoxModel.markParentNeedsRelayout();
}
// Set as initial value, use infinity as auto value.
_computedValue = double.infinity;
}
break;
case LEFT:
case RIGHT:
// Offset of positioned element starts from the edge of padding box of containing block.
if (parentPaddingBoxWidth != null) {
_computedValue = value! * parentPaddingBoxWidth;
} else {
// Mark parent to relayout to get renderer height of parent.
if (renderBoxModel != null) {
renderBoxModel.markParentNeedsRelayout();
}
_computedValue = double.infinity;
}
break;
case TRANSLATE:
case BACKGROUND_SIZE:
case BORDER_TOP_LEFT_RADIUS:
case BORDER_TOP_RIGHT_RADIUS:
case BORDER_BOTTOM_LEFT_RADIUS:
case BORDER_BOTTOM_RIGHT_RADIUS:
// Percentages for the horizontal axis refer to the width of the box.
// Percentages for the vertical axis refer to the height of the box.
double? borderBoxWidth = renderStyle!.borderBoxWidth ?? renderStyle!.borderBoxLogicalWidth;
double? borderBoxHeight = renderStyle!.borderBoxHeight ?? renderStyle!.borderBoxLogicalHeight;
double? borderBoxDimension = axisType == Axis.horizontal ? borderBoxWidth : borderBoxHeight;
if (borderBoxDimension != null) {
_computedValue = value! * borderBoxDimension;
} else {
_computedValue = propertyName == TRANSLATE
// Transform will be cached once resolved, so avoid resolve if width not defined.
// Use double.infinity to indicate percentage not resolved.
? double.infinity
: 0;
}
break;
}
break;
default:
// @FIXME: Type AUTO not always resolves to 0, in cases such as `margin: auto`, `width: auto`.
return 0;
}
return _computedValue!;
}