Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] Fix division by zero for transparent shadows #41391

Merged
merged 5 commits into from
Apr 21, 2023

Conversation

bdero
Copy link
Member

@bdero bdero commented Apr 21, 2023

A division by zero happens if the shadow color is fully transparent, and the NaNs are getting assigned to the RGB values of the paint color being handed to the rrect shadow draw. This doesn't cause a problem when wide gamut is off because NaN output ends up being interpreted as zero (thus making the shadow output fully transparent black, which happens to be the expected and correct result). However, when a wide gamut attachment is present, the NaN output ends up being interpreted as a negative value.

Reproduction app:

import 'package:flutter/material.dart';

void main() => runApp(const GeneralDialogApp());

class EvilPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final Rect rect = Offset.zero & size;
    canvas.drawPaint(Paint()..color = Colors.white);
    canvas.saveLayer(null, Paint()..blendMode = BlendMode.srcOver);
    canvas.drawShadow(Path()..addRect(Rect.fromLTRB(100, 100, 300, 300)),
        Colors.black54, 15, false);
    canvas.drawShadow(Path()..addRect(Rect.fromLTRB(100, 100, 300, 300)),
        Colors.black54, 15, false);
    canvas.drawShadow(Path()..addRect(Rect.fromLTRB(100, 100, 300, 300)),
        Colors.transparent, 15, false);
    canvas.restore();
  }

  @override
  bool shouldRepaint(EvilPainter oldDelegate) => false;
  @override
  bool shouldRebuildSemantics(EvilPainter oldDelegate) => false;
}

class GeneralDialogApp extends StatelessWidget {
  const GeneralDialogApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      restorationScopeId: 'app',
      home: CustomPaint(painter: EvilPainter()),
    );
  }
}

Before:
image

After:
image

@bdero bdero requested review from zanderso and jonahwilliams April 21, 2023 07:16
@bdero bdero self-assigned this Apr 21, 2023
@bdero bdero force-pushed the bdero/shadow-div-by-zero branch from 72538e9 to 6c51ed4 Compare April 21, 2023 07:19
@flutter-dashboard
Copy link

Golden file changes have been found for this pull request. Click here to view and triage (e.g. because this is an intentional change).

If you are still iterating on this change and are not ready to resolve the images on the Flutter Gold dashboard, consider marking this PR as a draft pull request above. You will still be able to view image results on the dashboard, commenting will be silenced, and the check will not try to resolve itself until marked ready for review.

Changes reported for pull request #41391 at sha 20c8453

Copy link
Member

@zanderso zanderso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find!

@zanderso
Copy link
Member

Skia gold seems confused. I'm going to go ahead and land this.

@zanderso zanderso merged commit dd67063 into flutter:main Apr 21, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Apr 21, 2023
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Apr 21, 2023
…125316)

flutter/engine@3f7e12b...dd67063

2023-04-21 bdero@google.com [Impeller] Fix division by zero for transparent shadows (flutter/engine#41391)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
gaaclarke pushed a commit to gaaclarke/engine that referenced this pull request May 15, 2023
A division by zero happens if the shadow color is fully transparent, and
the NaNs are getting assigned to the RGB values of the paint color being
handed to the rrect shadow draw. This doesn't cause a problem when wide
gamut is off because NaN output ends up being interpreted as zero (thus
making the shadow output fully transparent black, which happens to be
the expected and correct result). However, when a wide gamut attachment
is present, the NaN output ends up being interpreted as a negative
value.

Reproduction app:
```dart
import 'package:flutter/material.dart';

void main() => runApp(const GeneralDialogApp());

class EvilPainter extends CustomPainter {
  @OverRide
  void paint(Canvas canvas, Size size) {
    final Rect rect = Offset.zero & size;
    canvas.drawPaint(Paint()..color = Colors.white);
    canvas.saveLayer(null, Paint()..blendMode = BlendMode.srcOver);
    canvas.drawShadow(Path()..addRect(Rect.fromLTRB(100, 100, 300, 300)),
        Colors.black54, 15, false);
    canvas.drawShadow(Path()..addRect(Rect.fromLTRB(100, 100, 300, 300)),
        Colors.black54, 15, false);
    canvas.drawShadow(Path()..addRect(Rect.fromLTRB(100, 100, 300, 300)),
        Colors.transparent, 15, false);
    canvas.restore();
  }

  @OverRide
  bool shouldRepaint(EvilPainter oldDelegate) => false;
  @OverRide
  bool shouldRebuildSemantics(EvilPainter oldDelegate) => false;
}

class GeneralDialogApp extends StatelessWidget {
  const GeneralDialogApp({super.key});

  @OverRide
  Widget build(BuildContext context) {
    return MaterialApp(
      restorationScopeId: 'app',
      home: CustomPaint(painter: EvilPainter()),
    );
  }
}
```

Before:

![image](https://user-images.githubusercontent.com/919017/233558512-0bfdcdc0-017d-4df3-870f-bd8808ef73b7.png)

After:

![image](https://user-images.githubusercontent.com/919017/233558076-b56c7f43-c81e-4ca6-897d-246251dae930.png)
XilaiZhang pushed a commit that referenced this pull request May 15, 2023
)

cherry-pick of #41391

---------

Co-authored-by: Brandon DeRosier <bdero@google.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
No open projects
Archived in project
Development

Successfully merging this pull request may close these issues.

2 participants