performPaint method

  1. @override
void performPaint(
  1. PaintingContext context,
  2. Offset offset
)
override

RenderLayoutBox real paint things after basiclly paint box model. Override which to paint layout or intrinsic things. Used by RenderReplaced, RenderFlowLayout, RenderFlexLayout.

Implementation

@override
void performPaint(PaintingContext context, Offset offset) {
  // If using inline formatting context, delegate painting to it first.
  if (establishIFC && _inlineFormattingContext != null) {
    // Calculate content offset (adjust for padding and border)
    final contentOffset = Offset(
      offset.dx + renderStyle.paddingLeft.computedValue + renderStyle.effectiveBorderLeftWidth.computedValue,
      offset.dy + renderStyle.paddingTop.computedValue + renderStyle.effectiveBorderTopWidth.computedValue,
    );

    // Paint the inline formatting context content
    _inlineFormattingContext!.paint(context, contentOffset);

    // Paint outside list marker if needed after IFC content
    _paintListMarkerIfNeeded(context, offset, contentOffset);

    // Paint positioned direct children in proper stacking order.
    for (final RenderBox child in paintingOrder) {
      if (child is RenderBoxModel && child.renderStyle.isSelfPositioned()) {
        final RenderLayoutParentData pd = child.parentData as RenderLayoutParentData;
        if (child.hasSize) context.paintChild(child, pd.offset + offset);
      }
    }
    return;
  }

  // Regular flow layout painting: skip RenderTextBox unless it paints itself (non-IFC)
  Offset _accumulateOffsetFromDescendant(RenderObject descendant, RenderObject ancestor) {
    Offset sum = Offset.zero;
    RenderObject? cur = descendant;
    while (cur != null && cur != ancestor) {
      final Object? pd = (cur is RenderBox) ? (cur.parentData) : null;
      if (pd is ContainerBoxParentData) {
        sum += (pd as ContainerBoxParentData).offset;
      } else if (pd is RenderLayoutParentData) {
        sum += (pd as RenderLayoutParentData).offset;
      }
      cur = cur.parent as RenderObject?;
    }
    return sum;
  }

  for (int i = 0; i < paintingOrder.length; i++) {
    RenderBox child = paintingOrder[i];
    bool shouldPaint = !isPositionPlaceholder(child);

    // Skip text boxes that are handled by IFC, but paint text boxes that paint themselves
    if (child is RenderTextBox) {
      shouldPaint = shouldPaint && (child as RenderTextBox).paintsSelf;
    }

    if (!shouldPaint) continue;

    final RenderLayoutParentData childParentData = child.parentData as RenderLayoutParentData;
    if (!child.hasSize) continue;

    bool restoreFlag = false;
    bool previous = false;
    // Only suppress descendants' positive stacking when painting the document root
    // (where we promote descendant positives to this level).
    final bool promoteHere = (renderStyle as CSSRenderStyle).isDocumentRootBox();
    if (promoteHere && child is RenderBoxModel) {
      final CSSRenderStyle rs = child.renderStyle;
      final int? zi = rs.zIndex;
      final bool isPositive = zi != null && zi > 0;
      if (!isPositive) {
        previous = rs.suppressPositiveStackingFromDescendants;
        rs.suppressPositiveStackingFromDescendants = true;
        if (child is RenderLayoutBox) {
          child.markChildrenNeedsSort();
        } else if (child is RenderWidget) {
          child.markChildrenNeedsSort();
        }
        restoreFlag = true;
      }
    }

    final bool direct = identical(child.parent, this);
    final Offset localOffset = direct ? childParentData.offset : _accumulateOffsetFromDescendant(child, this);
    context.paintChild(child, localOffset + offset);

    if (restoreFlag && child is RenderBoxModel) {
      (child.renderStyle as CSSRenderStyle).suppressPositiveStackingFromDescendants = previous;
      if (child is RenderLayoutBox) {
        child.markChildrenNeedsSort();
      } else if (child is RenderWidget) {
        child.markChildrenNeedsSort();
      }
    }
  }

  // Non-IFC flow: still attempt to paint outside marker if applicable
  _paintListMarkerIfNeeded(context, offset, offset + Offset(
    renderStyle.paddingLeft.computedValue + renderStyle.effectiveBorderLeftWidth.computedValue,
    renderStyle.paddingTop.computedValue + renderStyle.effectiveBorderTopWidth.computedValue,
  ));
}