diff --git a/lib/web_ui/lib/src/engine/html/path/path_ref.dart b/lib/web_ui/lib/src/engine/html/path/path_ref.dart index 1cbc082a836a4..7e66e42ee87db 100644 --- a/lib/web_ui/lib/src/engine/html/path/path_ref.dart +++ b/lib/web_ui/lib/src/engine/html/path/path_ref.dart @@ -263,15 +263,12 @@ class PathRef { // The location delta of control point specifies corner radius. if (vector1_0x != 0.0) { // For CW : Top right or bottom left corners. - assert(vector2_1x == 0.0 && vector1_0y == 0.0); dx = vector1_0x.abs(); dy = vector2_1y.abs(); } else if (vector1_0y != 0.0) { - assert(vector2_1x == 0.0 || vector2_1y == 0.0); dx = vector2_1x.abs(); dy = vector1_0y.abs(); } else { - assert(vector2_1y == 0.0); dx = vector1_0x.abs(); dy = vector1_0y.abs(); } @@ -288,9 +285,19 @@ class PathRef { radii.add(ui.Radius.elliptical(dx, dy)); ++cornerIndex; } else { - assert((verb == SPath.kLineVerb && - ((pts[2] - pts[0]) == 0 || (pts[3] - pts[1]) == 0)) || - verb == SPath.kCloseVerb); + if (assertionsEnabled) { + if (verb == SPath.kLineVerb) { + final bool isVerticalOrHorizontal = + SPath.nearlyEqual(pts[2], pts[0]) || + SPath.nearlyEqual(pts[3], pts[1]); + assert( + isVerticalOrHorizontal, + 'An RRect path must only contain vertical and horizontal lines.' + ); + } else { + assert(verb == SPath.kCloseVerb); + } + } } } return ui.RRect.fromRectAndCorners(bounds, diff --git a/lib/web_ui/test/html/path_ref_test.dart b/lib/web_ui/test/html/path_ref_test.dart new file mode 100644 index 0000000000000..2eaff94dfeab7 --- /dev/null +++ b/lib/web_ui/test/html/path_ref_test.dart @@ -0,0 +1,78 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:test/bootstrap/browser.dart'; +import 'package:test/test.dart'; +import 'package:ui/src/engine.dart'; +import 'package:ui/ui.dart'; + +// TODO(yjbanov): https://github.com/flutter/flutter/issues/76885 +const bool issue76885Exists = true; + +void main() { + internalBootstrapBrowserTest(() => testMain); +} + +void testMain() { + test('PathRef.getRRect with radius', () { + final SurfacePath path = SurfacePath(); + final RRect rrect = RRect.fromLTRBR(0, 0, 10, 10, const Radius.circular(2)); + path.addRRect(rrect); + expect(path.toRoundedRect(), rrect); + }); + + test('PathRef.getRRect with radius larger than rect', () { + final SurfacePath path = SurfacePath(); + final RRect rrect = RRect.fromLTRBR(0, 0, 10, 10, const Radius.circular(20)); + path.addRRect(rrect); + expect( + path.toRoundedRect(), + // Path.addRRect will correct the radius to fit the dimensions, so when + // extracting the rrect out of the path we don't get the original. + RRect.fromLTRBR(0, 0, 10, 10, const Radius.circular(5)), + ); + }); + + test('PathRef.getRRect with zero radius', () { + final SurfacePath path = SurfacePath(); + final RRect rrect = RRect.fromLTRBR(0, 0, 10, 10, const Radius.circular(0)); + path.addRRect(rrect); + expect(path.toRoundedRect(), isNull); + expect(path.toRect(), rrect.outerRect); + }); + + test('PathRef.getRRect elliptical', () { + final SurfacePath path = SurfacePath(); + final RRect rrect = RRect.fromLTRBR(0, 0, 10, 10, const Radius.elliptical(2, 4)); + path.addRRect(rrect); + expect(path.toRoundedRect(), rrect); + }); + + test('PathRef.getRRect elliptical zero x', () { + final SurfacePath path = SurfacePath(); + final RRect rrect = RRect.fromLTRBR(0, 0, 10, 10, const Radius.elliptical(0, 3)); + path.addRRect(rrect); + expect(path.toRoundedRect(), isNull); + expect(path.toRect(), rrect.outerRect); + }); + + test('PathRef.getRRect elliptical zero y', () { + final SurfacePath path = SurfacePath(); + final RRect rrect = RRect.fromLTRBR(0, 0, 10, 10, const Radius.elliptical(3, 0)); + path.addRRect(rrect); + expect(path.toRoundedRect(), isNull); + expect(path.toRect(), rrect.outerRect); + }); + + // This test demonstrates the issue with attempting to reconstruct an RRect + // with imprecision introduced by comparing double values. We should fix this + // by removing the need to reconstruct rrects: + // https://github.com/flutter/flutter/issues/76885 + test('PathRef.getRRect with nearly zero corner', () { + final SurfacePath path = SurfacePath(); + final RRect original = RRect.fromLTRBR(0, 0, 10, 10, const Radius.elliptical(0.00000001, 5)); + path.addRRect(original); + expect(path.toRoundedRect(), original); + }, skip: issue76885Exists); +}