Skip to content

Shadows depend on internal canvas state #51237

@yjbanov

Description

@yjbanov

Steps to Reproduce

flutter run the following Flutter app:

Sample app
import 'dart:ui';
import 'package:vector_math/vector_math_64.dart';

const Color _kShadowColor = Color.fromARGB(255, 255, 0, 0);
final Path shadowPath = Path()..addRect(const Rect.fromLTRB(0, 0, 20, 20));

Future<void> main() async {
  window.onDrawFrame = () {
    final SceneBuilder builder = SceneBuilder();

    void _paintPicture(Rect bounds, void Function(Canvas) painter) {
      final PictureRecorder recorder = PictureRecorder();
      painter(Canvas(recorder, bounds));
      builder.addPicture(Offset.zero, recorder.endRecording());
    }

    void _paintOutline() {
      _paintPicture(Rect.largest, (Canvas canvas) {
        canvas.drawRect(
          const Rect.fromLTRB(0.0, 0.0, 20.0, 20.0),
          Paint()
            ..color = const Color.fromARGB(255, 0, 0, 255)
            ..style = PaintingStyle.stroke
            ..strokeWidth = 1.0,
        );
      });
    }

    void _paintPhysicalShapeShadow(double elevation, Offset offset) {
      builder.pushOffset(offset.dx, offset.dy);
      builder.pushPhysicalShape(
        path: shadowPath,
        elevation: elevation,
        shadowColor: _kShadowColor,
        color: const Color.fromARGB(0, 0, 0, 0),
      );
      _paintOutline();
      builder.pop(); // physical shape
      builder.pop(); // offset
    }

    void _paintBitmapCanvasShadow(double elevation, Offset offset) {
      builder.pushOffset(offset.dx, offset.dy);
      _paintPicture(Rect.largest, (Canvas canvas) {
        canvas.drawShadow(
          shadowPath,
          _kShadowColor,
          elevation,
          true,
        );
      });
      _paintOutline();
      builder.pop(); // offset
    }

    _paintPicture(Rect.largest, (Canvas canvas) {
      canvas.drawColor(const Color.fromARGB(255, 255, 255, 255), BlendMode.color);
    });

    builder.pushTransform(Matrix4.diagonal3Values(5, 5, 1).storage);
    builder.pushOffset(10, 40);

    for (int i = 0; i < 7; i++) {
      _paintPhysicalShapeShadow(i.toDouble(), Offset(40.0 * i, 0));
    }

    for (int i = 0; i < 7; i++) {
      _paintBitmapCanvasShadow(i.toDouble(), Offset(40.0 * i, 80));
    }

    for (int i = 0; i < 7; i++) {
      _paintPhysicalShapeShadow(i.toDouble(), Offset(40.0 * i, 160));
    }

    builder.pushOffset(0.0, 240.0);
    _paintPicture(Rect.largest, (Canvas canvas) {
      for (int i = 0; i < 7; i++) {
        canvas.drawShadow(
          shadowPath,
          _kShadowColor,
          i.toDouble(),
          true,
        );
        canvas.drawRect(
          const Rect.fromLTRB(0.0, 0.0, 20.0, 20.0),
          Paint()
            ..color = const Color.fromARGB(255, 0, 0, 255)
            ..style = PaintingStyle.stroke
            ..strokeWidth = 1.0,
        );
        canvas.translate(40.0, 0);
      }
    });
    builder.pop(); // offset

    builder.pop();
    builder.pop();
    window.render(builder.build());
  };
  window.scheduleFrame();
}

Expected results:

The shadows in each column should be identical.

Actual results:

The shadows are different.

shadows

This is observable as of 3cee8e0

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority issues at the top of the work lista: desktopRunning on desktopa: tabletTablets and landscape phonesc: renderingUI glitches reported at the engine/skia or impeller rendering levelcustomer: housedependency: skiaSkia team may need to help usengineflutter/engine related. See also e: labels.found in release: 1.24Found to occur in 1.24has reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-androidAndroid applications specificallyplatform-iosiOS applications specificallyplatform-linuxBuilding on or for Linux specificallyplatform-macBuilding on or for macOS specificallyplatform-windowsBuilding on or for Windows specificallyr: fixedIssue is closed as already fixed in a newer version

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions