Skip to content

Legacy behavior of unordered rectangles is broken #140490

@flar

Description

@flar

Before the DisplayList and Impeller were added to Flutter, 3 methods would handle unordered rectangles as if they were sorted. An unordered rectangle is one with a negative width or height, or right < left or bottom < top. While those rectangles would be considered empty by their own isEmpty property, they would render as if they were re-ordered such that width and height were > 0 in drawRect, drawOval, and clipRect as seen in the test sample below.

The example renders 4 boxes:

  • 5 calls using an ordered rect in the upper left
  • 5 calls using a horizontally flipped rect in the upper right
  • 5 calls using a vertically flipped rect in the lower left
  • 5 calls using a completely flipped (both horizontally and vertically) rect in the lower right

Each box contains 5 rendering calls within it:

  • drawRect(filled) in the upper left
  • drawOval(filled) in the upper right
  • clipRect in the center
  • drawRect(stroked) in the lower left
  • drawOval(stroked) in the lower right
Unordered rect example code
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: CustomPaint(
          foregroundPainter: _MyPainter(),
          size: const Size(450, 450),
        ),
        ),
      );
  }
}

class _MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawRect(
      Rect.fromLTWH(0, 0, size.width, size.height),
      Paint()..color = Colors.grey.shade300,
    );

    void draw(Rect rect, double x, double y, Color color) {
      Paint paint = Paint()
        ..color = color
        ..strokeWidth = 5.0;

      canvas.save();
      canvas.translate(x, y);

      paint.style = PaintingStyle.fill;
      canvas.drawRect(rect, paint);

      canvas.save();
      canvas.translate(0, 100);
      paint.style = PaintingStyle.stroke;
      canvas.drawRect(rect, paint);
      canvas.restore();

      canvas.save();
      canvas.translate(100, 0);
      paint.style = PaintingStyle.fill;
      canvas.drawOval(rect, paint);
      canvas.restore();

      canvas.save();
      canvas.translate(100, 100);
      paint.style = PaintingStyle.stroke;
      canvas.drawOval(rect, paint);
      canvas.restore();

      canvas.save();
      canvas.translate(50, 50);
      canvas.clipRect(rect);
      canvas.drawPaint(paint);
      canvas.restore();

      canvas.restore();
    }

    draw(const Rect.fromLTRB(10, 10, 40, 40), 50, 50, Colors.blue);
    draw(const Rect.fromLTRB(40, 10, 10, 40), 250, 50, Colors.green);
    draw(const Rect.fromLTRB(10, 40, 40, 10), 50, 250, Colors.purple);
    draw(const Rect.fromLTRB(40, 40, 10, 10), 250, 250, Colors.orange);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
Output on Flutter commit a7d2de2 (just before adding DisplayList) (all primitives render) Screenshot 2023-12-20 at 3 55 30 PM
Output on the current Flutter ToT (notice missing clipRect output in the center of the unsorted test areas) Screenshot 2023-12-20 at 4 01 01 PM

Metadata

Metadata

Assignees

Labels

engineflutter/engine related. See also e: labels.

Type

No type

Projects

Status

✅ Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions