Skip to content

Use one resolver for a core font's hashed name #2020

Closed

Description

@gravitypdf-bot

Follow-up to #2016. A core font can end up under a hashed name ({stem}-{sha8}{ext}) in two ways, and every reader of a family's files has to handle both. Add one method that answers "what is this family file's own copy, and is it really on disk", and move the readers onto it. Best done after #2016 and the PRs based on it (#2008, #2010 to #2014) have landed.

The two ways

  • A Font Manager record has the name: a name rewrite. Model_Font_Sources::get_record_collisions() maps the plain name to the hashed name, use_hashed_names() writes that into the family's font data, and with_record_aliases() adds the hashed name to the manifest. The family's file is then actually called Foo-abcd1234.ttf.
  • Any other conflict: a path rewrite. The family's file stays Foo.ttf, and get_font_path() returns the hashed copy if there is one, otherwise the plain file.

What it costs

  • get_hashed_name() needs an "already hashed" case, because hashed names are manifest keys under the first scheme.
  • Model_Font_Downloader::get_core_font_row() has to translate names itself so sizes and previews read the font's own copy. Under the first scheme they were already right, which is how that was missed.
  • get_core_families() counts a file as on disk through get_font_path(), which falls back to the plain file. Another font's file with no hashed copy therefore lists as the family's core font, with that file's size, and delete_downloaded_font() deletes it, while is_installed() rejects the same file.
  • remove_older_hashed_copies() only runs on a conflict save, so a family with a record collision leaves the older release's hashed copy behind when a new manifest changes the sha. That orphan no longer matches is_hashed_copy(), so add_unregistered_fonts_to_mPDF() can register it as a user font.
  • is_on_disk() still uses the plain-name check, so Sun-ExtA/ExtB substitution can disagree with what the finder would load when only a hashed copy exists.
  • There are several overlapping "is this font present" checks: is_downloaded(), is_installed(), is_size_conflict(), has_hashed_copy(), and the downloader's is_conflict() and is_resolved().

Proposal

Add a single resolver on Model_Font_Sources, and have get_core_families(), register_font_data(), the Font Manager rows, delete and the older-copy cleanup use it, ideally without hashed-name aliases in the manifest.

The two schemes can't fully merge, so this is about unifying the reading side:

  • A record conflict has to stay a name rewrite that reaches mPDF's font data. mPDF only gives the finder a file name, so if a record and a family both asked for Foo.ttf, the finder couldn't tell them apart.
  • Making every conflict a name rewrite would mean a stat per family file whenever font data is registered, and font data that changes whenever a conflict appears.

To decide

Should deleting a family remove another font's file at its name when no hashed copy exists? Delete is currently deliberately "whatever its hash", and tests in Test_Downloaded_Fonts expect that. Counting only the font's own files would protect the file, and would make those tests change. With downloads off, such a family would also drop out of the Font Manager list.

Watch out for

  • Failures and back-offs are keyed by the manifest name, and the required-font list and sync read family files, so check those if the manifest's keys change.
  • Nothing new on the render path should hash an existing file.
  • Constructor signatures stay as they are.

Activity

  1. added 2 commits that reference this issue on Nov 11, 2026
    e101c98
    6a9f509
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions