CSS Text Line Spacing Exposed!

Want evenly spaced lines of text like when writing on the lined paper we all used as kids? Should be easy. Turns out with CSS it is not. This post will show why. It is the result of too much time reading specs and making tests as I worked on Inkscape’s multi-line text.

The first thing to understand is that CSS text works by filling line boxes with glyphs and then stacking the boxes, much as is done in printing with movable type.

Four lines of movable type placed in a composing stick over a box of movable type.

Movable type placed in a composing stick. The image has been flipped horizontally so the glyphs are legible. (Modified from photo by Willi Heidelbach [CC BY 2.5], via Wikimedia Commons)

A line of CSS text is composed of a series of glyphs. It corresponds to a row of movable type where each glyph represents (mostly) a piece of type. The CSS ‘font-size’ property corresponds to the height of the type. A CSS line box contains a line of CSS text plus any leading (extra space) above and below the line.

Four lines of text mimicking the above figure.

The same four lines of text as in the previous figure. The CSS line boxes are shown by red rectangles. The line boxes are stacked without any leading between the lines.

The lines in the above figure are set tight, without any spacing between the lines. This makes the text hard to read. It is normal in typesetting to add a bit of leading between lines to give the lines a small amount of separation. This can be done with CSS through the ‘line-height’ property. A typical value of the ‘line-height’ property would be ‘1.2’ which means in the simplest terms to make the distance between the baselines of the text be 1.2 times the font size. CSS dictates that the extra space be split, half above the line, half below the line. The following example uses a ‘line-height’ value of 1.5 (to make the figure clearer).

Same four lines of text as in above figure but with leading added between lines.

The same four lines of text as in the previous figure but with leading added by a ‘line-height’ value of 1.5. The distance between the baselines (light-blue lines) is 1.5 times the font size. (Line boxes without leading are shown in green, line boxes with leading in red.)

Unlike with physical type faces, lines can be moved closer together than the height of the glyph boxes by using a ‘line-height’ value less than one. Normally you would not want to do this.

Same four lines of text as in above figure but with negative leading.

The same four lines of text as in the previous figure but with negative leading generated by a ‘line-height’ value of 0.8.

When only one font is used (same family and size), the distance between the baselines is consistent and easy to predict. But with multiple fonts it becomes a bit of a challenge. To understand the inner workings of ‘line-height’ we first need to get back to basics.

Glyphs are designed inside an em box. The ‘font-size’ property scales the em box so when rendered the height of the em box matches the font size. For most scripts, the em box is divided into two parts by a baseline. The ascent measures the distance between the baseline and the top of the box while the descent measures the distance between the baseline and the bottom of the box.

Diagram of 'em' box showing ascent and descent.

The coordinate system for defining glyphs is based on the “em box” (blue square). The origin of the coordinate system for Latin based glyphs is at the baseline on the left side of the box. The baseline divides the em box into two parts.

The distinction between ‘ascent’ and descent’ is important as the height of the CSS line box is calculated by finding independently the maximum ascent and the maximum descent of all the glyphs in a line of text and then adding the two values. The ratio between ascent and descent is a font design issue and will be different for different font families. Mixing font families may then lead to a line box height greater than that for a single font family.

Two 'M' glyphs from different fonts aligned to their alphabetic baseline.

Two ‘M’ glyphs with the same font size but from different font families (DejaVu Sans and Scheherazade). Their glyph boxes (blue rectangles) have the same height (equal to the em box or font size) but the boxes are shifted vertically so that their baselines are aligned. The resulting line box (dashed red rectangle), assuming a ‘line-height’ value of ‘1’, has a height that is greater than if just one font was used.

Keeping the same font family but mixing different sizes can also give results that are a bit unexpected.

Two text blocks.

Left: Text with a font size of 25 pixels and with a ‘line-height’ value of ‘2’. Right: Same as left but font size of 50px for middle line. Notice how the line boxes (red dashed rectangles) are lined up on a grid but that the baselines (light-blue lines) on the right are not; the middle right line’s baseline is off the grid.

So far, we’ve discussed only ‘line-height’ values that are unitless. Both absolute (‘px’, ‘pt’, etc. ) and relative (‘em’, ‘ex’, ‘%’) units are also allowed. The “computed” value of a unitless value is the unitless value while the “computed” value of a value with units is the “absolute” value. The actual value “used” for determining line box height is for a unitless value, the computed value multiplied by the font size, while for the values with units it is the “absolute value” For example, assuming a font size of 24px:

‘line-height:1.5′
computed value: 1.5, used value: 36px;
‘line-height: 36px’
computed and used values: 36px;
‘line-height: 150%’
computed and used values: 36px;
‘line-height: 1.5em’
computed and used values: 36px.

The importance of this is that it is the computed value of ‘line-height’ that is inherited by child elements. This gives different results for values with units compared to those without as seen in the following figure:

Two text blocks.

Left: Text with a font size of 25 pixels and with a ‘line-height’ value of ‘2’. Right: Same as left but ‘line-height’ value of ‘2em’. With the unitless ‘line-height’ value, the child element (second line, span with larger font) inherits the value ‘2’. As the larger font has a size of 50px, the “used” value for ‘line-height’ is 100px (2 times 50px) thus the line box is 100px tall. With the ‘line-height’ value of ‘2em’, the computed value is 50px. This is inherited by the child element which is then used in calculating the line box height. CodePen.

The astute observer will notice that in the above example the line box height of the middle line on the right is not 50 pixels as one might naturally expect. It is actually a bit larger. Why? Recall that the line box height is calculated from the maximum ascent and maximum descent of all the glyphs. One small detail was left out. CSS dictates that an imaginary zero width glyph called the “strut” be included in the calculation. This strut represents a glyph in the containing block’s initial font and with the block’s initial font size and line height. This throws everything out of alignment as shown in the figure below.

'A' and 'D' glyphs aligned to a common baseline with the 'D' having twice the font size as the 'A'.

Let the ‘A’ represents the strut. The glyph boxes for the ‘A’ and ‘D’ without considering line height are shown by blue rectangles. The glyph boxes with line height taken into account are shown by red-dashed rectangles. For the ‘D’, the glyph boxes with and without taking into account the line height are the same. Note that both the ‘A’ and ‘D’ boxes with line height factored in have the same height (2em relative to the containing block font size). The two boxes are aligned using the ‘alphabetic’ baseline. This results in the ‘A’ glyph box (with effect of line height) extending down past the bottom of the ‘D’ glyph box. The resulting line box (solid-pink rectangle) height is thus greater than either of the glyph box heights. The extra height is shown by the light gray rectangle.

So how can one keep line boxes on a regular grid? The solution is to rely on the strut! The way to do this is to make sure that the ascents and descents all child elements are smaller than the containing block strut’s ascent and descent values. One can do this most easily by setting ‘line-height’ to zero in child elements.

Two blocks of text, both showing evenly spaced lines. The third line on the right has text with a font size twice the rest of the lines.

Text with evenly spaced lines. Left: All text with the same font size. Right: The third line has text with double the font size but with a ‘line-height’ value of ‘0’. This ensures that the strut controls the spacing between lines. CodePen.

As one can see, positioning text on a regular grid can be done through a bit of effort. Does it have to be so difficult? There maybe an easier solution on the horizon. The CSS working group is working on a “Line Grid” specification that may make this trivial.

SVG Working Group Meeting Report — Sydney — 2016

The SVG Working Group had a four day face-to-face meeting in Sydney this month. Like last year, the first day was a joint meeting with the CSS Working Group. I would like to thank all the people that donated to Inkscape’s SVG Standards Work fund as well as to the Inkscape general fund that made my attendance possible.

Joint CSS and SVG Meeting

Minutes

CSS Stroke and Fill Specification

The CSS working group would like to allow the use of the SVG ‘stroke’ and ‘fill’ properties on CSS text as well as other places in CSS (e.g. box border). They’ve created a prototype document that basically copies the SVG stroke and fill text adding the necessary parts to get it to work with CSS text. This document has been temporary called Text Decoration 4 (the title will certainly be changed). They’ve proposed converting the ‘stroke’ and ‘fill’ properties to short-hands. (A short-hand property allows setting multiple CSS properties at the same time.) They also would like to see the ‘stroke-alignment’ property implemented (this property allows one to stroke only the inside or only the outside of a shape). I pointed out the difficulty in actually defining how ‘stroke-alignment’ would work. The SVG WG moved some of the advance stroking properties out of the SVG 2 specification into an SVG Stroke module to avoid holding up the SVG 2 specification. (See my blog entry on this as well as the issues in the SVG Stroke module.) Other issues discussed were how glyphs are painted (‘paint-order’, ‘text-shadow’), multiple strokes/fills, dashing, and ‘text-decoration-fill/stroke’.

Text Issues

Next we covered a whole slew of text issues I raised dealing with flowed text in SVG.

Strategy for using CSS in SVG for wrapping

The first issue was to agree on how SVG and CSS are related. I presented my strategy: that HTML/CSS and SVG have there own methods to define an area to fill called the wrapping area. Once this area is defined, one uses CSS rules to fill it. Here is how one defines the wrapping area in both HTML/CSS and SVG:

The CSS/HTML code:
    <style>
      .wrapper { shape-inside: xxx; ... }
      .float-left { shape-outside: yyy; ... }
      .float-right { shape-outside: zzz; ... }
    </style>
    <div id="wrapper">
      <div id="float-left"/>
      <div id="float-right"/>
      <p>
	Some text.
      </p>
    </div>
The result:
Defining a fill area using <div&gt and floats.

Wrapped text in HTML. One starts with a wrapper <div>. The ‘shape-inside’ property on this <div> reduces the wrapping area to the circle. Two floats <div>s are defined, one on the left (green rectangle) and right (red rectangle). The area that the floats exclude is reduced by the half-ellipses defined by the ‘shape-outside’ property. The final wrapping area is the light blue shape.

The CSS/SVG code:
    <style>
      .my_text { shape-inside: xxx; shape-outside: yyy, zzz; ... }
    </style>
    <text id="my_text">Some text.</text>
The result:
Defining a fill area in SVG.

Wrapped text in SVG 2. One starts with a element. The ‘shape-inside’ property on this element defines the wrapping area. The ‘shape-outside’ property reduces the wrapping area. The final wrapping area is the light blue shape.

It was pointed out at a discussion on Day 2, that the use of ‘shape-outside’ in SVG was not consistent with the CSS model. The ‘shape-outside’ property defines the effective shape of an element as seen by other elements. We agreed to change ‘shape-outside’ to an SVG only property ‘shape-subtract’.

How is the first line placed in a wrapped shape?

When the top of a wrapping area is not horizontal, how do you decide where the first line of text is placed?
Different strategies for locating the position of the first line in pyramid shape.

Alternative solutions for where to start layout of the first line, from top to bottom: First place a chunk of text fits: No restrictions, Restricted to multiples of ‘line-height’, Restricted to multiples of half ‘line-height’.

We were informed that with CSS floats, the line is moved down until the first text chunk fits. To be consistent with CSS, we should follow the same rule. A future CSS Line Grid specification may allow one to control line position.

Overflow text

What should happen when the shape isn’t big enough for all the text? This is mostly an issue for browsers where the user can specify a larger font (i.e. for accessibility reasons). CSS has an ‘overflow’ property that selects either clipping or scrolling. Neither of these is a great solution for SVG. The tentative solution in the CSS Shapes 2 specification of extending the <div> below the wrapping area doesn’t work for SVG. I proposed that there should be a means to expose the overflowed text, such as displaying it on hovering over the ellipses at the end of the displayed text. There was some interest in this. For the moment, the best solution is probably to explicitly not define what should happen, leaving it to a future time to specify the behavior. In reflecting on this after the meeting, I think one strategy is to suggest that authors provide an overflow region by adding an additional shape to the value of the ‘shape-inside’ property.

How does text wrap in a shape with a doughnut hole or other feature that breaks a line into parts?

Since SVG can have arbitrary shapes, it is possible to create shapes that break a single text line into parts. How should these shapes be filled?
A shape a bit like an 'H' showing text be laid out on both sides of the central break.

An example of a shape that breaks lines into parts.

The ‘wrap-flow’ property does not apply here as that dictates how text is flowed around floats. A new ‘wrap-inside’ property has been proposed. For the moment, however, it was agreed that text should flow as shown in the above figure. This would be the default value of any new property.

Flowing into multiple shapes

The aborted SVG 1.2 specification allowed text to be flowed sequentially into multiple shapes. This is something that Inkscape implemented and I would like to see this ability preserved. The proposed CSS methods for doing this don’t work for SVG. I proposed giving the ‘shape-inside’ property a list of shapes. It was agreed that this would be an acceptable solution for SVG. (And it can provide a place for over-flowed text.)

How is the first glyph positioned on a line?

When dealing with rectangles, it is straight forward to find the position of the first glyph but with arbitrary shapes it is more difficult. I asked what was the correct CSS method. I was told that one considers the glyph box extended upwards/downwards as dictated by using the height of the entire line box. (For example, if one has a ‘line-height’ value of 2 with a 16px font, the line box has a height of 32px.) It’s not clear where this is specified in CSS.

Baseline issues

We next switch from text wrapping to baseline issues. Text is normally laid out along a baseline which can be different depending on the script. For example, western scripts normally use an Alphabetic baseline while Indic scripts use a Hanging baseline.
Three different scripts showing their baselines.

