jsvg icon indicating copy to clipboard operation
jsvg copied to clipboard

The SVG 'style' attribute parsing is not CSS standard compliant

Open dhendriks opened this issue 2 months ago • 1 comments

The AttributeNode.preprocessAttributes method has the following code:

    private static void preprocessAttributes(@NotNull Map<String, String> attributes,
            @NotNull Map<String, String> styleAttributes) {
        String styleStr = attributes.get("style");
        if (styleStr != null && !isBlank(styleStr)) {
            String[] styles = styleStr.split(";");
            for (String style : styles) {
                if (isBlank(style)) continue;
                String[] styleDef = style.split(":", 2);
                styleAttributes.put(styleDef[0].trim().toLowerCase(Locale.ENGLISH), styleDef[1].trim());
            }
        }
    }

It parses the style attribute by splitting on ; and then :. This is not CSS standard compliant, as it doesn't consider comments, quoted strings, etc. It should be parsed like a declaration in a style sheet, according to the standard: https://www.w3.org/TR/css-style-attr/.

dhendriks avatar Oct 22 '25 06:10 dhendriks

Good catch. There already is a (slightly) better CSS parser implemented, which should be used here. Although the CSS parser is still far from being standard compliant e.g. it always assumes that declarations are valid, or #143.

I am very happy to merge improvements to the CSS parser implementation.

weisJ avatar Oct 22 '25 11:10 weisJ

I have two similar findings:

  1. when referencing to defined gradients. e.g.
<defs id="defs9">
  <linearGradient id="linearGradient20" inkscape:collect="always">
    <stop id="stop16" offset="0" style="stop-color:#00ace7;stop-opacity:1;" />
    <stop id="stop18" offset="1" style="stop-color:#27cafd;stop-opacity:1;"/>
  </linearGradient>
  <linearGradient gradientUnits="userSpaceOnUse" y2="19.696302" x2="33.616657" y1="41.445858" x1="33.474358" id="linearGradient22" xlink:href="#linearGradient20" inkscape:collect="always"/>
</defs>

<g transform="matrix(0.967767,0,0,0.967767,-16.852218,-14.07372)" id="icn_Refresh_hv">
        <path
                style="fill-opacity:1;fill:url(#linearGradient22)"
                id="path2"
                d="m 35.334,28.475 5.28,-3.386 c 0.609,-0.601 0.609,-1.207 0,-1.809 l -5.28,-3.386 c -0.165,-0.117 -0.37,-0.185 -0.591,-0.185 -0.554,0 -0.998,0.425 -0.998,0.95 v 1.764 c -5.311,0.014 -9.615,4.261 -9.615,9.499 0,5.247 4.317,9.499 9.638,9.499 4.941,0 9.012,-3.659 9.575,-8.373 0.004,-0.013 0.018,-0.158 0.018,-0.221 0,-0.498 -0.412,-0.905 -0.92,-0.905 L 40,32 c -0.356,0 -0.504,0.621 -0.593,1.138 -0.506,2.766 -2.844,4.852 -5.652,4.852 -3.178,0 -5.751,-2.679 -5.751,-5.99 0,-3.3 2.557,-5.973 5.725,-5.989 l 0.016,1.7 c 0,0.524 0.444,0.949 0.998,0.949 0.221,0 0.426,-0.067 0.591,-0.185 z"/>
    </g>

2025-11-07 16:50:49,272 WARN [AWT-EventQueue-0] unknown.jul.logger:88 - Expected 'RAW_DATA' but got 'Token{type=IDENTIFIER, data='url'}'

  1. when having colors (same example from above). If you start the color with a digit:

2025-11-07 16:48:28,433 WARN [AWT-EventQueue-0] unknown.jul.logger:88 - Identifier starting with unexpected char '7'

if you start it with a letter

2025-11-07 16:50:49,271 WARN [AWT-EventQueue-0] unknown.jul.logger:88 - Expected 'RAW_DATA' but got 'Token{type=ID_NAME, data='de01fd'}'

mlaggner avatar Nov 07 '25 16:11 mlaggner

I suppose this is with the snapshot version?

weisJ avatar Nov 09 '25 20:11 weisJ

I tried this with the snapshot

mlaggner avatar Nov 10 '25 06:11 mlaggner

Indeed the snapshot version contained a non-finished version of CSS parser usage with inline style attributes. Latest snapshot should be good now.

weisJ avatar Nov 16 '25 21:11 weisJ