googlefonts / googlefonts/fontc

Glyphs v2 "Custom" (XXXX) point axis at non-default position

Open
#1,958 3 comments 0 reactions 0 assignees View on GitHub
crater
Dominant language
Rust
Stars
193
Forks
21
Avg merge
1d 17h
Merged PRs (30d)
65

Description

There are a number of issues related to the funny implicit axes in glyphs v2 fonts. This issue is derived from a diff in [Charmonman](https://github.com/cadsondemak/Charmonman) @ 8590fc4aae.

I fed this diff to my dog, and got back the following. There was a proposed patched, but it didn't feel great, so I'm just opening an issue to track.

## Background

Glyphs v2 files implicitly define three axes when no explicit "Axes" custom parameter is present:

| Index | Tag | Name | Canonical default |
|-------|-----|------|-------------------|
| 0 | `wght` | Weight | 100.0 (design) |
| 1 | `wdth` | Width | 100.0 (design) |
| 2 | `XXXX` | Custom | **0.0** |

Charmonman has two masters (`wght` 400 and 700), both with `customValue = 10`. The XXXX axis is therefore a **point axis** — min = default = max = 10 — with no actual variation.

## What fontmake does

In [`glyphsLib/builder/axes.py`](https://github.com/googlefonts/glyphsLib/blob/f8c11742befe0a37aa6708be39a3c56da73cdc12/Lib/glyphsLib/builder/axes.py#L288-L299), an axis is added to the designspace if any of these conditions hold:

```python
if (
minimum < maximum # has a range
or minimum != axis_def.default_user_loc # point, but NOT at the canonical default
or not is_identity_map
or axis_wanted
):
self.designspace.addAxis(axis)
```

For XXXX: `minimum = 10`, `axis_def.default_user_loc = 0.0`. Because `10 != 0.0`, the axis is included even though it is a point. The result in fvar is `min = default = max = 10.0`.

For `wdth`: `minimum = 100`, `default_user_loc = 100.0`. Because `100 == 100` and it is a point, it is **not** included.

## What fontc does

`StaticMetadata::new` filters axes unconditionally on `is_point()`:

```rust
let variable_axes = axes.iter().filter(|a| !a.is_point()).cloned().collect();
```

`is_point()` returns `true` when `min == default == max`. XXXX has min = max = default = 10, so it is dropped. fontc never checks whether the value differs from the canonical default for that axis tag.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with fontc's StaticMetadata::new axis filtering and the is_point() behavior, then compare them with the referenced glyphsLib/builder/axes.py logic. Reproduce the Charmonman case using the linked commit and inspect the generated axis metadata; done means the intended handling of a non-default XXXX point axis is established and covered by an appropriate regression check.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.