Page MenuHomePhabricator

librsvg does not default x1, y1, x2, y2 correctly for userSpaceOnUse
Open, Needs TriagePublicBUG REPORT

Description

Steps to replicate the issue (include links if applicable):

<linearGradient id="lgback" gradientUnits="userSpaceOnUse">
      <stop offset="0%" stop-color="white" />
      <stop offset="100%" stop-color="red" />
</linearGradient>
<rect width="100%" height="100%" fill="url(#lgback)" />
<linearGradient id="lgback" gradientUnits="userSpaceOnUse" x1="0%" x2="100%" y1="0%" y2="0%">
      <stop offset="0%" stop-color="white" />
      <stop offset="100%" stop-color="red" />
</linearGradient>

What happens?:
The rectangle displayed solid red rather than a gradient.

What should have happened instead?:
The SVG 1.1 specification says that x1, y1, x2, and y2 default to those values.
See https://www.w3.org/Graphics/SVG/1.1/pservers.html#LinearGradients

A white-to-red gradient should have displayed.

Since red showed, some gradient information was recognized.
It is possible that x1 defaulted to 0 and x2 defaulted to 1 (factors that work for objectBoundingBox).

Software version (skip for WMF-hosted wikis like Wikipedia):

Other information (browser name/version, screenshots, etc.):

Event Timeline

Glrx renamed this task from librsvg x, y, width, height not defaulted for userSpaceOnUse to librsvg does not default x1, y1, x2, y2 correctly for userSpaceOnUse.Sep 2 2022, 8:54 PM

Consider relation to radialGradient in T193942 and T143086.

Apparently not a default value issue.

Downloaded https://upload.wikimedia.org/wikipedia/commons/archive/b/bd/20220902193021%21Test.svg and replaced
<linearGradient id="lgback" gradientUnits="userSpaceOnUse" x1="0%" x2="100%" y1="0%" y2="0%">
with
<linearGradient id="lgback" gradientUnits="userSpaceOnUse">

The rectangle displays a gradient and no solid red locally in librsvg2-2.52.9. So I assume this got fixed at some point in upstream?

Downloaded https://upload.wikimedia.org/wikipedia/commons/archive/b/bd/20220902193021%21Test.svg and replaced
<linearGradient id="lgback" gradientUnits="userSpaceOnUse" x1="0%" x2="100%" y1="0%" y2="0%">
with
<linearGradient id="lgback" gradientUnits="userSpaceOnUse">

The rectangle displays a gradient and no solid red locally in librsvg2-2.52.9. So I assume this got fixed at some point in upstream?

I'll presume you copied the SVG at https://commons.wikimedia.org/wiki/File:SVG_Test_dim_filter_mask.svg (which has explicit x1, x2, y1, y2 values) rather than from https://upload.wikimedia.org/wikipedia/commons/archive/b/bd/20220902193021%21Test.svg (which does not specify the value).

The test is painting a gradient over the same gradient; the intention is to cover a horizontal dimension line, so the text should not have a line through it. The fourth group from the top should look like the fifth group from the top.

I had manually removed the values. However checking again with librsvg2-2.54.5, the results locally differ per zoom level which is super confusing.

Screenshot from 2022-10-11 06-23-41.png (310×480 px, 15 KB)

Screenshot from 2022-10-11 06-23-52.png (607×851 px, 64 KB)

Screenshot from 2022-10-11 06-24-01.png (773×1 px, 92 KB)

@Aklapper

I presume you are using --zoom

I'll assume that the first PNG is less than 1, the second PNG is 1, and the third zoom is greater than 1.

It looks like the filter's default values of 0 and 100% are confused by the zoom level. I suspect that the filter code processes the gradient with percentage values set to the unzoomed width/height of the image.

Say the native width is 800 px.
There is a gradient fill that goes from 0% to 100%. That should be from 0 to 800 pixels when the zoom is 1. White is at 0 and Red is at 800.

The filter is applied to centered text at x=400; assume the text goes from x=300 to 500 pixels.
The filter then applies the 0 to 800 gradient and gets the correct fill.

For a zoom of 0.5, the image width will be 0 to 400 pixels.
If the filter accesses the gradient ignoring zoom, then the gradient still runs from 0 to 800 pixels (i.e., not scaled by the zoom), then the fill will use the left half (150 to 250 pix) of the 800-wide fill and be much lighter.

For a zoom of 2.0, the image width will be 0 to 1600 pixel.
If the filter believes the gradient still runs from 0 to 800 pixels, then the fill will sample from 600 to 1000px. That will be redder and saturate to red at the center of the text.