Skip to content

CustomPainter: saveLayer with ImageFilter.blur gives unexpected offset from the edge #183884

Description

@antontishkov

Steps to reproduce

Please use the code sample.

Expected results

I'm trying to draw a blurred red rectangle that is partially outside the CustomPainter/Canvas edge. Like this:

Image

This is a very simple task with many possible implementations.

Actual results

I ran into a problem when I tried to implement this using negative scale (canvas.scale(-1, 1)) and saveLayer with ImageFilter.blur. Please see the code sample. Only 46 lines of code.

In DartPad, everything looks exactly as it should! The screenshot above is from DartPad. However, in the iOS simulator, the same code produces an unexpected offset from the edge of the canvas:

Image

I can't find an explanation for this behavior. Is it a bug?

Code sample

Code sample
import 'dart:ui';
import 'package:flutter/material.dart';

void main() {
  runApp(
    Container(
      alignment: Alignment.center,
      color: Colors.grey,
      child: Container(
        color: Colors.black,
        padding: EdgeInsetsGeometry.all(1),
        width: 352,
        height: 352,
        child: ClipRect(
          child: CustomPaint(size: Size(350, 350), painter: TestPainter()),
        ),
      ),
    ),
  );
}

class TestPainter extends CustomPainter {
  const TestPainter();

  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawRect(
      Rect.fromLTWH(0, 0, 350, 350),
      Paint()..color = Colors.white,
    );

    canvas.scale(-1, 1);
    canvas.saveLayer(
      Rect.fromLTWH(-150, 100, 300, 100),
      Paint()..imageFilter = ImageFilter.blur(sigmaX: 10, sigmaY: 10),
    );
    canvas.drawRect(
      Rect.fromLTWH(-150, 0, 300, 300),
      Paint()..color = Colors.red,
    );
    canvas.restore();
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

Screenshots or Video

Logs

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.41.5, on macOS 26.2 25C56 darwin-arm64, locale xx) [546ms]
    • Flutter version 3.41.5 on channel stable at /Users/xxxxx/Development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 2c9eb20739 (2 days ago), 2026-03-17 16:14:01 -0700
    • Engine revision 052f31d115
    • Dart version 3.11.3
    • DevTools version 2.54.2
    • Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations,
      enable-native-assets, omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration

[✓] Android toolchain - develop for Android devices (Android SDK version 36.1.0) [2,7s]
    • Android SDK at /Users/xxxxx/Library/Android/sdk
    • Emulator version 36.2.12.0 (build_id 14214601) (CL:N/A)
    • Platform android-36, build-tools 36.1.0
    • Java binary at: /Users/xxxxx/Library/Java/JavaVirtualMachines/corretto-22.0.2/Contents/Home/bin/java
      This JDK is specified in your Flutter configuration.
      To change the current JDK, run: `flutter config --jdk-dir="path/to/jdk"`.
    • Java version OpenJDK Runtime Environment Corretto-22.0.2.9.1 (build 22.0.2+9-FR)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 26.3) [1 109ms]
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 17C529
    • CocoaPods version 1.16.2

[✓] Chrome - develop for the web [5ms]
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Connected device (4 available) [10,8s]
    • iPhone 16e (mobile)              • F0F08FFB-1780-4D9E-9638-2DB271A7E24F • ios            • com.apple.CoreSimulator.SimRuntime.iOS-26-2
      (simulator)
    • macOS (desktop)                  • macos                                • darwin-arm64   • macOS 26.2 25C56 darwin-arm64
    • Chrome (web)                     • chrome                               • web-javascript • Google Chrome 146.0.7680.153

[✓] Network resources [677ms]
    • All expected network resources are available.

• No issues found!

Metadata

Metadata

Assignees

Labels

P1High-priority issues at the top of the work liste: impellerImpeller rendering backend issues and features requestsengineflutter/engine related. See also e: labels.platform-androidAndroid applications specificallyplatform-iosiOS applications specificallyteam-engineOwned by Engine teamtriaged-engineTriaged by Engine team

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions