@@ -557,6 +557,61 @@ void main() async {
557
557
expect (tabToTofuComparison, isFalse);
558
558
});
559
559
560
+ test ('drawRect, drawOval, and clipRect render with unsorted rectangles' , () async {
561
+ final PictureRecorder recorder = PictureRecorder ();
562
+ final Canvas canvas = Canvas (recorder);
563
+
564
+ canvas.drawColor (const Color (0xFFE0E0E0 ), BlendMode .src);
565
+
566
+ void draw (Rect rect, double x, double y, Color color) {
567
+ final Paint paint = Paint ()
568
+ ..color = color
569
+ ..strokeWidth = 5.0 ;
570
+
571
+ canvas.save ();
572
+ canvas.translate (x, y);
573
+
574
+ paint.style = PaintingStyle .fill;
575
+ canvas.drawRect (rect, paint);
576
+
577
+ canvas.save ();
578
+ canvas.translate (0 , 100 );
579
+ paint.style = PaintingStyle .stroke;
580
+ canvas.drawRect (rect, paint);
581
+ canvas.restore ();
582
+
583
+
584
+ canvas.save ();
585
+ canvas.translate (100 , 0 );
586
+ paint.style = PaintingStyle .fill;
587
+ canvas.drawOval (rect, paint);
588
+ canvas.restore ();
589
+
590
+ canvas.save ();
591
+ canvas.translate (100 , 100 );
592
+ paint.style = PaintingStyle .stroke;
593
+ canvas.drawOval (rect, paint);
594
+ canvas.restore ();
595
+
596
+ canvas.save ();
597
+ canvas.translate (50 , 50 );
598
+ canvas.clipRect (rect);
599
+ canvas.drawPaint (paint);
600
+ canvas.restore ();
601
+
602
+ canvas.restore ();
603
+ }
604
+
605
+ draw (const Rect .fromLTRB (10 , 10 , 40 , 40 ), 50 , 50 , const Color (0xFF2196F3 ));
606
+ draw (const Rect .fromLTRB (40 , 10 , 10 , 40 ), 250 , 50 , const Color (0xFF4CAF50 ));
607
+ draw (const Rect .fromLTRB (10 , 40 , 40 , 10 ), 50 , 250 , const Color (0xFF9C27B0 ));
608
+ draw (const Rect .fromLTRB (40 , 40 , 10 , 10 ), 250 , 250 , const Color (0xFFFF9800 ));
609
+
610
+ final Picture picture = recorder.endRecording ();
611
+ final Image image = await picture.toImage (450 , 450 );
612
+ await comparer.addGoldenImage (image, 'render_unordered_rects.png' );
613
+ });
614
+
560
615
Matcher closeToTransform (Float64List expected) => (dynamic v) {
561
616
Expect .type <Float64List >(v);
562
617
final Float64List value = v as Float64List ;
@@ -676,83 +731,82 @@ void main() async {
676
731
Expect .fail ('$value is too close to $expected ' );
677
732
};
678
733
679
- test ('Canvas.clipRect(doAA=true) affects canvas.getClipBounds' , () async {
680
- final PictureRecorder recorder = PictureRecorder ();
681
- final Canvas canvas = Canvas (recorder);
682
- const Rect clipBounds = Rect .fromLTRB (10.2 , 11.3 , 20.4 , 25.7 );
683
- const Rect clipExpandedBounds = Rect .fromLTRB (10 , 11 , 21 , 26 );
684
- canvas.clipRect (clipBounds);
685
-
686
- // Save initial return values for testing restored values
687
- final Rect initialLocalBounds = canvas.getLocalClipBounds ();
688
- final Rect initialDestinationBounds = canvas.getDestinationClipBounds ();
689
- expect (initialLocalBounds, closeToRect (clipExpandedBounds));
690
- expect (initialDestinationBounds, closeToRect (clipExpandedBounds));
691
-
692
- canvas.save ();
693
- canvas.clipRect (const Rect .fromLTRB (0 , 0 , 15 , 15 ));
694
- // Both clip bounds have changed
695
- expect (canvas.getLocalClipBounds (), notCloseToRect (clipExpandedBounds));
696
- expect (canvas.getDestinationClipBounds (), notCloseToRect (clipExpandedBounds));
697
- // Previous return values have not changed
698
- expect (initialLocalBounds, closeToRect (clipExpandedBounds));
699
- expect (initialDestinationBounds, closeToRect (clipExpandedBounds));
700
- canvas.restore ();
701
-
702
- // save/restore returned the values to their original values
703
- expect (canvas.getLocalClipBounds (), initialLocalBounds);
704
- expect (canvas.getDestinationClipBounds (), initialDestinationBounds);
705
-
706
- canvas.save ();
707
- canvas.scale (2 , 2 );
708
- const Rect scaledExpandedBounds = Rect .fromLTRB (5 , 5.5 , 10.5 , 13 );
709
- expect (canvas.getLocalClipBounds (), closeToRect (scaledExpandedBounds));
710
- // Destination bounds are unaffected by transform
711
- expect (canvas.getDestinationClipBounds (), closeToRect (clipExpandedBounds));
712
- canvas.restore ();
713
-
714
- // save/restore returned the values to their original values
715
- expect (canvas.getLocalClipBounds (), initialLocalBounds);
716
- expect (canvas.getDestinationClipBounds (), initialDestinationBounds);
717
- });
718
-
719
- test ('Canvas.clipRect(doAA=false) affects canvas.getClipBounds' , () async {
720
- final PictureRecorder recorder = PictureRecorder ();
721
- final Canvas canvas = Canvas (recorder);
722
- const Rect clipBounds = Rect .fromLTRB (10.2 , 11.3 , 20.4 , 25.7 );
723
- canvas.clipRect (clipBounds, doAntiAlias: false );
734
+ test ('Canvas.clipRect affects canvas.getClipBounds' , () async {
735
+ void testRect (Rect clipRect, bool doAA) {
736
+ final PictureRecorder recorder = PictureRecorder ();
737
+ final Canvas canvas = Canvas (recorder);
738
+ canvas.clipRect (clipRect, doAntiAlias: doAA);
739
+
740
+ final Rect clipSortedBounds = Rect .fromLTRB (
741
+ min (clipRect.left, clipRect.right),
742
+ min (clipRect.top, clipRect.bottom),
743
+ max (clipRect.left, clipRect.right),
744
+ max (clipRect.top, clipRect.bottom),
745
+ );
746
+ Rect clipExpandedBounds;
747
+ if (doAA) {
748
+ clipExpandedBounds = Rect .fromLTRB (
749
+ clipSortedBounds.left.floorToDouble (),
750
+ clipSortedBounds.top.floorToDouble (),
751
+ clipSortedBounds.right.ceilToDouble (),
752
+ clipSortedBounds.bottom.ceilToDouble (),
753
+ );
754
+ } else {
755
+ clipExpandedBounds = clipSortedBounds;
756
+ }
724
757
725
- // Save initial return values for testing restored values
726
- final Rect initialLocalBounds = canvas.getLocalClipBounds ();
727
- final Rect initialDestinationBounds = canvas.getDestinationClipBounds ();
728
- expect (initialLocalBounds, closeToRect (clipBounds));
729
- expect (initialDestinationBounds, closeToRect (clipBounds));
758
+ // Save initial return values for testing restored values
759
+ final Rect initialLocalBounds = canvas.getLocalClipBounds ();
760
+ final Rect initialDestinationBounds = canvas.getDestinationClipBounds ();
761
+ expect (initialLocalBounds, closeToRect (clipExpandedBounds));
762
+ expect (initialDestinationBounds, closeToRect (clipExpandedBounds));
763
+
764
+ canvas.save ();
765
+ canvas.clipRect (const Rect .fromLTRB (0 , 0 , 15 , 15 ));
766
+ // Both clip bounds have changed
767
+ expect (canvas.getLocalClipBounds (), notCloseToRect (clipExpandedBounds));
768
+ expect (canvas.getDestinationClipBounds (), notCloseToRect (clipExpandedBounds));
769
+ // Previous return values have not changed
770
+ expect (initialLocalBounds, closeToRect (clipExpandedBounds));
771
+ expect (initialDestinationBounds, closeToRect (clipExpandedBounds));
772
+ canvas.restore ();
773
+
774
+ // save/restore returned the values to their original values
775
+ expect (canvas.getLocalClipBounds (), initialLocalBounds);
776
+ expect (canvas.getDestinationClipBounds (), initialDestinationBounds);
777
+
778
+ canvas.save ();
779
+ canvas.scale (2 , 2 );
780
+ final Rect scaledExpandedBounds = Rect .fromLTRB (
781
+ clipExpandedBounds.left / 2.0 ,
782
+ clipExpandedBounds.top / 2.0 ,
783
+ clipExpandedBounds.right / 2.0 ,
784
+ clipExpandedBounds.bottom / 2.0 ,
785
+ );
786
+ expect (canvas.getLocalClipBounds (), closeToRect (scaledExpandedBounds));
787
+ // Destination bounds are unaffected by transform
788
+ expect (canvas.getDestinationClipBounds (), closeToRect (clipExpandedBounds));
789
+ canvas.restore ();
790
+
791
+ // save/restore returned the values to their original values
792
+ expect (canvas.getLocalClipBounds (), initialLocalBounds);
793
+ expect (canvas.getDestinationClipBounds (), initialDestinationBounds);
794
+ }
730
795
731
- canvas.save ();
732
- canvas.clipRect (const Rect .fromLTRB (0 , 0 , 15 , 15 ));
733
- // Both clip bounds have changed
734
- expect (canvas.getLocalClipBounds (), notCloseToRect (clipBounds));
735
- expect (canvas.getDestinationClipBounds (), notCloseToRect (clipBounds));
736
- // Previous return values have not changed
737
- expect (initialLocalBounds, closeToRect (clipBounds));
738
- expect (initialDestinationBounds, closeToRect (clipBounds));
739
- canvas.restore ();
796
+ testRect (const Rect .fromLTRB (10.2 , 11.3 , 20.4 , 25.7 ), false );
797
+ testRect (const Rect .fromLTRB (10.2 , 11.3 , 20.4 , 25.7 ), true );
740
798
741
- // save/restore returned the values to their original values
742
- expect (canvas. getLocalClipBounds ( ), initialLocalBounds );
743
- expect (canvas. getDestinationClipBounds ( ), initialDestinationBounds );
799
+ // LR swapped
800
+ testRect ( const Rect . fromLTRB ( 20.4 , 11.3 , 10.2 , 25.7 ), false );
801
+ testRect ( const Rect . fromLTRB ( 20.4 , 11.3 , 10.2 , 25.7 ), true );
744
802
745
- canvas.save ();
746
- canvas.scale (2 , 2 );
747
- const Rect scaledClipBounds = Rect .fromLTRB (5.1 , 5.65 , 10.2 , 12.85 );
748
- expect (canvas.getLocalClipBounds (), closeToRect (scaledClipBounds));
749
- // Destination bounds are unaffected by transform
750
- expect (canvas.getDestinationClipBounds (), closeToRect (clipBounds));
751
- canvas.restore ();
803
+ // TB swapped
804
+ testRect (const Rect .fromLTRB (10.2 , 25.7 , 20.4 , 11.3 ), false );
805
+ testRect (const Rect .fromLTRB (10.2 , 25.7 , 20.4 , 11.3 ), true );
752
806
753
- // save/restore returned the values to their original values
754
- expect (canvas. getLocalClipBounds ( ), initialLocalBounds );
755
- expect (canvas. getDestinationClipBounds ( ), initialDestinationBounds );
807
+ // LR and TB swapped
808
+ testRect ( const Rect . fromLTRB ( 20.4 , 25.7 , 10.2 , 11.3 ), false );
809
+ testRect ( const Rect . fromLTRB ( 20.4 , 25.7 , 10.2 , 11.3 ), true );
756
810
});
757
811
758
812
test ('Canvas.clipRect with matrix affects canvas.getClipBounds' , () async {
0 commit comments