freetype-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[ft-devel] New `slight' auto-hinting mode


From: Werner LEMBERG
Subject: [ft-devel] New `slight' auto-hinting mode
Date: Fri, 28 Apr 2017 07:46:25 +0200 (CEST)

Folks,


I've introduced a new `slight' auto-hinting mode: It only hints along
the vertical axis and does nothing horizontally.  Additionally, it
returns fractional advance widths; in other words, you have to do
sub-pixel positioning to get correct results.

You might think: Wait, the `light' hinting mode already does that!
Why a new auto-hinting mode?

Here are the reasons.  This is a long post, with a lot of technical
details – sorry for that :-)

What I describe first is the situation of the last released version
(2.7.1).  I concentrate on TrueType fonts, since here we have buggy
behaviour.  Later on I discuss the current fixes applied to FreeType
together with the resulting problems.  Please comment!


0. Preliminary
--------------

`Size metrics' are the metrics data stored in an `FT_Size' object
(which in turn is part of `FT_Face').  It (a) provides scaling values
to convert font units to the desired output size, and (b) represents
some major global font values scaled to the output size.


1. The algorithm
----------------

Computing the size metrics works as follows.

(1a) The user calls either `FT_Request_Size' or `FT_Set_Char_Size' to
     set the desired horizontal and vertical resolution, height, and
     width for a given font face.  `FT_Request_Size' offers various
     possibilities how to derive the scaling values, but this is of no
     interest here.

(1b) For TrueType fonts, both functions internally call
     `tt_size_request', which in turn calls `FT_Request_Metrics'
     first, then `tt_size_reset'.

(1c) The internal function `FT_Request_Metrics' sets up values in the
     `FT_Size_Metrics' structure: It first computes `x_scale' and
     `y_scale' (fractional values in 16.16 format), then `x_ppem' and
     `y_ppem' (which are integers), and finally the values `ascender',
     `descender', `height', and `max_advance'.  The last four values
     are in 26.6 format, but they are rounded (`height',
     `max_advance'), ceiled (`ascender'), or floored (`descender') to
     integer values.
 
(1d) Depending on a flag in the `head' table of a TTF (which is
     basically always set), `tt_size_reset' recomputes `ascender',
     `descender', `height', and `max_advance' – this time all four
     values are rounded, as mandated by the OpenType specification; no
     ceiling or flooring.

     Then the function recomputes `x_scale' and `y_scale' using the
     integer `x_ppem' and `y_ppem' values – this is also mandated by
     the OpenType specification.

     Finally, `max_advance' is recomputed using the new `x_scale'
     value.

(1e) The just computed size metrics (by `tt_size_reset') is copied to
     the top-level structure (`face->size->metrics').


2. The bugs
-----------

It's (1e) which causes a lot of headache.

  http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=b0962ac

This commit was added in 2011 (with version 2.4.6), but only recently
I did fully understand the implications of this change – better late
than never :-)

The commit tries to fix a real issue, see

  http://lists.nongnu.org/archive/html/freetype-devel/2011-07/msg00022.html

and its follow-ups.  Unfortunately, the side effects are quite severe,
making most GNU/Linux distributions (with Fedora as the most prominent
exception) always un-patch this change.

(2a) As explained in (1d), the size metrics, together with the even
     more important scaling values, are recomputed to be in accordance
     with the OpenType specification.  Since the top-level scaling is
     now based on integer ppem values it is no longer possible to
     scale an unhinted TTF to a size that would result in a fractional
     ppem value – scaling values are no longer continuous but discrete
     values.

     This was reported as Savannah bug #50470.

       https://savannah.nongnu.org/bugs/index.php?50470

(2b) If we have a TrueType font without the flag in the `head' table,
     (1d) is not applied.  While very unlikely, this might still
     happen.  As a consequence, auto-hinting depends on a flag that is
     only useful for native bytecode hinting!  The auto-hinter should
     *always* ignore this flag, defining and using its own metrics.

(2c) The idea of `light' auto-hinting is to apply hints only
     vertically, leaving the horizontal stuff unchanged.  Ideally,
     this should also be true for horizontal metrics, but
     unfortunately this is not the case.

     The `light' auto-hinter takes its scaling values from the
     top-level size metrics structure.  However, (1e) changes both the
     vertical *and* horizontal scaling for TTFs; this means horizontal
     metrics change for `light' auto-hinting, too.


3. The fixes
------------

I've tried to fix the above issues with some commits.

(3a) Reverting the change from 2011, which seems no longer be
     necessary due to other code changes.

       
http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=bcc74f4

     For TrueType fonts, the top-level size metrics object is now
     again independent from the font driver's internal size metrics
     object.

(3b) Fixing bug #50470.

       
http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=5f18d86

     If FT_LOAD_NO_HINTING is requested, the top-level size metrics
     object gets used.

(3c) As mentioned above, not all GNU/Linux distributions un-patched
     (1e) for the last six years.  In other words, change (3a)
     essentially has no effect on the majority of GNU/Linux
     distributions, but some *are* affected, experiencing heavy visual
     changes – see again bug #50470 for additional information.

     For this reason, I committed the following three changes.

       
http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=5aa6716
       
http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=ab10ffc
       
http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=0a5315d

     The patches deprecate the `light' hinting mode, introducing a new
     one called `slight' (as described in the very beginning of this
     e-mail) that is not affected by backwards compatibility
     considerations.  I've also introduced a compilation option
     `AF_CONFIG_OPTION_TT_SIZE_METRICS' so that distributions can
     preserve the `light' hinting mode if they wish, without the need
     to directly patch the source code.

     Note that this change also affects Type 1 and CID-keyed fonts if
     AF_CONFIG_OPTION_TT_SIZE_METRICS is defined: TT-like metrics are
     now applied to other font formats also if they are auto-hinted.
     On the other hand, CFF (and CFF2) fonts are not affected because
     light hinting automatically uses the native hinter for this
     format.  Type 1 and CID fonts will hopefully use the CFF hinter
     soon, so this side effect is rather neglegible.


4. Discussion
-------------

The basic question is: Do we need a new auto-hinting mode at all?
Basically, the `light' mode is completely equivalent to `slight' *if
AF_CONFIG_OPTION_TT_SIZE_METRICS is not defined*.  Using the
`lsb_delta' and `rsb_delta' fields, it is also possible to derive
fractional advance widths in `light' mode: Using the values from
`face->glyph', we have

  frac_adv_width = advance.x + (lsb_delta - rsb_delta)

This isn't described well, since the example for the deltas given in
the documentation only talks about integer advance widths.

However, in my opinion the `light' mode is tainted forever with (1e),
which some distributions use and others not.  Using a new mode, we can
overcome this dichotomy, without having the dead weight of backwards
compatibility.

What do you think?  Shall I remove (3c), enforcing (3a) to all users?
Or shall the new mode stay?  It's easy to revert the changes, if you
can convince me :-)


    Werner

reply via email to

[Prev in Thread] Current Thread [Next in Thread]