LettError/MutatorMath

Designspace needs to store information about the axes.

Closed this issue · 16 comments

  • name
  • axis id (4 letter thing, standardised for some)
  • non-normalised minimum and maximum values

axis id (4 letter thing, standardised for some)

Call it "axis tag" please.

non-normalised minimum and maximum values

And default?

Bender stuff can go here as well. Better if it matches avar table closely.

@behdad Something like this?

<!-- optional: list of axis elements -->
<axes>
    <axis   
            <!-- required: 4 letter axis tag see [ref] -->
            tag="aaaa"
            <!-- optional: human readable name -->
            name="nice name for axis"
            <!-- required: minimum value for axis -->
            minimum="72"
            <!-- required: maximum value for axis -->
            maximum="1000"
            <!-- optional: default value for axis -->
            default ="96"
    />
        <!-- optional child element: one or more avar table values, "warpmap"
        <point input="<number>" output="<number>" />
    </axis>
</axes>
  • not sure how closely to match the avar values: I would prefer not to use normalised values in the output as the rest of mutatorMath does not normalise the designspace in the same way as opentype does.
  • if no attribute for default is found use the minimum value
  • if no name attribute is found use the tag atribute.
  • maybe point is not the right name for the variation table point.

This seems to work. Merge?

not sure how closely to match the avar values: I would prefer not to use normalised values in the output as the rest of mutatorMath does not normalise the designspace in the same way as opentype does.

Let's leave avar out initially.

if no attribute for default is found use the minimum value

I prefer if we mark it an error if min, default, or max is not present.

if no name attribute is found use the tag atribute.

Is name supposed to be user-visible name? Also, spec allows specifying postscriptName separately.

What's missing here is name that relates this to the elements elsewhere in the designspace file. Or maybe that's what you meant by name. In that case, user-visible name needs to be encoded somewhere else.

maybe point is not the right name for the variation table point.

Agree.

<!-- optional: list of axis elements -->
<axes>
    <axis   
            <!-- required: 4 letter axis tag [see Opentype spec] -->
            tag="aaaa"
            <!-- required: name as it is used in the designspace locations -->
            name="axisname"
            <!-- required for axes that have no standard tag: a descriptive name that can be used in interfaces -->
            labelname="Descriptive Axis Name"
            <!-- required: number, minimum value for axis -->
            minimum="72"
            <!-- required: number, maximum value for axis -->
            maximum="1000"
            <!-- required: number, initial value for axis -->
            default ="96"
    />
        <!-- optional child element: one or more input, output pairs that maps user space to design space. -->
        <map input="<number>" output="<number>" />
    </axis>
</axes>

Other way around? We call 'initial' default but whatever works for you.

No user-visible name? The name is optional, or maybe prohibited, for standard axes, but required for custom axes.

For the mapping, syntax is find. Is there an implied mapping of minimum, initial, and maximum to themselves?

  • Ok, default it is.
  • A user-facing name: would that also open the door to requiring localisations? Where would this string appear?
  • Yes, implied are (minimum ▶️minimum) and (maximum ▶️maximum). Is that too clever?

A user-facing name: would that also open the door to requiring localisations? Where would this string appear?

Appears in slider apps! Opens door for localization, but we can worry about that later. Maybe we can add those as elements inside the element, such that localized versions can appear like:

  <name xml:lang="fa-IR">قطر</name>

Yes, implied are (minimum ▶️minimum) and (maximum ▶️maximum). Is that too clever?

That's fine as long as it's well-documented. OT1.8 also requires that default maps to itself.

Another option is to define a mapping function that carries the shape; and we scale it to map onto min/max. It would have been indeed easier if the default->default requirement wasn't there. I'm not quite sure myself here.

designSpaceDocument object for reading and writing designspaces in Python.

Glad to see this happening. A few minor notes. Section 3.2, : this is used by varlib, not just MutatorMath. Varlib uses this element in order to identify which master design should be used for the default font. Transitional designs: I'd like to see some more data to support figuring out which glyphs should be substituted for which other glyph in some area of the design space. This is sort of possible right now: you can check for instance elements to find out which glyphs have transitional substitutions, which works fine, but currently heuristics are needed to guess what in area in the design space the transitions should happen, based on the instances in which the transitions appear. One way to do this would be to have a element under which contains a list of transitional glyph elements. Each specifies the default glyph and alternate glyph, and contains a list of applicable axis elements. Each axis element specifies start and end of the area where the transition as effect. If this data is present, then the substitution elements are superseded.

@readroberts

  1. I'm sorry, I think I fumbled with the numbers right around the time you posted. Which element do you mean with section 3.2?
  2. Transitional designs: I agree that guessing is no good. I had sketched out some rule elements in #55 and then I got cold feet: it would never be able to efficiently describe all the conditional GPOS / GSUB possibilities. But is this what you have in mind?
<!-- optional: list of substitution rules -->
    <rules>
        <rule name="vertical bars" enabled="true">
            <sub name="cent" byname="cent.alt"/>
            <sub name="dollar" byname="dollar.alt"/>
            <condition tag="wght" minimum ="250.000000" maximum ="750.000000"/>
            <condition tag="wdth" minimum ="100"/>
            <condition tag="opsz" minimum="10" maximum="40"/>
        </rule>
    </rules>

rules

rules element: groups all the rules. Contains one or more rule elements

rule

rule element: a single rule. Contains one or more sub elements, and one or more condition elements. All conditions must evaluate to true for the rule to be

  • name: attribute, optional. String. Descriptive name for this rule.
  • enabled: attribute, optional. Bool. If this rule should be evaluated or not.

sub

sub element: a single glyph to glyph substitution.

  • name attribute, required. Name of the source glyph.
  • byname attribute, required. Name of the replacement glyph.

condition

condition element: a single condition that has to evaluate to true for this rule to be valid.

  • tag element: attribute, required. OpenType axis tag.
  • minimum attribute, required. Number.
  • maximum attribute, required. Number.

I was referring to the '3.2 info element'. For the discussion of glyph substitution in order to support transitional designs, I understand why you got cold feet. I was thinking only of leveraging the current mechanism in the design space file for specifying glyph substitutions in instances. I now take your point that for variable fonts, this substitution is only a small subset of the problem of how to specify GPOS and GSUB that are conditional on design space points. With this in mind, I think it would be a mistake to try to duplicate all the possible GPOS/GSUB lookup specifications in the design space file. Maybe it would still be useful to specify sets of rules in the design space file, but after thinking about your point, I suspect it would be better to specify all this stuff in the feature file syntax.

#60 adds support for reading and writing axis elements, removes many log calls and fixes a problem with a ufo3 attribute called in a ufo2 context.

#61 Bender object was not processing the axes data. Fixed. More tests added.

It might be useful if MutatorMath also respects the info element in a master as an indication that this one needs to be the neutral/default/origin. If no master has this info element, then mutatorMath can use the method to pick one as does now.

One objection to this might be that there might be pre-variable-font designspaces in use in which the mutator-assigned default is not the master that has the info element set. Such systems might have different results. But I don't know how much bother this really would be. I don't want to introduce undocumented, unexpected results in systems that used to work.

Alternatively we can decide to define a separate attribute to the designspace source element that marks that source as the default.

Closing this issue. If there is more to discuss about designspaces, let's do that there.