Skip to content

Commit 5f9ad01

Browse files
authored
Prepare the framework for having RRect assert on negative radii (#111515)
1 parent fb90be4 commit 5f9ad01

File tree

7 files changed

+62
-17
lines changed

7 files changed

+62
-17
lines changed

packages/flutter/lib/src/painting/border_radius.dart

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -392,13 +392,19 @@ class BorderRadius extends BorderRadiusGeometry {
392392
Radius get _bottomEnd => Radius.zero;
393393

394394
/// Creates an [RRect] from the current border radius and a [Rect].
395+
///
396+
/// If any of the radii have negative values in x or y, those values will be
397+
/// clamped to zero in order to produce a valid [RRect].
395398
RRect toRRect(Rect rect) {
399+
// Because the current radii could be negative, we must clamp them before
400+
// converting them to an RRect to be rendered, since negative radii on
401+
// RRects don't make sense.
396402
return RRect.fromRectAndCorners(
397403
rect,
398-
topLeft: topLeft,
399-
topRight: topRight,
400-
bottomLeft: bottomLeft,
401-
bottomRight: bottomRight,
404+
topLeft: topLeft.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
405+
topRight: topRight.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
406+
bottomLeft: bottomLeft.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
407+
bottomRight: bottomRight.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
402408
);
403409
}
404410

packages/flutter/lib/src/painting/box_border.dart

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,18 @@ abstract class BoxBorder extends ShapeBorder {
232232
canvas.drawRRect(borderRadius.toRRect(rect), paint);
233233
} else {
234234
final RRect borderRect = borderRadius.toRRect(rect);
235-
final RRect inner = borderRect.deflate(side.strokeInset);
235+
RRect inner = borderRect.deflate(side.strokeInset);
236+
// Clamp the inner border's radii to zero, until deflate does this
237+
// automatically, so that we can start asserting non-negative values
238+
// in the engine without breaking the framework.
239+
// TODO(gspencergoog): Remove this once https://github.com/flutter/engine/pull/36062 rolls into the framework.
240+
inner = RRect.fromLTRBAndCorners(
241+
inner.left, inner.top, inner.right, inner.bottom,
242+
topLeft: inner.tlRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
243+
topRight: inner.trRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
244+
bottomLeft: inner.blRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
245+
bottomRight: inner.brRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
246+
);
236247
final RRect outer = borderRect.inflate(side.strokeOutset);
237248
canvas.drawDRRect(outer, inner, paint);
238249
}

packages/flutter/lib/src/painting/rounded_rectangle_border.dart

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,18 @@ class RoundedRectangleBorder extends OutlinedBorder {
132132
final Paint paint = Paint()
133133
..color = side.color;
134134
final RRect borderRect = borderRadius.resolve(textDirection).toRRect(rect);
135-
final RRect inner = borderRect.deflate(side.strokeInset);
135+
RRect inner = borderRect.deflate(side.strokeInset);
136+
// Clamp the inner border's radii to zero, until deflate does this
137+
// automatically, so that we can start asserting non-negative values
138+
// in the engine without breaking the framework.
139+
// TODO(gspencergoog): Remove this once https://github.com/flutter/engine/pull/36062 rolls into the framework.
140+
inner = RRect.fromLTRBAndCorners(
141+
inner.left, inner.top, inner.right, inner.bottom,
142+
topLeft: inner.tlRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
143+
topRight: inner.trRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
144+
bottomLeft: inner.blRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
145+
bottomRight: inner.brRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
146+
);
136147
final RRect outer = borderRect.inflate(side.strokeOutset);
137148
canvas.drawDRRect(outer, inner, paint);
138149
}

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,18 @@ class TableBorder {
271271
paintBorder(canvas, rect, top: top, right: right, bottom: bottom, left: left);
272272
} else {
273273
final RRect outer = borderRadius.toRRect(rect);
274-
final RRect inner = outer.deflate(top.width);
274+
RRect inner = outer.deflate(top.width);
275+
// Clamp the inner border's radii to zero, until deflate does this
276+
// automatically, so that we can start asserting non-negative values
277+
// in the engine without breaking the framework.
278+
// TODO(gspencergoog): Remove this once https://github.com/flutter/engine/pull/36062 rolls into the framework.
279+
inner = RRect.fromLTRBAndCorners(
280+
inner.left, inner.top, inner.right, inner.bottom,
281+
topLeft: inner.tlRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
282+
topRight: inner.trRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
283+
bottomLeft: inner.blRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
284+
bottomRight: inner.brRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
285+
);
275286
final Paint paint = Paint()..color = top.color;
276287
canvas.drawDRRect(outer, inner, paint);
277288
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,17 @@ class _MulticastCanvas implements Canvas {
129129

130130
@override
131131
void drawDRRect(RRect outer, RRect inner, Paint paint) {
132+
// Clamp the inner border's radii to zero, until deflate does this
133+
// automatically, so that we can start asserting non-negative values
134+
// in the engine without breaking the framework.
135+
// TODO(gspencergoog): Remove this once https://github.com/flutter/engine/pull/36062 rolls into the framework.
136+
inner = RRect.fromLTRBAndCorners(
137+
inner.left, inner.top, inner.right, inner.bottom,
138+
topLeft: inner.tlRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
139+
topRight: inner.trRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
140+
bottomLeft: inner.blRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
141+
bottomRight: inner.brRadius.clamp(minimum: Radius.zero), // ignore_clamp_double_lint
142+
);
132143
_main.drawDRRect(outer, inner, paint);
133144
_screenshot.drawDRRect(outer, inner, paint);
134145
}

packages/flutter/test/material/checkbox_test.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ void main() {
553553
..drrect(
554554
color: material3 ? theme.colorScheme.onSurface : const Color(0x8a000000),
555555
outer: RRect.fromLTRBR(15.0, 15.0, 33.0, 33.0, const Radius.circular(1.0)),
556-
inner: RRect.fromLTRBR(17.0, 17.0, 31.0, 31.0, const Radius.circular(-1.0)),
556+
inner: RRect.fromLTRBR(17.0, 17.0, 31.0, 31.0, Radius.zero),
557557
),
558558
);
559559

@@ -568,7 +568,7 @@ void main() {
568568
..drrect(
569569
color: material3 ? theme.colorScheme.onSurface.withOpacity(0.38) : const Color(0x61000000),
570570
outer: RRect.fromLTRBR(15.0, 15.0, 33.0, 33.0, const Radius.circular(1.0)),
571-
inner: RRect.fromLTRBR(17.0, 17.0, 31.0, 31.0, const Radius.circular(-1.0)),
571+
inner: RRect.fromLTRBR(17.0, 17.0, 31.0, 31.0, Radius.zero),
572572
),
573573
);
574574
});
@@ -1420,7 +1420,7 @@ void main() {
14201420
..drrect(
14211421
color: borderColor,
14221422
outer: RRect.fromLTRBR(15, 15, 33, 33, const Radius.circular(1)),
1423-
inner: RRect.fromLTRBR(19, 19, 29, 29, const Radius.circular(-3)),
1423+
inner: RRect.fromLTRBR(19, 19, 29, 29, Radius.zero),
14241424
),
14251425
);
14261426
}
@@ -1479,7 +1479,7 @@ void main() {
14791479
..drrect(
14801480
color: borderColor,
14811481
outer: RRect.fromLTRBR(15, 15, 33, 33, const Radius.circular(1)),
1482-
inner: RRect.fromLTRBR(19, 19, 29, 29, const Radius.circular(-3)),
1482+
inner: RRect.fromLTRBR(19, 19, 29, 29, Radius.zero),
14831483
),
14841484
);
14851485
}

packages/flutter/test/widgets/box_decoration_test.dart

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -249,12 +249,7 @@ Future<void> main() async {
249249
350.0, 200.0, 450.0, 300.0,
250250
topRight: const Radius.circular(10.0),
251251
),
252-
inner: RRect.fromLTRBAndCorners(
253-
360.0, 210.0, 440.0, 290.0,
254-
topLeft: const Radius.circular(-10.0),
255-
bottomRight: const Radius.circular(-10.0),
256-
bottomLeft: const Radius.circular(-10.0),
257-
),
252+
inner: RRect.fromLTRBAndCorners(360.0, 210.0, 440.0, 290.0),
258253
)
259254
..circle(x: 400.0, y: 350.0, radius: 45.0),
260255
);

0 commit comments

Comments
 (0)