Skip to content

Commit b22821a

Browse files
authored
Optimize drawRRect to use dom_canvas (flutter#15970)
1 parent 2ce15cf commit b22821a

File tree

4 files changed

+122
-6
lines changed

4 files changed

+122
-6
lines changed

lib/web_ui/lib/src/engine/dom_canvas.dart

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,12 @@ class DomCanvas extends EngineCanvas with SaveElementStackTracking {
6767

6868
@override
6969
void drawRect(ui.Rect rect, SurfacePaintData paint) {
70+
_drawRect(rect, paint, 'draw-rect');
71+
}
72+
73+
html.Element _drawRect(ui.Rect rect, SurfacePaintData paint, String tagName) {
7074
assert(paint.shader == null);
71-
final html.Element rectangle = html.Element.tag('draw-rect');
75+
final html.Element rectangle = html.Element.tag(tagName);
7276
assert(() {
7377
rectangle.setAttribute('flt-rect', '$rect');
7478
rectangle.setAttribute('flt-paint', '$paint');
@@ -104,8 +108,8 @@ class DomCanvas extends EngineCanvas with SaveElementStackTracking {
104108
..transformOrigin = '0 0 0'
105109
..transform = effectiveTransform;
106110

107-
final String cssColor =
108-
paint.color == null ? '#000000' : colorToCssString(paint.color);
111+
final String cssColor = paint.color == null ? '#000000'
112+
: colorToCssString(paint.color);
109113

110114
if (paint.maskFilter != null) {
111115
style.filter = 'blur(${paint.maskFilter.webOnlySigma}px)';
@@ -124,11 +128,13 @@ class DomCanvas extends EngineCanvas with SaveElementStackTracking {
124128
}
125129

126130
currentElement.append(rectangle);
131+
return rectangle;
127132
}
128133

129134
@override
130135
void drawRRect(ui.RRect rrect, SurfacePaintData paint) {
131-
throw UnimplementedError();
136+
html.Element element = _drawRect(rrect.outerRect, paint, 'draw-rrect');
137+
element.style.borderRadius = '${rrect.blRadiusX.toStringAsFixed(3)}px';
132138
}
133139

134140
@override

lib/web_ui/lib/src/engine/surface/recording_canvas.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,9 @@ class RecordingCanvas {
228228
}
229229

230230
void drawRRect(ui.RRect rrect, SurfacePaint paint) {
231-
_hasArbitraryPaint = true;
231+
if (!rrect.webOnlyUniformRadii) {
232+
_hasArbitraryPaint = true;
233+
}
232234
_didDraw = true;
233235
final double strokeWidth =
234236
paint.strokeWidth == null ? 0 : paint.strokeWidth;

lib/web_ui/lib/src/ui/geometry.dart

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,7 @@ class RRect {
10841084
blRadiusY: radiusY,
10851085
brRadiusX: radiusX,
10861086
brRadiusY: radiusY,
1087+
uniformRadii: radiusX == radiusY,
10871088
);
10881089

10891090
/// Construct a rounded rectangle from its left, top, right, and bottom edges,
@@ -1103,6 +1104,7 @@ class RRect {
11031104
blRadiusY: radius.y,
11041105
brRadiusX: radius.x,
11051106
brRadiusY: radius.y,
1107+
uniformRadii: radius.x == radius.y,
11061108
);
11071109

11081110
/// Construct a rounded rectangle from its bounding box and the same radii
@@ -1121,6 +1123,7 @@ class RRect {
11211123
blRadiusY: radiusY,
11221124
brRadiusX: radiusX,
11231125
brRadiusY: radiusY,
1126+
uniformRadii: radiusX == radiusY,
11241127
);
11251128

11261129
/// Construct a rounded rectangle from its bounding box and a radius that is
@@ -1139,6 +1142,7 @@ class RRect {
11391142
blRadiusY: radius.y,
11401143
brRadiusX: radius.x,
11411144
brRadiusY: radius.y,
1145+
uniformRadii: radius.x == radius.y,
11421146
);
11431147

11441148
/// Construct a rounded rectangle from its left, top, right, and bottom edges,
@@ -1167,6 +1171,13 @@ class RRect {
11671171
blRadiusY: bottomLeft.y,
11681172
brRadiusX: bottomRight.x,
11691173
brRadiusY: bottomRight.y,
1174+
uniformRadii: topLeft.x == topLeft.y &&
1175+
topLeft.x == topRight.x &&
1176+
topLeft.x == topRight.y &&
1177+
topLeft.x == bottomLeft.x &&
1178+
topLeft.x == bottomLeft.y &&
1179+
topLeft.x == bottomRight.x &&
1180+
topLeft.x == bottomRight.y,
11701181
);
11711182

11721183
/// Construct a rounded rectangle from its bounding box and and topLeft,
@@ -1191,6 +1202,13 @@ class RRect {
11911202
blRadiusY: bottomLeft.y,
11921203
brRadiusX: bottomRight.x,
11931204
brRadiusY: bottomRight.y,
1205+
uniformRadii: topLeft.x == topLeft.y &&
1206+
topLeft.x == topRight.x &&
1207+
topLeft.x == topRight.y &&
1208+
topLeft.x == bottomLeft.x &&
1209+
topLeft.x == bottomLeft.y &&
1210+
topLeft.x == bottomRight.x &&
1211+
topLeft.x == bottomRight.y,
11941212
);
11951213

11961214
const RRect._raw({
@@ -1206,6 +1224,7 @@ class RRect {
12061224
this.brRadiusY = 0.0,
12071225
this.blRadiusX = 0.0,
12081226
this.blRadiusY = 0.0,
1227+
bool uniformRadii = false,
12091228
}) : assert(left != null),
12101229
assert(top != null),
12111230
assert(right != null),
@@ -1217,7 +1236,8 @@ class RRect {
12171236
assert(brRadiusX != null),
12181237
assert(brRadiusY != null),
12191238
assert(blRadiusX != null),
1220-
assert(blRadiusY != null);
1239+
assert(blRadiusY != null),
1240+
this.webOnlyUniformRadii = uniformRadii;
12211241

12221242
/// The offset of the left edge of this rectangle from the x axis.
12231243
final double left;
@@ -1264,6 +1284,10 @@ class RRect {
12641284
/// The bottom-left vertical radius.
12651285
final double blRadiusY;
12661286

1287+
/// If radii is equal for all corners.
1288+
// webOnly
1289+
final bool webOnlyUniformRadii;
1290+
12671291
/// The bottom-left [Radius].
12681292
Radius get blRadius => Radius.elliptical(blRadiusX, blRadiusY);
12691293

lib/web_ui/test/rrect_test.dart

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,88 @@ void main() {
4242
expect(rrect.contains(const Offset(1.7, 1.97)), isTrue);
4343
expect(rrect.contains(const Offset(1.0, 1.99)), isTrue);
4444
});
45+
46+
test('RRect.webOnlyUniformRadii returns true when all corner radii are equal',
47+
() {
48+
final RRect rect1 = RRect.fromRectAndCorners(
49+
const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0),
50+
topLeft: const Radius.elliptical(5, 5),
51+
topRight: const Radius.elliptical(5, 5),
52+
bottomLeft: const Radius.elliptical(5, 5),
53+
bottomRight: const Radius.elliptical(5, 5),
54+
);
55+
expect(rect1.webOnlyUniformRadii, isTrue);
56+
57+
final RRect rect2 = RRect.fromRectAndCorners(
58+
const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0),
59+
topLeft: const Radius.elliptical(1000, 5),
60+
topRight: const Radius.elliptical(5, 5),
61+
bottomLeft: const Radius.elliptical(5, 5),
62+
bottomRight: const Radius.elliptical(5, 5),
63+
);
64+
expect(rect2.webOnlyUniformRadii, isFalse);
65+
66+
final RRect rect3 = RRect.fromRectAndCorners(
67+
const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0),
68+
topLeft: const Radius.elliptical(5, 1000),
69+
topRight: const Radius.elliptical(5, 5),
70+
bottomLeft: const Radius.elliptical(5, 5),
71+
bottomRight: const Radius.elliptical(5, 5),
72+
);
73+
expect(rect3.webOnlyUniformRadii, isFalse);
74+
75+
final RRect rect4 = RRect.fromRectAndCorners(
76+
const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0),
77+
topLeft: const Radius.elliptical(5, 5),
78+
topRight: const Radius.elliptical(1000, 5),
79+
bottomLeft: const Radius.elliptical(5, 5),
80+
bottomRight: const Radius.elliptical(5, 5),
81+
);
82+
expect(rect4.webOnlyUniformRadii, isFalse);
83+
84+
final RRect rect5 = RRect.fromRectAndCorners(
85+
const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0),
86+
topLeft: const Radius.elliptical(5, 5),
87+
topRight: const Radius.elliptical(5, 1000),
88+
bottomLeft: const Radius.elliptical(5, 5),
89+
bottomRight: const Radius.elliptical(5, 5),
90+
);
91+
expect(rect5.webOnlyUniformRadii, isFalse);
92+
93+
final RRect rect6 = RRect.fromRectAndCorners(
94+
const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0),
95+
topLeft: const Radius.elliptical(5, 5),
96+
topRight: const Radius.elliptical(5, 5),
97+
bottomLeft: const Radius.elliptical(1000, 5),
98+
bottomRight: const Radius.elliptical(5, 5),
99+
);
100+
expect(rect6.webOnlyUniformRadii, isFalse);
101+
102+
final RRect rect7 = RRect.fromRectAndCorners(
103+
const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0),
104+
topLeft: const Radius.elliptical(5, 5),
105+
topRight: const Radius.elliptical(5, 5),
106+
bottomLeft: const Radius.elliptical(5, 1000),
107+
bottomRight: const Radius.elliptical(5, 5),
108+
);
109+
expect(rect7.webOnlyUniformRadii, isFalse);
110+
111+
final RRect rect8 = RRect.fromRectAndCorners(
112+
const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0),
113+
topLeft: const Radius.elliptical(5, 5),
114+
topRight: const Radius.elliptical(5, 5),
115+
bottomLeft: const Radius.elliptical(5, 5),
116+
bottomRight: const Radius.elliptical(1000, 5),
117+
);
118+
expect(rect8.webOnlyUniformRadii, isFalse);
119+
120+
final RRect rect9 = RRect.fromRectAndCorners(
121+
const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0),
122+
topLeft: const Radius.elliptical(5, 5),
123+
topRight: const Radius.elliptical(5, 5),
124+
bottomLeft: const Radius.elliptical(5, 5),
125+
bottomRight: const Radius.elliptical(5, 1000),
126+
);
127+
expect(rect9.webOnlyUniformRadii, isFalse);
128+
});
45129
}

0 commit comments

Comments
 (0)