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

Postscript names for UFO sources #489

Merged
merged 16 commits into from
Oct 23, 2023

Conversation

RickyDaMa
Copy link
Contributor

@RickyDaMa RickyDaMa commented Oct 17, 2023

Related to: #248

Reads postscript names from the lib.plist of UFO sources, and then uses them when writing the post table.

Compiling Oswald using its Makefile yields an identical post table to that of a fontc-compiled UFO-based Oswald.

Tests not yet updated to account for the extra field on StaticMetadata, or extra parameter of StaticMetadata::new. Very much just a proof of concept to gather feedback and see if there are any changes wanted in our approach before updating tests. Naturally, tests should also be added for reading/writing these names.

For discussion:

  1. How do we want to handle duplicate postscript entry values?
  2. What auto-generation do we need to implement for glyph names that are not included in AGLFN? What does fontmake do?
  3. Do we want to add a CLI flag to use design names instead of production names, similar to fontmake's --no-production-names?
  4. Shall we implement this feature for glyphs2fontir in this PR?

Implementation notes/thoughts:

  1. Do we want to check for equality of public.postscriptNames across all masters?
  2. Should we read postscript names and glyph order at the same time? Or at least, without loading the plist into memory twice?
  3. What error variant should we use for "public.postscriptNames is present, but not a dictionary"?
  4. Does postscript_names belong in the top-level StaticMetadata, or in misc (or context, like GlyphOrder)?
  5. Should we use a smaller type for postscript name values, i.e. GlyphName or Box<str> instead of String?

Tangent (though tests will currently fail if run): https://matklad.github.io/2022/10/24/actions-permissions.html

Store postscript names in StaticMetadata of IR
Postscript names taken from default master
Empty default for Glyphs.app sources (for now)
@anthrotype
Copy link
Member

Thanks!

  1. How do we want to handle duplicate postscript entry values?

duplicate as in the same key repeated more than once? does plist even allow that? Probably not as dict keys are unique. We should do whatever a normal plist parser does when encountering these, nothing more.

  1. What auto-generation do we need to implement for glyph names that are not included in AGLFN? What does fontmake do?

we should defer to that for a follow-up PR, it's ok to first implement writing the explicit postscriptNames; ufo2ft.postProcessor can make up AGLFN-compatible names from glyphs codepoints, we could implement that later.

  1. Do we want to add a CLI flag to use design names instead of production names, similar to fontmake's --no-production-names?

that's useful sometimes for debugging, to have human-readable names instead of uniXXXX, so I would say yes we want that. preferably matching the fontmake's CLI flag name so it's already familiar to fontamake's users.

  1. Shall we implement this feature for glyphs2fontir in this PR?

can be done in a follow-up PR. We can file an issue so we don't lose track of this temporary asymmetry between frontends

  1. Do we want to check for equality of public.postscriptNames across all masters?

taking the one from the designspace.lib or, if that missing, the one from the default master UFO lib.plist should suffice. It's not our job to validate these IMO.

  1. Should we read postscript names and glyph order at the same time? Or at least, without loading the plist into memory twice?

yeah, maybe, makes sense

I have a meeting now, will come back to this later

fontir/src/ir.rs Outdated Show resolved Hide resolved
@anthrotype
Copy link
Member

  1. What error variant should we use for "public.postscriptNames is present, but not a dictionary"?

WorkError::ParseError(lib_plist_file, "Not a dictionary".to_string()) as in

.ok_or_else(|| WorkError::ParseError(lib_plist_file, "Not a dictionary".to_string()))

  1. Does postscript_names belong in the top-level StaticMetadata, or in misc (or context, like GlyphOrder)?

it's fine in StaticMetadata, I think

@anthrotype
Copy link
Member

taking the one from the designspace.lib or, if that missing, the one from the default master UFO lib.plist should suffice.

it looks like ufo2ft only looks for postscriptNames defined in the default master UFO lib.plist, that's the one it uses in its postProcessor when compiling a VF. I confused this with the other "skipExportGlyphs" key which ufo2ft attempts to find in the designspace.lib first. Maybe it should do that as well for postscriptNames.. Anyway matching current fontmake.py is fine for now.

Golf code around about for readability (no nested Options)
Create type alias PostscriptNames
@RickyDaMa
Copy link
Contributor Author

RickyDaMa commented Oct 19, 2023

How do we want to handle duplicate postscript entry values?

duplicate as in the same key repeated more than once?

Duplicate as in the same value repeated more than once. There's currently no handling for this

taking the one from the designspace.lib or, if that missing, the one from the default master UFO lib.plist should suffice

Yeah this was how we were going to initially set out to implement it before we also realised it's not looked for in the DS in the Python stack. Maybe something to revise down the line, but probably out of scope for this PR


I've pushed a couple of the basic suggested changes, and shall now look into adding the CLI flag and removing the double load-from-disk

@anthrotype
Copy link
Member

Duplicate as in the same value repeated more than once. There's currently no handling for this

I don't think the python toolchain checks for this, does it? In any case, feel free to add or not add the additional check. To me it feels more like the job of a linter

@Hoolean
Copy link

Hoolean commented Oct 19, 2023

Hello all, and many thanks for the speedy review Cosimo :)

I don't think the python toolchain checks for this, does it? In any case, feel free to add or not add the additional check. To me it feels more like the job of a linter

IIRC in ufo2ft we do some sanitisation of names and add a suffix to ensure uniqueness, although I cannot see a uniqueness requirement in the post table spec; I am not sure if this was added for platform support or just to cooperate with ttLib's use of names as unique IDs. In most real-world instances where I have seen duplicate post names in sources it has been unintentional, however, and so I am torn.

@anthrotype
Copy link
Member

