Repository: linebender/resvg (language: rust)

Issue:
context-fill inconsistent with browser rendering
## Test SVG

```svg
<svg width="100mm" height="100mm" viewBox="0 0 100 100" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" >
   <defs>
      <pattern patternUnits="userSpaceOnUse" width="2" height="2" viewBox="0 0 2 2" id="circular-pattern">
         <circle fill="#117611" stroke="none" id="circle-in-pattern" cx="1" cy="1" r="1" />
      </pattern>
      <marker orient="auto" id="test-marker" refX="0" refY="1" markerWidth="10"
         markerHeight="10" viewBox="0 0 2 2" preserveAspectRatio="xMidYMid">
         <rect x="0" y="0" width="2" height="2" fill="context-fill" fill-rule="evenodd" stroke="none" />
      </marker>
   </defs>
   <path fill="url(#circular-pattern)" stroke="#ff0000" stroke-width="1" marker-end="url(#test-marker)" d="M 25,50 H 75" id="test-path" />
</svg>
```

## Output

I'm not sure which rendering is correct.

![context-fill](https://github.com/RazrFalcon/resvg/assets/2784308/9ed09893-2877-418c-87fa-dcd3a26a8b0c)

Please test with Chrome 126.0.6425.0 or above, they just fixed an [issue](https://chromiumdash.appspot.com/commit/9cf8ac20f215f9a9b29089729e9d302ec8fcf930).



Discussion / hints:
This SVG also renders differently in the three engines, so it could be a similar issue.

![marker-hatch](https://github.com/RazrFalcon/resvg/assets/2784308/6bfa1c52-1ac9-4b6d-b228-321cb84b02bf)

Will take a look.
Oh yeah, looks like we don't reverse the viewbox transform of the marker...
Classic SVG. No one was able to figure out what the spec suppose to mean.

librsvg for the reference:
![marker-context-fill-pattern](https://github.com/RazrFalcon/resvg/assets/725494/93eae27e-d5bc-4fbb-aaef-179e60f20e18)

Safari, Inkscape and Batik do not support `context-fill` with pattern at all.

@LaurenzV Which rendering do you think is correct regarding the first test case?
The Chrome one is correct.

Fix patch:
diff --git a/crates/usvg/src/parser/converter.rs b/crates/usvg/src/parser/converter.rs
index a53acd981..a95a59124 100644
--- a/crates/usvg/src/parser/converter.rs
+++ b/crates/usvg/src/parser/converter.rs
@@ -817,7 +817,11 @@ fn convert_path(
 
     let mut marker = None;
     if marker::is_valid(node) && visibility == Visibility::Visible {
-        let mut marker_group = Group::empty();
+        let mut marker_group = Group {
+            abs_transform: parent.abs_transform,
+            ..Group::empty()
+        };
+
         let mut marker_state = state.clone();
 
         let bbox = tiny_skia_path


Test patch:
diff --git a/crates/resvg/tests/integration/render.rs b/crates/resvg/tests/integration/render.rs
index 4220d6625..7d19d937e 100644
--- a/crates/resvg/tests/integration/render.rs
+++ b/crates/resvg/tests/integration/render.rs
@@ -659,6 +659,7 @@ use crate::render;
 #[test] fn painting_context_with_pattern_objectBoundingBox_in_use() { assert_eq!(render("tests/painting/context/with-pattern-objectBoundingBox-in-use"), 0); }
 #[test] fn painting_context_with_pattern_on_marker() { assert_eq!(render("tests/painting/context/with-pattern-on-marker"), 0); }
 #[test] fn painting_context_with_text() { assert_eq!(render("tests/painting/context/with-text"), 0); }
+#[test] fn painting_context_with_viewbox() { assert_eq!(render("tests/painting/context/with-viewbox"), 0); }
 #[test] fn painting_context_without_context_element() { assert_eq!(render("tests/painting/context/without-context-element"), 0); }
 #[test] fn painting_display_bBox_impact() { assert_eq!(render("tests/painting/display/bBox-impact"), 0); }
 #[test] fn painting_display_none_on_clipPath() { assert_eq!(render("tests/painting/display/none-on-clipPath"), 0); }
diff --git a/crates/resvg/tests/tests/painting/context/with-viewbox.png b/crates/resvg/tests/tests/painting/context/with-viewbox.png
new file mode 100644
index 000000000..aa575fd62
Binary files /dev/null and b/crates/resvg/tests/tests/painting/context/with-viewbox.png differ
diff --git a/crates/resvg/tests/tests/painting/context/with-viewbox.svg b/crates/resvg/tests/tests/painting/context/with-viewbox.svg
new file mode 100644
index 000000000..a07f72cea
--- /dev/null
+++ b/crates/resvg/tests/tests/painting/context/with-viewbox.svg
@@ -0,0 +1,18 @@
+<svg id="svg1" viewBox="0 0 100 100" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
+    <title>`context-fill` with viewBox on SVG (SVG 2)</title>
+
+    <pattern id="patt1" patternUnits="userSpaceOnUse" width="20" height="20">
+        <rect id="rect1" x="0" y="0" width="10" height="10" fill="grey"/>
+        <rect id="rect2" x="10" y="10" width="10" height="10" fill="green"/>
+    </pattern>
+
+    <marker id="marker1" refX="10" refY="10" markerWidth="20" markerHeight="20" orient="0.25turn">
+        <path id="path-marker" d="M 10 0 16 20 H 4 Z" fill="context-fill"/>
+    </marker>
+
+    <path id="path1" fill="url(#patt1)" d="M 50 7.5 l 25 80 l -65 -50 l 80 0 l -65 50 Z"
+          marker-start="url(#marker1)" marker-mid="url(#marker1)" marker-end="url(#marker1)"/>
+
+    <!-- image frame -->
+    <rect id="frame" x="0.5" y="0.5" width="99" height="99" fill="none" stroke="black"/>
+</svg>