paint method
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();
}