Re: [css-font-loading] load, check and testing for character coverage

Tab Atkins wrote:

> With some caveats, it *is* a question that can be answered, and it's
> the more useful question to answer.
>
> When you call check() with some font list, you're asking "if I start
> to draw into a canvas with this font list, will I get what I
> expect?". If you "expect" to get the first font on the list, save
> for character fallbacks to lesser fonts in the list, then we can
> *almost* answer completely right.

> By default we have to just assume that you're only going to use
> characters you already know are in the font; if you specify a string
> of sample text, we can be indeed be completely correct if you didn't
> lie in the unicode-range of one or more faces.

This is a faulty assumption. Sites use fontlists to cover all manner of
scripts. And if the string being handled is user input, there's no
guarantee fonts in the fontlist will provide coverage at all. Assuming
unicode-range values match the actual cmaps is a fundamental
misunderstanding I think -- the range is there to simply say, "unless
characters are in this range, you don't need to download this font".
It's not intended to be a full copy of the cmap.

> By checking whether every font in the list is either (a)
> a loaded downloadable font, or (b) a known system font, and that at
> least one font can handle every sample character, we can give a
> definitive answer to this.

Again, there's nothing in the data for unloaded fonts that indicates a
font "can handle" characters. The unicode-range value is simply an
indication that it might.

> If it returns "true", you can go ahead and start rendering.  If it
> returns "false", you need to .load() that string and wait for it to
> finish.

Is this the only use case for check()? That's a question that's really
important to answer here. I think both Cameron and I are unsure whether
this is the only use case you see for the check() method. If
conditionally calling load() is the only use case, the logic for check()
should be the same as load(), which it's not if check() is doing "error
checking" in addition to testing load state.

> The third case is that the search for matching font faces
> returns nothing, indicating that some of your sample characters
> can't be rendered by *any* of the fonts in the list.  This is an
> error condition; either you misspelled your font names, or you're
> planning on using some characters that nothing can render.  Either
> way, we definitely shouldn't return "true" (using that font string
> won't render like you expected), and probably shouldn't return
> "false" either (.load() won't do anything).  This is why, near the
> end of the f2f, I suggested throwing in this case instead.

It's not correct to say that it's an "error". Fontlists may or may not
cover the range of characters used. Look at the localization links at
the bottom of the Facebook landing page (www.facebook.com) for which the
fontlist is always 'arial, helvetica, lucida grande, sans-serif'.  For
some of the items in the list, system font fallback will occur. That's
not an "error", that's the nature of fontlists in CSS.

The check() method is there simply to allow users to determine whether
all fonts that might need to be loaded have actually been loaded. So if
Facebook associated a particular font with their brand, in the case of
the Facebook localization links, you'd have:

  var localizations = ["English (US)", "日本語", "Português (Brasil)",
    "中文(简体)", "Tiếng Việt", "Español", "Bahasa Indonesia", "한국어",
    "Français (France)", "Deutsch"];

  var fontlist = "fb font, arial, helvetica, lucida grande, sans-serif";
  localizations.forEach(function(str) {
    if (document.fonts.check(fontlist, str)) {
      // draw the localization string with the fontlist
    } else {
      // draw ui to indicate waiting for a font load
      document.fonts.load(fontlist, str).then(function() {
        // draw the localization string with the fontlist
      });
    }
  }

Authors shouldn't be required to do some form of analysis on the
fontlist and possible contents to determine whether this will result in
errors or throws.

> I think throwing captures it correctly.  It lets you know when
> you've misspelled something, or have inadequate unicode-ranges, so
> that you can fix these problems.  Both "true" and "false" have the
> very real possibility of silently swallowing errors.

Throwing is actually worse here since you *force* developers to add
extra code that's completely unnecessary. As described above, I think
this is a problem with your assumptions about the nature of fontlists and
unicode-range values not being valid.

I see two options to this problem: (1) check() simply returns true/false
based on whether loads might occur or not or (2) remove the check()
method entirely. Throwing or check() trying to support glyph coverage
functionality is not the right thing to do.

Regards,

John Daggett

Received on Monday, 25 May 2015 07:44:48 UTC