W3C home > Mailing lists > Public > www-svg@w3.org > January 2010

Re: Minutes, January 18 2010 SVG WG telcon - gradient issue

From: Ken Stacey <ken@svgmaker.com>
Date: Wed, 20 Jan 2010 19:32:07 +1000
Message-ID: <4B56CD97.5070903@svgmaker.com>
To: www-svg@w3.org
On 19/01/2010 7:08 AM, Erik Dahlstrom wrote:
> update on the gradient issue (www-svg)
> 
>    AG: asv and inkscape do the same thing
>    ... same as firefox
> 
>    DS/CL: seems like the path of least resistence then
> 
>    CL: different from opera?
> 
>    ED: yes
> 
>    CL: can you get everything you want by one way or the other?
> 
>    AG: you can get the same result using any of these methods, by
>    specifying different values
>    ... mostly a question of what looks best when squished/transformed
>    ... technically both ways are correct
>    ... don't have a preference

First, a quick description of the two methods when applied with 
userSpaceOnUse.

A. Gradient normal is perpendicular to the gradient vector in current 
user space.

B. Gradient normal is perpendicular to the gradient vector in viewport 
space.

This is a case for method A.

The spec does go some way towards defining the gradient normal.  At
least for objectBoundingBox:

http://www.w3.org/TR/SVG11/pservers.html#LinearGradients
"""
When gradientUnits="objectBoundingBox"  and gradientTransform is the
identity matrix, the stripes of the linear gradient are perpendicular to
the gradient vector in object bounding box space (i.e., the abstract
coordinate system where (0,0) is at the top/left of the object bounding
box and (1,1) is at the bottom/right of the object bounding box). When
the object's bounding box is not square, the stripes that are
conceptually perpendicular to the gradient vector within object bounding
box space will render non-perpendicular relative to the gradient vector
in user space due to application of the non-uniform scaling
transformation from bounding box space to user space.
"""

Since the stripes are transformed by the the application of the 
non-uniform scaling transformation from bounding box space to user 
space, you would expect the CTM to further transform the stripes.  A 
reasonable conclusion, or ambigious?

Although unstated for userSpaceOnUse, I would expect the stripes of the 
linear gradient for these gradientUnits to be similarly defined - to be 
"perpendicular to the gradient vector in user space" and make the same 
conclusion that the CTM further transforms the stripes.  Reasonable, or not?

gradientTransform says:
"""
gradientTransform = "<transform-list>"
Contains the definition of an optional additional transformation from 
the gradient coordinate system onto the target coordinate system (i.e., 
userSpaceOnUse or objectBoundingBox). This allows for things such as 
skewing the gradient. This additional transformation matrix is 
post-multiplied to (i.e., inserted to the right of) any previously 
defined transformations, including the implicit transformation necessary 
to convert from object bounding box units to user space.
If attribute gradientTransform is not specified, then the effect is as 
if an identity transform were specified.
"""

What is the gradient coordinate system?  Not defined anywhere. But 
whatever it is, it does appear to be in place prior to any transforms 
are applied (for both userSpaceOnUse and objectBoundingBox).

I would think that the gradient coordinate system x axis is defined by 
the gradient vector, and the y axis is defined by the gradient normal at 
this time.  That fits with method A thinking.

I take the gradientTransform definition as saying:

[viewport x y] = CTM . GTM . [gradientTransform] . [gradient x y]

where, CTM accumulates all transformations on the referencing element 
and GTM is the gradient space to user space transformation.

For an identity gradientTransform,

[viewport x y] = CTM . GTM . [gradient x y]

Consistent with how every graphic element behaves when transformed.


How would you apply a gradientTransform with method B?  There is only a 
one dimensional coordinate space defined at the time of application. 
Only after all transformations have been applied, a "y" axis appears. 
Not consistent in my view.

> 
>    ED: personally I prefer using objectBoundingBox units, since that's
>    more reusable
>    ... the issue only affects userspaceonuse gradients, right?

I think that they should be conceptually the same.  Differing only in 
the transformation from object bounding box space to user space.

> 
>    AG: will email the list with the results, completing my action

Below is a test case for comparison between implementations and applies 
transformations to two simple linearGradients.  A horizontal gradient 
vector and a diagonal gradient vector.  The gradient vectors are shown 
by the magenta lines.  The gradient normal* is shown by yellow lines.

*For the objectBoundingBox case these lines follow the spec description 
quoted above - perpendicular in object bounding box space.  For 
userSpaceOnUse I have assumed the gradient normal is perpendicular in 
user space.

