W3C home > Mailing lists > Public > public-svg-wg@w3.org > January to March 2009

Vector Effects Comments/Suggestions

From: Anthony Grasso <anthony.grasso@cisra.canon.com.au>
Date: Wed, 04 Mar 2009 10:22:01 +1100
Message-ID: <49ADBB99.3070604@cisra.canon.com.au>
To: Chris Lilley <chris@w3.org>
CC: W3C SVG Public Working Group <public-svg-wg@w3.org>
Hi Chris,

Really good work on getting a draft of the Vector effects module done up! The
examples look great!

I've looked over the draft in some detail and have a few comments and questions. 
Sorry for such a long email, but I've tried to make suggestions where possible 
to make things a bit easier.



Rendering a vectorEffect element
--------------------------------
The vector effect section states:
[[
   Alternatively, vector effects can be used as a drawing element; in such case 
its input is considered to be empty (and the vePath element must be used to get 
input data).
]]

Unlike all other declaration elements (filters, patterns, clipPaths, gradients
etc), this sentence seems to be stating that a vectorEffect element can be used 
to produce rendered output directly; that is it can be used as a graphics element.
This is unusual for an SVG element and this is the only reference to its use as
a drawing element. I'm assuming in this case there would be no referencing 
element, so the input path could be invalid or empty, but empty has been specified.

It may be worth adding wording to say an input object must be referenced when
vectorEffects element is in the defs and say what
the case is when it's a drawing element.

There should also be special handling for attributes that require there to be a
referencing element. Is it safe to assume that:
1.  The currentFill, currentStroke, currentFillOpacity and currentStrokeOpacity
properties will use the current fill, stroke, fill-opacity and stroke-opacity as 
resolved for the vectorEffect element when there is no referencing element?

2.  The objectBoundingBox value for vectorEffectUnits will be ignored, and 
userSpaceOnUse will be used instead when there is no referencing element (or the 
bounds could be taken of the empty input path, but that would result in zero 
width/height coordinate space).

Can the vectorEffects element be a valid target for the 'use' element? Though
given the assumptions above it probably should be, but can it be when it's being 
used in the defs element?


Coordinate system and vectorEffectsUnits
----------------------------------------
The vectorEffect element allows for userSpaceOnUse and objectBoundingBox as the
coordinate systems and I think it needs to describe how these behave in a bit 
more detail. All other SVG references explicitly describe the behaviour.
Assuming behaviour is similar to other elements, the spec could be worded to say:
[[
   userSpaceOnUse: Use the current user coordinate system. If the vectorEffect
element is rendered directly, this is the user space in existence at the time 
the vectorEffect element is encountered. If the vectorEffect is referenced via a 
vector-effect attribute, this is the user space in existence on the referencing 
element. Similarly, percentages are resolved against the current viewport.

   objectBoundingBox: Establish a new coordinate system based on the bounds of
the referencing object. If the vectorEffect element is rendered directly there 
is no referencing object; assume this case is invalid and use userSpaceOnUse 
instead (i.e. ignore the vectorEffectUnits when rendering directly, and always 
use userSpaceOnUse).
]]

There are no units specified for the children of the vectorEffect, which is
similar to the clipPath element (unlike filters, masks, and patterns etc which 
have units for the children) or should there be? I guess this is ok as it is.


objectBoundingBox units and vePathRef
-------------------------------------
The vector effect module states that the 'SourcePath' is transformed to be in
the correct coordinate space based on the vectorEffectUnits. The vePathRef 
allows access to other path definitions to be used by the vectorEffect, but the 
specification does not mention the coordinate space to apply to these paths.

I assume that no additional transforms are applied to the paths referenced by
vePathRef, and they are interpreted in the user space established by the 
vectorEffectUnits (after any additional transformations applied by a transform 
attribute on the referenced path itself)?


Common vector effect primitive attributes
-----------------------------------------
The section I didn't quite understand because it contradicts almost every schema
definition in the vector effects module when it states that the following 
attributes are common to all of the vector effect primitives: 'in', 'in2', 
'result', 'transform' and 'transformPath'. For example, the 'in2' property 
doesn't apply to all vector effect primitives or does it?