Example baselines (red lines) in three different scripts. From left to right: alphabetic, hanging, ideographic. The EM box is shown in blue for the ideographic script.

The proposed CSS definition of the ‘dominant-baseline’ property differs from the SVG 1.1 definition in that several of the SVG 1.1 values are missing. We discussed the missing values. Some of the missing values will be added to the CSS definition. There is one fundamental difference between CSS and SVG 1.1: With SVG 1.1 (and XSL 1.1), the baseline table does not change automatically when the font size is change. One must explicitly reset the table by setting the ‘dominant-baseline’ property to the ‘reset-size’ value. The proposed CSS definition will automatically reset the table on change in font size. I’m not sure this is a necessarily good change (it’s definitely not backwards compatible) but then this is probably such a small corner case that it doesn’t really matter.

Figure from the XSL 1.1 specification showing the default behavior upon ‘font-size’ change. The baseline table does not change.

The CSS ‘auto’ value has one small problem for SVG. With vertical text, if the value of ‘text-orientation’ is ‘sideways’, the alphabetic baseline is used. SVG 1.1 always uses the central baseline for vertical text. The CSS specification will be fixed to be compatible with SVG 1.1.

We also discussed default values for the various baselines. In principle, one gets the values of the baselines from the font but most fonts don’t have baseline tables; for interoperability we need defaults. It was decided that the CSS group would investigate this more and come up with a recommended set of default values.

Filters

I brought up a couple of issues dealing with SVG/CSS Filter Effects module. The first was the status of the document. Progress towards finishing this document seems to have stopped. Two of the three editors are no longer very active. The third editor was present and said he would push this through.

I was also interested in the next level as I have a filter primitive I would like to see added. It turns out that Level 2 has already been started. Not much is in there now. Apple, however, has a bunch of filter primitives they would like to add.

Next we covered the issue of artifacts created by using eight bit per channel colors (8 bpc) in the filter chain. The specification as written doesn’t directly specify that 8 bpc color should be used but a couple examples do assume this. I proposed that they be converted to use the range 0 to 1 so that one can use floats to describe color channels. This would solve the problem. Dean Jackson from Apple will investigate the possibility of requiring that floats be used rather than ints in the filter chain.

A blob showing artifacts due to the use of only an 8 bit bump map as input to a lighting filter primitive.

An example of the artifacts one gets due to using only 8 bit alpha channel bump map as the input into a lighting filter primitive.

Gradient Banding

An unplanned topic… how to get rid of banding in gradients. Dithering is a well known technique. Can dithering be added to CSS gradients? There seems to be support for this idea. The syntax and technique needs to be specified.

SVG Meeting — Day 1

Minutes

Path Stroking: Conformance

I brought up some time ago the inconstancy in how paths are stroked with the half the stroke width is greater than the radius of curvature (see my blog post). I suggested that maybe we define the proper way to stroke a path. Another SVG Working Group member took an action to research this topic more. He consulted members of the PDF standards group as well as hardware vendors. After he presented his findings we agreed that being more specific at this time wasn’t really a viable option as the way paths are stroked is such a fundamental property of the underlying graphics libraries that are used to render SVG.

Fallback for the ‘arc’s Line Join

It has been noted that the currently specified fallback for the ‘arcs’ line join of a ‘miter’ join is less than idea. I presented a number of alternative options to the working group. They agreed to a change in the fallback to one of two possible fallbacks:

Fallback options: Blue: increasing the radius of the inner arc to meet the outer arc. Red: increasing the radius of the inner arc while decreasing the radius of the outer arc until the two meet.

I added to Inkscape trunk’s ‘Join type’ LPE the different possible fallbacks for people to test. A full discussion can be found at here. If you have an opinion, let me know.

Path morphing

With the possible demise of SMIL animations, I asked what was the status of turning the path data attribute into a property so that it can be animated using CSS/Web Animations. The response was that it hasn’t been forgotten and that Chrome will soon have an implementation. (SMIL usage shot up dramatically after YouTube started to use SMIL to animate the Play/Pause button.) CSS path animation will be based on SVG 1.1’s path animation. A future version might include more flexible rules for path interpolation (at the moment, animated paths must have the same number and type of path commands).

SVG Meeting — Day 2

Minutes (Some minutes missing due to operator error…. The meeting crossed midnight GMT which confuses the minute making bot.)

Presentation Attributes

