computeContentBoxLogicalWidth method

void computeContentBoxLogicalWidth()

Implementation

void computeContentBoxLogicalWidth() {
  RenderBoxModel current = renderBoxModel!;
  RenderStyle renderStyle = this;
  double? logicalWidth;

  CSSDisplay? effectiveDisplay = renderStyle.effectiveDisplay;

  // Width applies to all elements except non-replaced inline elements.
  // https://drafts.csswg.org/css-sizing-3/#propdef-width
  if (effectiveDisplay == CSSDisplay.inline && current is! RenderReplaced) {
    _contentBoxLogicalWidth = null;
    return;
  } else if (effectiveDisplay == CSSDisplay.block ||
      effectiveDisplay == CSSDisplay.flex ||
      effectiveDisplay == CSSDisplay.sliver) {
    // Use width directly if defined.
    if (renderStyle.width.isNotAuto) {
      logicalWidth = renderStyle.width.computedValue;
    } else if (renderStyle.parent != null) {
      RenderStyle parentRenderStyle = renderStyle.parent!;
      RenderBoxModel parent = parentRenderStyle.renderBoxModel!;
      // Block element (except replaced element) will stretch to the content width of its parent in flow layout.
      // Replaced element also stretch in flex layout if align-items is stretch.
      if (current is! RenderReplaced || parent is RenderFlexLayout) {
        RenderStyle? ancestorRenderStyle = _findAncestorWithNoDisplayInline();
        // Should ignore renderStyle of display inline when searching for ancestors to stretch width.
        if (ancestorRenderStyle != null) {
          logicalWidth = ancestorRenderStyle.contentBoxLogicalWidth;
          // 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.inline) {
    if (renderStyle.width.isNotAuto) {
      logicalWidth = renderStyle.width.computedValue;
    } else if ((renderStyle.position == CSSPositionType.absolute || renderStyle.position == CSSPositionType.fixed) &&
        current is! RenderReplaced &&
        renderStyle.width.isAuto &&
        renderStyle.left.isNotAuto &&
        renderStyle.right.isNotAuto) {
      // The width of positioned, non-replaced element is determined as following algorithm.
      // https://www.w3.org/TR/css-position-3/#abs-non-replaced-width
      if (current.parent is! RenderBoxModel) {
        logicalWidth = null;
      }
      // Should access the renderStyle of renderBoxModel parent but not renderStyle parent
      // cause the element of renderStyle parent may not equal to containing block.
      RenderBoxModel parent = current.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.
      RenderStyle parentRenderStyle =
          parent.isScrollingContentBox ? (parent.parent as RenderBoxModel).renderStyle : parent.renderStyle;
      // Width of positioned element should subtract its horizontal margin.
      logicalWidth = (parentRenderStyle.paddingBoxLogicalWidth ?? 0) -
          renderStyle.left.computedValue -
          renderStyle.right.computedValue -
          renderStyle.marginLeft.computedValue -
          renderStyle.marginRight.computedValue;
    } else if (current.hasSize && current.constraints.hasTightWidth) {
      logicalWidth = current.constraints.maxWidth;
    }
  }

  // Get width by aspect ratio for replaced element if width is auto.
  if (logicalWidth == null && aspectRatio != null) {
    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;
}