Google taking the SMIL out of SVG.

Google has recently announced their intention to drop SMIL support in Blink, the rendering engine for Chrome. SMIL is a way to animate SVG’s in a declarative way. Google’s argument is that SMIL animation has not become hugely popular and that Web Animations will provide the same functionality. As a result of this announcement, the SVG working group decided to move SMIL from SVG 2 and into its own specification. One could say that SMIL is on life support at the moment.

SMIL’s lack of use is most likely due to its lack of support in IE. Microsoft has declared they will not implement SMIL in IE but they have hinted in the past that they are open to a native JS implementation built on top of Web Animations.

So why would losing SMIL be a great loss?

  1. SMIL declarative animations are easier to write compared to JavaScript or CSS/Web Animations.
  2. SMIL animations are in general more performant.
  3. With SMIL animations one can independently animate different attributes and properties.
  4. JavaScript is not allowed to run inside SVGs in many situations due to security issues so it is not a viable alternative in many cases.
  5. Web Animations don’t replace all the functionality of SMIL. For example, one cannot animate attributes including paths. In particular you won’t be able to do this:
Morphing Batman logos.

A variety of Batman logos, animated with SMIL.

Ironically, YouTube is planning on using SMIL to animate buttons.

As usual, if you are reading this in a blog aggregator and the images don’t display correctly, try viewing on my blog website. Aggregators don’t play well with SVG.

(For more on animating paths, see my blog post on path animations.)

You can read about Google’s intention and the debate that is going at the chromium.org Google group. If you use SMIL or plan to, let Google know that it is important to you.


A figure just to have a nice image in Google+ (which doesn’t do SVG… another reason to frown):

Frown face.

Paths: Stroking and Offsetting

Path stroking and offsetting are two intertwined topics; stroking is often implemented by path offsetting. This post explores some of the problems encountered with these path operations.

Stroking: It’s not as easy as it looks.

What could be easier that stroking a path? It’s a fundamental concept in all graphics libraries. You construct a path:

in PostScript:

newpath
100 100 moveto
150 100 lineto
10 setlinewidth
stroke

in SVG:

<path d="M 100,100 150,100" stroke-width="10"/>

and voila, you have a horizontal path, 50 pixels long, that is 10 pixels wide.

Hmm, if only it were that easy. It turns out that stroking an arbitrary path can be quite complicated. Different graphics libraries can give quite different results.

A simple Bezier path segment with high curvature at one end.

A Bezier path segment with high curvature at the end. Web browsers differ on the rendering. (SVG)

Firefox's rendering of the circle. It appears solid.
Chome's rendering of the circle. It appears like a donut.

Rendering of above path: Firefox (left/top), Chrome (right/bottom). (PNG)

There are two different ways to stroke a path. The first method is to pass a line segment of length ‘stroke-width’, centered on and perpendicular to the path, from one end to the other. Any pixels the line crosses are part of the stroke. This seems to be what Firefox does. (An equivalent method is to pass a circle of diameter ‘stroke-width’ centered on the path and then clip the semi-circles at the ends.) The second method is to construct two paths, offset by half the ‘stroke-width’ on each side of the original path and then fill the area between the two paths. This seems to be what Chrome does.

A simple Bezier path segment with high curvature at one end.

A Bezier path segment with high curvature at the end. Stroke constructed by offsetting path. Red: original path, blue: offset paths. (SVG)

Rendering engines appear to fall into one of these two camps:

Sweep a line:
Firefox, Adobe Reader
Offset paths:
Chrome, Inkscape (Cairo), Opera (Presto), Evince, Batik, rsvg

The difference can be also be seen in circular paths.

Two circular paths with strokes of different widths.

Two same size circular paths with different stroke widths. When one-half the stroke width exceeds the circle radius (right circle), web browsers differ in their rendering. (SVG)

Firefox's rendering of the circle. It appears solid.
Chome's rendering of the circle. It appears like a doughnut.

Rendering of a circular path when one-half the stroke width is greater than the radius in: Firefox (left/top), Chrome (right/bottom). (PNG)

When using the Offset paths method, an inner path is always created. As the direction of this path is the same regardless of the stroke width, one cannot differentiate between the case where the stroke width is less than one-half the radius and the case where it is not. This can be seen in the animation below:

Two circular paths with strokes of different widths. The drawing of the stroke is animated.

Stroking the path. The arrows indicate the direction of the offset paths. If the drawing is not animated, view the image by itself. (SVG)

Interestingly, some renderers draw a filled circle when one-half the ‘stroke-width’ is greater than the radius for an SVG <circle> (i.e. not a circular <path>) while others still draw a doughnut. However, for the SVG <rect> element, the rectangles are always drawn filled if the ‘stroke-width’ is greater than either the ‘width’ or ‘height’ (at least in the renderers I tested).

So what does the SVG specification say about how to stroke a path? Nothing…! One can look to PostScript and PDF on which SVG is partially based for a hint on what it should say. The PostScript and PDF specifications say the same thing. From the PDF 1.7 reference:

The S operator paints a line along the current
path. The stroked line follows each straight or curved segment
in the path, centered on the segment with sides parallel to
it. Each of the path’s subpaths is treated separately…

This seems to indicate that the sweeping the line technique is what is expected and indeed, Adobe’s own product, Adobe Reader, appears to do just that.

Stroke Alignment

Designers often want more control over how a stroke is positioned: only on the inside, only on the outside, or some arbitrary ratio of the two. The new SVG ‘stroke-alignment‘ property offers this control. For a closed path, it is relatively easy to figure out how this property should behave:

A figure eight path showing various methods for offsetting.

Top: the original path. Middle: left: stroke inside; right: stroke outside. Bottom: left: stroke to left; right: stroke to right.

For an open path, it is not quite so easy. What is inside, what is outside? One can define the terms by looking at what is filled: inside is in the fill, outside is not in the fill. With this definition, a single straight line segment would render nothing for an ‘inside’ stroke and a stroke on both sides for an ‘outside’ stroke. The SVG specification has a slightly different definition for ‘outside’ (see figure). For an open path it may make more sense to talk about left/right rather than inside/outside.

A figure eight path showing various methods for offsetting.

Top to bottom: Default stroke. Fill area (in gray). Inside (according to SVG specification?). Outside (implemented here by masking). Inside (another interpretation). Outside (according to SVG specification?). Stroke on left (round end cap in pink).

Handling line joins is fairly straight forward. End caps, at least ’round’ ones, are another matter. Does one draw half an end cap? Or does the radius of the end cap match the width of the (shifted) stroke?

Left: straight lines, right: curved lines.

Round end caps. Top to bottom: Default stroke. Stroke alignment ‘outside’, end-cap radius doubled. Stroke alignment ‘outside’, end-cap radius same as normal.

The ‘stroke-alignment’ property was recently removed from the SVG 2 specification draft and moved into a separate SVG Strokes module, partly due to the difficulty in specifying exactly how it should behave.

The ‘stroke-alignment’ ‘inside’/’outside’ values can be simulated via other methods. The new ‘paint-order‘ property allows one to paint the stroke before the fill and thus simulating stroking only the outside of the path (this only works for opaque fill). A mask can also be used to simulate stroking the outside of path. A clip path can be used to simulate stroking the inside of a path.

Offset Paths

We’ve seen that offsetting a path can be used for constructing strokes. What about offsetting a path for the purpose of creating a new path? This is quite useful in mapping. For example you might want to show multiple bus routes going along a road with different offsets for each route. More stylistically, you could produce the shadowing seen around land masses in older, hand-drawn maps.

Section of map showing lines ringing a group of islands.

An excerpt from a submarine cable map showing the use of offset paths to shade around land masses. Note also the use of inside strokes to define country boundaries.

Offsetting paths is in practice extremely tricky! Here are a few of the problems:

  1. Offsets of Bezier segments are not Beziers; in fact they are 10th-order polynomials. In practice, one can do a pretty good job of estimating the offset by breaking up a Bezier path into smaller segments.
  2. Offset paths can have loops at cusps.
  3. Offset paths may require breaking apart left and right offset paths and recombining to form outset and inset paths. It can be difficult to get this right.

Entire scientific papers are written on this topic.[1]

Here is a simple example path with offsets both inside and outside:

Path with a series of offsets.

Left: insets, right: outsets. Red path is original.

In this case, the outsets correspond to the outer edge of a stroked path with appropriate width when the ‘stroke-linejoin’ type is ’round’. The insets correspond to the inner edge of such strokes. Taking a closer look at the offset paths shows a number of cusp loops:

Complex path with offsets.

The same original path as in the above figure. Left: the light blue region is created by stroking the original path. As can be seen it matches the corresponding outset (blue) and inset (green) paths. Right: The raw offset paths used to construct the visible outset and inset paths. In this case, the outset path is constructed from the raw outset path (blue) and the inset path is constructed from the raw inset path (green). Cusp loops and overlaps have been removed.

Determining what is outset or inset becomes more difficult as a path loops back on itself. Both the outset and inset paths can consist of parts of both the right-offset and left-offset paths as shown below:

A path that loops back on itself three times.

Left: The left-offset path (blue) and the right-offset path (green), relative to the path’s direction (clock-wise). Right: The resulting outset path (blue) and inset path (green).

Here’s an example where Inkscape’s Linked Offset function gets it wrong:

A circular path segment on top of a figure eight segment.

The resulting outset path (blue) and inset path (green) as found by Inkscape’s Linked Offset function.

The previous examples assumed that the line joins for outside joins are rounded. It would be desirable to be able to specify the type of join to use. This can maintain the feel of the original path.

A triangle path with 's' shaped sides with various offsets.

Left: Outset path with three different types of joins: ‘bevel’, ’round’, and ‘arcs’. Right: Outset paths with various offsets and with the ‘arcs’ line join. Note: the ‘arcs’ line join fails for the outer most path as the generated arcs do not intersect; this results in falling back to a ‘miter’ line join.

Allowing more freedom to define stroke position and being able to offset strokes are highly desirable features for designers, but as this post shows, they are not so simple to implement. Before we can add such features to SVG, we need to define robust algorithms for generating proper offset paths.

References

  1. An offset algorithm for polyline curves Xu-Zheng Liu, Jun-Hai Yong, Guo-Qin Zheng, Jia-Guang Sun.

An image for the sole purpose of having a good PNG image to show in Google+ which doesn’t support SVG images, bad Google+.

Complex path with offsets.

SVG Working Group Meeting Report — Sydney

The SVG Working Group had a four day face-to-face meeting in Sydney this month. The first day was a joint meeting with the CSS Working Group.

I would like to thank the Inkscape board for funding my travel. This was an expensive trip as I was traveling from Paris and Sydney is an expensive city… but I think it was well worth it as the SVG WG (and CSS WG, where appropriate) approved all of my proposals and worked through all of the issues I raised. Unfortunately, due to the high cost of this trip, I have exhausted the budgeted funding from Inkscape for SVG WG travel this year and will probably miss the two other planned meetings, one in Sweden in June and one in Japan in October. We target the Sweden meeting for moving the SVG 2 specification from Working Draft to Candidate Recommendation so it would be especially good to be there. If anyone has ideas for alternative funding, please let me know.

Highlights:

A summary of selected topics, grouped by day, follows:

Joint CSS and SVG Meeting

Minutes

  • SVG sizing in HTML.

    We spent some time discussing how SVG should be sized in HTML. For corner cases, the browsers disagree on how large an SVG should be displayed. There is going to be a lot work required to get this nailed down.

  • CSS Filter Effects:

    We spent a lot of time going through and resolving the remaining issues in the CSS Filter Effects specification. (This is basically SVG 1.1 filters repackaged for use by HTML with some extra syntax sugar coating.) We then agreed to publish the specification as a Candidate Recommendation.

  • CSS Blending:

    We discussed publishing the CSS Blending specification as a Recommendation, the final step in creating a specification. I raised a point that most of the tests assumed HTML content. It was requested that more SVG specific test be created. (Part of the requirement for Recommendation status is that there be a test suite and that two independently developed renderers pass each test in the suite.)

  • SVG in OpenType, Color Palettes:

    The new OpenType specification allows for multi-colored SVG glyphs. It would be nice to set those colors through CSS. We discussed several methods for doing so and decided on one method. It will be added to the CSS Fonts Level 4 specification.

  • Text Rendering:

    The ‘text-rendering‘ property gives renderers a hint on what speed/precision trade-offs should be made. It was pointed out that the layout of text flowed into a box will change as one zooms in and out on a page in Firefox due to font-hinting, font-size rounding, etc. The Google docs people would like to prevent this. It was decided that the ‘geometricPrecision’ value should require that font-metrics and text-measurement be independent of device resolution and zoom level. (Note: this property is defined in SVG but both Firefox and Chrome support it on HTML content.)

  • Text Properties:

    Text in SVG 2 relies heavily on CSS specifications that are in various states of readiness. I asked the CSS/SVG groups what is the policy for referencing these specs. In particular, SVG 2 needs to reference the CSS Shapes Level 2 specification in order to implement text wrapping inside of SVG shapes. The CSS WG agreed to publish CSS Shapes Level 2 as a Working Draft so we can reference it. We also discussed various technical issues in defining how text wraps around excluded areas and in flowing text into more than one shape.

SVG Day 1

Minutes

  • CamelCase Names

    The SVG WG decided some time ago to avoid new CamelCase names like ‘LinearGradient’ which cause problems with integration in HTML (HTML is case insensitive and CamelCase SVG names must be added by hand to HTML parsers). We went through the list of new CamelCase names in SVG 2 and decided which ones could be changed, weighing arguments for consistency against the desire to not introduce new CamelCase names. It was decided that <meshGradient> should be changed to <mesh>. This was mostly motivated by the ability to use a mesh as a standalone entity (and not only as a paint server). Other changes include: <hatchPath> to <hatchpath>, <solidColor> to <solidcolor>, …

  • Requiring <foreignObject> HTML to be rendered.

    There was a proposal to require any HTML content in a <foreignObject> element to be rendered. I pointed out that not all SVG renderers are HTML renderers (Inkscape as an example). It was decided to have separate conformance classes, one requiring HTML content to be rendered and one not.

  • Requiring Style Sheets Support:

    It was decided to require style sheet support. We discussed what kind of style sheets to require. We decided to require basic style sheet support at the CSS 1 or CSS 2.1 level (that part of the discussion was not minuted).

  • Open Issues:

    We spent considerable time going through the specification chapter by chapter looking at open issues that would block publishing the specification as a Candidate Recommendation. This was a long multi-day process.

SVG Day 2

Minutes