SVG has the idea of presentation attributes. These are attributes that can also be set using CSS. Recently, we’ve promoted quite a few geometric attributes to be presentation attributes to allow setting them with CSS (it does seem a bit strange to “style” the position of a rectangle… but that is what we’ve enabled). As we add new properties, should these also be turned into presentation attributes? It is a bit of a maintenance burden to ensure all new properties are also presentation attributes, especially as we adopt a plethora of new text properties. We have already decided to require CSS so there is not necessarily a need for new presentation attributes. HTML has already deprecated/removed presentation attributes in favor of CSS. After a bit of discussion, we have decided to follow HTML’s lead.

Other Topics

Topics covered included how SVG is integrated into HTML, coordinate precision in generated content, and aligning dashes to corners. As mentioned earlier, we decided to create a ‘shape-subtract’ property rather than misuse the ‘shape-outside’ property. Most of the afternoon was spent with specification editing.

SVG Meeting — Day 3

This was a specification editing day. (It is extremely useful to have the working group present when editing as any issues that arise can be immediately dealt with.)

Font Features Land in Inkscape Trunk

I’ve just landed basic font features support in the development version of Inkscape. What are font features and why should you be excited? (And maybe why should you not be too excited.)
The letter combination 'st' shown without a ligature and with a 'historical' ligature.

Font Features

Font features support allows one to enable (or disable) the OpenType tables within a given font, allowing you to select alternative glyphs for rendering text.
A series of examples showing the same text with and without applying various OpenType tables.

A sample of font features in action. The font is Linux Biolinum which has reasonable OpenType tables. Try the SVG (with WOFF).

The new CSS Fonts Module Level 3 adds a variety of CSS properties for defining which OpenType tables to enable/disable (as well as having nice examples of each property’s use — this is one of the more readable W3C specifications). Inkscape trunk supports the ‘font-variants-liguatures’, ‘font-variant-caps’, ‘font-variant-numeric’, ‘font-variant-position’, and ‘font-feature-settings’ properties. The properties can be set under the Variants tab in the Text and Font dialog.
The 'Variants' Tab in the 'Text and Fonts' dialog showing a series of buttons to select which font features are enabled.

The Variants tab in the Text and Font dialog.

Why you shouldn’t be too excited

Being able to enable various font features within a font is quite exciting but there are quite a few caveats at the moment:
  • One must use a trunk build of Inkscape linked with the latest unstable version of Pango (1.37.1 or greater).
  • Font feature support in fonts is usually minimal and often buggy. It’s hard to know what OpenType tables are available in which fonts.
  • Browser support is sparse. Firefox has rather good support. Chrome support seems limited to ligatures. UPDATE: As of Chrome 52, Chrome supports font features.
  • Correct display of alternative glyphs requires that the same font as used in content creation is used for rendering. On the Web the best way to do this is to use WOFF but Inkscape has no support for using User fonts (this is a future goal of Inkscape but will require considerable work).

Thanks

I would like to thank: Behdad Esfahbod, maintainer of Pango for adding the code to Pango to make accessing the OpenType tables possible. Thanks as well to Matthias Clasen and Akira Togoh who are the source of the patch to Pango. Thanks also to all the people that supported the Inkscape Hackfest in Toronto where I was able to meet and discuss Pango issues with Behdad in person and also where the idea of adding font feature support to Inkscape germinated.

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 allocating the funds for this trip as well as all the Inkscape donors that made it possible. 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 — 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.

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.

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).

Inkscape and Font Faces, a drama featuring SVG, Pango, and others.

I have just disabled “faux” or “synthesized” font faces in Inkscape trunk. The post explains why.

Background

Fonts often come in groups of related faces that all belong to the same family. For example, the group for the family ‘Nimbus Roman No9 L’ consists of the faces Regular, Regular Italic, Medium, and Medium Italic.[1]
Four lines of text showing the four different faces.

The four faces of ‘Nimbus Roman No9 L’. From top to bottom: Regular, Regular Italic, Medium, and Medium Italic.

Font designers take a lot of time to create the different faces. This can be illustrated by comparing individual characters between the faces.
Comparison of the letters 'a', 'f', 'l', 'v', 'z', and 'Q'.

Comparison between the Regular and Regular Italic faces of ‘Nimbus Roman No9 L’. Note how the font designer customized the different characters.

Comparison of the letters 'O', 'X'.

Comparison between the Regular and Medium faces of ‘Nimbus Roman No9 L’. Note that the Medium glyphs (black) are not just thickened versions of the Regular glyphs (red outline). In fact, the top and bottom of the bolder ‘O’ are actually thinner.

Font Faces and SVG