I guess later on the spec will need to define which attributes apply to which
primitives.


The empty vectorEffect
----------------------
An empty vectorEffect is defined as:

<vectorEffect/>

The spec states that no rendering is performed, but does not indicate if the
final path is available. I guess it would be useful if an empty vector effect 
returns an initial input path 'in' as the final output path so it is available 
for textPath, clipPath, vePathRef and text flow, but the path itself is not be 
rendered.


The default vectorEffect
------------------------
The default vector effect is declared as:

<vectorEffect>
   <veFill/>
   <veStroke/>
   <veMarker/>
</vectorEffect>

According to the specification this will produce the default SVG rendering
behaviour. I think this has several problems:
1.  The veStroke uses fill and fill-opacity to do the stroking, but the spec
doesn't actually say that fill and stroke are initialised to the source stroke 
and stroke-opacity.

2.  There is no mention of how other stroke properties such as dash-array etc 
are set.

3.  The veMarker doesn't have any mention of where or how the marker properties 
are set.


Suggestions for each point:
1.  The fill and fill-opacity properties have different behaviour on veStroke
and are initialised to currentStroke and currentStrokeOpacity if no other values 
have been set.

2.  The other veStroke stroking properties inherit from the referencing object
if no other values have been set. Another solution would be to have 
currentDashArray etc.

3.  The veMarker inherits marker properties from the referencing object if no
other properties have been set. Another solution would be that 
currentMarkerStart, currentMarkerMid and currentMarkerEnd could be created to be 
in keeping with the stroke and fill properties.


Inheritance
-----------
The vector effects module doesn't state how inheritance is handled. There is a
brief mention on the veStroke element that stroking is done "taking into account 
the stroke properties on the source element". If it is assumed that properties 
inherit via the referencing element this will allow most of the "default" vector 
effect properties to work (though it does allow the vectorEffect element to 
potentially override values).

As a suggestion could we say that the properties inherit from the element
referencing the vectorEffect element; or if being rendered directly so there is 
no referencing element, properties inherit from the ancestors of the 
vectorEffect element. It should also be noted that this is different to other 
similar elements such as filters, clips etc where inheritance would normally be 
stated as: Properties inherit into the vectorEffect element from its ancestors; 
properties do not inherit from the element referencing the vectorEffect element. 
This is not done for vector effects.


Stroking and path outline construction
--------------------------------------
At some point the vector effects module will need to describe how to implement
stroking or how to construct the path segment outline of logical path 
operations. Currently this is an issue for some primitives that are dependent on 
the path segment construction of the final paths.
For instance:
1.  The path may or may not be flattened. If flattened, different error
tolerances may have been used, resulting in a different number and position of 
path segments. If not flattened, different path segments may have been used when 
replacing intersections in path outlines or when stroking. Also Bezier envelope 
calculations may have been approximated with simpler curves. This affects any 
veSetback operations applied to the shape as they break the path into segments.

2.  The direction of the path outline might be clockwise or anti-clockwise. This
affects any textPath operations (direction and normal vector calculations), any 
dashing operations (direction), and any marker operations (normal vector 
calculations).

3.  The stroked path may or may not be an outline. The stroke may consist only
of the points in the outline, or it may consist of rectangles and other 
overlapping shapes for the joins and end caps to be painted with a non-zero 
winding rule. In other cases the stroke may almost be an outline, but it has not 
handled self-intersecting lines, so later parts of the line overlap earlier 
parts of the line (again relying on the fill rule to correctly handle filling 
the path).

Given that path handling and construction may be dependant on capabilities of
underlying rendering libraries should the sepcification state that the user 
should be warned about inconsistent results between user agents, or the methods 
should be properly specified?

Sorry I don't have any quick fixes for the above issues :(


Path outline of unclosed paths
------------------------------
At some point the specification will need to describe how to produce the outline
of a line (an unclosed path) in the result of a logically combined path. The two 
most likely options I can think of are:
a.  The line remains a simple line. Not sure how of if this will work.

b.  The line is changed to a closed path; that is, the line will trace back over
itself to form a complete path with zero width. This fits better with the 
description of an 'outline', which implies a closed path solution.

