diff --git a/lib/web_ui/lib/src/engine/dom_canvas.dart b/lib/web_ui/lib/src/engine/dom_canvas.dart index 1382c623db6eb..bb3a0dc51c2a4 100644 --- a/lib/web_ui/lib/src/engine/dom_canvas.dart +++ b/lib/web_ui/lib/src/engine/dom_canvas.dart @@ -67,8 +67,12 @@ class DomCanvas extends EngineCanvas with SaveElementStackTracking { @override void drawRect(ui.Rect rect, SurfacePaintData paint) { + _drawRect(rect, paint, 'draw-rect'); + } + + html.Element _drawRect(ui.Rect rect, SurfacePaintData paint, String tagName) { assert(paint.shader == null); - final html.Element rectangle = html.Element.tag('draw-rect'); + final html.Element rectangle = html.Element.tag(tagName); assert(() { rectangle.setAttribute('flt-rect', '$rect'); rectangle.setAttribute('flt-paint', '$paint'); @@ -104,8 +108,8 @@ class DomCanvas extends EngineCanvas with SaveElementStackTracking { ..transformOrigin = '0 0 0' ..transform = effectiveTransform; - final String cssColor = - paint.color == null ? '#000000' : colorToCssString(paint.color); + final String cssColor = paint.color == null ? '#000000' + : colorToCssString(paint.color); if (paint.maskFilter != null) { style.filter = 'blur(${paint.maskFilter.webOnlySigma}px)'; @@ -124,11 +128,13 @@ class DomCanvas extends EngineCanvas with SaveElementStackTracking { } currentElement.append(rectangle); + return rectangle; } @override void drawRRect(ui.RRect rrect, SurfacePaintData paint) { - throw UnimplementedError(); + html.Element element = _drawRect(rrect.outerRect, paint, 'draw-rrect'); + element.style.borderRadius = '${rrect.blRadiusX.toStringAsFixed(3)}px'; } @override diff --git a/lib/web_ui/lib/src/engine/surface/recording_canvas.dart b/lib/web_ui/lib/src/engine/surface/recording_canvas.dart index 00b3fdae2b2a5..6cf38cb634623 100644 --- a/lib/web_ui/lib/src/engine/surface/recording_canvas.dart +++ b/lib/web_ui/lib/src/engine/surface/recording_canvas.dart @@ -228,7 +228,9 @@ class RecordingCanvas { } void drawRRect(ui.RRect rrect, SurfacePaint paint) { - _hasArbitraryPaint = true; + if (!rrect.webOnlyUniformRadii) { + _hasArbitraryPaint = true; + } _didDraw = true; final double strokeWidth = paint.strokeWidth == null ? 0 : paint.strokeWidth; diff --git a/lib/web_ui/lib/src/ui/geometry.dart b/lib/web_ui/lib/src/ui/geometry.dart index d11c5d4414110..dc50d198fbfce 100644 --- a/lib/web_ui/lib/src/ui/geometry.dart +++ b/lib/web_ui/lib/src/ui/geometry.dart @@ -1084,6 +1084,7 @@ class RRect { blRadiusY: radiusY, brRadiusX: radiusX, brRadiusY: radiusY, + uniformRadii: radiusX == radiusY, ); /// Construct a rounded rectangle from its left, top, right, and bottom edges, @@ -1103,6 +1104,7 @@ class RRect { blRadiusY: radius.y, brRadiusX: radius.x, brRadiusY: radius.y, + uniformRadii: radius.x == radius.y, ); /// Construct a rounded rectangle from its bounding box and the same radii @@ -1121,6 +1123,7 @@ class RRect { blRadiusY: radiusY, brRadiusX: radiusX, brRadiusY: radiusY, + uniformRadii: radiusX == radiusY, ); /// Construct a rounded rectangle from its bounding box and a radius that is @@ -1139,6 +1142,7 @@ class RRect { blRadiusY: radius.y, brRadiusX: radius.x, brRadiusY: radius.y, + uniformRadii: radius.x == radius.y, ); /// Construct a rounded rectangle from its left, top, right, and bottom edges, @@ -1167,6 +1171,13 @@ class RRect { blRadiusY: bottomLeft.y, brRadiusX: bottomRight.x, brRadiusY: bottomRight.y, + uniformRadii: topLeft.x == topLeft.y && + topLeft.x == topRight.x && + topLeft.x == topRight.y && + topLeft.x == bottomLeft.x && + topLeft.x == bottomLeft.y && + topLeft.x == bottomRight.x && + topLeft.x == bottomRight.y, ); /// Construct a rounded rectangle from its bounding box and and topLeft, @@ -1191,6 +1202,13 @@ class RRect { blRadiusY: bottomLeft.y, brRadiusX: bottomRight.x, brRadiusY: bottomRight.y, + uniformRadii: topLeft.x == topLeft.y && + topLeft.x == topRight.x && + topLeft.x == topRight.y && + topLeft.x == bottomLeft.x && + topLeft.x == bottomLeft.y && + topLeft.x == bottomRight.x && + topLeft.x == bottomRight.y, ); const RRect._raw({ @@ -1206,6 +1224,7 @@ class RRect { this.brRadiusY = 0.0, this.blRadiusX = 0.0, this.blRadiusY = 0.0, + bool uniformRadii = false, }) : assert(left != null), assert(top != null), assert(right != null), @@ -1217,7 +1236,8 @@ class RRect { assert(brRadiusX != null), assert(brRadiusY != null), assert(blRadiusX != null), - assert(blRadiusY != null); + assert(blRadiusY != null), + this.webOnlyUniformRadii = uniformRadii; /// The offset of the left edge of this rectangle from the x axis. final double left; @@ -1264,6 +1284,10 @@ class RRect { /// The bottom-left vertical radius. final double blRadiusY; + /// If radii is equal for all corners. + // webOnly + final bool webOnlyUniformRadii; + /// The bottom-left [Radius]. Radius get blRadius => Radius.elliptical(blRadiusX, blRadiusY); diff --git a/lib/web_ui/test/rrect_test.dart b/lib/web_ui/test/rrect_test.dart index 857af2c7eb332..6753ba33bbece 100644 --- a/lib/web_ui/test/rrect_test.dart +++ b/lib/web_ui/test/rrect_test.dart @@ -42,4 +42,88 @@ void main() { expect(rrect.contains(const Offset(1.7, 1.97)), isTrue); expect(rrect.contains(const Offset(1.0, 1.99)), isTrue); }); + + test('RRect.webOnlyUniformRadii returns true when all corner radii are equal', + () { + final RRect rect1 = RRect.fromRectAndCorners( + const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0), + topLeft: const Radius.elliptical(5, 5), + topRight: const Radius.elliptical(5, 5), + bottomLeft: const Radius.elliptical(5, 5), + bottomRight: const Radius.elliptical(5, 5), + ); + expect(rect1.webOnlyUniformRadii, isTrue); + + final RRect rect2 = RRect.fromRectAndCorners( + const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0), + topLeft: const Radius.elliptical(1000, 5), + topRight: const Radius.elliptical(5, 5), + bottomLeft: const Radius.elliptical(5, 5), + bottomRight: const Radius.elliptical(5, 5), + ); + expect(rect2.webOnlyUniformRadii, isFalse); + + final RRect rect3 = RRect.fromRectAndCorners( + const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0), + topLeft: const Radius.elliptical(5, 1000), + topRight: const Radius.elliptical(5, 5), + bottomLeft: const Radius.elliptical(5, 5), + bottomRight: const Radius.elliptical(5, 5), + ); + expect(rect3.webOnlyUniformRadii, isFalse); + + final RRect rect4 = RRect.fromRectAndCorners( + const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0), + topLeft: const Radius.elliptical(5, 5), + topRight: const Radius.elliptical(1000, 5), + bottomLeft: const Radius.elliptical(5, 5), + bottomRight: const Radius.elliptical(5, 5), + ); + expect(rect4.webOnlyUniformRadii, isFalse); + + final RRect rect5 = RRect.fromRectAndCorners( + const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0), + topLeft: const Radius.elliptical(5, 5), + topRight: const Radius.elliptical(5, 1000), + bottomLeft: const Radius.elliptical(5, 5), + bottomRight: const Radius.elliptical(5, 5), + ); + expect(rect5.webOnlyUniformRadii, isFalse); + + final RRect rect6 = RRect.fromRectAndCorners( + const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0), + topLeft: const Radius.elliptical(5, 5), + topRight: const Radius.elliptical(5, 5), + bottomLeft: const Radius.elliptical(1000, 5), + bottomRight: const Radius.elliptical(5, 5), + ); + expect(rect6.webOnlyUniformRadii, isFalse); + + final RRect rect7 = RRect.fromRectAndCorners( + const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0), + topLeft: const Radius.elliptical(5, 5), + topRight: const Radius.elliptical(5, 5), + bottomLeft: const Radius.elliptical(5, 1000), + bottomRight: const Radius.elliptical(5, 5), + ); + expect(rect7.webOnlyUniformRadii, isFalse); + + final RRect rect8 = RRect.fromRectAndCorners( + const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0), + topLeft: const Radius.elliptical(5, 5), + topRight: const Radius.elliptical(5, 5), + bottomLeft: const Radius.elliptical(5, 5), + bottomRight: const Radius.elliptical(1000, 5), + ); + expect(rect8.webOnlyUniformRadii, isFalse); + + final RRect rect9 = RRect.fromRectAndCorners( + const Rect.fromLTWH(1.0, 2.0, 3.0, 4.0), + topLeft: const Radius.elliptical(5, 5), + topRight: const Radius.elliptical(5, 5), + bottomLeft: const Radius.elliptical(5, 5), + bottomRight: const Radius.elliptical(5, 1000), + ); + expect(rect9.webOnlyUniformRadii, isFalse); + }); }