Since Inkscape uses SVG as its native file format, we need to take a quick look at how SVG describes font faces. SVG 1.1 (which for fonts is basically the same as CSS 2.1 ) defines the following font-selection properties:
  • font-family.
  • font-style: normal, italic, oblique.
  • font-variant: normal, small-caps.
  • font-weight: normal, bold, bolder, lighter, 100, 200, 300, 400, 500, 600, 700, 800, 900.
  • font-stretch: normal, wider, narrower, ultra-condensed, extra-condensed, condensed, semi-condensed, semi-expanded, expanded, extra-expanded, ultra-expanded.
In the past, most software offered only a choice of four faces: Regular, Italic, Bold, and Bold-Italic. This was a limitation set by Microsoft Windows as it only supported four faces inside one font file.[2] The creation of faux faces ensures that each of these four faces are present even if only one true face is available. But font foundries typically offer more than four faces in a family. For example, ‘Helvetica’ from Linotype has 34 faces, ‘DejaVu Sans’ has nine. SVG and CSS, recognizing this, allow access to more faces. But still there are limitations. For example, SVG and CSS only supports nine weight variants, the numbers 100, 200, …, 900 but some faces have a weight of 1000 (as supported by FontLab).[3] Since Inkscape relies on SVG, it cannot directly support a weight of 1000. Also, SVG and CSS have no way to distinguish between two faces in the same font-family that differ in away not described by the above properties (e.g. Pochoir Regular and Pochoir Sprayed). One should note that the Bold and Italic buttons in the Inkscape text toolbar have recently been replaced by a drop-down list to accommodate more face options. There is a new CSS3 Font module being written. The main change from CSS2 is that the property font-variant is being changed from a font-selection property to a font-feature property with expanded functionality. It will allow one to select between various glyphs in a single font face. Small caps will no longer be found in a separate face but be embedded into a “normal” face. As of now, CSS3 Fonts does not add the font weight 1000. (If you think that this is important, tell them!)

Font Faces and Pango/Cairo/FreeType/Fontconfig

Inkscape interfaces to the fonts on a system through Pango. There is surprisingly little documentation on how this works. If a font does not have an Italic/Oblique or a Bold face, Pango will still indicate that it does. At some point along the line synthesized faces are created. A little bit of sleuthing finds that Pango can create an Oblique face from a Regular face in the Pango/Cairo interface code but does not appear to be able to embolden a face. The Oblique face is made by skewing the “Regular” glyphs by 25%.[4] The style name is set to “Oblique”. This doesn’t appear to be what is happening with Inkscape. Hunting further, one finds that Cairo has functions that interact with FreeType to request synthesized fonts. The enumeration “cairo_ft_synthesize_t” can have the values (from the documentation):
  • CAIRO_FT_SYNTHESIZE_BOLD: Embolden the glyphs (redraw with a pixel offset).
  • CAIRO_FT_SYNTHESIZE_OBLIQUE: Slant the glyph outline by 12 degrees to the right.
FreeType has functions that create faux faces.[5] However, a close examination shows that the faux Italic faces in Inkscape are not skewed by 12 degrees. On Linux, font configuring is handled by Fontconfig. On my Fedora box, all the configuration options for synthesized faces are located in the file /etc/fonts/conf.d/90-synthetic.conf. This file dictates that fonts without a slanted face (Italic or Oblique) should have a faux face created with a skew of 20%. This is exactly what I saw when I examined a faux Italic face in Inkscape. Taking a step back, one finds that Pango has routines that directly interact with Fontconfig. It is one of the supported back ends (the others being Uniscribe on MS Windows and CoreText on MacOS X). In the function pango_fc_list_faces() one finds the source of the names for the faux faces: “Regular”, “Bold”, “Italic”, “Bold Italic”. So we have found the source of the faux faces in Inkscape (at least on Linux). On Linux, you can disable faux font faces by removing the 90-synthetic.conf configuration file (however, this does not disable faux faces in Chrome). This is probably not what you want to do. For programs that consume content, such such as Web browers, the Italic and Bold faux faces would probably be missed. The different faces are often used to highlight important information. In addition, browsers use font fallbacks to replace missing glyphs. A faux face might be a better fallback than a distantly related font face. As the glyphs are typically rendered small, you probably won’t notice much the inferior design. In the future, when a web designer wants more control over the use of faux faces, CSS3 Fonts will have a property to disable font synthesization. It doesn’t appear that any browser supports this yet.

Font Faces and Inkscape

Inkscape has happily provided the user with synthesized font faces without warning. These faces are at best imitations of the properly designed faces. Here is an example of the font face “Impact Condensed” as displayed by Chrome:
Two lines of text using Impact.

The top line is the normal (condensed) face while the bottom line is a faux bold face. Notice how the space between the dot and the base of the ‘i’ has disappeared, there is no longer a gap in the ‘e’, and how some letters overlap others.

The Firefox version is even worse! Who in their right mind would want to use a faux bold Impact face? For programs that create content, like Inkscape, the usefulness of faux faces is questionable. Fortunately, Inkscape did not actually render faux bold faces on the canvas (although they did appear in the style lists and the preview section of the Text and Font dialog). The faux Italic/Oblique faces were rendered on the Inkscape canvas. This doesn’t seem so bad at first since the rendering quality of a faux Italic/Oblique face is not nearly as bad as a faux Bold face. However, it too was not so desirable:
  • The artist was not made aware that they were using a poor imitation of a real Italic font.
  • There was a good chance the face won’t be rendered correctly downstream. At least on Linux, PDF and Postscript output will show the regular face rather than the faux Italic face (but quite perversely, will show the faux Bold face).
  • Different operating systems may create the faux fonts in different ways. On Linux, the faux faces were created by the Fontconfig backend.
  • Only one each of faux Italic, Bold, and Bold-Italic faces were created per font-family even if more than one “regular” face exists (for example, a face with four weights would have just one faux Italic face created).
One could have tracked down and fixed the faux face rendering problems for all three Pango backends, and one could have added a warning in the Inkscape Text toolbar and Text and Font dialog that one is using a faux face, but it didn’t seem like it was worth the amount of effort it would have taken. The simplest solution (and the best in my view and the majority of those who have commented on this in the Inkscape Developer’s mailing list) was to disable faux font faces in Inkscape. It was a one line fix.

Work-arounds

How to work around not having the faux font faces if you find you really need them?
  • The easiest solution is to choose another font-family that does have the faces you need. There are an incredible number of font-families out there.
  • One is still able to type “Italic” or “Bold” in the Text toolbar Style entry box. (The rendering problems remain unchanged but the styling will be saved in the SVG.)
  • A faux Italic face can be simulated by skewing a text object. The only problem with this method is that multiline text won’t be lined up properly. The Transform dialog can be used to set a precise amount of skewing.
  • A faux Bold face can be simulated by adding a stroke to the text. The text may then need to be shrunk and shifted slightly to account for the added width and height with the stroke, and the distance between the glyphs may need to be adjusted; there is an entry in the Text toolbar that allows one to adjust glyph spacing.

Footnotes

Spec Writing Madness

Hidden image for G+. In the last SVG Working Group teleconference we discussed some aspects of CSS clipping. This discussion highlighted the sometimes unintended consequences of what seems to be a series of simple rational choices. First, some background. Chunks of the SVG specification are being pulled out of the spec in order that they can be shared between SVG and CSS. This is overall a good thing. Web designers gains new features that are consistent across both SVG and HTML; things like filter effects, transforms, animation, etc. Web browser vendors are more motivated to perfect their implementation of old SVG features and implement new ones if they are also used in HTML. But this modularization process has its problems. The CSS forces are stronger than the SVG forces and their interests sometimes overwhelm those who see SVG as more of a pure drawing specification. CSS clipping is part of the CSS Masking spec. With this spec, it is possible to define masks and clip paths in terms of the bounding box of the object that is being masked or clipped. Three ways to determine the bounding box are specified:
  • ‘border-box’
  • ‘padding-box’
  • ‘content-box’
Note that these terms are rooted in the CSS box model.
Image from the CSS2 specification showing a series of boxes within each other.

The CSS2 box model as shown in the CSS2 specification.

Equivalent SVG based terms might be:
  • ‘painted-box’ (includes fill, stroke, markers)
  • ‘stroke-box’ (includes fill, stroke)
  • ‘geometric-box’ (includes fill)
Triangle with fill but no stroke.

The dashed line is the bounding box for ‘geometric-box’.

Triangle with fill and stroke.

The dashed line is the bounding box for ‘stroke-box’.

Triangle with fill, stroke, and markers.

The dashed line is the bounding box for ‘painted-box’.

