use fixed offsets for sub/super values of vertical-align

RESOLVED FIXED in mozilla33

Status

()

defect
RESOLVED FIXED
5 years ago
5 years ago

People

(Reporter: jtd, Assigned: jtd)

Tracking

Trunk
mozilla33
Points:
---
Dependency tree / graph

Firefox Tracking Flags

(Not tracked)

Details

()

Attachments

(7 attachments)

Gecko currently maps the 'sub' and 'super' values of vertical-align to offsets calculated using font metrics. This leads to really inconsistent results across fonts, with some subscripts/superscripts offset too much or in other cases not enough.  I think we should switch to using fixed offsets, just as Webkit does.

User agent stylesheets across browsers generally implement styling for the sub/sup elements using something like:

  sub {
    font-size: smaller;
    vertical-align: sub;
  }

  sup {
    font-size: smaller;
    vertical-align: super;
  }

The precise interpretation of what the 'sub' and 'super' values translate to varies across browsers. Here's a testpage for various fonts:

  http://people.mozilla.org/~jdaggett/tests/subsupersizing.html

The black text is the default browser rendering, the transparent red text is the same elements rendered with fixed offsets.  The offsets can be adjusted using the up/down arrows. The 'n' key toggles between whether the subscript or superscript is adjusted. The 'f' switches the font.

Webkit implements fixed offsets equivalent to:

  sub {
    font-size: smaller;
    vertical-align: -20%;
  }

  sup {
    font-size: smaller;
    vertical-align: 34%;
  }

IE also implements what appear to be fixed offsets, equivalent to:

  sub {
    font-size: 80%;
    vertical-align: -12%;
  }

  sup {
    font-size: 80%;
    vertical-align: 43%;
  }

Only Gecko bases the offset values on the some of the subscript/superscript values in the font.  The OS/2 table contains a whole slew of these metrics:

  SHORT 	ySubscriptXSize 	 
  SHORT 	ySubscriptYSize 	 
  SHORT 	ySubscriptXOffset 	 
  SHORT 	ySubscriptYOffset 	 
  
  SHORT 	ySuperscriptXSize 	 
  SHORT 	ySuperscriptYSize 	 
  SHORT 	ySuperscriptXOffset 	 
  SHORT 	ySuperscriptYOffset

The metrics code in gfx only uses ySubscriptYOffset and ySuperscriptYOffset. Note: under DirectWrite, these are ignored and the x-height is used which is particularly bad for subscripts.

Unfortunately, many fonts don't implement these in a consistent way, such that there's wide variation of the placement of subscripts/superscripts in Gecko. In general, I think we should "defer to the font" but in this case I don't think this leads to particularly good results.

I think we should just match Webkit behavior here for the values of 'sub' and 'super'.

For 'font-variant-position' I think we should used these fixed defaults when synthesizing glyphs.
Black rendered with ySubscriptYOffset/ySuperscriptYOffset values, red rendered using fixed offsets used by Webkit browsers.
Returned fixed values for the subscript/superscripts offsets.
Attachment #8444999 - Flags: review?(cam)
Since we're using fixed offsets, remove the subscript/superscript offsets from the metrics sturct.
Attachment #8445000 - Flags: review?(cam)
Posted image example using Times
Example showing existing code (left) vs. patched code (right). Note how far down the CnH2nOn subscripts fall in the existing code case.
In this case, the metrics for Minion produce subscripts that aren't low enough.
I'd be interested to know what font designers think about this, as it means we'd be choosing to ignore parameters that are supposed to be in their hands. Might be worth raising the question on Typophile?

It'd also be interesting to know whether other common software such as word processors makes any use of these fields, or if they're universally ignored.
(In reply to John Daggett (:jtd) from comment #0)
> Webkit implements fixed offsets equivalent to:
> 
>   sub {
>     font-size: smaller;
>     vertical-align: -20%;
>   }
> 
>   sup {
>     font-size: smaller;
>     vertical-align: 34%;
>   }

If we're going to settle on these, it would be good to have them in a spec somewhere.

Should there be a way to opt in to the font-supplied values, maybe if you are using a downloadable font and therefore know what it is?

> Unfortunately, many fonts don't implement these in a consistent way, such
> that there's wide variation of the placement of subscripts/superscripts in
> Gecko. In general, I think we should "defer to the font" but in this case I
> don't think this leads to particularly good results.

OK.  That test page shows a couple of shockers...

> I think we should just match Webkit behavior here for the values of 'sub'
> and 'super'.

Sounds fair.
(In reply to Jonathan Kew (:jfkthame) from comment #7)
> I'd be interested to know what font designers think about this, as it means
> we'd be choosing to ignore parameters that are supposed to be in their
> hands. Might be worth raising the question on Typophile?

That might be good to find out whether we should have a mechanism for opting into the font-supplied values when the font author hasn't supplied variant glyphs.  But given that no other browser looks at the font values, and the particularly poor cases it comes up with some common fonts currently, I think it's sound to change our current behaviour.
Comment on attachment 8444999 [details] [diff] [review]
patch, use fixed subscript/superscript offsets for all fonts

Review of attachment 8444999 [details] [diff] [review]:
-----------------------------------------------------------------

::: gfx/thebes/gfxFontConstants.h
@@ +195,5 @@
>  #define NS_FONT_VARIANT_POSITION_NORMAL             0
>  #define NS_FONT_VARIANT_POSITION_SUPER              1
>  #define NS_FONT_VARIANT_POSITION_SUB                2
>  
> +// based on fixed offset values used within Webkit

s/Webkit/WebKit/

@@ +197,5 @@
>  #define NS_FONT_VARIANT_POSITION_SUB                2
>  
> +// based on fixed offset values used within Webkit
> +#define SUBSCRIPT_OFFSET_RATIO     (0.20)
> +#define SUPERSCRIPT_OFFSET_RATIO   (0.34)

Can you call these NS_FONT_*.
Attachment #8444999 - Flags: review?(cam) → review+
Attachment #8445000 - Flags: review?(cam) → review+
The reason this blocks bug 1024804 is that for font-variant-position it's necessary to create synthetic fallback glyphs for subscripts/superscripts.  It would be good for consistency if those glyphs match the behavior of HTML subscripts/superscripts.  

As I tested using the subscript/superscript metrics I found that for many fonts the OS/2 subscript/superscript metrics are often either not correct or simply that they introduce a lot of variation across fonts. Rather than have several different models of synthesizing subscript/superscript glyphs, I think it's much simpler and more consistent to use a simple model with fixed offsets for both HTML subscripts/superscripts and for fallback glyphs when the subs/sups features aren't supported in a font. 

Using fixed offsets ensures consistency across these different features (i.e. HTML vs. font-variant-position) and across user agents (i.e. Gecko vs. Webkit).
(In reply to John Daggett (:jtd) from comment #11)
> The reason this blocks bug 1024804 is that for font-variant-position it's
> necessary to create synthetic fallback glyphs for subscripts/superscripts. 
> It would be good for consistency if those glyphs match the behavior of HTML
> subscripts/superscripts.

I wonder how common it is for a document to mix the use of HTML <sup> and <sub> tags and CSS-styled super/subscripts using font features? My guess would be that most documents will use either one technique or the other, but not intermingle them.

If so, it would arguably be more important for those glyphs to match (as near as possible) the scaling and position of any true sub/superscript glyphs in the same font. For example, if most of the superscripts in a document are able to use true 'sups' forms, but there's one occurrence involving a character that is not supported by the 'sups' feature and therefore falls back to a synthetic form, it would be desirable for this to harmonize with the true superscripts - which may differ significantly from HTML <sup> rendering.

This would only work, of course, if the font designer provides metrics that are appropriate for creating synthetic glyphs that harmonize with the font's real sub/superscripts. Perhaps that's so rarely done correctly that it's a lost cause - I'm not sure.
I wonder how much of the problems were from using OS/2 offsets without using OS/2 sizes.  That wouldn't explain the peculiarity of Times unless it wants full size scripts.
Dump of data for all the fonts on my system, which includes a smattering of Windows and commercial fonts in addition to the OSX defaults.
(In reply to Jonathan Kew (:jfkthame) from comment #12)
> I wonder how common it is for a document to mix the use of HTML <sup> and
> <sub> tags and CSS-styled super/subscripts using font features? My guess
> would be that most documents will use either one technique or the other, but
> not intermingle them.
> 
> If so, it would arguably be more important for those glyphs to match (as
> near as possible) the scaling and position of any true sub/superscript
> glyphs in the same font. For example, if most of the superscripts in a
> document are able to use true 'sups' forms, but there's one occurrence
> involving a character that is not supported by the 'sups' feature and
> therefore falls back to a synthetic form, it would be desirable for this to
> harmonize with the true superscripts - which may differ significantly from
> HTML <sup> rendering.

I think the much more common case will be situations where the fallback case appears with synthesized case. For example, in the example used in the screenshots, CnH2nOn will use the fallback case but C6H12O6 will use variant glyphs.

I think there's a common misconception that designers generally use the subscript/superscript metrics to match the placement of the variant glyphs. In general, this appears to *not* be the case. Adobe generally uses a common set of defaults for most fonts in their library and many of Microsoft fonts use a different set of the defaults across fonts in their library (see the attached metrics data).

I added the ability to compare variant forms to my testpage:

  http://people.mozilla.org/~jdaggett/tests/subsupersizing.html

Use 'v' to flip between the default rendering and the rendering with the variant glyph, 'm' to flip between fixed offsets and the offsets/sizes specified by the font. Calibri, Constantia, Cambria all place the variant glyph differently from the positioning implied by the subscript/superscript metrics.

> This would only work, of course, if the font designer provides metrics that
> are appropriate for creating synthetic glyphs that harmonize with the font's
> real sub/superscripts. Perhaps that's so rarely done correctly that it's a
> lost cause - I'm not sure.

There's actually another problem with using the subscript/superscript metrics and that is that the offset/size information is sometimes radically wrong -- Helvetica Neue, Hiragino Mincho, MS PGothic all have this problem (we already hack the metrics for MS PGothic in the GDI case).
(In reply to Karl Tomlinson (needinfo?:karlt) from comment #13)
> I wonder how much of the problems were from using OS/2 offsets without using
> OS/2 sizes.  That wouldn't explain the peculiarity of Times unless it wants
> full size scripts.

The Times case turns out to be the lack of metrics altogether, in which case our current code sticks in the x-height, which is generally much too large for a subscript offset.  In general the size is generally a default value between 0.6 and 0.66, but in cases where it's outside that range it can be radically wrong in some cases -- Helvetica Neue has values of 0.204!!!

There's a subtle ripple here that I realized as I looked at this a bit more. The 'smaller' value of 'font-size' effectively scales font size non-linearly, at small sizes it's around 0.8 while at larger sizes it's closer to 0.667. Using the typical size values of 0.6 - 0.667 at normal body text sizes generate *very* hard to read subscripts and superscripts.
HTML subscript and superscript elements generally use these default styles:

  sub { font-size:smaller; vertical-align: sub }
  sup { font-size:smaller; vertical-align: super }

Variations in the size scaling factor for 'smaller':
  
  base  smaller  ratio
  8     7        0.88
  9     8        0.89
  10    9        0.90
  11    9.33     0.85
  12    9.67     0.81
  13    10       0.77
  14    11       0.79
  15    12       0.80
  16    13       0.81
  17    14.5     0.85
  18    16       0.89
  19    16.33    0.86
  20    16.67    0.83

This data was taken from dumping textruns, so it shows the gfx font size and not something measured via script.

At much larger sizes (e.g. >45px), the ratio becomes 0.667.
"smaller" is done via the table at http://mxr.mozilla.org/mozilla-central/source/layout/style/nsRuleNode.cpp#2781 (sStrictFontSizeTable) with the last row being the one used by default.  See nsRuleNode::FindNextSmallerFontSize.
(In reply to Boris Zbarsky [:bz] from comment #18)
> "smaller" is done via the table at
> http://mxr.mozilla.org/mozilla-central/source/layout/style/nsRuleNode.
> cpp#2781 (sStrictFontSizeTable) with the last row being the one used by
> default.  See nsRuleNode::FindNextSmallerFontSize.

Right, I saw that code. For this bug my point was simply to illustrate that default HTML subscripts/superscripts don't use a fixed size ratio, because of the behavior of 'font-size: smaller' it's effectively non-linearly scaled. So even using the single scaling factor contained within OS/2 metrics is somewhat incongruous with existing behavior across browsers.
https://hg.mozilla.org/mozilla-central/rev/6af052a9805e
https://hg.mozilla.org/mozilla-central/rev/c134a28bc143
Status: NEW → RESOLVED
Closed: 5 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla33
You need to log in before you can comment on or make changes to this bug.