Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement support for syntax for STAT table #176

Closed
brawer opened this issue Apr 13, 2017 · 22 comments · Fixed by #1127
Closed

Implement support for syntax for STAT table #176

brawer opened this issue Apr 13, 2017 · 22 comments · Fixed by #1127
Assignees

Comments

@brawer
Copy link
Contributor

brawer commented Apr 13, 2017

Could the AFDKO feature syntax support a table STAT statement? See @moyogo’s proposal to encode STAT in designspace documents, but @LettError didn’t like it (because he thinks it it adds too much cruft to the designspace format).

@davelab6
Copy link

I'm curious to hear from the adobe type team on this :)

@readroberts
Copy link
Contributor

Yes, a STAT table definition could exist be added to the feature file, but it needs thought. I haven't spent enough time on this yet, as we are still getting a complete CFF2 workflow to work. However, what we have now requires a lot of hand editing and understanding of low-level formats. Once this pass 1 is all done, which will be in just a few weeks, I and others in the team team will start thinking hard about to how to specify all the VF meta data in a way which is more elegant and easy to use. We will be sharing our ideas and seeking suggestions from all the usual contributors.

@miguelsousa
Copy link
Member

Here's the proposed FEA syntax for the STAT table.
Please direct your feedback to Sairus Patel (@sairuspatel).

table STAT {

   ElidedFallbackName {
      name <name string>;+
   };

   DesignAxis <axisTag> <axisOrdering num> {
      name <name string>;+
   };+

   # format 1 (if one pair specified)
   # format 4 (if several locations specified)
   AxisValue {
      flag <FLAG>+ ;
      location <axisTag> <value>;+
      name <name string>;+
   }

   # format 2
   AxisValue {
      flag <FLAG>+ ;
      location <axisTag> <nominalValue> <rangeMinValue>-<rangeMaxValue>;
      name <name string>;+
   }

   # format 3
   AxisValue {
      flag <FLAG>+ ;
      location <axisTag> <value> <linkedValue>;
      name <name string>;+
   }

   # format 5 (to be proposed): range-based style linking,
   # combination of format 2 & 3.
   # The specified range (with nominal value) is to be linked
   # to the specified linked value.
   AxisValue {
      flag <FLAG>+ ;
      location <axisTag> <nominalValue> <rangeMinValue>-<rangeMaxValue> <linkedValue>;
      name <name string>;+
   }

} STAT;

Examples

table STAT {

   ElidedFallbackName { name "Regular"; }

   DesignAxis wght 0 { name "Weight"; }
   DesignAxis ital 1 { name "Italic"; }

   # These examples are for illustrative purposes only;
   # they won’t all be in a single STAT table:

   # format 1
   AxisValue {
      location wght 400;
      name "Regular";
      name 3 1 0x411 "\5B9A\671F\7684";
      flag ElidableAxisValueName;
   }

   # format 2
   AxisValue {
      location wght 400 300-500;
      name "Regular";
      flag ElidableAxisValueName;
   }

   # format 3
   AxisValue {
      location wght 400 700;
      name "Regular";
      flag ElidableAxisValueName;
   }

   # format 3
   AxisValue {
      location ital 0 1;
      name "Regular";
      flag ElidableAxisValueName;
   }

   # format 4
   AxisValue {
      location wght 500;
      location ital 1;
      name "Mediumitalic";
   }

   # format 5 (to be proposed)
   AxisValue {
      location wght 400 300-500 700; # style-link 300-500 wght to 700
      name "Regular";
      flag ElidableAxisValueName;
   }

} STAT;

@madig
Copy link

madig commented Mar 2, 2019

Hm, in my STAT-in-Designspace musings, I found 3 use-cases that need to be supported by a STAT generator:

  1. One VF contains all axes of a family (e.g. Venn contains the weight and width axes in one VF)
  2. Two or more VFs contain a subset of all axes available in a family (e.g. Source Sans Pro has separate VFs for uprights and italics with one weight axis each)
  3. Static fonts

The example you gave is the obvious choice for case 1, but what is to happen in cases 2 and 3? Should the feature compiler subset the given table? Then it needs to know what instances are defined (can look at the fvar table, what about static fonts though?) and which axes are missing and where the font stands on them (how?). Expect the designer to define the table twice in each main master's feature file? Again, static fonts?

At Dalton Maag, we decided to ship fonts with various axis subsets, i.e. the big package has weight, width and slant axes while smaller packages have e.g. just a weight axis and we sell the uprights and slanted versions separately. We have just one set of UFOs, but multiple Designspace files with just the axes we want. How would a feature file fit in there? I hear @anthrotype's team is working on a variable font subsetter capable of subsetting axes, which would make this workflow obsolete though, so let's see.

@readroberts
Copy link
Contributor

@madig @sairuspatel I think you may be expecting that one STAT table definition would be used for all the fonts in a family or package. This definition is in a font-specific feature file, not in the designspace file. All three of the cases would be covered by different STAT tables, each specific to each font. Also, just because a specific variable font (VF) does not use an axis does not mean it should be omitted from the STAT table for that VF - quite the opposite. All the static and variable fonts in a family should all share the the same list of axes, but would have different AxisValue records. Even a VF does not have an 'ital' axis, when it is part of a family which does, the VF font should have a DesignAxis element for 'ital', and an AxisValue 'location ital 0 1;' to say where it is in the family design space.

@madig
Copy link

madig commented Mar 13, 2019

That's what I mean -- but how would the proposed STAT table feature file syntax fit into the usual compilation workflow? When you generate two VFs out of Source Sans Pro (upright plus italic) and also static instances, both from two Designspaces, how do you inject the right STAT table and from where into the binaries?

@readroberts
Copy link
Contributor

readroberts commented Mar 13, 2019

For at least the afdko workflow, the VF font inherits all the tables and features of the default source font. The STAT table is injected by defining it in the feature file for the default master font. (With some exceptions,, of course - the CFF table is converted to a CFF2 table, and some features and other data are modified.)

@madig
Copy link

madig commented Mar 13, 2019

So... what about e.g. the static instances then?

@anthrotype
Copy link
Member

what about e.g. the static instances then?

they also inherit the features of the default master, normally.

@madig
Copy link

madig commented Mar 13, 2019

Which is not what we want here, no?

@readroberts
Copy link
Contributor

I suspect you are thinking about a workflow in which one default font and all the region fonts and meta data are set up for the complete family, and build tools can start use the complete family data set to generate not only the complete family VF font, but also static fonts and VF fonts which contain a subset of the region fonts and axes. In the workflow this proposal is intended for, the static font would be built without VF machinery, just the way a font is usually built, but with a STAT table defined in the source feature file. The VF fonts which use a subset of the region source fonts and of the axes would also be built a feature file for the default font that is specific to the subset VF font.

@madig
Copy link

madig commented Mar 13, 2019

Ah wait, the workflow you're proposing is that you have masters with one default master, from which the feature file is taken for VFs, and the instances you generate and store separately so you can hand-edit their feature files and make per-instance STAT tables?

I am thinking of running fontmake on a Designspace file and having it generate not only the VF, but also static instances in one go. In that workflow, the proposed feature file way won't work without subsetting smarts in fontmake.

@miguelsousa
Copy link
Member

Ah wait, the workflow you're proposing is that you have masters with one default master, from which the feature file is taken for VFs, and the instances you generate and store separately so you can hand-edit their feature files and make per-instance STAT tables?

The proposal is about new FEA syntax for supporting the STAT table. There's nothing in there that ties it to a particular font production workflow. It's all FEA syntax, and in FEA syntax each document provides an abstraction (of OT tables and features) for one font, and one font alone. In FEA syntax there's no concept of nor support for a family of fonts. Sure, one can use include() to share FEA code that is common to more than one font style in the family, but those include will ultimately boil down to a single FEA document that is used for building each font.

I am thinking of running fontmake on a Designspace file and having it generate not only the VF, but also static instances in one go. In that workflow, the proposed feature file way won't work without subsetting smarts in fontmake.

It's clear what you're trying to do, and your comments make sense in light of you trying to understand where and how to plug the STAT FEA code into fontmake. But we believe those are workflow questions that you'll need to solve, rather than limitations of the proposed STAT syntax.
Here's an analogy that hopefully will help: in FEA syntax, it's not possible to specify family-wide STAT table code in the same way as it's not possible to specify family-wide kern feature code.

@readroberts
Copy link
Contributor

Any other comments? Else this syntax will be added to the feature file spec in a few weeks.

@miguelsousa miguelsousa unpinned this issue Jun 22, 2019
@cjchapman cjchapman added the high priority important but not urgent label Oct 2, 2019
@cjchapman cjchapman changed the title Syntax for STAT table Implement support for syntax for STAT table Oct 2, 2019
@cjchapman cjchapman assigned khaledhosny and unassigned readroberts Oct 2, 2019
@khaledhosny
Copy link
Collaborator

I have some questions about how the proposed syntax would interact with other tables:

  1. Should ElidedFallbackName check for existing identical name IDs and reuse it? If yes, how would this handle possible platform and encoding discrepancies since the STAT table stores only the I'd.
  2. The spec states that axis records need to at least cover all axes in the fvar table for variable fonts, and must use the same name IDs, but there wouldn't be an fvar table when building the STAT, so how would this requirement be handled or should it be left to the user/variable font builder to check and enforce?

@twardoch
Copy link

It would be useful if table GSUB and table GPOS were defined, and makeOTF were modified so that either multiple FEA files can be supplied, or the tool could be ran on an existing font multiple times, each time specifying a different FEA file. #1078

Having STAT syntax in FEA would be useful, but it would be great if there was specified behavior that only tables specified with the table keyword are created or replaced.

@readroberts
Copy link
Contributor

For question 1), I do see the issue that both the ElidedFallbackName and the axis valueNameID contain only the name table nameID value. I think that in the feature file spec, the name entries in the STAT table should support the full name table name record attributes. Access to the current state of the name table is implied. The implementation should reuse a name id if an exact match is found, else not. This should happen in makotfexe.

For question 2), I think that validating that the fvar and STAT table axis names match in both text string and also script/platform/language should happen, but should be left to the font building tool. This is also where the optimization of sharing name records between the fvar and STAT table should happen. As Khaled points out, this can't happen in makeotfexe, as this creates the STAT table in the source default font, and in the current workflow, the fvar table is only created when the VF font is built.

@khaledhosny
Copy link
Collaborator

I implemented enough of STAT support to be able to build the example from #176 (comment), with few changes that I’d like to discuss before moving forward:

  • All blocks end with a semicolon, for consistency with the rest of the spec (and because I was getting an infinite loop otherwise 😄 )
    -   ElidedFallbackName { name "Regular"; }
    +   ElidedFallbackName { name "Regular"; };
  • Ranges need space after the hyphen, otherwise it will be interpreted as a minus sign, alternative a different symbol can be used:
    -      location wght 400 300-500;
    +      location wght 400 300 - 500;
  • Format 5 is not implemented, not sure if this was ever proposed and whether I still have to implement it.
  • ElidedFallbackName always adds a new name id, sharing would be rather complicated (what if the name table has, say name id with a matching string for one language but not others, or more languages than ElidedFallbackName provides, or less, or... If one wants to use, say, name id 2, ElidedFallbackName must provide exactly the same name entries as in the name table. I suggest instead that we provide an alternate syntax that sets the name id directly, e.g.:
     ElidedFallbackName <name id>;

@cjchapman
Copy link
Contributor

@khaledhosny: I discussed this with @josh-hadley and we agree with your suggested changes. We also agree that there is no need for you to implement format 5 since it is not part of the OpenType standard yet.

@khaledhosny
Copy link
Collaborator

Just to be clear, for ElidedFallbackName which if my proposed solutions do you prefer? Not sharing the name ids (what I already do, does not affect file size much as the makeotf shares duplicate strings already), or allowing name id to be specified directly?

@josh-hadley
Copy link
Collaborator

Oh, sorry, we thought your proposal meant “if a string is specified, create a new name entry, and if an integer is specified, use that nameID”. After review and further discussion, we have a couple of refinements to suggest: 1) use the proposed syntax with braces, etc. for specifying a string (ElidedFallbackName {name <string>;};), but use a different/mutually exclusive keyword to specify the ID directly (ElidedFallbackNameId <integer>;). 2) for the string case, try to find/re-use an existing name string and only add if the string is not found.

So basically if a user wants to specify by ID/directly, the onus in on them to ensure it exists. Specifying a string, makeotfexe has to do the heavy lifting (per @readroberts previous reply).

@khaledhosny
Copy link
Collaborator

OK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.