RE: hmtx transform - thinking out loud (yet again)

Hello Behdad,

While I appreciate your sentiment let’s try to take the emotions out of considerations and simply compare the following two options. Considering that we only have two flag bits to indicate the table transform, you proposed to do the following:

1)      Check that lsb[i]==xmin[i] for all values in longHorMetric array;

2)      If the above is true, check that leftSideBearing[j]==xmin[j] for all values in leftSideBearing array;

3)      If the above is true (meaning both arrays are well behaved), eliminate both longHorMetric.lsb[] and leftSideBearing[] and set the transform flag bit 0.

What I am proposing to consider is the following:

1)      Check that lsb[i]==xmin[i] for all values in longHorMetric array;

2)      If the above is true, eliminate longHorMetric.lsb[] and set transform flag bit 0;

3)      Check that leftSideBearing[j]==xmin[j] for all values in leftSideBearing array;

4)      If the above is true, eliminate leftSideBearing[] and set transform flag bit 1;

The only difference in implementation between what you proposed and what I propose to consider is using the second flag bit (that otherwise remains reserved/unused), which allows two arrays be eliminated independently of one another and, by doing so, improve the overall efficiency of the transform.

If my understanding of the two options under consideration are correct, how is this “vastly over-engineering”? Where else do you see this heading?

Thank you,
Vlad



From: Behdad Esfahbod [mailto:behdad@google.com]
Sent: Sunday, September 13, 2015 3:29 PM
To: Levantovsky, Vladimir
Cc: w3c-webfonts-wg (public-webfonts-wg@w3.org)
Subject: Re: hmtx transform - thinking out loud (yet again)

Honestly, seeing where this is heading, I retract my proposal.  Just forget it...  I'll try to fix it in OpenType itself...  You are vastly overengineering it.

On Thu, Sep 10, 2015 at 1:44 AM, Levantovsky, Vladimir <Vladimir.Levantovsky@monotype.com<mailto:Vladimir.Levantovsky@monotype.com>> wrote:
Hello WG,

As a follow up to my previous email below and our discussion today during the WG call:
We only have two mechanisms available  to signal the transform-specific conditions – flags and transformLength. For the ‘hmtx’ table in particular, the only parts that can be subjected to transform are either

-          lsb array that is part of the longHorMetric structure (for proportional glyphs), or

-          leftSideBearing array (for monospaced glyphs), or

-          both of them.

There are no other possible conditions that can be exploited for ‘hmtx’ table optimization and we only have three possible flag values that could be to indicate a transform version number. If we are comfortable using up all of the available flag values for the ‘hmtx’ table and leaving no room for future updates (and the only reason I am even considering this possibility is because I cannot see anything else that could be done to define the updated ‘hmtx’ transforms in the future) – we can simply use all available flag values now so that:
00 – would indicate no transform for ‘hmtx’ table (as is currently the case);
01 – would indicate a transform where only lsb array from longHorMetric was eliminated;
10 – would indicate a transform where only leftSideBearing array was eliminated;
11 – would indicate a transform where both lsb and leftSideBearing arrays were eliminated from the ‘hmtx’ table.

This would exhaust all possible flag settings but it also offers a complete coverage of all possible transform conditions. The main benefit of doing this would be an opportunity to distinguish the cases for CJK fonts where a much smaller lsb array may be left intact while the larger leftSideBearing array can still be eliminated.

From the implementation point of view – I don’t see any additional complexity that would be introduced by using additional flags settings. With “all or nothing” approach, the encoder is expected to run (lsb == xmin) check on both lsb arrays values and decide whether the transform can or cannot be applied. A more flexible approach would still require the same (lsb == xmin) check on both arrays but the only difference is that the encoder is able to specify precisely which of the array can be eliminated as a result of the transform and signal it via flags.

The reverse transform is also trivial – using the flags and the numGlyphs and numberOfHMetrics values a decoder will simply reverse the transform by recreating a particular data array using xmin numbers from associated run of glyphs.

Again, this will use up all available flag settings and all possible transform combinations at the same time – I really don’t see any downside of doing so because if we keep the reserved flags values for this particular table they will likely remain unused for eternity.

Comments are welcome!
I would like to hear your opinions on this and would really appreciate if we can quickly finalize this on the email list (so that the bulk of what’s written here can become a part of the amended spec - one way or another).

Thank you,
Vlad

P.S. For every reply to this email Rod will contribute an undisclosed amount to cover our lunch during the F2F meeting in October – don’t be bashful and send your comments and replies in, ASAP!


From: Levantovsky, Vladimir [mailto:Vladimir.Levantovsky@monotype.com<mailto:Vladimir.Levantovsky@monotype.com>]
Sent: Thursday, September 03, 2015 10:09 PM
To: w3c-webfonts-wg (public-webfonts-wg@w3.org<mailto:public-webfonts-wg@w3.org>)
Subject: hmtx transform - thinking out loud

Folks,

As I am getting my hands on the spec piece related to ‘hmtx’ transform, a question came up that I would like to discuss with the group.
In order to setup the discussion, here is the hmtx table structure:

typedef struct   _longHorMetric {
         USHORT   advanceWidth;
         SHORT            lsb;
}  longHorMetric;
longHorMetric [numberOfHMetrics]; /* provides aw and lsb values for all proportional glyphs in a font */
SHORT leftSideBearing [numGlyphs – numberOfHMetrics]; /* optional, provides lsb values for all monospaced glyphs in a font */

(As you can see, the second leftSideBearing array is an optional component which could have a length of zero if numGlyphs = numberOfHMetrics, otherwise it contains the lsb values for the run of monospaced glyphs that all share the same advanceWidth.)

Here is the issue I am trying to resolve – besides the transform number bitfield (two bits of flags which are supposed to be set to ‘01’ for the hmtx table) we have only one tool in our possession to signal whether the table has or has not been transformed – the “transformLength field. However, there are three possible cases to consider:

1)    A font that has only proportional glyphs with lsb values encoded as part of longHorMetircs array (and empty leftSideBearing array);

2)    A font that has only monospaced glyphs with longHorMetric represented by a single value followed by the leftSideBearing array of lsb values;

3)    A font that has a run of proportional glyphs followed by a run of monospaced glyphs (such as e.g. a Chinese font that has proportional Latin glyphs followed by monospaced Kanji), where the longHorMetric array will include the lsb values for proportional glyphs and leftSideBearing array will provide lsb for monospaced portion.

The first two cases are easy – once we check and confirmed that lsb values in an array match the xMin for each glyph we can simply remove them from the ‘hmtx’ table and encode the new transformLength in woff2 table directory. However, in case 3, there may be fonts that

a)      Have lsb values matching xMin for the proportional glyphs but not for monospaced, therefore while lsb field of longHorMetric can be eliminated the leftSideBearing array must stay;

b)      Vice versa, the lsb values of the proportional glyphs don’t match the xMins but the monospaced portion of the font does; therefore, we would need to keep longHorMetric[] as is but can eliminate the leftSideBearing[];

c)       Both proportional and monospaced glyph runs are well-behaved where lsb = xMin for all glyphs, and both lsb field of the longHorMetric and the leftSideBearing[] can be eliminated.

Last option 3c would be easy to implement since it’s similar to “all or nothing approach” we take for cases 1) and 2). Supporting options 3a and 3b however would also be desired (especially option 3b for a large CJK font) but they require additional signaling to indicate what part of the hmtx data was eliminated and which one stayed. I am struggling to come up with the way to accommodate this additional signaling.

Any creative ideas would be greatly appreciated!

Thank you,
Vlad

Received on Monday, 14 September 2015 02:00:20 UTC