I hope this helps the discussion.

Ken

<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1100 800"
      xmlns:xlink="http://www.w3.org/1999/xlink">
   <defs>
     <linearGradient id="usou1" x1="0" y1="50" x2="200" y2="50" 
gradientUnits="userSpaceOnUse">
       <stop offset="0" stop-color="red"/>
       <stop offset="0.5" stop-color="green"/>
       <stop offset="1.0" stop-color="blue"/>
     </linearGradient>
     <linearGradient id="usou2" x1="0" y1="0" x2="200" y2="100" 
gradientUnits="userSpaceOnUse">
       <stop offset="0" stop-color="red"/>
       <stop offset="0.5" stop-color="green"/>
       <stop offset="1.0" stop-color="blue"/>
     </linearGradient>
     <linearGradient id="obb1" x1="0" y1="0.5" x2="1" y2="0.5" 
gradientUnits="objectBoundingBox">
       <stop offset="0" stop-color="red"/>
       <stop offset="0.5" stop-color="green"/>
       <stop offset="1.0" stop-color="blue"/>
     </linearGradient>
     <linearGradient id="obb2" x1="0" y1="0" x2="1" y2="1" 
gradientUnits="objectBoundingBox">
       <stop offset="0" stop-color="red"/>
       <stop offset="0.5" stop-color="green"/>
       <stop offset="1.0" stop-color="blue"/>
     </linearGradient>
     <g id="r1">
       <rect width="200" height="100" />
       <line x1="0" y1="50" x2="200" y2="50" stroke="magenta" 
stroke-width="2"/>
       <line x1="100" y1="0" x2="100" y2="100" stroke="yellow" 
stroke-width="2"/>
     </g>
     <g id="r3">
       <rect width="200" height="100" />
       <line x1="0" y1="0" x2="200" y2="100" stroke="magenta" 
stroke-width="2"/>
       <line x1="-100" y1="-50" x2="100" y2="50" stroke="yellow" 
stroke-width="2" transform="matrix(0,-1,1,0,100,50)"/>
     </g>
     <g id="r4">
       <rect width="200" height="100" />
       <line x1="0" y1="0" x2="200" y2="100" stroke="magenta" 
stroke-width="2"/>
       <line x1="0" y1="100" x2="200" y2="0" stroke="yellow" 
stroke-width="2"/>
     </g>
     <text id="tusou" font-family="Arial" fill="black" font-size="20" 
x="750" y="50">userSpaceOnUse</text>
     <text id="tobb" font-family="Arial" fill="black" font-size="20" 
x="750" y="50">objectBoundingBox</text>
   </defs>
   <text font-family="Arial" fill="black" font-size="20"  y="50"><tspan 
x="100">No transform</tspan><tspan x="350">scale(0.5,1)</tspan><tspan 
x="500">matrix(1,0.25,0.5,1,x,y)</tspan></text>
   <g transform="translate(100,100)" fill="url(#usou1)">
    <use xlink:href="#r1" />
    <use xlink:href="#r1" transform="matrix(0.5,0,0,1,250,0)"/>
    <use xlink:href="#r1" transform="matrix(1,0.25,0.5,1,400,0)"/>
    <use xlink:href="#tusou"/>
   </g>
   <g transform="translate(100,250)" fill="url(#obb1)">
    <use xlink:href="#r1" />
    <use xlink:href="#r1" transform="matrix(0.5,0,0,1,250,0)"/>
    <use xlink:href="#r1" transform="matrix(1,0.25,0.5,1,400,0)"/>
    <use xlink:href="#tobb"/>
   </g>
   <g transform="translate(100,450)" fill="url(#usou2)">
    <use xlink:href="#r3" />
    <use xlink:href="#r3" transform="matrix(0.5,0,0,1,250,0)"/>
    <use xlink:href="#r3" transform="matrix(1,0.25,0.5,1,400,0)"/>
    <use xlink:href="#tusou"/>
   </g>
   <g transform="translate(100,600)" fill="url(#obb2)">
    <use xlink:href="#r4" />
    <use xlink:href="#r4" transform="matrix(0.5,0,0,1,250,0)"/>
    <use xlink:href="#r4" transform="matrix(1,0.25,0.5,1,400,0)"/>
    <use xlink:href="#tobb"/>
   </g>
</svg>
Received on Wednesday, 20 January 2010 09:32:40 GMT

This archive was generated by hypermail 2.3.1 : Friday, 8 March 2013 15:54:44 GMT