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

On Thu, May 14, 2015 at 10:10 PM, John Daggett <jdaggett@mozilla.com> wrote:
> 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.
[snip examples]
> 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.

Yes, they're definitely different, and I don't think I'm conflating them.

> Tab Atkins wrote:
>> Cameron 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.

We're not discussing load(); its behavior is clear.  (If the list is
just local fonts, you get an immediately-fulfilled promise for an
empty array.)

Whether check() should be answering "is a load needed?" or "is
everything you might need to render available?" is the question at
hand; you can't just assume it.

We got feedback from early users that the former question yields
confusing answers in degenerate cases; misspelling a font name would
return true, same as correctly spelling the font and having it loaded.
Apparently people prefer to ask the latter question, so I adjusted the
degenerate case answer to match.

>> > 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'm not conflating these.

> 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

Whoops, second case is clearly a spec bug, thanks for bringing it up.
(Though it doesn't reflect on the question at hand. ^_^)

The latter three are all false on purpose; you can't possibly render
as intended by that declaration (as the font doesn't exist).

> 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.

Can you describe what gotchas you envision? The current behavior is
intended to avoid a particular gotcha, that misspellings acted like
successful loads.

> 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.

Agreed; I'll see what I can do about that.

> 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.

??? Yes it does.  It controls whether system fonts show up in the
returned list; that's well-described in the algorithm.  load() sets it
to false, because it's only concerned with loadable fonts, and system
fonts are irrelevant and would clunk up the array the promise resolves
to for no benefit.  check() sets it to true, so you can use the same
"font" string in check() and your actual code, with system fonts
included.

~TJ

Received on Friday, 15 May 2015 18:41:04 UTC