diff --git a/lib/web_ui/lib/src/engine/html/path_to_svg_clip.dart b/lib/web_ui/lib/src/engine/html/path_to_svg_clip.dart index 24f5fe5eb044e..4bc0bff9c33bb 100644 --- a/lib/web_ui/lib/src/engine/html/path_to_svg_clip.dart +++ b/lib/web_ui/lib/src/engine/html/path_to_svg_clip.dart @@ -51,7 +51,11 @@ SVGSVGElement pathToSvgClipPath(ui.Path path, clipPath.setAttribute('clipPathUnits', 'objectBoundingBox'); svgPath.setAttribute('transform', 'scale($scaleX, $scaleY)'); } - + if (path.fillType == ui.PathFillType.evenOdd) { + svgPath.setAttribute('clip-rule', 'evenodd'); + } else { + svgPath.setAttribute('clip-rule', 'nonzero'); + } svgPath.setAttribute('d', pathToSvg((path as SurfacePath).pathRef, offsetX: offsetX, offsetY: offsetY)); return root; } diff --git a/lib/web_ui/test/html/canvas_clip_path_golden_test.dart b/lib/web_ui/test/html/canvas_clip_path_golden_test.dart index a4643c3a97359..7242600b361e6 100644 --- a/lib/web_ui/test/html/canvas_clip_path_golden_test.dart +++ b/lib/web_ui/test/html/canvas_clip_path_golden_test.dart @@ -119,6 +119,50 @@ Future testMain() async { await canvasScreenshot(rc, 'image_clipped_by_oval_path', region: const Rect.fromLTWH(0, 0, 600, 800)); }); + + test('Clips with fillType evenOdd', () async { + final engine.RecordingCanvas rc = engine.RecordingCanvas(const Rect.fromLTRB(0, 0, 500, 500)); + rc.save(); + const double testWidth = 400; + const double testHeight = 350; + + // draw RGB test image + rc.drawImageRect(createTestImage(), const Rect.fromLTRB(0, 0, testWidth, testHeight), + const Rect.fromLTWH(0, 0, testWidth, testHeight), engine.SurfacePaint()); + + // draw a clipping path with: + // 1) an outside larger rectangle + // 2) a smaller inner rectangle specified by a path + final Path path = Path(); + path.addRect(const Rect.fromLTWH(0, 0, testWidth, testHeight)); + const double left = 25; + const double top = 30; + const double right = 300; + const double bottom = 250; + path + ..moveTo(left, top) + ..lineTo(right,top) + ..lineTo(right,bottom) + ..lineTo(left, bottom) + ..close(); + path.fillType = PathFillType.evenOdd; + rc.clipPath(path); + + // draw an orange paint path of size testWidth and testHeight + final Path paintPath = Path(); + paintPath.addRect(const Rect.fromLTWH(0, 0, testWidth, testHeight)); + paintPath.close(); + rc.drawPath(paintPath, + engine.SurfacePaint() + ..color = const Color(0xFFFF9800) + ..style = PaintingStyle.fill); + rc.restore(); + + // when fillType is set to evenOdd from the clipping path, expect the inner + // rectangle should clip some of the orange painted portion, revealing the RGB testImage + await canvasScreenshot(rc, 'clipPath_uses_fillType_evenOdd', + region: const Rect.fromLTWH(0, 0, 600, 800)); + }); } engine.HtmlImage createTestImage({int width = 200, int height = 150}) {