This will affect various functions such as markers, textPath, stroking, dashing
and veSetback as it will determine whether the routines will retrace the line 
backward using normals in the opposite direction.


vePathRef
---------
The vePathRef element is used to reference paths to be combined by vePath. I
think the specification should describe how various properties on the referenced 
path are treated. Below are some suggestions about various properties.

clip-path: If the referenced path has a clip-path, that this is applied to the
path before it is returned to vePathRef. The clip-path will be interpreted in 
the user space established by the vectorEffect element.

transform: If the referenced path has a transform, that this is applied to the
path before returning the path to vePathRef.

vector-effect: The vector-effect property is applied before any other
compositing operators (clip, masking, etc), so assume that if the referenced 
paths has a vector-effect property that this is applied before returning the 
path to vePathRef. I assume that if the vector-effect on the path contains any
veStroke, veFill or veMarker primitives that these are not evaluated again as 
only the resultant path is required?

marker: Any marker-start/mid/end are not applied, so the paths from the markers
are not included. I guess doing the opposite is also possible but probably more 
complicated. Not sure which is more useful though.


vePathRef and text
------------------
If the vePathRef is used to reference text, this has the same issues as the
clipPath element, namely that SVG glyphs can contain
arbitrary SVG markup, but vePathRef can only deal with paths.
Some suggestions to handle this case:
1.  If the referenced text has text-decoration applied, the paths of the
underline/overline/strike-through are not included.

2.  If the glyphs are for bitmap text, the glyphs are ignored.

3.  If the glyphs are SVG glyphs with complex children then any elements
involving bitmap data are ignored: So, there will be no masking, filters, images 
or compositing applied.

Note: Another possible solution would be for any or all of the above to simply
result in an error if they were encountered.


veSetback offset values
-----------------------
The veSetback element I think will need to describe a number of situations
with offset values. The veSetback element allows two types of offsets values to set:
1.  Sub-path start/end offsets: These are applied to the start/end of each sub-path.

2.  Internal start/end offsets: These are applied to segments internal to each
sub-path.

The operation of veSetback is described as:
Breaks the path into individual segments and shortens both ends of every segment
by the distance specified by setback-offset
I assume when applying offset values:
1.  Any offset value can extend until they reach an operation applied by another
offset value. So, if no internal offsets have been specified, the sub-path 
start/end offsets may extend over more than a single segment. Another reasonable 
behaviour could be that all start/end offsets are limited to the smallest 
segment, though this seems an unnecessary limitation for the sub-path start/end 
offsets.

2.  If reducing the segment length by the start/end offsets results in a segment
having a negative length, then the length will be clamped to zero (making it the 
equivalent to replacing the segment with a moveto command). This point could be 
calculated based on: point_offset = segment_length * start_offset / 
(start_offset + end_offset) to give a weighted position to the point (as 
choosing the start/end/mid point seems a bit too arbitrary).
    Other reasonable behaviours for the negative length could be: generate an 
error; draw the segment backwards (change of path direction); or completely 
remove the segment. I don't really have an opinion about either solution.

3.  Negative offset values are invalid and will result in an error (so offsets
can't extend the path).

4.  Zero offset values are effectively ignored. This means that specifying a
zero offset for the internal offsets would not cause separate sub-paths to be 
formed.

Another reasonable behaviour would be that a zero offset caused the internal
segments to be broken into separate sub-paths, via replacing the initial lineto 
of each segment with a moveto command).


clipout and fill operations
---------------------------
The "individual fill operations" mentioned in the clipout property will need to
be explained futher at some point.

Do you think "individual fill operation" should refer to veStroke, veFill and
veMarker in their entirety, and not refer to the individual fill operations that 
make up each of these elements?

When clipout is set to 'clip', the veFill is executed, then the entire path
for the veFill is selected as a clip before the next operation, and so on.


vector-effect applicability
---------------------------
The vector-effect property states that it can be applied to graphic objects, but
elsewhere this is limited to paths and basic shapes. Is it reasonable to say 
that the vector-effect property applies only to paths and basic shapes; so it 
cannot be applied to graphics objects such as text, or used to modify the 
outlines of images or video, or applied to another vectorEffect element etc?


