WICG / local-font-access

Web API for enumerating fonts on the local system
https://wicg.github.io/local-font-access
Apache License 2.0
75 stars 16 forks source link

Better support for Font Matching and Font Substitution #95

Open my2iu opened 2 years ago

my2iu commented 2 years ago

I think the API should be extended with better support for font matching and font substitution.

Here is an example use case: a web app loads a word processor document. That document references 20 fonts. The app looks through the local fonts to see if the computer has those fonts available or to find good substitutes if those fonts aren't available. A similar situation might happen for a web app that uses CSS or other stylesheet system to describe its styling and has to run its own css font matching to render (does Flutter do this?)

I can think of a few different ways that this font matching/substitution could be better supported:

  1. There could be an explicit API for font matching. The web app supplies descriptions of all the fonts it needs (e.g. name, weight, character sets, etc), the API will find close matches for them and ask the user for permission to expose these fonts to the web app
  2. extend queryLocalFonts() to support querying on more fields like weight, style, name, id, etc. That way, for each font that it needs, a web app can query to find good candidate font matches
  3. extend the FontMetadata so that web apps can ask for individual font tables instead of entire fonts. That way web apps can scan through all the fonts themselves and create their own cache/index of font information that they can use for font matching. Right now, it's only possible to get blobs with entire fonts, so a web app might need to scan through gigabytes of font data to create such an index, which is too slow
inexorabletash commented 1 year ago

Re: "extend queryLocalFonts() to support querying on more fields like weight, style, name, id, etc. That way, for each font that it needs, a web app can query to find good candidate font matches"

We explored adding these properties to the enumeration data in #61, but received feedback that this didn't actually help - web applications would extract this data and more specifics from the fonts when building the index anyway.

Re: "Right now, it's only possible to get blobs with entire fonts, so a web app might need to scan through gigabytes of font data to create such an index, which is too slow"

In Chrome, at least, the Blobs are file-backed and can be parsed without being fully loaded into memory. It should only be necessary to pull in the table directory, and then any necessary tables for building the app's index.

We did early experiments with exposing only tables rather than the blob, but learned that there were few existing libraries that operated on tables themselves - they all wanted the full data! More data would be helpful - e.g. demonstrations that the performance doing it from script/wasm with the existing APIs is poor.

my2iu commented 1 year ago

Yes, JS-native font renderers were based on whole font files because web developers had to supply their own font files. These APIs don’t provide a way to consume individual font tables because there was no way to extract individual tables without writing that code yourself. It’s a chicken-vs-the-egg problem. These JS-native renderers will likely be deprecated over time because they lack features and don’t handle things like internationalization properly. Libraries like Harfbuzz, which do interface with OS-level APIs, do have support for ingesting individual tables because those are the preferred interface for OS-level APIs. WASM versions of Harfbuzz will likely replace existing JS-native font renderers because Harfbuzz supports proper internationalization and more types of fonts. Already, Typr.js includes Harfbuzz for internationalization, and newer versions of Harfbuzz include all of Typr.js’s functionality anyway, so it will be just a short step to deprecation.

As for performance, the spec is intended for all browsers not just Chrome, and if implementations require memory-mapped files to achieve reasonable performance, then that should be in the specification. If memory-mapped files is only an implementation detail, then the spec should provide alternate APIs that can achieve adequate performance.

In terms of running performance experiments, that’s really something that only Google has the bandwidth to do. You should get some interns to do that.

my2iu commented 1 year ago

In terms of an enhanced queryLocalFonts(), it might be enough to just allow queries on font family name and font subfamily name. I know that this data is already in the FontMetadata, but it might be useful to allow queries on those fields because fonts have different names in different languages. The value in the FontMetadata might not match the language of the name that a program is searching for, but an enhanced queryLocalFonts() could handle that. Perhaps, that query could also automatically look in the typographical family name, typographic subfamily name, WWS family name, and WWS subfamily name as well.