Note: Day 2 and Day 3 minutes are merged.

  • Superpaths:

    Superpaths is the name for the ability to reuse path segment data. This is useful, for example, to define the boundary between two shapes just once, reusing the path segment for both shapes. SVG renderers might be able to exploit this information to provide better anti-aliasing between two shapes knowing they share a common border. The SVG WG endorses this proposal but it probably won’t be ready in time for SVG 2. Instead, it will be developed in a separate Path enhancement module.

  • Line-Join: Miter Clipped:

    It was proposed on the SVG mailing list that there be a new behavior for the miter ‘line-join’ value in regards to the ‘miter-limit’ property. At the moment, if a miter produces a line cap that extends farther than the ‘miter-limit’ value then the miter type is changed to bevel. This causes abrupt jumps when the angle between the joined lines changes such that the miter length crosses over the ‘miter-limit’ value (see demo). A better solution is to clip the line join at the ‘miter-limit’. This is done by some rendering libraries including the one used on Windows. We decided to create a new value for ‘line-join’ with this behavior.

  • Auto-Path Closing:

    The ‘z’ path command closes paths by drawing a line segment to the first point in the path. This is fine if the path is made up of straight lines but becomes problematic if the path is made up of curves. For example, it can cause rendering problems for markers as there will be an extra line segment between the start and end of the path. If the last point is exactly on top of the first point, one can remove this closing line segment but this isn’t always possible, especially if one is using the relative path commands with rounding errors. A more detailed discussion can be found here. We decided to allow a ‘z’ command to fill in missing point data using the first point in the path. For example in: d=”m 100,125 c 0,-75 100,-75 100,0 c 0,75 -100,75 z” the missing point of the second Bezier curve is filled in by the first point in the path.

  • Text on a Shape:

    An Inkscape developer has been working on putting text on a shape by converting shapes to paths while storing the original shape in the <defs> section. It would be much easier if SVG just allowed text on a shape. I proposed that we include this in SVG 2. This is actually quite easy to specify as we have already defined how shapes are converted to paths (needed by markers on shapes and putting dash patterns on shapes). A couple minor points needed to be decided: Do we allow negative path offsets? (Yes) How do we decide which side of a path the text should be put? (A new attribute) The SVG WG approved adding text on a shape to SVG 2.

  • Marker knockouts, mid-markers, etc:

    A number of new marker features still need some work. To facilitate finishing SVG 2 we decided to move them to a separate specification. There is some hesitation to do so as there is fear that once removed from the main SVG specification they will be forgotten about. This will be a trial of how well separating parts of SVG 2 into separates specifications works. The marker knockout feature, very useful for arrowheads is one feature moved into the new specification. On day 3 we approved publishing the new Markers Level 1 specification as a First Public Working Draft.

  • Text properties:

    With our new reliance on CSS for text layout, just what CSS properties should SVG 2 support? We don’t want to necessarily list them all in the SVG 2 specification as the list could change as CSS adds new properties. We decided that we should support all paragraph level properties (‘text-indent’, ‘text-justification’, etc.). We’ll ask the CSS working group to create a definition for CSS paragraph properties that we can then reference.

  • Text ‘dx’, ‘dy’, and ‘rotate’ attributes:

    SVG 1.1 has the properties ‘dx’, ‘dy’, and ‘rotate’ attributes that allow individual glyphs to be shifted and rotated. While not difficult to support on auto-wrapped text (they would be applied after CSS text layout), we decided that they weren’t really needed. They can still be used on SVG 1.1 style text (which is still part of SVG 2).

SVG Day 3

Minutes

Note: Day 3 minutes are at end of Day 2 minutes.

  • Stroking Enhancements:

    As part of trying to push SVG 2 quickly, we decided to move some of the stroking enhancements that still need work into a separate specification. This includes better dashing algorithms (such as controlling dash position at intersections) and variable width strokes. We agreed to the publication of SVG Strokes as a First Public Working Draft.

  • Smoothing in Mesh Gradients:

    Coons-Patch mesh gradients have one problem: the color profile at the boundary between patches is not always smooth. This leads to visible artifacts which are enhanced by Mach Banding. I’ve discussed this in more detail here. I proposed to the SVG WG that we include the option of auto-smoothing meshes using monotonic-bicubic interpolation. (There is an experimental implementation in Inkscape trunk which I demonstrated to the group.) The SVG WG accepted my proposal.

  • Motion Path:

    SVG has the ability to animate a graphical object along a path. This ability is desired for HTML. The SVG and CSS working groups have produced a new specification, Motion Path Module Level 1, for this purpose. We agreed to publish the specification as a First Public Working Draft.

SVG Working Group Meeting Report — Santa Clara (TPAC)

This post got delayed due to work on ‘units’ for the 0.91 Inkscape release followed by the holidays.

The SVG Working Group had a two day meeting in Santa Clara as part of TPAC (the yearly meeting of all W3C working groups) at the end of October. This is an occasion to meet in person with other groups who have some shared interests in your group’s work. I would like to thank the Inkscape board for partially funding my attendance and W3C for waiving the conference fee.

Here are some highlights of the meeting:

Day 1, Morning

Minutes

The morning session was divided into two parts: the first part was an SVG only meeting while the second part was a joint meeting with the Task Force for Accessibility.

  • SVG blending when embedded via <img>:

    This is probably not a real interesting topic to readers of this blog other than it can give one a flavor of the types if discussions that go on inside the SVG working group. We spent considerable time debating if elements inside an SVG that are included into a web page by the HTML <img> tag should blend with elements outside the SVG (other than following the simple “painters model” where transparency is allowed). Recall that in SVG 2 (and CSS) it is possible to select blend modes using the ‘mix-blend-mode’ CSS property (see my blog post about blending). So the question becomes should objects like a rectangle (inside the SVG referenced by an <img> element) with a ‘mix-blend-mode’ value of say ‘screen’ blend with an image in the HTML page behind? We finally concluded that an author would expect an external SVG to be isolated and not blend with other objects in the HTML page.

  • Accessibility:

    The Accessibility Task Force asked to meet with us to discuss accessibility issues in graphics. Work has begun on SVG2 Accessibility API Mappings. An example of how accessibility can work with graphics can be found in a Surfin’ Safari blog post.

Day 1, Afternoon

Minutes