Vector effects and basic shapes
-------------------------------
All path based vector effects (veJoin, veSetback, veReverse) are described in
terms of path operations on moveto, and lineto commands etc. Basic shapes of 
course are described using their control points, not SVG path commands. Do you 
think the specification should clarify if shapes become some reasonable
path approximation as though they were path commands? Or do they remain as 
shapes - if so, how should this work?

If shapes are broken up into path commends the direction of the paths around the
basic shapes could be clockwise in the current user space. Any thoughts?


in, in2 and result
------------------
Each vector effect primitive can specify a result name to store its resultant
path in, and each primitive can also specify one or more names to use as input. 
The specification states that the name 'SourcePath' when used by 'in' or 'in2' 
will refer to the input path, and any other string refers to a primitive node.
I have some suggestions for these inputs:
1.  If 'SourcePath' is specified as the result string for a primitive, this
mapping will be ignored. Other alternatives that are an error could be 
generated, or possibly that SourcePath could be replaced (any thoughts)

2.  If in or in2 refer to primitives that do not exist then the vectorEffect
will be in error.

3.  If in or in2 refer to their own output or a primitive that occurs later then
the vectorEffect will be in error(i.e. no forward referencing or recursive 
referencing).

4.  A vectorEffect in error will be handled as other errors; halt and catch
fire... :P I guess this is up to the host language?


Path length
-----------
Operations such as veSetback and dashing in veStrokePath or veStroke can specify
lengths to use as distances along the current path. The interpretation of these 
lengths is dependent on the user agent's calculation of the path length; as a 
result I think there is potential to have inconsistent results. Do you think 
that these elements should be able to specify a pathLength which can be used to 
adjust the user agent's calculation of the path length (same as the pathLength 
property on the path element)?


Anti-aliasing and clipout
--------------------------
If clipout is set to ‘clip', the description of the algorithm states:
[[
   The value "clip" means that painting operations should be processed last to
first and after every painting operation a clipping should be applied that 
excludes (clips out) the path just painted from the paintable region.
]]

Should this take into account any anti-aliasing that is commonly done along the
edges of the rendered path segments? I guess this is fine for render engines 
with no anti-aliasing, but I suspect will produce edge artefacts in render 
engines that do support anti-aliasing.


General vector effect spec enhancements
---------------------------------------
  - The description for the clipout property will need more wording, as it tends
to imply that the overall effect of ‘clip' is that regions just painted won't be 
painted over. Do you think this should be reworded to indicate that the effect 
of the last operation is that - regions won't be painted over when rendering in
reverse, but the overall effect is that each painted region is completely 
replaced by later paint operations when rendering forward (i.e. it's describing 
a knock-out group operation). Note, this is also me assuming that I've read the 
specification correctly.

  - The vectorEffect mentions that it can be used as a drawing element. Given
that it is completely different behaviour to all similar containers such as 
clipPath, filter, it may be worth stating what effect display/visibility has on 
any of the vector effect elements (with regards to returning a path and 
execution of veFill etc).

  -  The vector effect description refers to ‘primitive shapes', but I don't
think there is such things in SVG. Would it be possible to replace this with 
‘basic shapes', which is a defined list of shapes and consistent with other SVG 
specs?

  - Some of the examples use 'color' for setting the colour - should it be
'fill-color'?

  - The vector-effect attribute has the value 'non-scaling-stroke'. This is
being really picky but most other SVG defined values (e.g. for vectorEffectUnits 
attribute) are defined in camelCase. Should 'non-scaling-stroke' be changed to 
'nonScalingStroke'? Although I guess this can't be changed given that SVG Tiny 
1.2 defines the value 'non-scaling-stroke'. Perhaps this module could use "-" 
property names like CSS instead of camelCase? I don't really have an opinion 
either way.




Hope you found the comments useful. If you need any clarifications or want a 
hand with spec changes please let me know.

Regards,

Anthony
Received on Tuesday, 3 March 2009 23:22:52 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Tuesday, 3 March 2009 23:22:54 GMT