Skip to content

Commit 13f106b

Browse files
authored
Allow Clip.none as a valid clipBehavior (#95593)
1 parent f82c020 commit 13f106b

File tree

3 files changed

+112
-66
lines changed

3 files changed

+112
-66
lines changed

packages/flutter/lib/src/rendering/proxy_box.dart

Lines changed: 67 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,13 +1429,13 @@ class RenderClipRect extends _RenderCustomClip<Rect> {
14291429
/// If [clipper] is null, the clip will match the layout size and position of
14301430
/// the child.
14311431
///
1432-
/// The [clipBehavior] must not be null or [Clip.none].
1432+
/// The [clipBehavior] must not be null. If [clipBehavior] is
1433+
/// [Clip.none], no clipping will be applied.
14331434
RenderClipRect({
14341435
RenderBox? child,
14351436
CustomClipper<Rect>? clipper,
14361437
Clip clipBehavior = Clip.antiAlias,
14371438
}) : assert(clipBehavior != null),
1438-
assert(clipBehavior != Clip.none),
14391439
super(child: child, clipper: clipper, clipBehavior: clipBehavior);
14401440

14411441
@override
@@ -1455,15 +1455,20 @@ class RenderClipRect extends _RenderCustomClip<Rect> {
14551455
@override
14561456
void paint(PaintingContext context, Offset offset) {
14571457
if (child != null) {
1458-
_updateClip();
1459-
layer = context.pushClipRect(
1460-
needsCompositing,
1461-
offset,
1462-
_clip!,
1463-
super.paint,
1464-
clipBehavior: clipBehavior,
1465-
oldLayer: layer as ClipRectLayer?,
1466-
);
1458+
if (clipBehavior != Clip.none) {
1459+
_updateClip();
1460+
layer = context.pushClipRect(
1461+
needsCompositing,
1462+
offset,
1463+
_clip!,
1464+
super.paint,
1465+
clipBehavior: clipBehavior,
1466+
oldLayer: layer as ClipRectLayer?,
1467+
);
1468+
} else {
1469+
context.paintChild(child!, offset);
1470+
layer = null;
1471+
}
14671472
} else {
14681473
layer = null;
14691474
}
@@ -1495,14 +1500,14 @@ class RenderClipRRect extends _RenderCustomClip<RRect> {
14951500
///
14961501
/// If [clipper] is non-null, then [borderRadius] is ignored.
14971502
///
1498-
/// The [clipBehavior] argument must not be null or [Clip.none].
1503+
/// The [clipBehavior] argument must not be null. If [clipBehavior] is
1504+
/// [Clip.none], no clipping will be applied.
14991505
RenderClipRRect({
15001506
RenderBox? child,
15011507
BorderRadius borderRadius = BorderRadius.zero,
15021508
CustomClipper<RRect>? clipper,
15031509
Clip clipBehavior = Clip.antiAlias,
15041510
}) : assert(clipBehavior != null),
1505-
assert(clipBehavior != Clip.none),
15061511
_borderRadius = borderRadius,
15071512
super(child: child, clipper: clipper, clipBehavior: clipBehavior) {
15081513
assert(_borderRadius != null || clipper != null);
@@ -1541,14 +1546,21 @@ class RenderClipRRect extends _RenderCustomClip<RRect> {
15411546
@override
15421547
void paint(PaintingContext context, Offset offset) {
15431548
if (child != null) {
1544-
_updateClip();
1545-
layer = context.pushClipRRect(
1546-
needsCompositing,
1547-
offset,
1548-
_clip!.outerRect,
1549-
_clip!,
1550-
super.paint, clipBehavior: clipBehavior, oldLayer: layer as ClipRRectLayer?,
1551-
);
1549+
if (clipBehavior != Clip.none) {
1550+
_updateClip();
1551+
layer = context.pushClipRRect(
1552+
needsCompositing,
1553+
offset,
1554+
_clip!.outerRect,
1555+
_clip!,
1556+
super.paint,
1557+
clipBehavior: clipBehavior,
1558+
oldLayer: layer as ClipRRectLayer?,
1559+
);
1560+
} else {
1561+
context.paintChild(child!, offset);
1562+
layer = null;
1563+
}
15521564
} else {
15531565
layer = null;
15541566
}
@@ -1578,13 +1590,13 @@ class RenderClipOval extends _RenderCustomClip<Rect> {
15781590
/// If [clipper] is null, the oval will be inscribed into the layout size and
15791591
/// position of the child.
15801592
///
1581-
/// The [clipBehavior] argument must not be null or [Clip.none].
1593+
/// The [clipBehavior] argument must not be null. If [clipBehavior] is
1594+
/// [Clip.none], no clipping will be applied.
15821595
RenderClipOval({
15831596
RenderBox? child,
15841597
CustomClipper<Rect>? clipper,
15851598
Clip clipBehavior = Clip.antiAlias,
15861599
}) : assert(clipBehavior != null),
1587-
assert(clipBehavior != Clip.none),
15881600
super(child: child, clipper: clipper, clipBehavior: clipBehavior);
15891601

15901602
Rect? _cachedRect;
@@ -1620,16 +1632,21 @@ class RenderClipOval extends _RenderCustomClip<Rect> {
16201632
@override
16211633
void paint(PaintingContext context, Offset offset) {
16221634
if (child != null) {
1623-
_updateClip();
1624-
layer = context.pushClipPath(
1625-
needsCompositing,
1626-
offset,
1627-
_clip!,
1628-
_getClipPath(_clip!),
1629-
super.paint,
1630-
clipBehavior: clipBehavior,
1631-
oldLayer: layer as ClipPathLayer?,
1632-
);
1635+
if (clipBehavior != Clip.none) {
1636+
_updateClip();
1637+
layer = context.pushClipPath(
1638+
needsCompositing,
1639+
offset,
1640+
_clip!,
1641+
_getClipPath(_clip!),
1642+
super.paint,
1643+
clipBehavior: clipBehavior,
1644+
oldLayer: layer as ClipPathLayer?,
1645+
);
1646+
} else {
1647+
context.paintChild(child!, offset);
1648+
layer = null;
1649+
}
16331650
} else {
16341651
layer = null;
16351652
}
@@ -1667,13 +1684,13 @@ class RenderClipPath extends _RenderCustomClip<Path> {
16671684
/// consider using a [RenderClipRect], which can achieve the same effect more
16681685
/// efficiently.
16691686
///
1670-
/// The [clipBehavior] argument must not be null or [Clip.none].
1687+
/// The [clipBehavior] argument must not be null. If [clipBehavior] is
1688+
/// [Clip.none], no clipping will be applied.
16711689
RenderClipPath({
16721690
RenderBox? child,
16731691
CustomClipper<Path>? clipper,
16741692
Clip clipBehavior = Clip.antiAlias,
16751693
}) : assert(clipBehavior != null),
1676-
assert(clipBehavior != Clip.none),
16771694
super(child: child, clipper: clipper, clipBehavior: clipBehavior);
16781695

16791696
@override
@@ -1693,16 +1710,21 @@ class RenderClipPath extends _RenderCustomClip<Path> {
16931710
@override
16941711
void paint(PaintingContext context, Offset offset) {
16951712
if (child != null) {
1696-
_updateClip();
1697-
layer = context.pushClipPath(
1698-
needsCompositing,
1699-
offset,
1700-
Offset.zero & size,
1701-
_clip!,
1702-
super.paint,
1703-
clipBehavior: clipBehavior,
1704-
oldLayer: layer as ClipPathLayer?,
1705-
);
1713+
if (clipBehavior != Clip.none) {
1714+
_updateClip();
1715+
layer = context.pushClipPath(
1716+
needsCompositing,
1717+
offset,
1718+
Offset.zero & size,
1719+
_clip!,
1720+
super.paint,
1721+
clipBehavior: clipBehavior,
1722+
oldLayer: layer as ClipPathLayer?,
1723+
);
1724+
} else {
1725+
context.paintChild(child!, offset);
1726+
layer = null;
1727+
}
17061728
} else {
17071729
layer = null;
17081730
}

packages/flutter/lib/src/widgets/basic.dart

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -662,10 +662,15 @@ class ClipRect extends SingleChildRenderObjectWidget {
662662
/// If [clipper] is null, the clip will match the layout size and position of
663663
/// the child.
664664
///
665-
/// The [clipBehavior] argument must not be null or [Clip.none].
666-
const ClipRect({ Key? key, this.clipper, this.clipBehavior = Clip.hardEdge, Widget? child })
667-
: assert(clipBehavior != null),
668-
super(key: key, child: child);
665+
/// The [clipBehavior] argument must not be null. If [clipBehavior] is
666+
/// [Clip.none], no clipping will be applied.
667+
const ClipRect({
668+
Key? key,
669+
this.clipper,
670+
this.clipBehavior = Clip.hardEdge,
671+
Widget? child,
672+
}) : assert(clipBehavior != null),
673+
super(key: key, child: child);
669674

670675
/// If non-null, determines which clip to use.
671676
final CustomClipper<Rect>? clipper;
@@ -677,13 +682,11 @@ class ClipRect extends SingleChildRenderObjectWidget {
677682

678683
@override
679684
RenderClipRect createRenderObject(BuildContext context) {
680-
assert(clipBehavior != Clip.none);
681685
return RenderClipRect(clipper: clipper, clipBehavior: clipBehavior);
682686
}
683687

684688
@override
685689
void updateRenderObject(BuildContext context, RenderClipRect renderObject) {
686-
assert(clipBehavior != Clip.none);
687690
renderObject
688691
..clipper = clipper
689692
..clipBehavior = clipBehavior;
@@ -723,7 +726,8 @@ class ClipRRect extends SingleChildRenderObjectWidget {
723726
///
724727
/// If [clipper] is non-null, then [borderRadius] is ignored.
725728
///
726-
/// The [clipBehavior] argument must not be null or [Clip.none].
729+
/// The [clipBehavior] argument must not be null. If [clipBehavior] is
730+
/// [Clip.none], no clipping will be applied.
727731
const ClipRRect({
728732
Key? key,
729733
this.borderRadius = BorderRadius.zero,
@@ -752,13 +756,15 @@ class ClipRRect extends SingleChildRenderObjectWidget {
752756

753757
@override
754758
RenderClipRRect createRenderObject(BuildContext context) {
755-
assert(clipBehavior != Clip.none);
756-
return RenderClipRRect(borderRadius: borderRadius!, clipper: clipper, clipBehavior: clipBehavior);
759+
return RenderClipRRect(
760+
borderRadius: borderRadius!,
761+
clipper: clipper,
762+
clipBehavior: clipBehavior,
763+
);
757764
}
758765

759766
@override
760767
void updateRenderObject(BuildContext context, RenderClipRRect renderObject) {
761-
assert(clipBehavior != Clip.none);
762768
renderObject
763769
..borderRadius = borderRadius!
764770
..clipBehavior = clipBehavior
@@ -793,10 +799,15 @@ class ClipOval extends SingleChildRenderObjectWidget {
793799
/// If [clipper] is null, the oval will be inscribed into the layout size and
794800
/// position of the child.
795801
///
796-
/// The [clipBehavior] argument must not be null or [Clip.none].
797-
const ClipOval({Key? key, this.clipper, this.clipBehavior = Clip.antiAlias, Widget? child})
798-
: assert(clipBehavior != null),
799-
super(key: key, child: child);
802+
/// The [clipBehavior] argument must not be null. If [clipBehavior] is
803+
/// [Clip.none], no clipping will be applied.
804+
const ClipOval({
805+
Key? key,
806+
this.clipper,
807+
this.clipBehavior = Clip.antiAlias,
808+
Widget? child,
809+
}) : assert(clipBehavior != null),
810+
super(key: key, child: child);
800811

801812
/// If non-null, determines which clip to use.
802813
///
@@ -816,13 +827,11 @@ class ClipOval extends SingleChildRenderObjectWidget {
816827

817828
@override
818829
RenderClipOval createRenderObject(BuildContext context) {
819-
assert(clipBehavior != Clip.none);
820830
return RenderClipOval(clipper: clipper, clipBehavior: clipBehavior);
821831
}
822832

823833
@override
824834
void updateRenderObject(BuildContext context, RenderClipOval renderObject) {
825-
assert(clipBehavior != Clip.none);
826835
renderObject
827836
..clipper = clipper
828837
..clipBehavior = clipBehavior;
@@ -866,7 +875,8 @@ class ClipPath extends SingleChildRenderObjectWidget {
866875
/// consider using a [ClipRect], which can achieve the same effect more
867876
/// efficiently.
868877
///
869-
/// The [clipBehavior] argument must not be null or [Clip.none].
878+
/// The [clipBehavior] argument must not be null. If [clipBehavior] is
879+
/// [Clip.none], no clipping will be applied.
870880
const ClipPath({
871881
Key? key,
872882
this.clipper,
@@ -886,7 +896,6 @@ class ClipPath extends SingleChildRenderObjectWidget {
886896
Widget? child,
887897
}) {
888898
assert(clipBehavior != null);
889-
assert(clipBehavior != Clip.none);
890899
assert(shape != null);
891900
return Builder(
892901
key: key,
@@ -917,13 +926,11 @@ class ClipPath extends SingleChildRenderObjectWidget {
917926

918927
@override
919928
RenderClipPath createRenderObject(BuildContext context) {
920-
assert(clipBehavior != Clip.none);
921929
return RenderClipPath(clipper: clipper, clipBehavior: clipBehavior);
922930
}
923931

924932
@override
925933
void updateRenderObject(BuildContext context, RenderClipPath renderObject) {
926-
assert(clipBehavior != Clip.none);
927934
renderObject
928935
..clipper = clipper
929936
..clipBehavior = clipBehavior;
@@ -1014,7 +1021,8 @@ class PhysicalModel extends SingleChildRenderObjectWidget {
10141021
shape: shape,
10151022
clipBehavior: clipBehavior,
10161023
borderRadius: borderRadius,
1017-
elevation: elevation, color: color,
1024+
elevation: elevation,
1025+
color: color,
10181026
shadowColor: shadowColor,
10191027
);
10201028
}

packages/flutter/test/widgets/clip_test.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ void main() {
8787
await tester.pumpWidget(const ClipRect(clipBehavior: Clip.antiAlias));
8888

8989
expect(renderClip.clipBehavior, equals(Clip.antiAlias));
90+
91+
await tester.pumpWidget(const ClipRect(clipBehavior: Clip.none));
92+
93+
expect(renderClip.clipBehavior, equals(Clip.none));
9094
});
9195

9296
test('ClipRRect constructs with the right default values', () {
@@ -105,6 +109,10 @@ void main() {
105109
await tester.pumpWidget(const ClipRRect(clipBehavior: Clip.hardEdge));
106110

107111
expect(renderClip.clipBehavior, equals(Clip.hardEdge));
112+
113+
await tester.pumpWidget(const ClipRRect(clipBehavior: Clip.none));
114+
115+
expect(renderClip.clipBehavior, equals(Clip.none));
108116
});
109117

110118
testWidgets('ClipOval updates clipBehavior in updateRenderObject', (WidgetTester tester) async {
@@ -117,6 +125,10 @@ void main() {
117125
await tester.pumpWidget(const ClipOval(clipBehavior: Clip.hardEdge));
118126

119127
expect(renderClip.clipBehavior, equals(Clip.hardEdge));
128+
129+
await tester.pumpWidget(const ClipOval(clipBehavior: Clip.none));
130+
131+
expect(renderClip.clipBehavior, equals(Clip.none));
120132
});
121133

122134
testWidgets('ClipPath updates clipBehavior in updateRenderObject', (WidgetTester tester) async {
@@ -129,6 +141,10 @@ void main() {
129141
await tester.pumpWidget(const ClipPath(clipBehavior: Clip.hardEdge));
130142

131143
expect(renderClip.clipBehavior, equals(Clip.hardEdge));
144+
145+
await tester.pumpWidget(const ClipPath(clipBehavior: Clip.none));
146+
147+
expect(renderClip.clipBehavior, equals(Clip.none));
132148
});
133149

134150
testWidgets('ClipPath', (WidgetTester tester) async {

0 commit comments

Comments
 (0)