Thanks Harry. Indeed, looks like that dedup logic was deliberately added in ufo2ft to address some fonttools quirk:
googlefonts/ufo2ft#274

while the post spec may not require the names to be unique, it kind of defeats the purpose of having multiple glyphs mapped to the same postscript name if you use the name to identify a specific glyph or reverse-cmap, which is what AGLFN is primarily about. If cmap maps from unicode codepoint to glyph (ids), it's impossible for a given codepoint to map to more than one glyph at a time.

I think it's rare that sources have duplicate postscript glyph names, and if they do it's usually by mistake, I don't see a use case for it besides wanting to make a deliberately broken font for testing purposes. But sure let's add the dedup logic

@anthrotype
Copy link
Member

sure let's add the dedup logic

also feel free to kick the can down the road and not do it in this PR (can file an issue)

@anthrotype
Copy link
Member

anyway, when decompiling post, fonttools seems to be able to deduplicate glyph names as needed:

https://github.com/fonttools/fonttools/blob/6d531fed449d299c31e4cf69957b3fdd81cb982d/Lib/fontTools/ttLib/tables/_p_o_s_t.py#L117-L122

since we are not using fonttools to compile the binary font, we don't have this problem, so it's only about whether or not we think a valid post should contain unique names. Given the post spec does not enforce this requirement, I believe we should not either.

@anthrotype
Copy link
Member

it's impossible for a given codepoint to map to more than one glyph at a time.

while that's true, if you also think about alternate glyphs substituted for via GSUB, then indirectly it is possible to say that both glyph "A" and glyph "A.ss01" are mapped to 0x0041, and in fact AGL spec says one should drop the suffix after the period when mapping from glyph name to character string: https://github.com/adobe-type-tools/agl-specification#2-the-mapping

yeah I think I have convinced myself that we do not need to do any checks for duplicates here

@anthrotype
Copy link
Member

I don't see a use case

now I do see it. If you don't care about the nice debug glyph names and being able to distinguish glyph "A" from "A.ss01" (e.g. when decompiling the font in a font editor) but only care about AGL compliance and reverse-cmapping of names to characters for old PDF distillers, then it may be beneficial to actually reuse postscript names for alternate glyphs that ultimately are mapped to the same unicode codepoint(s) such that the post table is as compact as needed.

@RickyDaMa
Copy link
Contributor Author

I've added a duplicate value check. I agree with Harry that this is often a mistake, so I'm erring on the side of being (hopefully) more helpful. Given that it's not strictly spec to have to have unique values, it's just a warning

I've also added the --no-production-names flag. I think I've followed the existing modus operandi there, feel free to point out if I haven't

Shall look at deduplicating the plist loads tomorrow, then onto tests!

ufo2fontir/src/source.rs Outdated Show resolved Hide resolved
Loses some resolution in a very rare error (public.postscriptNames not being a dictionary)
Fix glyph_order signature in other test
Double negatives are the curse of programmers everywhere
Add debug printing of bitflags in arg_default_matches_flags_default for
ease of debugging
Add Default::default() to params of StaticMetadata::new where needed
@RickyDaMa RickyDaMa marked this pull request as ready for review October 20, 2023 16:08
@RickyDaMa
Copy link
Contributor Author

RickyDaMa commented Oct 20, 2023

Okay, I think the PR is in a good state now. I've addressed the suggestions, and implemented tests. Let me know if there's anything further you'd like to see :)

Once merged, I'll open any appropriate issues to track the deficiencies in the current implementation: not supporting glyphs sources, not matching fontmake's name generation, etc.

let arg_default = Args::parse_from(vec!["program", "--source", "dont.care"]).flags();
let flags_default = Flags::default();
debug!("flags_default: {:#032b}", flags_default.bits());
debug!("args_default: {:#032b}", arg_default.bits());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of firing up the logger and writing to debug make the assert do what you want, either by altering the left/right values or by adding a custom panic string to show the {:#032b} strings

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure thing. Only downside is it means I can't align the values when they're printed

ufo2fontir/src/source.rs Outdated Show resolved Hide resolved
ufo2fontir/src/source.rs Outdated Show resolved Hide resolved
ufo2fontir/src/source.rs Outdated Show resolved Hide resolved
ufo2fontir/src/source.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@rsheeter rsheeter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM subject to nits being fixed

Note corresponding fontmake flag for --no-postscript-names
Move debug logs into assertion
Change duplicate_values_check name
Make filter expr one line
Only check for postscript duplicate values when warn logs are enabled
Don't duplicate code in tests (add Flags param to build_static_metadata)
@RickyDaMa
Copy link
Contributor Author

All comments addressed, let me know if there's anything else!

@@ -70,6 +72,7 @@ impl From<StaticMetadataSerdeRepr> for StaticMetadata {
from.axes,
from.named_instances,
from.glyph_locations.into_iter().collect(),
from.postscript_names,
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello again! A wee question, tangential to this PR: we noticed that misc is serialised in StaticMetadataStaticMetadataSerdeRepr but not deserialised in StaticMetadataSerdeReprStaticMetadata; do we populate it elsewhere, or could this be a bug? 🐛

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like a bug to me

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall I sort this as part of this PR, or file this as a bug?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

technically it's a separate issue, might be worth tackling it separately

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raised as #499

@anthrotype anthrotype added this pull request to the merge queue Oct 23, 2023
Merged via the queue into googlefonts:main with commit 4f35733 Oct 23, 2023
8 checks passed
anthrotype added a commit that referenced this pull request Oct 23, 2023
After PR #489, fontc should use the same glyph postscript names as fontmake does, so we no longer need to pass the --no-production-names flag to compare the two sets of fonts
@RickyDaMa RickyDaMa deleted the postscript-names branch October 23, 2023 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants