W3C home > Mailing lists > Public > www-style@w3.org > March 2010

Re: [css3-fonts] opentype font feature support

From: Christoph Päper <christoph.paeper@crissov.de>
Date: Thu, 4 Mar 2010 14:30:21 +0100
Message-Id: <6F4B60F7-2426-4351-B270-B65DC203A3FE@crissov.de>
To: www-style list <www-style@w3.org>
John Daggett:
>  http://dev.w3.org/csswg/css3-fonts/
> 
> Included are additional properties for supporting OpenType font features,

Yay! But, …

the draft properties are very close to OT features. That is not really a good thing, since those are not coherently or consistently designed. In many cases a more abstract approach is more author-friendly and also does not discriminate against AAT etc.

6.1 font-kerning: normal | inherit | enabled | disabled

There are few properties that use generic on/off state names like ‘enabled’ and ‘disabled’. I would prefer not to see more of them, but I do not know which pair of words would be better here, ‘kern’/? perhaps.

6.2 font-variant-ligatures: normal | inherit | <ligature-values>
    <ligature-values> = [ common-ligatures     | no-common-ligatures 
                        | additional-ligatures | no-additional-ligatures 
                        | historical-ligatures | no-historical-ligatures 
                        ]+

This probably would be written better like this:

    <ligature-values> =  [ common-ligatures     | no-common-ligatures ] 
                      || [ additional-ligatures | no-additional-ligatures ]
                      || [ historical-ligatures | no-historical-ligatures ]

Is this grade of control really necessary or useful? In which cases does ‘hlig’ not imply ‘dlig’ and where does ‘dlig’ not imply ‘liga’? 
I read Adobe Indesign(?) only allows the user to switch on and off “discretionary ligatures”, which combines ‘hlig’ and ‘dlig’.

 Table: Usefulness of combinations
 R | L A H use   L A H use   L A H use
---+-----------+-----------+-----------     Legend
 o | + + + yes   o + + ?     - + + no     R required      (rlig)
 o | + + o yes   o + o ?     - + o no     L common        (liga)
 o | + + - yes   o + - ?     - + - no     A additional    (dlig)
 o | + o + ?     o o + ?     - o + no     H historic      (hlig)
 o | + o o yes   o o o yes   - o o ?      C contextual    (clig)
 o | + o - ?     o o - ?     - o - ?      D discretionary (dlig+hlig)
 o | + - + no    o - + no    - - + no     + enable
 o | + - o ?     o - o ?     - - o ?      o default, normal, inherit
 o | + - - yes   o - - ?     - - - yes    - disable

I believe we can fulfill the Pareto principle (80:20) with four values besides ‘normal’:

     + + +             ‘all-ligatures’
     + + -  or  + + o  ‘additional-ligatures’
     + - -  or  + o o  ‘common-ligatures’, ‘ligatures’
     - - -             ‘no-ligatures’ 
     o o o             ‘normal’

  font-variant-ligation: full | most | some/partial | none | normal

For finer control there still is‘font-feature-setting’.

6.3 font-variant-alternates: normal | inherit | <alternates-values>
    <alternates-values> = [ stylistic(<number>) 
                          | styleset(<number> [,<number>]+) 
                          | contextual        | no-contextual 
                          | contextual-swash(<number>) 
                          | swash(<number>) 
                          | historical-forms 
                          | ornament(<number>) 
                          | alt-annotation(<number>) 
                          | ruby
                          ]+

Now this part I don’t like at all. It lumps too much together with too many numbers. CSS is not designed to allow modifications on a per character level. We should go with the usual OT suggestion and assume that the first alternative variant in a font is the preferred one. That means drop all “(<number>)” and ‘styleset’ altogether.

For finer control there still is ‘font-feature-setting’.

6.3.1 Swashes

I would prefer to have swashes fallback to italics, therefore:

  font-style: normal | italic | oblique | swash | inherit
  normal < upright < oblique/slanted < italic < swash < cursive < script

That is, unless I am mistaken and swashes also worked well with upright faces. After all, there are upright italic fonts. Hm, what about broken scripts, i.e. “blackletter”, “gothic”, Fraktur.

6.3.2 Styles