The default value is ‘border-box’. This may make perfect sense in HTML space. For consistency, the default value should be the same for masking and for clipping and it should be the same for HTML and SVG. During our meeting, we discussed what would make the most sense for SVG. Most people (including me) would find it very strange if the clipping of an object depended on what we would consider styling, thus ‘geometric-box’ would make the most sense. It might be possible to have the default style sheet set to that value for SVG but it is not clear this is what the SVG WG will choose to do. If they don’t, then by default, a clip path will depend on styling. Which can lead to some strange effects. Suppose you have a triangle with a stroke. The ‘stroke-box’ and ‘painted-box’ depend on the thickness of that stroke, the line-join type, and in the case of miter join, the miter-join limit. OK, we can do the calculation to find the resulting bounding box, its just a few CPU cycles. Next lets add a dash pattern to the stroke. I was surprised to learn, that some people think that the dash pattern should effect the ‘stroke-box’ and that many graphics libraries are programmed that way. The box changes depending on if a dash hits a corner or not.
Triangle with fill, and dashed stroke.

The dashed line is the bounding box for ‘stroke-box’.

Now let’s go way out, suppose we animate the dash pattern (something you can so in SVG). As the dashes march around the triangle the bounding box will change. And since the clip path depends on the bounding box, it too will change… Probably not something that you would have expected or actually wanted.
A triangle showing an animated dash pattern marching around the triangle.

Note how the bounding box changes as the dash pattern moves.

A Spinning Newspaper or a Study of HTML vs. SVG

While wandering through the Web, I came across a simple but nice demo of CSS3 Animations: a spinning newspaper cover like one would see in an old black and white movie. It would be just perfect for a personal website I have but there is one problem: the example uses an image, JPEG to be exact. I want to be able to easily change the text. No problemo… I can just substitute a <div> for the <img> element and then fill that how I want. To begin, I followed the demo example and used the following CSS: .newspaper { animation-name: spinning; animation-duration: 1s; animation-timing-function: ease; animation-iteration-count: 1; animation-direction: normal; } @keyframes spinning { 0% {width:10px; height: 7px; transform:rotate(0deg);} 100% {width:468px; height: 330px; transform:rotate(1440deg);} } One thing to note is that this CSS won’t actually work in any browser at the moment. Firefox and Webkit based browsers support CSS3 Animations but only using prefixes (i.e. -moz-, -webkit-). While prototyping and testing in multiple browsers I found it convenient to use the “-prefix-free” JavaScript code that automatically adds the necessary prefixes (read the documentation about how to use it locally with Chrome and Opera). After you get everything working, you can manually add the prefixes if you need to avoid using JavaScript. I added a <div> for the newspaper name and immediately came across the first problem. The text doesn’t scale. Following the given example, I adjusted the @keyframe to include “font-size: 0%” and “font-size: 100%”. This didn’t work as expected. The fonts scaled alright, but as they scaled the font size was being rounded to an integer. This lead to discrete jumps in font size which caused visable effects in the text layout. I have to admit my CSS box-model fu is sadly lacking. I was having trouble getting everything to layout correctly. Later I realized that I had introduced a typo in my CSS style sheet. <rant>I personally hate how HTML5 has gone the route of allowing errors to go unnoticed. Coming from a programming background, I much prefer that my HTML/CSS crashes and burns when there is a syntax error. I’ve wasted more time trying to understand why something isn’t working the way I think it should only to discover later I was missing a simple colon.</rant> Given the frustrations I was having with CSS layout and with the font-sizing problem (which was a show stopper), I decided to try inline SVG for the layout. This worked out suprising well and within a few minutes I had the layout I wanted. (It helped that I was able to recycle some of the CSS classes I had already defined.) I still had a problem with how the animation was working. The transformation origin was moving so the spinning was starting around the top-left corner. At this point I realized that the @keyframes CSS was not optimal. There was no need to change the width, height, and font-size when a scaling could be simply added to the transform. I change the appropriate lines to: 0% { transform:scale(0) rotate(0deg);} 100% { transform:scale(1) rotate(1440deg); } Now the amination worked as expected. Once I got the SVG version working, I went back and tackled the CSS/HTML version. It took quite awhile, but I finally got it to look (almost) like the SVG version. Having completed that exercise I can give the following summary: SVG Advantages:
  • Easy layout. No dealing with collapsing margins, shifting borders, paddings, floats, vertical centering hacks. The one problem I came across was that paths must be defined in terms of user units (pixels) and not the percentages that I used everywhere else.
  • Easy to add vertical separators of random length.
CSS Advantages:
  • SVG does not have text wrapping but one can use a <p> inside <foreignobject>.
  • SVG text cannot automatically be vertically centered. Changing font-size requires manually shifting text.
Here are the final figures. Note that these are just PNGs. For a look at the spinning SVG and HTML covers go to my website (it is too difficult to get these to work inside the blog).

SVG/CSS

Newspaper cover mockup.

HTML/CSS

Newspaper cover mockup.