Skip to content

Add ufoz support - #407

Merged
cmyr merged 3 commits into
mainfrom
ufoz2
Jul 13, 2026
Merged

Add ufoz support#407
cmyr merged 3 commits into
mainfrom
ufoz2

Conversation

@cmyr

@cmyr cmyr commented May 14, 2026

Copy link
Copy Markdown
Member

If passed a file (not a directory) and with the 'ufoz' feature enabled, norad will attempt to treat the file as a zip'd ufo directory.

@RickyDaMa RickyDaMa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think there are significant improvements that we could implement while everything is in flux. Sorry I don't have the time to offer to help beyond these little reviews 🙏

Comment thread src/font.rs
Comment on lines +224 to +225
#[cfg(feature = "ufoz")]
if metadata.is_file() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why are we only checking it's a file, not looking at the extension?

If we were ever to add JSON UFO loading, we're going to clash with this

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

my thinking is basically: if it's a directory, try to load it as a ufo. If it's a file, try to load it as a ufoz. I believe in the wild I've seen zipped ufos with the .zip extension, and I'm not sure what doing the extension check really buys us?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Compatibility with e.g. JSONified UFOs or any other single-file UFO formats we may want to support in future. Granted they're not enshrined in the spec the same as I believe ufoz is, but JSONified UFOs are phenomenally useful to work with in build systems as it massively reduces I/O usage while still keeping human readable files for debugging.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

that makes sense, and i'm not opposed to adding json support if it would be genuinely helpful (and it might be worth even proposing as an extension to the spec, if you're finding it has real-world benefits. In any case I propose we punt on this until support for that materializes, and then we can do something fancier here like actually checking for the zip's magic bytes.

Comment thread src/zip_source.rs Outdated
Comment on lines +15 to +17
impl ZipSource {
/// Open a zip archive at the given path and load all file entries into memory.
pub fn open(path: &Path) -> Result<Self, FontLoadError> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Would it be possible to just decompress what we need on the fly, instead of everything at once ahead of time?

If we store the archive in ZipSource instead of the decompressed entries. I guess the issue is that FontSource doesn't let you mutate self currently, but that could be changed or worked around I guess?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yea, so this is possible but we'd either need the trait to take &mut self, or we'd need interior mutability.

Ultimately it comes down to the tradeoffs: doing it all up front increases peak memory usage but is also more efficient, since we don't need to seek around the zip contents and do redundant deflating?

One issue I would point out here though is that the current design means we deflate everything even if we have a sparse DataRequest, and that does smell bad, but it's easy enough for us to thread DataRequest through to ZipSource::open and then avoid that work, so i'll make that change.

Comment thread src/zip_source.rs Outdated
@cmyr
cmyr force-pushed the a-general-loading-api branch from 5378f30 to 2dee764 Compare June 24, 2026 18:14
@cmyr
cmyr force-pushed the a-general-loading-api branch 2 times, most recently from cc1e973 to 5b5ee69 Compare June 25, 2026 17:03
@cmyr
cmyr force-pushed the a-general-loading-api branch 2 times, most recently from f4737b9 to cc6c587 Compare June 25, 2026 18:34
Base automatically changed from a-general-loading-api to main July 3, 2026 16:31
cmyr added 2 commits July 8, 2026 11:19
If passed a file (not a directory) and with the 'ufoz' feature enabled,
norad will attempt to treat the file as a zip'd ufo directory.
Add end-to-end integration tests for ufoz loading

Verify that loading a UFO from a zip archive via Font::load produces a
Font identical to loading the same UFO from a directory, covering the
wrapper-dir, __MACOSX, data/images, DataRequest, and error paths.
@RickyDaMa RickyDaMa linked an issue Jul 8, 2026 that may be closed by this pull request
@cmyr

cmyr commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

@RickyDaMa if this looks good to you i'll get it in :)

@RickyDaMa RickyDaMa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

One final thing that could be nice to do is to add this to our Cargo.toml:

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

So that the docs are generated for all features, and feature-specific API is labelled with what feature has to be enabled.

It's not the cleanest example because the underlying code is generated, but you can see this in the docs for static-lang-word-lists' constants

Comment thread Cargo.toml Outdated
- Thread DataRequest through to ZipSource::open, so we don't decompress
  things we don't need
- improve find_zip_root
@cmyr
cmyr merged commit a345dd4 into main Jul 13, 2026
5 checks passed
@cmyr
cmyr deleted the ufoz2 branch July 13, 2026 17:53
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.

UFOZ support

2 participants