The afternoon session was a joint meeting with the CSS working group.

  • Text Decoration

    CSS has expanded the possibilities of how text is decorated (underlines, over-lines, etc.) by adding three new properties in CSS Text Decorations Module Level 3. The new properties ‘text-decoration-line’ and ‘text-decoration-style’ are easy to adopt into SVG (and in fact are already read and rendered by Inkscape 0.91). The new property ‘text-decoration-color’ is more problematic. SVG has long supported separate ‘fill’ and ‘stroke’ properties on text which also applies to text decoration. By careful nesting of <tspan>’s one can have a different underline color from the text color. Furthermore, SVG allows various paints to be applied to the text decoration, like a gradent or pattern fill. The ‘text-decoration-color’ property allows the color of the text decoration to be set directly, without the need for nested <tspan>’s so it is a quite attractive idea but how to support the richness found in SVG?

    I proposed a number of solutions (see my presentation). The CSS group agreed that my favorite solution, that adding ‘text-decoration-fill’ and ‘text-decoration-stroke’ was the proper way to move forward. (BTW, the CSS working would like to eventually allow fill and stroke on HTML text.)

  • Fitting Text in a Box

    We’ve had numerous requests for the ability to adjust the size of text to fit it inside a given box (note, this is not the same as wrapping text into a shape). SVG has the attribute ‘textLength’ which allows a renderer to adjust the spacing or glyph width to match text to a given length. It was intended to allow renderers to adjust the length of a given text string to account for differences in font metrics if a the specified font wasn’t available; it was never intended to be an overall solution to fitting text inside a box, in fact the SVG 2 spec currently warns against using it in this way. I received a proposal from another Inkscape developer on expanding ‘textLength’ to be more useful in fitting text in a box. It seems to me that finding a solution to this problem would be of more general interest than just for SVG so I added this topic to the SVG/CSS agenda. I prepared a presentation to provide a starting point for the discussion.

    We had quite a lengthy discussion. The consensus seemed to be that CSS could use a set of simple knobs to make small adjustments to text, mostly for the purpose of labels. This would satisfy most use cases. Large adjustments could (should?) be the domain of script libraries. It was decided to solicit more feedback from users.

  • Image Rendering

    CSS Images 3 has co-opted the SVG ‘image-rendering‘ property and redefined in to specify what about an image is important to preserve when scaling as compared to a speed/accuracy trade off as in SVG 1.1. I prepared a short report on a couple of issues I found. The first is that the specification does not describe very well the meaning of the new ‘crisp-edges’ value. Tab Atkins, one of the spec’s authors has agreed to elaborate and add some figures to demonstrate what is intended. I found the Wikipedia section Pixel art scaling algorithms to be particularly enlightening on the subject.

    The second issue is that some browsers and Inkscape use the now deprecated ‘optimizeSpeed’ value to indicate that the nearest neighbor algorithm should be used for scaling. This is important when scaling line art. I asked, and Tab agreed, that ‘optimizeSpeed’ value should correspond to the new ‘pixelated’ value to not break existing content (and not ‘auto’ as is currently in the spec).

  • Connectors

    I’ve been working on a connectors proposal for SVG. There is renewed interest as being able to show relationships between elements would greatly aid accessibility. We even had a brief meeting with the HTML working group where it was suggested that connectors (possibly without visual links) may be of interest to aid accessibility of HTML. One problem I’ve had is how to reference ports inside a <symbol> element. I asked the CSS group for suggestions (this is obviously not a styling issue but the CSS group members are experts at syntax). Tab Atkins suggested: url(#AndGate1) Out, Mid1, Mid2, url(#AndGate2) InA, where, for example, Out is the point defined inside the symbol with the ‘id’ AndGate1.

Day 2

Minutes

The SVG working group met for entire day covering a real hodge-podge of topics, some not well minuted. Here are a few highlights:

  • NVidia presentation.

    NVidia gave a quite impressive demonstration of their OpenGL extensions for rendering 2D vectors, (think SVG), showing an entire HTML web page from the New York Times being rotated and scaled in real time on their Tegra based Shield tablet with all the text rendered as vectors (they can render 700,000 paths per second). They are trying to get other vendors interested in the extensions but it doesn’t seem to be a high priority for them.

  • CTM Calculations

    For mapping applications, a precision of greater than single precision is necessary for calculating the Current Transformation Matrix (CTM) due to rounding errors. It was proposed and accepted that SVG dictate that such calculations be done as double precision (as Inkscape already does). (Note: single precision is sufficient for actual rendering.)

  • Going to Last Call Working Draft

    We discussed when we’ll get SVG 2 out the door. It is a very large specification with various parts in various stages of readiness. We decided to target the February face-to-face meeting in Sydney as the date we move to the next stage in the specification process… where no new features can be added and incomplete ones removed.

  • HTML in SVG

    There has been a desire by some for quite awhile to allow HTML directly inside SVG (not wrapped by a <foriegnElement> tag). I personally am quite hesitant to see this happen. SVG as at the moment a nice stand-alone graphics specification that doesn’t necessarily have to be rendered in a Web browser. Incorporating HTML would threaten this.

  • SVG in HTML

    This is the opposite of the previous topic, allowing SVG to be directly embedded in HTML without using a name space.

  • Non-scaling Patterns

    Just as it often useful to have non-scaling stroke widths (especially for technical drawings), it would also be useful to have non-scaling patterns and hatches. We agreed that this should be added to the specification.

  • Minimum Stroke Width

    It would be useful to have a minimum stroke-width so that certain strokes do not disappear when a drawing is scaled down. It was claimed that this will be handled by vector-effect but I don’t see how.

  • SVG in Industry

    It was mentioned that Boeing is moving all their 787 docs to SVG so they can be viewed in browsers.

Unfortunately, we ran out of time before we could cover some of my other topics: stroke-miterlimit, text on a shape, and auto-path closing.

Descending into the bowels of Inkscape code

Introduction

This post is more geared to Inkscape developers than Inkscape users. I hope that by recording my trials and tribulations here it can help others in their coding efforts.

I have been working on adding support for ‘context-fill’ and ‘context-stroke’ to Inkscape. These magical ‘fill’ ans ‘stroke’ property values will allow Inkscape to finally match marker fill (e.g. arrowhead color) to path stroke (e.g. arrow tail) in a simple way. These new property values are part of SVG 2.

Adding this support is a multi-step process. First one must be able to read the new values and then one must be able to apply the values. The former part is rather straight forward. It simply required modifying the SPIPaint class by adding a new ‘enum’ SPPaintOrigin with entries that keep track of where the paint originates. The previous ‘currentColor’ boolean has been incorporated into this new ‘enum’. The latter part proved to be much more of a challenge.

Where does the ‘apply’ code go?

The ‘context-fill’ and ‘context-stroke’ values are applicable to things that are cloned. The driving force for these values is certainly the <marker> element but <symbol> and <pattern> elements could also find the values useful as could anything cloned by the <use> element. For the moment, I concentrated on implementing the values in markers and things cloned by the <use> element.

The first question that comes to mind is: Where in the code is styling applied? This turns out to not be best starting question for cloned objects. A better question is: How does the cloning take place? To answer this question I implemented three routines with the same name: recursivePrintTree(); but, as member functions of different classes: SimpleNode, SPObject, and DisplayItem. These represent different stages in Inkscape’s processing of an SVG document. Here are the findings:

XML Tree (SimpleNode)
The XML Tree matches the structure of the XML file with some extra elements possibly added by Inkscape such as <metadata> and <sodipodi:namedview>. This is the tree that is shown in the XML editor dialog. No cloning is evident.
Object Tree (SPObject)
The object tree is similar to the XML tree. Its main purpose is to handle the CSS styling which involves merging the various sources of styling (external style sheets (rect: {fill:red;}), styling properties (style=”fill:red”), and presentation attributes (fill=”red”), as well as handling all the necessary cascading of styles from parent to child. A few non-rendering elements are missing such as <RFD:rfd> and some new elements appear. Here is our first clue: the object tree includes the unnamed clones of elements created by the <use> element. It makes sense that they appear here. Cloned objects descending from a <use> element participate in the style cascading process. Marker clones, however, are no where to be seen.
Display Tree (DisplayItem)
The display (or rendering) tree includes only elements that will be rendered. All the styling has been worked out; all the placement and sizing of graphical items has been calculated. The metadata, the Inkscape editing data, and the <defs> section are all gone. But now clones of the markers appear, one clone for each node where a marker is placed, each containing the geometric data of position, scale, and orientation. This is a quite reasonable way to handle markers as each marker clone is identical to its siblings (at least until ‘context-fill’ and ‘context-stroke’ came along).

The above “tree” analysis gives the structure of each tree after it has been built, but doesn’t explain how each tree is created. This has ramifiations of how one can handle the ‘context-fill’ and ‘context-stroke’ values.

Creating the XML tree

There are a couple of ways to create the XML tree. The most common is via sp_repr_read_file(). This is used in SPDocument::createNewDoc() as well as routines to read in filters, templates, etc. Files opened by Inkscape from the command line use XSLT::open() which allows XSLT stylesheets to be applied to the SVG file (something I didn’t know we supported). Both functions call sp_repr_do_read() to read the actual files and both end up with an Inkscape::XML::Document.

Creating the object tree

Once the XML tree is created, it is passed to SPDocument::creatDoc() which builds the object tree top down via the recursive calling of SPObject::invoke_build() starting with the document root <svg> element. SPObject::invoke_build() calls the virtual function SPObject::build() which handles element specific things such as reading in attributes. Attributes are read by calling SPObject::readAttr() which performs a few checks before calling the virtual SPObject::set() function. The set() function for SPUse reads in ‘href’, the reference to the object to be cloned by the <use> element. Reading in the reference inserts a copy of the referenced object (the clone) into the object tree via SPUse::href_changed().

Markers are not cloned; only references to the marker elements are added at this step, in the SPShape::build() function.

Creating the display tree

The display tree is created by calling recursively SPItem::invoke_show() on the root object (SPItem, derived from SPObject, is for visible objects). This is done in SPDesktop::setDocument(). SPItem::invoke_show immediately calls the virtual function SPItem::show() which handles element specific things. (SPRoot::show() calls SPGroup::show() which calls SPGroup::_showChildren.) SPItem::show() creates an instance of an appropriate display class object that is derived from Inkscape::DrawingItem(). The virtual function DrawingItem::setStyle() is called to set the style information. One thing to note is that the a child is constructed (with styling) before adding it to the tree so a child’s style cannot be directly dependent on an ancestor in the tree. But ‘context-fill’ and ‘context-stroke’ need ancestor style information so we need to supply that in a different way.

Markers are tracked by a map of vectors of pointers to Inkscape::DrawingItem instances. This map is stored in SPMarker. The map is indexed by a key for each type of marker (start, mid, end) on a particular path. The vector has an entry for each position along the path a marker is to be placed. The DrawingItem instances are created in a two step process from SPShape::show(). First a call to sp_marker_show_dimensions() ensures that the vector is of the correct size. Then a call to sp_shape_update_marker_view() calls sp_marker_show_instance() which creates a new Inkscape::DrawingItem instance if it doesn’t already exist.

Setting the style of a clone

As mentioned above, style is handled in the virtual function DrawingItem()::setStyle(). The DrawingShape and DrawingText setStyle() functions call NRStyle.set() where the work of translating the style information from the object tree form to the display tree form takes place (in the display tree, the styling information is in a form used by the Cairo rendering library). To handle ‘context-fill’ and ‘context-stroke’ we would like to walk up the display tree to find the style of the element that references the clone, i.e. the <use> element or the <path> or <shape> elements in the case of markers. But at the point the setStyle() function is called on an element in the clone, the clone has not yet been inserted into the display tree, so one cannot walk up the display tree. What we can do is hand two sets of styling information from the object tree to to the setStyle() function, the first being the stying information for the object at hand and the second being the styling information that should be used in the case of ‘context-fill’ and ‘context-stroke’. We know the later for the <use> element as its clone is in the object tree. All that is required is setting a pointer to the context style information in the SPUse class and then passing it down to its children. This solution doesn’t work for markers as their clones are not in the object tree. The solution for markers is calling a function that walks down the tree setting the correct styling information after the cloned marker elements are added to the display tree.

Future work

There are still quite a few things to be done. In particular, before we can switch to using ‘context-fill’ and ‘context-stroke’, as well as the ‘orient’ attribute value ‘auto-start-reverse’ (which allows us to handle both start and end arrows with just one marker) we’ll need a fallback solution for SVG 1.1 renderers. Here is a list of things to do:

  • Handle gradients and patterns.
  • Handle text (appendText()).
  • Export to SVG 1.1.
  • Redo markers.svg (source of markers in Inkscape).

Reflections

All the code is now in trunk. To implement ‘context-fill’ and ‘context-stroke’, I added about 200 lines of code. I don’t know the exact amount of time it took, but I would guess a minimum of 20 hours. That works out to about 10 lines per hour… not very productive. The first part, reading in ‘context-stroke’ and ‘context-fill’ took about an hour. I am quite familiar with this part of the code, having C++ified the SPStyle and related classes and having implemented other new properties and property values. It was the second part that took so long. Although I have worked with parts of this code before, it was often quite opaque as to which code is doing what (and why). I ended up going down many false paths. There is a serious lack of comments and often confusing variable and function names (what the heck is an ‘arenaitem’?). A few comments at the appropriate places could have shaved up to 90% of the time it took. In this case, the different way markers and clones are handled required solving the same problem twice.

When you begin a project, it is very hard to estimate the time it will take. I would have thought this project could be done in less than 5 hours, possibly in just a couple. It didn’t turn out that way. On the otherhand, implementing the new CSS property ‘paint-order’ which I thought would take considerable time, took only a couple of hours.

SVG Working Group Meeting Report — London

The SVG Working Group had a four day Face-to-Face meeting just before The Graphical Web conference in Winchester (UK). The meetings were hosted by Mozilla in their London office.

Here are some highlights of the meeting:

Day 1

Minutes

  • Symbol and marker placement shorthands:

    Map makers use symbols quite extensively. We decided at a previous meeting to add the ‘refX’ and ‘refY’ attributes (from <marker>) to <symbol> so that symbols can be aligned to a particular point on a map without having to do manual position adjustments. We have since been asked to provide ‘shorthand’ values for ‘refX’ and ‘refY’. I proposed adding ‘left’, ‘center’, and ‘right’ to ‘refX’ (defined as 0%, 50%, and 100%) of the view box as well as ‘top’, ‘center’, and ‘bottom’ to ‘refY’. These values follow those used in the ‘transform-origin’ property. We debated the usefulness and decided to postpone the decision until we had feedback from those using SVG for maps (see Day 4).

    For example, to center a symbol at the moment, one has to subtract off half the width and height from the ‘x’ and ‘y’ attributes of the <use> element:

      <symbol id="MySquare" viewBox="0 0 20 20">
        <rect width="100%" height="100%"
    	  style="fill:none;stroke:black;stroke-width:2px"/>
      </symbol>
      <use x="100" y="100" width="100" height="100"
           xlink:href="#MySquare"/>
    

    By using ‘refX’ and ‘refY’ set to ‘center’, one no longer needs to perform the manual calculations:

      <symbol id="MySquare" viewBox="0 0 20 20"
                      refX="center" refY="center">
        <rect width="100%" height="100%"
    	  style="fill:none;stroke:black;stroke-width:2px"/>
      </symbol>
      <use x="150" y="150" width="100" height="100"
                 xlink:href="#MySquare"/>
    
    A square symbol centered in an SVG.

    An example of a square <symbol> centered inside an SVG.

  • Marker and symbol overflow:

    One common ‘gotcha’ in using hand-written markers and symbols is that by default anything drawn outside the marker or symbol viewport is hidden. People sometimes naively draw a marker or symbol around the origin. Since this is the upper-left corner of the viewport, only one quarter of the marker or symbol is shown. We decided to change the default to not hide the region outside the viewport, however, if this is shown to break too much existing content, the change might be reverted (it is possible that some markers/symbols have hidden content outside the viewport).

  • Two triangle paths with markers on corners. Only one-fourth of each marker on the left path is shown.

    Example of markers drawn around origin point. Left: overflow=’hidden’ (default), right: overflow=”visible’.

  • Variable-stroke width:

    Having the ability to vary stroke width along a path is one of the most requested things for SVG. Inkscape has the Live Path Effect ‘Power Stroke’ extension that does just that. However, getting this into a standard is not a simple process. We must deal with all kinds of special cases. The most difficult part will be to decide how to handle line joins. (See my post from the Tokyo meeting for more details.) As a step towards moving this along, we need to decide how to interpolate between points. One method is to use a Centripital Catmull-Rom function. Johan Engelen quickly added this function as an option to Inkscape’ Power Stroke implementation (which he wrote) for us to test.

Day 2

Minutes

  • Path animations:

    In the context of discussing the possibility of having a canonical path decomposition into Bezier curves (for speed optimization) we briefly discussed allowing animation between paths with different structures. Currently, SVG path animations require the start and end paths to have the same structure (i.e. same types of path segments).

  • Catmull-Rom path segments.

    We had a lengthy discussion on the merits of Catmull-Rom path segments. The main advantage of Catmull-Rom paths is that the path goes through all the specified points (unlike Bezier path segments where the path does not go through the handles). There are some disadvantages… adding a new segment changes the shape of the previous segment, the paths tend not to be particularly pretty, and if one is connecting data points, the curves have the tendency to over/under shoot the data. The majority of the working group supports adding these curves although there is some rather strong dissent. The SVG 2 specification already contains Catmull-Rom paths text.

    After discussing the merits of Catmull-Rom path segments we turned to some technical discussions: what exact form of Catmull-Rom should we use, how should start and end segments be specified, how should Catmull-Rom segments interact with other segment types, how should paths be closed?

    Here is a demo of Catmull-Rom curves.

Day 3

Minutes

  • <tref> decission:

    One problem I see with the working group is that it is dominated by browser interests: Opera, Google (both Blink), Mozilla (Gecko), and Adobe (Blink, Webkit, Gecko). (Apple and Microsoft aren’t actively involved with the group although we did have a Microsoft rep at this meeting.) This leaves those using SVG for other purposes sometimes high and dry. Take the case of <tref>. This element is used in the air-traffic control industry to shadow text so it is visible on the screen over multi-color backgrounds. Admittedly, this is not the best way to do this (the new ‘paint-order’ property is a perfect fit for this) but the fact is that it is being used and flight-control software can’t be changed at a moments notice. Last year there was a discussion on the SVG email list about deprecating <tref> due to some security issues. From reading the thread, it appeared the conclusion was reached that <tref> should be kept around using the same security model that <use> has.

    Deprecating <tref> came up again a few weeks ago and it was decided to remove the feature altogether and not just deprecate it (unfortunately I missed the call). The specification was updated quickly and Blink removed the feature immediately (Firefox had never implemented it… probably due to an oversight). It has reached the point of no-return. It seems that Blink in particular is eager to remove as much cruft as possible… but one person’s cruft is someone else’s essential tool. (<tref> had other uses too, such as allowing localization of Web pages through a server.)

  • Blending on ‘fill’ and ‘stroke':

    We have already decided to allow multiple paint servers (color, gradient, pattern, hatch) on fills and strokes. It has been proposed that blending be allowed. This would follow the model of the ‘background-blend-mode’ property. (Blending is already allowed between various element using the ‘mix-blend-mode’ property’, available in Firefox (nightly), Chrome, and the trunk version of Inkscape.)

  • CSS Layout Properties:

    The SVG attributes: ‘x’, ‘y’, ‘cx’, ‘cy’, ‘r’, ‘rx’, ‘ry’ have been promoted to properties (see SVG Layout Properties). This allows them to be set via CSS. There is an experimental implementation in Webkit (nightly). It also allows them to be animated via CSS animations.

A pink square centered in SVG if attributes supported, nothing otherwise.

A test of support of ‘x’, ‘y’, ‘width’, and ‘height’ as properties. If supported, a pink square will be displayed on the center of the image.

Day 4

Minutes

  • Shared path segments (Superpaths):

    Sharing path segments between paths is quite useful. For example, the boundary between two countries could be given as one sub-path, shared between the paths of the two countries. Not only does this reduce the amount of data needed to describe a map but it also allows the renderer to optimize the aliasing between the regions. There is an example polyfill available.

    We discussed various syntax issues. One requirement is the ability to specify the direction of the inserted path. We settled for directly referencing the sub-path as d=”m 20,20 #subpath …” or d=”m 20,20 -#subpath…”, the latter for when the subpath should be reversed. We also decided that the subpath should be inserted into the path before any other operation takes place. This would nominally exclude having separate properties for each sub-path but it makes implementation easier.

  • Here, MySubpath is shared between two paths:

      <path id="MySubpath" d="m 150,80 c 20,20 -20,120 0,140"/>
      <path d="m 50,220 c -40,-30 -20,-120 10,-140 30,-20 80,-10
                       90,0 #MySubpath c 0,20 -60,30 -100,0 z"
    	style="fill:lightblue" />
      <path d="m 150,80 c 20,-14 30,-20 50,-20 20,0 50,40 50,90
                       0,50 -30,120 -100,70 -#MySubPath z"
    	style="fill:pink" />
    

    This SVG code would render as:

    Two closed paths sharing a common section.

    The two closed paths share a common section.

  • Stroke position:

    An often requested feature is to be able to position a stroke with some percentage inside or outside a path. We were going to punt this to a future edition of SVG but there seems to be quite a demand. The easiest way to implement this is to offset the path and then stroke that (remember, one has to be able to handle dashes, line joins, and end caps). If we can come up with a simple algorithm to offset a stroke we will add this to SVG 2. This is actually a challenging task as an offset of a Bezier curve is not a Bezier… thus some sort of approximation must be used. The Inkscape ‘Path->Linked Offset’ is one example of offsetting. So is the Inkscape Power Stroke Live Path Effect (available in trunk).

  • Symbol and marker placement shorthands, revisited:

    After feedback from mappers, we have decided to include the symbol and marker placement shorthands: ‘left’, ‘center’, ‘right’, ‘top’, and ‘bottom’.

  • Units in path data:

    Currently all path data is in User Units (pixels if untransformed). There is some desire to have the ability to specify a unit in the path data. Personally, I think this is mostly useless, especially as units (cm, mm, inch, etc.) are useless as there is no way to set a preferred pixel to inch ratio (and never will be). The one unit that could be useful is percent. In any case, we will be investigating this further.

Lots of other technical and administrative topics were discussed: improved DOM, embedding SVG in HTML, specification annotations, testing, etc.

The ‘paint-order’ property in SVG 2

Introduction

SVG 2 has a new ‘paint-order’ property which can be used to select the order in which the fill, stroke, and markers are painted. This is of especially great use for text where having the stroke painted on top of the fill leads to distorted glyphs.

Sample text showing effect of paint-order.

Sample text showing the effect of the ‘paint-order’ property.

As of March 2014, Chrome and Firefox Nightly support the ‘paint-order’ property. Inkscape trunk also has rendering support for the property (if compiled in).

Test SVGs

Tests with different orders of 'fill', 'stroke', and 'markers'.

Each square has the indicated value of the ‘paint-order’ property.

Tests with different orders of 'fill', 'stroke', and 'markers'.

Each line of text has the indicated value of the ‘paint-order’ property.

Blending coming to an SVG renderer near you! (Including Inkscape)

SVG has supported a limited set of blend modes through the use of SVG filters. Now SVG (and HTML) are getting a full set of blend modes that can be directly applied to all graphical objects. Chrome already has some support for the new blending method.

Here is a snippet of SVG from the specification CSS Blending and Compositing Level 1:

<svg>
  <rect width="120" height="120" fill="black"/>
  <circle cx="40" cy="40" r="40" fill="red"/>
  <circle cx="80" cy="40" r="40" fill="lime"/>
  <circle cx="60" cy="80" r="40" fill="blue"/>
</svg>

Normally, SVG uses the painter’s model where each element is painted on top of the previous. So the above SVG gets rendered as (actual inline SVG):

Inlined SVG. Circles drawn using painter’s model.

With CSS blending, one can specify how the blending between the elements is done by setting the ‘mix-blend-mode’ property. The following style rule:

circle { mix-blend-mode: screen; }

yields the following figure:

Inlined SVG. Circles blended with ‘mix-blend-mode’ = ‘screen’.

which in a browser (recent Chrome) that supports CSS blending should look like this:

Red, lime, and blue overlapping circles, blended with 'screen' mode.

PNG.

Why the black background? If the background was white, the circles would not be visible. This is because the circles blend not only with each other but also with the background. (With the ‘screen’ blending mode, any color blended with a white background results in white.) To stop blending with the background, one can use the ‘isolation’ property. By wrapping the three circles in a group and setting the ‘isolation’ property to ‘isolate’, the three circles are first blended onto a transparent, black background and then the resulting image is painted normally. The code looks like this:

<svg>
  <g>
    <circle cx="40" cy="40" r="40" fill="red"/>
    <circle cx="80" cy="40" r="40" fill="lime"/>
    <circle cx="60" cy="80" r="40" fill="blue"/>
  </g>
</svg>

and the CSS:

circle { mix-blend-mode: screen; }
g { isolation: isolate; }

The resulting image should look like this:

Red, green, and blue overlapping circles, blended with 'screen' mode.

PNG.

I wasn’t able to get the ‘isolation’ property to work with Chrome (which should support it), thus I used a PNG in the above figure.

At the SVG Working Group meeting last week, the group approved moving the CSS Compositing and Blending Level 1 to a Candidate Recommendation. Since this a joint specification, the CSS Working group must also give their approval. A Candidate Recommendation is the last step before becoming a Recommendation (i.e. an official W3C specification). During this last step two things must happen. First a comprehensive test suite must be written and second at least two different implementations must pass the tests for each feature in the specification. This latter requirement ensures that the specification is clear enough that it can be implemented (and also demonstrates there is a real interest in the specification).

Chrome already implements the specification so just one more implementation is needed. It is expected that Firefox will soon support the specification. There is also a test plan that includes SVG tests. So we are well on the way to getting this through the last step.

In addition, I’ve also just added support for CSS Blending to Inscape trunk. For the moment, a compile time flag must be set to enable the support. There is no GUI (other than the XML editor) and there is still a bit of work to be done (the Inkscape canvas background needs to be isolated from the drawing and I’ve seen a bug when part of the drawing is cached.

The CSS Compositing and Blending Level 1 specification also include a full set of Porter-Duff compositing operators. For the moment, they only apply to Canvas. It was intended that they apply to HTML and SVG but the rendering models used by browsers cannot yet accomodate them. They will be included in the next version of the specification, CSS Compositing and Blending Level 2. The SVG working group approved the start on the next level at the last meeting.

Blending and compositing has been included in SVG filters from the beginning. However, only a limited set of blending modes and compositing operators are available in SVG filters. Unfortunately, CSS Filters Level 1 has not extended filters to include the new blending modes and compositing operators despite being trivial to implement once the original set has been implemented (it took me all of an hour to add them to Inkscape trunk). Again the motivation is to speed up approval of the level 1 specification; level 2 will include them. Work on level 2 is expected to begin early next year.

If you are interested in playing with then new blending modes and compositing modes in Inkscape, check out Inkscape trunk and set the flags WITH_CSSBLEND and/or WITH_CSSCOMPOSITE (see the file configure.ac). As mentioned above, there is no GUI for the new non-filter based blending modes. The new blending modes and compositing operators for filters are available through the Filters dialog.

You can also have a look at my Blending Test Page.

SVG Working Group Meeting Report — Tokyo

The SVG Working Group had a three day Face-to-Face meeting in Tokyo at the beginning of June. The first two days (hosted by Mozilla) were devoted to SVG proper while the third day (hosted by Google) was a joint meeting with the CSS Working Group. As typical, a lot of time was devoted to nitty-gritty details that only browser coders could love but there were still plenty of things of interest for artists and their brethren:

  • Wrapped text:

    I presented a proposal based on using the CSS Exclusions and CSS Shapes specifications. As I wrote earlier, the current Level 1 version of these specifications are missing the exact features we need, namely “shape-inside” (to provide a wrapping context) and references to SVG elements; both were recently removed. However, when we met with the CSS working group we were told that they would be back in the Level 2 specs. Alan Stearns promised to get the Level 2 drafts out soon so we have something to reference.

    Doug Schepers presented his idea on a simple way to provide a rectangular wrapping context which would not require CSS Exclusions or CSS Shapes:

     <text x="20" y="30" width="200"
        font-size="20px"
        alignment-baseline="top">This text wraps at 200 pixels.<text>
    
    Horizontally wrapped text inside box 200 px wide.

    Horizontally wrapped text.

    Or for vertical text:

     <text x="20" y="30" height="200"
        font-size="20px"
        alignment-baseline="text-before-edge">テキストは
           10文字の後に折り返されます。<text>
    
    Vertically wrapped text inside box 200 px high.

    Vertically wrapped text.

    Specifying only the “width” or the “height” creates an infinitely long rectangle for wrapping text. Specifying both creates a finite rectangle. The visibility of text that overflows this finite rectangle is controlled by the overflow property.

    One small problem with Doug’s proposal is that the values of “x” and “y” normally refer to the baseline of the first line of text and not the upper left corner of the rectangle wrapping area. This can be changed by specifying the “alignment-baseline” property to top or text-before-edge.

    Note that Doug’s proposal and my proposal are not mutually exclusive and we will mostly like incorporate both.

    Both the SVG and CSS working groups are amenable to the proposals. There are some details to work out. For example, in my initial proposal one would specify that text should flow sequentially into two different objects by giving a comma separated list: shape-inside=”url(#shape1), url(#shape2)”. This, I am told, won’t work as in CSS it indicates that the text should flow into the two shapes as if they were one shape. Instead, it has been suggested that either CSS Regions and/or CSS Fragments be used. This, however, seems overly complex.

  • Variable width stroke:

    We discussed various aspects of variable width strokes. It is clear that it will take some work to come up with a good specification. Problems include: how to specify positions, widths, smoothing, line joins, and end caps. Whether or not this gets into SVG 2 will depend on how fast these issues are resolved and in the timing of SVG 2. It it doesn’t get into SVG 2, it certainly will get into the next version.

    For example, here are some possible ways of drawing a “round” stroke-linejoin:

    Possible ways to draw a “round” stroke-linejoin when there is a discontinuity in line width at a corner node. Top: using a “pen” with diameter of the smallest width. Bottom: using an ellipse.

    Circles and ellipses work well when the two line segments intersect at 90 degrees. At other angles or when the line widths are changing they aren’t as useful. Here is an attempt at using a Bezier with a handle length chosen so that it matches a “round” stroke-linejoin when the width is constant.

    Possible way to draw a “round” stroke-linejoin: using a Bezier curve. The handle length is calculated so that it reduces to a circular arc when the width is constant (length is 0.552 × angle between tangents in degrees / 90 × distance from end to intersection of tangents). The handles are shown in purple.

    Here is a challenge: Come up with a method that produces a suitable “round” stroke-linejoin in each of the following cases:

    Figures with various angles between the two path sections.

    A triangle shape is applied to a path with two sections. The angle between the two sections is changed from figure to figure. How would you construct a “round” stroke-linejoin between the two sections that works in all cases?

  • Marker rendering issues:

    SVG renderers differ on how markers are rendered for corner cases such as a polyline with one point (see: http://paullebeau.com/svg2/markers/). We sorted out the details. As part of the discussion, we agreed that markers should apply to rectangles, ellipses, and circles (and in the future stars). The basic rule, is that markers are drawn as if these shapes were rendered as paths. We explicitly decided that circles and ellipses would have four markers.

    Marks shown on a rectangle, rounded rectangle, circle, and ellipse.

    Markers drawn on various shapes.

  • New value for the marker property orient: “auto-start-reverse”:

    This value indicates that a marker should be reversed if it is at the start of a path. This is so that one needs to define only one marker (like an arrowhead) and use it both as a start and an end marker (like a double-headed arrow). This has already been added to the spec and is in the process of being implemented in Firefox.

      <defs>
       <marker id="MyArrowHead"
          viewBox="0 0 10 10" refX="0" refY="5" 
          markerUnits="strokeWidth"
          markerWidth="4" markerHeight="3"
          orient="auto-start-reverse"
          fill="black">
          <path d="M 0 0 L 10 5 L 0 10 z" />
        </marker>
      </defs>
      <path marker-start="url(#MyArrowHead)"
            marker-end="url(#MyArrowHead)"
           d="m 75,75 150,0" />
    
    Double headed arrow using auto-start-reverse.

    Path with just one defined marker using orient=”auto-start-reverse”.

  • Hatch patterns:

    I recently added hatch patterns to the SVG 2 specification. The work was approved with a few small changes (renaming a property and specifying that only solid colors can be used… no hatches inside hatches!).

  • Multiple fill and stroke properties:

    As part of our discussion of hatch patterns, we discussed the ability to specify multiple fill and stroke properties. This is useful, for example, to draw a hatch over a gradient fill, or in drawing cross-hatching. We agreed to how this would be specified. This is a first step to allowing things like multiple stroke widths and colors on paths but at the moment there is some resistance to handling these more complicated cases. The feeling is that we need to start limiting what is being added to SVG 2 so that we can get it finished.

      <defs>
       <hatch id="MyHatch1" ... >
       <hatch id="MyHatch2" ... >
      </defs>
      <rect x="50" y="50" width="200" height="200"
         fill="url(#MyHatch1),url(#MyHatch2),#a0a0ff"</rect>
    
    A simple cross hatch over a light blue fill.

    A multiple fill consisting of two hatch patterns over a solid light blue fill”.

  • Filter compositing: feBlend:

    As anybody who has used the feBlend filter primitive to blend an element with transparency with a background image knows that the background gets added twice, once with the blending and once when the blend result is composited with the background. (See my example.) We can’t change the behavior of feBlend as there is too much content out there that uses it. We did agree to add a new attribute that will allow turning off compositing.

Flowed text in SVG: One step forward, one step back.

Background

The ability to flow text into an arbitrary shape or even a simple box has been a feature long in demand in SVG. Thus it is on the list of required features for SVG 2.[1] The SVG 1.2 draft specification[2] included the ablility to flow text (and graphics!) into arbitrary shapes. Unfortunately, SVG 1.2 never got off the ground and only Inkscape and Batik seem to have implemented parts of flowed text.

Inkscape’s implementation supports text flowed into arbitrary paths. If the path has a hole, text will wrap around it. Inkscape also supports text flowed into multiple shapes. Inkscape (nor Batik) implemented flowing images or some of the fancier elements that control line and paragraph breaks.

Text flowed inside a Chinese coin. Text wraps around hole.

Text flowed into a Chinese Coin. Done in Inkscape.

Text flowed into three circles.

Text flowed into three circles. Done in Inkscape.

Flowed text in SVG 1.2 does have some problems. First, it is complicated. There are eleven separate elements (Inkscape supports five, Batik seven). Second, there is some missing functionality. For example, there is no way to set a margin (as seen in the above examples). Third, the reality is that none of the browsers will implement SVG 1.2 flowed text even if it were part of SVG 2. They want a solution that works for both HTML and SVG.

Enter CSS and a step forward

Almost nine years after the SVG 1.2 draft came out, interest in flowing text into and around shapes has made it to HTML. The CSS working group has produced a draft specification[3] for text flowing and wrapping. The specification is fairly simple and straight forward. One specifies shapes to flow text into (‘shape-inside’) and shapes to flow text around (‘shape-ouside’). Then one specifies how the text should wrap (e.g. only wrap on the left side of a ‘shape-outside’ shape) and how close the text should come to the shapes (‘wrap-margin’ for outside shapes and ‘wrap-padding’ for inside shapes). There are a set of canned shapes defined (rectangle, circle, ellipse, or polygon) or one can link to an SVG shape or path. One can also use the alpha value of an image to generate a shape.

With this, 95% of the work for getting text wrapping in SVG is done. A few small changes are needed to adapt to the spec to SVG. For example, in HTML, one always has a box to provide a ‘wrapping-context’. In SVG you must supply the wrapping context using the ‘shape-outside’ property. In SVG, you might want to limit shapes to actual SVG shapes or paths (rather than using the canned shapes). SVG would need to add the value ‘justified’ to ‘text-align’ and add the property ‘line-height’ (already defined in CSS). The ‘x’ and ‘y’ attributes on <text> and <tspan> would be ignored (but left for use as a fallback). The trickiest part is figuring out how SVG would specify linebreaks and paragraphs since SVG does not have the <br/> and <p></p> elements.

Here is a simple example of how CSS Exclusions might work in SVG:

<def>
  <circle id="mycircle" cx="150" cy="150" r="125"/>
</def>
<text x="100" y="100" font-size="18px" text-align="justified"
       line-height="125%" wrap-margin="25"
       shape-inside="url(#myshape)">This is a mockup of...</text>
Text flowed using CSS Exclusions.

Text flowed into circle using CSS Exclusions.

And one step back

I just knocked off adding hatches to SVG 2 this week and was ready to take a closer look at text wrapping so I could present a plan for its specification at the upcoming SVG Working Group meeting. I looked at the lastest CSS Exclusions public working draft and started formulating a plan. Things looked easy. But then, a few days ago, it was announced on the CSS Working Group mailing list that the CSS Exclusions draft had been split into an Exclusions specification[4] and a Shapes specifications[5]. This seemed OK at first but in looking at the current editor’s drafts (a step before publishing a public working draft) I noticed two problems. In the Exclusions editors draft ‘shape-inside’ had been removed, to be postponed to a future specification; and in the Shapes draft, it was no longer possible to reference SVG shapes and paths. These are the VERY two things that are most required for having flowed text in SVG are gone. Hopefully we can get these back.

  1. SVG 2 Requirement.
  2. SVG 1.2 Working Draft (27 October 2004.
  3. CSS Exclusions Working Draft (3 May 2013).
  4. CSS Exclusions Editor’s draft (22 May 2013).
  5. CSS Shapes Editor’s draft (20 May 2013).