Open RazrFalcon opened 5 years ago
If we try to change a font than even Firefox fails.
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" font-family="Arial" font-size="64">
<path id="crosshair" d="M 20 100 L 180 100 M 100 20 L 100 180
M 79 20 L 79 180 M 121 20 L 121 180"
stroke="gray" stroke-width="0.5"/>
<text id="text1" x="100" y="100" text-anchor="middle" fill="red">
AVA
</text>
<text id="text2" x="100" y="100" text-anchor="middle">
A<tspan font-weight="bold">V</tspan>A
</text>
<rect id="frame" x="1" y="1" width="198" height="198" fill="none" stroke="black"/>
</svg>
Since everyone failed (except my own library) I'm not even sure what should be done in this case. At least I think that the expected result is the one that resvg
produces.
PS: Batik doesn't support text shaping at all, so we can ignore it.
It seems they all consider it separate text chunks and ignore kerning, how about if you use a ligature like 'fi', I would assume they render separate glyphs because of being in different dom nodes
In the latter example, there are two different faces involved ("Arial" and "Arial Bold" [1]), and AFAIK GPOS/kern will only apply within the same face. (Compare with if the <tspan>
had a different font-family
.)
[1] Or whatever "Arial" ends up mapped to. Even if an implementation was to synthesize bold, it'd need to modify the metrics as well and in practice treat it as a separate face.
@fsoder Yes, it's actually to separated font files. The problem is that I don't understand how it should be handled. What is the correct/expected result?
@msand I'm not sure how to define it.
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" font-family="Verdana" font-size="48">
<path id="crosshair" d="M 20 100 L 180 100 M 100 20 L 100 180" stroke="gray" stroke-width="0.5"/>
<!-- \x66\x69 -->
<text id="text1" x="100" y="60" text-anchor="middle">
fi
</text>
<!-- \x66\xE2\x80\x8C\x69 -->
<text id="text2" x="100" y="100" text-anchor="middle">
fi
</text>
<!-- \xEF\xAC\x81 -->
<text id="text3" x="100" y="140" text-anchor="middle">
fi
</text>
<!-- \x66\xE2\x80\x8C\x69 -->
<text id="text4" x="100" y="180" text-anchor="middle">
f<tspan font-weight="bold">i</tspan>
</text>
<rect id="frame" x="1" y="1" width="198" height="198" fill="none" stroke="black"/>
</svg>
Not sure what to expect, but Inkscape and QtSvg definitely have some problems.
... What is the correct/expected result?
Assuming that kerning would not apply across different faces, then I'd say that the renderings that don't apply kerning would seem to be the expected ones.
One might also argue that - assuming support for the font-kerning
property - that all renderings are correct (since the initial value of said property is auto
and leaves it to the UA to decide if kerning should be applied or not - and maybe resvg is applying kerning optically).
I suspect that this is more in territory of the CSS Fonts and CSS Text specifications. The latter says:
Text shaping must not be broken across inline box boundaries when there is no effective change in formatting, or if the only formatting changes do not affect the glyphs (as in applying text decoration).
Text shaping should not be broken across inline box boundaries otherwise, if it is reasonable and possible for that case given the limitations of the font technology.
https://drafts.csswg.org/css-text-3/#boundary-shaping
(Example 33 just after the quoted text gives an example [the last] that is close to what the latter example is about.)
So basically, we can do whatever we want? But in the first example, Firefox is still the correct one, because a color change doesn't affect glyphs?
CSS Text specifications
New docs are impossible to navigate...
@fsoder actually, the main problem is that it breaks BIDI reordering (see https://github.com/w3c/svgwg/issues/635) as well.
... in the first example, Firefox is still the correct one, because a color change doesn't affect glyphs?
Yes.
... the main problem is that it breaks BIDI reordering (see #635) as well.
I think the same applies there. (Firefox and Batik appear to render that correctly; librsvg is not reordering correctly, and others don't shape as expected.)
@RazrFalcon Was thinking mainly about testing with some font where fi is ligaturized, e.g. Times, and comparing with e.g. fe, to see how the handling of text chunks / ligatures / kerning / shaping is affected by other attributes and by being in different dom nodes or not, such as this:
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" font-family="Times" font-size="48">
<path id="crosshair" d="M 20 100 L 180 100 M 100 20 L 100 180" stroke="gray" stroke-width="0.5" />
<!-- \x66\x69 -->
<text id="text1" x="100" y="60" text-anchor="middle">
fi
</text>
<!-- \x66\x69 -->
<text id="text2" x="100" y="100" text-anchor="middle">
f<tspan fill="green">i</tspan>
</text>
<!-- \x66\x65 -->
<text id="text3" x="100" y="140" text-anchor="middle">
fe
</text>
<!-- \x66\x65 -->
<text id="text4" x="100" y="180" text-anchor="middle">
f<tspan fill="green">e</tspan>
</text>
<rect id="frame" x="1" y="1" width="198" height="198" fill="none" stroke="black" />
</svg>
Btw, do you have some script you're using to create images for all the renderers? Would you mind sharing it?
It's not a script, but an GUI app that I use to test resvg
. It's available here, but it's not ready for a public use. Main problem is to build and install all dependencies (e.g. batik, headless chrome, latest librsvg), which can be non-trivial.
Results:
Only Qt is different/broken.
@RazrFalcon Seems none of them are using the ligaturized glyph, here's chrome locally:
Could your version of Times be missing the GSUB tables? https://docs.microsoft.com/en-us/typography/opentype/spec/gsub http://ilovetypography.com/OpenType/opentype-features.html
Maybe some OS interference. I'm on linux.
Seems firefox preserves the ligature, even if it's different dom nodes:
Safari renders the same as chrome
Wow! Looks cool. But the question is what behavior is required by the standard.
Well, at least here it seems to depend on how one interprets a "DOM text node / separated by markup", if it includes tspan elements then firefox seems to break the definition of text chunk & ligatures at least, otherwise, if only text elements are text nodes, then chrome is breaking the spec: https://www.w3.org/TR/SVG2/text.html#TermTextChunk
text chunk An independent block of text in which all characters are positioned together. Each new absolute positioning adjustment (due to an ‘x’ or ‘y’ attribute, or forced line break) creates a new text chunk. Ligature substitution and bidi-reordering only occur within a text chunk. Text chunks are only relevant to pre-formatted text.
And later: https://www.w3.org/TR/SVG2/text.html#FontsGlyphs
Ligatures are an important feature of advance text layout. Some ligatures are discretionary while others (e.g. in Arabic) are required. The following explicit rules apply to ligature formation:
Ligature formation should not be enabled when characters are in different DOM text nodes; thus, characters separated by markup should not use ligatures.
Ligature formation should not be enabled when characters are in different text chunks.
Discretionary ligatures should not be used when the spacing between two characters is not the same as the default space (e.g. when letter-spacing has a non-default value, or text-align has a value of justify and text-justify has a value of distribute). (See CSS Text Module Level 3, ([css-text-3]).
And in the end of: https://www.w3.org/TR/SVG2/text.html#GlyphsMetrics
While kerning or ligature processing might be font-specific, the preferred model is that kerning and ligature processing occurs between combinations of characters or glyphs after the characters have been re-ordered.
Seems the svg spec doesn't specify much about when kerning gets enabled / disabled by other attributes. But, as long as the font-face is the same, (and perhaps the font-size as well?) then it should be possible to use the values from the kern tables. Or perhaps some other spec clarifies this?
Only relevant thing I can find is the part referenced by @fsoder
7.3. Shaping Across Element Boundaries Text shaping must be broken at inline box boundaries when any of the following are true for any box whose boundary separates the two typographic character units:
Any of margin/border/padding separating the two typographic character units in the inline axis is non-zero.
vertical-align is not baseline.
The boundary is a bidi isolation boundary.
Text shaping must not be broken across inline box boundaries when there is no effective change in formatting, or if the only formatting changes do not affect the glyphs (as in applying text decoration).
Text shaping should not be broken across inline box boundaries otherwise, if it is reasonable and possible for that case given the limitations of the font technology.
So if the same glyphs and metrics would have been chosen, when authored without separating markup, then it must not break shaping. Nothing seems to specify how to handle scaling of kerning if the glyphs have different font-size/weight etc. thus it seems safe to ignore kerning at that point. And, e.g. color shouldn't disable kerning, from a strict reading of that at least. But, seems the de-facto standard way to implement the spec has been to disable kerning if capitalized characters are separated by markup from characters they would otherwise have kerning adjustments for. As can be seen from your Text and AVA examples. But, they preserve kerning for lower case characters, such as fe and fi in my example.
Hmm, seems the kerning is affected even with lower case:
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" font-family="Arial" font-size="48" style="font-kerning: normal">
<path id="crosshair" d="M 20 100 L 180 100 M 100 20 L 100 180" stroke="gray" stroke-width="0.5"/>
<text id="text1" x="100" y="100" text-anchor="middle">
f<tspan>fi</tspan>
</text>
<text id="text2" x="100" y="140" text-anchor="middle">
ffi
</text>
<rect id="frame" x="1" y="1" width="198" height="198" fill="none" stroke="black"/>
</svg>
What looked like kerning was just glyphs rendering further than their advance.
And, here again, Firefox seems to apply kerning if the glyphs and metrics are the same. But, all kinds of font- text- styles can disable kerning if they are applied on the tspan, while not necessarily including changes to neither glyphs nor metrics.
Some thoughts:
This isn't about “text chunks”, which is a specific term in SVG to describe the units for text-anchor
alignment. This is about text shaping within a chunk (or within an inline box, to use CSS terms).
This isn't SVG specific at all; I would expect SVG text to show the same behavior as other CSS-styled text. The guidance quoted by Frederik above (https://github.com/w3c/svgwg/issues/634#issuecomment-457926065) applies
I think it is standard not to apply kerning between glyphs from different fonts. Kerning is font-face (and size) specific, you can't assume that the same adjustment is appropriate when the previous glyph size & position wasn't defined by the same font.
But, within the same font, a color/fill change doesn't need to disable kerning, or even contextual alternates. That said, this is the type of situation considered by the CSS Text rule "Text shaping should not be broken… if it is reasonable and possible for that case given the limitations of the font technology." I don't think we want to say that a user agent is outright wrong for turning off optional text-shaping features when style changes. But linguistically required alternates, like Arabic initial/medial/final letter forms, should still be preserved.
Ligatures and color/fill change are another matter. I'm surprised to see what looks like Firefox painting half of a ligature glyph in one color and half in the other. That doesn't necessarily mean that the only alternative would be to disable ligatures, though. Another option would be to paint the entire glyph using the styles applied to the first character in the ligature. (Which is similar to how we handle ligatures and text chunks within a single element.) That said, the Firefox approach (split the ligature glyph for coloring purposes) is probably closer to how you want ::selection
highlights to be painted.
The current rule in SVG is to disable ligatures when there is any element boundary separating the characters. The rule in CSS Text is that element boundaries must have no effect on text shaping if they do not change formatting in a way that affects glyph rendering. So these rules are in conflict & given the lack of interop we probably want to reconsider the SVG rule on this point.
Firefox's behavior in painting a glyph with two different colors is definitely interesting... but it would probably yield unexpected results for complex scripts where reordering is possible.
The SVG Working Group just discussed tspan and text shaping
.
Here is an another example which doesn't rely on ligatures:
<svg id="svg1" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" font-family="Noto Sans" font-size="48">
<path id="crosshair" d="M 20 100 L 180 100 M 100 20 L 100 180" stroke="gray" stroke-width="0.5"/>
<text id="text1" x="85" y="100">и<tspan fill="green">̆ </tspan></text>
<text id="text2" x="85" y="145">й</text>
<rect id="frame" x="1" y="1" width="198" height="198" fill="none" stroke="black"/>
</svg>
Results:
I'm surprised that basically everyone split the ̆
, while both codepoints are in the same text chunk and should be normalized into a single codepoint/grapheme.
According to the SVG spec, text shaping should be done to the whole text chunk, which in our case is the whole word. But looks like only Firefox does this right. Is it so or am I missing something?