markNeedsPaint method

void markNeedsPaint()

Mark this render object as having changed its visual appearance.

Rather than eagerly updating this render object's display list in response to writes, we instead mark the render object as needing to paint, which schedules a visual update. As part of the visual update, the rendering pipeline will give this render object an opportunity to update its display list.

This mechanism batches the painting work so that multiple sequential writes are coalesced, removing redundant computation.

Once markNeedsPaint has been called on a render object, debugNeedsPaint returns true for that render object until just after the pipeline owner has called paint on the render object.

See also:

  • RepaintBoundary, to scope a subtree of render objects to their own layer, thus limiting the number of nodes that markNeedsPaint must mark dirty.

Implementation

void markNeedsPaint() {
  assert(!_debugDisposed);
  assert(owner == null || !owner!.debugDoingPaint);
  if (_needsPaint) {
    return;
  }
  _needsPaint = true;
  // If this was not previously a repaint boundary it will not have
  // a layer we can paint from.
  if (isRepaintBoundary && _wasRepaintBoundary) {
    assert(() {
      if (debugPrintMarkNeedsPaintStacks) {
        debugPrintStack(label: 'markNeedsPaint() called for $this');
      }
      return true;
    }());
    // If we always have our own layer, then we can just repaint
    // ourselves without involving any other nodes.
    assert(_layerHandle.layer is OffsetLayer);
    if (owner != null) {
      owner!._nodesNeedingPaint.add(this);
      owner!.requestVisualUpdate();
    }
  } else if (parent is RenderObject) {
    parent!.markNeedsPaint();
  } else {
    assert(() {
      if (debugPrintMarkNeedsPaintStacks) {
        debugPrintStack(label: 'markNeedsPaint() called for $this (root of render tree)');
      }
      return true;
    }());
    // If we are the root of the render tree and not a repaint boundary
    // then we have to paint ourselves, since nobody else can paint us.
    // We don't add ourselves to _nodesNeedingPaint in this case,
    // because the root is always told to paint regardless.
    //
    // Trees rooted at a RenderView do not go through this
    // code path because RenderViews are repaint boundaries.
    if (owner != null) {
      owner!.requestVisualUpdate();
    }
  }
}