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

I think we need to be careful to distinguish the load/check methods of
FontFaceSet from the implicit loading that occurs when text on a page uses
downloadable fonts. Specifically, the "matching" behavior of the load
method is *not* the matching behavior used by the implicit loading
mechanism which effectively only loads fonts as needed to support page
content. They don't have the same behavior and, after discussing this with
Cameron a bit, I think there are good reasons for them not behaving the
same way. I think a couple examples will illustrate this.

Simple implicit load example:

  @font-face {
    font-family: fontA;
    src: url(fonts/simple.woff);
  }

  <p style="font-family: fontA">This is a simple case</p>

When the page is loaded and layout is performed, the 'simple.woff' font
resource will be implicitly loaded. *If* it contains Latin glyphs, it will
be used for the content of the paragraph element.

Complex implicit load example 1:

  @font-face {
    font-family: fontB;
    src: url(fonts/bigfont-fallback.woff);
    /* no unicode-range descriptor ==> full range of Unicode codepoints */
  }

  @font-face {
    font-family: fontB;
    src: url(fonts/bigfont-latin.woff);
    unicode-range: u+0-2ff, u+21??; /* latin and arrows */
  }

  <p style="font-family: fontB">This is still a simple case</p>

When the page is loaded and layout is performed, the 'bigfont-latin.woff'
font resource will be implicitly loaded. If it contains Latin glyphs for
the characters in the paragraph element, it's the *only* font resource that
will be loaded.

Complex implicit load example 2:

  <p style="font-family: fontB">Using the ⇒ arrow!</p>

The content here uses the right double arrow (U+21D2), so when layout is
performed the 'bigfont-latin.woff' font resource will be implicitly loaded.
If this font resource doesn't contain a glyph for the double arrow,
'bigfont-fallback.woff' will also be downloaded. So depending upon the
content, more font resources may be loaded.

The load method of FontFaceSet on the other hand will load *all* faces for
a given family that might contain glyphs for a given string, based on the
value of the 'unicode-range' descriptor:

  document.load("16px fontB", "This is still a simple
case").then(function() {
    // at this point both 'bigfont-latin.woff' and
    // 'bigfont-fallback.woff' have been loaded
  });

This is less efficient than the mechanism used by the implicit load
mechanism but it's conservative, which is important for the actual use
cases, such as canvas text drawing usage:

  document.load("16px fontB", "Using the ⇒ arrow!").then(function() {
    // all possible fonts have been loaded at this point
    ctx.font = "16px fontB";
    ctx.fillText("Using the ⇒ arrow!", 50, 50);
  });

The alternative would be to require the 'load' mechanism to mimic the way
implicit loading works but I think that's a bad idea, it adds unnecessary
complexity. It would also make check unfeasible, since it couldn't evaluate
whether all necessary loads had completed or not.

Tab Atkins wrote:

> > For example, assuming Helvetica is a system font:
> >
> >   document.fonts.check("16px Helvetica", "上")
> >
> > Should this return false, because the font does not have a glyph for the
> > specified character, or should it return true as if we treated system
> > fonts as having an unspecified unicode-range (and therefore covering all
> > characters)?
>
> I'm inclined to say we should assume that unicode-range is set
> to be equal to the font's cmap.

No, load/check should only consider whether a load is needed or not. System
fonts are by definition already loaded. Downloadable fonts are loaded based
on the coverage of the unicode-range descriptor. The cmap is irrelevant
here. This is the key difference with the implicit loading mechanism.

> > In line with the check method meaning “will loads be kicked off”, I
> > think it should return true if the list of matching font faces is empty.
>
> It originally did. I changed it to false based on feedback that it was
> confusing that the method returns true if you can render without
> loads, or if you can't possibly render it at all. ^_^ The current
> semantics mean that "true" indicates you can successfully render the
> text as desired immediately (assuming you're not lying in
> unicode-range), while "false" means you can't - either the necessary
> fonts aren't loaded yet, or none of your desired fonts can render it
> at all, and you'll fallback to an (undesired) default font.

This is a bad way to describe load/check. They are *not* guarantees of
glyph coverage, they are simply guarantees that all possible font loads
have already completed. We should be careful not to conflate these methods
with any sort of glyph coverage assurance.

I agree strongly with Cameron, step (3) of the algorithm for 'check' should
return true and not false as stated in the spec. All the examples below
should return 'true', since no font load would occur when attempting to
render text in these cases:

  document.fonts.check("16px Helvetica") ==> spec: true
  document.fonts.check("16px Helvetica", "") ==> spec: false
  document.fonts.check("16px Helvetica", "hello") ==> spec: true
  document.fonts.check("16px Flaming Balls of Phlegm") ==> spec: false
  document.fonts.check("16px Flaming Balls of Phlegm", "") ==> spec: false
  document.fonts.check("16px Flaming Balls of Phlegm", "hello") ==> spec:
false

Assuming "Flaming Balls of Phlegm" is a non-existent font family, in none
of these cases is a font load needed. The 'check' method should always
return 'true' otherwise authors are going to run into some nasty gothca's
with this method.

I think it would be a good idea to include a note about load/check being
different from the implicit load mechanism, along with an example
illustrating this point.

I should also point out here that the "allow system fonts" flag is
unnecessary in the 'find the matching faces' algorithm. The spec doesn't
really define what it is, so best to remove it I think.

Cheers,

John Daggett

[1] http://dev.w3.org/csswg/css-font-loading/#font-face-set-check

Received on Friday, 15 May 2015 05:11:04 UTC