paint method

void paint(
  1. Canvas canvas,
  2. Rect rect,
  3. Path? clipPath,
  4. ImageConfiguration configuration,
)

Forked from flutter with parameter customization of _paintImage method: https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/painting/decoration_image.dart#L231

Implementation

void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration) {
  bool flipHorizontally = false;
  if (_details.matchTextDirection) {
    assert(() {
      // We check this first so that the assert will fire immediately, not just
      // when the image is ready.
      if (configuration.textDirection == null) {
        throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('DecorationImage.matchTextDirection can only be used when a TextDirection is available.'),
          ErrorDescription(
            'When BoxDecorationImagePainter.paint() was called, there was no text direction provided '
            'in the ImageConfiguration object to match.',
          ),
          DiagnosticsProperty<DecorationImage>('The DecorationImage was', _details,
              style: DiagnosticsTreeStyle.errorProperty),
          DiagnosticsProperty<ImageConfiguration>('The ImageConfiguration was', configuration,
              style: DiagnosticsTreeStyle.errorProperty),
        ]);
      }
      return true;
    }());
    if (configuration.textDirection == TextDirection.rtl) flipHorizontally = true;
  }

  final ImageStream newImageStream = _details.image.resolve(configuration);
  if (newImageStream.key != _imageStream?.key) {
    final ImageStreamListener listener = ImageStreamListener(
      _handleImage,
      onError: _details.onError,
    );
    _imageStream?.removeListener(listener);
    _imageStream = newImageStream;
    _imageStream!.addListener(listener);
  }
  if (_image == null) {
    if (DebugFlags.enableBackgroundLogs) {
      renderingLogger.finer('[Background] awaiting image load stream=${newImageStream.key} rect=$rect');
    }
    return;
  }

  if (clipPath != null) {
    canvas.save();
    canvas.clipPath(clipPath);
  }
  // Prefer computed longhands. If they appear to be default (e.g., 0%/left)
  // but the author-specified shorthand exists, resolve from the raw shorthand
  // as a defensive fallback to avoid stale/default axes.
  CSSBackgroundPosition px = _backgroundPositionX;
  CSSBackgroundPosition py = _backgroundPositionY;
  bool isDefault(CSSBackgroundPosition p) =>
      p.length == null && p.calcValue == null && (p.percentage ?? -1) == -1;
  final String rawPos = _renderStyle.target.style.getPropertyValue(BACKGROUND_POSITION);
  if (rawPos.isNotEmpty && (isDefault(px) || isDefault(py))) {
    try {
      final List<String> pair = CSSPosition.parsePositionShorthand(rawPos);
      final CSSBackgroundPosition ax = CSSPosition.resolveBackgroundPosition(
          pair[0], _renderStyle, BACKGROUND_POSITION_X, true);
      final CSSBackgroundPosition ay = CSSPosition.resolveBackgroundPosition(
          pair[1], _renderStyle, BACKGROUND_POSITION_Y, false);
      if (isDefault(px)) px = ax;
      if (isDefault(py)) py = ay;
      if (DebugFlags.enableBackgroundLogs) {
        renderingLogger.finer('[Background] fallback axes from shorthand: raw="$rawPos" -> '
            'x=${ax.cssText()} y=${ay.cssText()}');
      }
    } catch (_) {}
  }

  _paintImage(
    painterRef: null,
    canvas: canvas,
    rect: rect,
    image: _image!.image,
    debugImageLabel: _image!.debugLabel,
    scale: _details.scale * _image!.scale,
    colorFilter: _details.colorFilter,
    positionX: px,
    positionY: py,
    backgroundSize: _backgroundSize,
    centerSlice: _details.centerSlice,
    repeat: _details.repeat,
    flipHorizontally: flipHorizontally,
    filterQuality: FilterQuality.low,
  );

  if (clipPath != null) canvas.restore();
}