I’ve written above to drop ‘styleset’, but keep ‘stylistic’. Actually the former works better with the CSS model since it always applies to more than one character. However, this is probably better reserved for font descriptors inside ‘@font-face’ rules.

6.3.3 Ornaments

The OT feature ‘ornm’ has two modes. CSS must not use the one that replaces normal (ASCII) characters with ornaments, because that degrades badly. (Generated content /might/ be a different case.) CSS may support the other mode, i.e. alternates for the bullet U+2022. I’m not sure this feature is worth it, though.

 font-variant-bullet: normal | inherit | ornament | <number>
 list-style-bullet:   normal | inherit | ornament | <number>

Here ‘ornament’ equals ‘1’.

6.3.4 Annotation

I’m not really sure what ‘alt-annotation’ is supposed to do, but it got to lose the ‘alt’ prefix at least.
Otherwise ‘annotation’ might be similar to and could therefore be unified with ‘ruby’.

6.3.5 Other glyph substitution

It is obvious that ‘historical-forms’ shares applications with ‘historical-ligatures’ (6.2) and ‘<char-variant-value>’ (6.6.1), perhaps also with ‘oldstyle-nums’ (6.5).

Likewise, the antonyms ‘contextual’ and ‘no-contextual’ influence ligatures (6.2), although ‘clig’ isn’t mapped directly. I’m not certain they interface with the selection of initial, medial, final and isolated forms (‘init’, ‘medi’, ‘fina’, ‘isol’).

There are several approaches these observations could lead to. They are not all mutual exclusive.

  font-variant-epoch:   normal | <alternates-values>
  font-variant-context: normal | <alternates-values>
  <alternates-values> = ligature || position || numeral || language || …

This first approach lets the author choose which features (types of alternates) should depend on history and context. There has to be a method to specify or derive these contexts. The following, second approach looks at the problem from a different angle: the author can provide the context which selects ligatures and alternates automatically.

  font-variant-substitution: normal | random | context
                           | [ <language> | <epoch> | <complexity> | <application> ]+
                           [,[ <language> | <epoch> | <complexity> | <application> ]]*

  <language>    = local | normal | national | global
                | <string> /* [BCP47] */
  <epoch>       = ancient | historic | normal | modern | futuristic
                | <number> /* year */
  <application> = normal | name | heading | title | poster | table
                | annotation | index | decoration | code | math | …
  <complexity>  = simple | normal | complex
  <layout>      = vertical | horizontal | ltr | rtl

Alternative keyword names: local = regional, global = international; ancient = antique, modern = contemporary, futuristic = post-modern; poster = display, decoration = ornament, science = math = formula.

There are probably more feasible approaches.

6.4 font-variant-caps: normal | inherit | <caps-value>
    <caps-value> = small-caps | petite-caps | titling-caps | unicase

 uppercase > titling > uppercase+small > small > uppercase+tiny > petite

We should be able to select whether only lowercase letters are affected or uppercase ones, too. Pre-applying “text-transform: lowercase” is but a work-around for that. This property should be able to influence <numeral-height> (6.5).

The value ‘unicase’ might better fit within ‘text-transform’ and fall back to ‘uppercase’.

  text-transform: capitalize | uppercase | lowercase | unicase | none | inherit
                  capitalize ~ mixedcase                         none ~ normal

Is ‘unicase’ applicable for uncial scripts?

Adhoc synthetic unicase for any bicameral script: 
Use the majuscule where the minuscule glyph does not have a descender xor an ascender and therefore only spans the middle row (baseline to x-height) or all three basic rows, otherwise use the minuscule glyph and move or scale as necessary to fit between baseline and cap-height. For the roman script this usually leaves AbCdEfghIJklMNPpqRStUVWXyZ. (Actual unicase typefaces use different conventions, though.)

Is ‘titling-caps’ only useful when used with “text-transform: uppercase”? (Assuming everybody uses that feature appropriately and nobody inputs all uppercase text for a bicameral script.)

6.5 font-variant-numeric: normal | inherit | <numeric-values>
    <numeric-values> = [ lining-nums        | oldstyle-nums
                       | proportional-nums  | tabular-nums
                       | diagonal-fractions | stacked-fractions
                       | slashed-zero
                       ]+

This probably would be written better like this:

    <numeric-values> =  [ lining-nums        | oldstyle-nums ]
                     || [ proportional-nums  | tabular-nums ]
                     || [ diagonal-fractions | stacked-fractions ]
                     || slashed-zero

'nums' matches 'caps', so why not 'fracs'? :)

    <numeric-values> = <numeral-style> || <fraction-style> || slashed-zero

6.5.1 Fractions

    <fraction-style> = diagonal-fractions | stacked-fraction | linear-fractions

I added ‘linear-fractions’ for the plain “3/4” style.

6.5.2 Numerals

    <numeral-style>  = <numeral-width> || <numeral-height>
    <numeral-height> = lining | oldstyle
    <numeral-width>  = proportional | tabular

In <numeral-height> ‘oldstyle' is a common, but not an adequate term. Wikipedia knows the synonyms in the antonym lists following this paragraph numerals or figures (why not ‘digits’?). Surprisingly the alternative does not feature the common antonyms ‘modern’, ‘new-style’, ‘uppercase’ etc., but only ‘lining’ and ‘titling’.

 Height                               Width
   text       <> (table, tabular)       proportional    <> (constant)
  *non-lining <> lining                 (variable)      <> (fixed)
   lowercase  <> (uppercase)            (text, textual) <> tabular
   antique    <> (modern)
   old-style  <> (new-style)
   billing    <> titling
   ranging    <> ?
   hanging    <> ?           Keywords in parentheses not found on WP.

Since not all of the 4 <numeral-style> variants may be available, the last matched should probably be used – or should a mismatch reset to default ‘normal’? Note that the caps features may influence numeral style, too.

6.5.3 Programmer style

Slashed zero only makes sense in combination with 1:I:l differentiation, so we should combine that to a ‘distinctive appearance’ style, see ‘code’ <application> (6.3.5). Humans usually don't care when characters look the same, except if writing source code or entering passwords.

6.6 font-variant-east-asian: normal | inherit | <east-asian-variations>
    <east-asian-variations> = <char-variant-value> || <char-width-value>
    <char-variant-value> = hojo-kanji | jis78 | jis83 | jis90 | jis04 | nlckanji 
                         | simplified | traditional | traditional-names
    <char-width-value>   = full-width | proportional-width

There seem to be several OT features related to Indian, Korean, Khmer and Syriac scripts, do none of them require exposure to CSS authors?

6.6.1 Sinogram variants

If I read [OPENTYPE-FEATURES] correctly, ‘hojo’ are from 1990, and ‘nlck’ – there should be a hyphen in the CSS value, if it remains – are from 2000 and ‘jp04’ is a subset thereof. Although recent, these somewhat qualifiy as historic forms (6.3.5). ‘tnam’ is also specific to Japanese, but a ‘name’ <application> (6.3.5) does not have to be.

Simplified and traditional forms may be selected by language code (with area or time subcode), or by <complexity> (6.3.5).

6.6.2 Character width

There is no reason <char-width-value> couldn’t be applied to Western scripts, although we call “full” width “fixed” or “monospaced”. Actually “full” (‘fwid’) rather contrasts with “half” (‘hwid’, ‘halt’) or other fractions (“third” ‘twid’, “quarter” ‘qwid’).

  font-variant-width:       normal | proportional | fixed
  font-variant-width-fixed: full | half | third | quarter

6.7 font-variant: normal | inherit | [<ligature-values> | <alternates-values> | <caps-value> | <numeric-values> | <east-asian-variations>]+

It’s not necessary that you can set all values with the shorthand, but it should reset all that are not specified to ‘normal’.

6.8 font-feature-settings: normal | <string>

(The example currently provided would be dealt with in 6.6.2.)

6.9 font-lang-sys: normal | inherit | <string>

This property currently uses OT language tags which are not really well designed or know as far as I know. It would be better for authors to use [BCP47] and let UAs do the mapping. Why is this abbreviated as much as it is? ‘font-language-system’ would still be shorter than ‘font-variant-east-asian’. 

I’m not sure whether this property could be integrated into <language> (6.3.5), but it would be desirable.

PS: Is there a significant difference between "foo || bar" and "[foo | bar]+"?
Received on Thursday, 4 March 2010 13:30:57 GMT

This archive was generated by hypermail 2.3.1 : Tuesday, 26 March 2013 17:20:25 GMT