W3C home > Mailing lists > Public > www-style@w3.org > April 2013

Re: [css-font-load-events] Using Futures

From: Bjoern Hoehrmann <derhoermi@gmx.net>
Date: Fri, 05 Apr 2013 02:29:25 +0200
To: "Tab Atkins Jr." <jackalmage@gmail.com>
Cc: www-style list <www-style@w3.org>, Anne van Kesteren <annevk@annevk.nl>
Message-ID: <p1url8lpmnmpubfjc5u8tgqitbccr5l4r9@hive.bjoern.hoehrmann.de>
* Tab Atkins Jr. wrote:
>[...]

(Some gut reactions:)

>1. Sites that are going to do some type of DOM measurement that will
>depend on the loaded font (such as the size/position of an inline, or
>the height of a block), would like to be able to check if all fonts
>are loaded, and be notified when any currently-loading fonts are done.

The dependency would be on the font that is "ultimately" used, not on
any loaded font, otherwise web pages would break when users disable the
use of illegible fonts in their browser...

>[http://gitbug.com/slightlyoff/DOMFuture]

http://github.com/slightlyoff/DOMFuture

>Here's my proposed new API (explanations/justifications will follow):
>
>partial interface document {
>  readonly attribute FontList fonts;
>}
>
>interface FontList : EventTarget {
>  /* whatever idl magic you need to make this an array-like filled
>with Font objects */
>  Future ready()
>  boolean checkFont(DOMString font, optional DOMString text = " ");
>  Future loadFont(DOMString font, optional DOMString text = " ");
>  attribute EventHandler onloading;
>  attribute EventHandler onloadingdone;
>}

Having event listener attributes on the object strikes me as a bad idea.
It is likely that several separate components would want to listen for
them, but having the attributes encourages code that would override the
listeners of one component in another, leading to bugs that are annoying
to debug (only happens on high latency networks, only with empty cache).

>First of all, I'm replacing document.fontLoader with document.fonts,
>an array-like of Font objects.  Each Font object is a readonly version
>of a CSSFontFaceRule object, without any links into the CSSOM.  This
>seems like a useful convenience API all by itself, but it's also
>something that can be safely exposed to Workers, as there's no
>DOM/CSSOM link to make it unsafe.  The FontList contains Font objects
>for all the @font-face rules in all the stylesheets for the document,
>in document order.

That sounds more like `document.styleSheets.fontFaceRules` to me. It's
rather unclear to me that this filtered and read-only view is a good
idea.

>The FontList.ready() function returns a Future.  This is initially
>unresolved, and resolves when the browser has loaded all stylesheets
>and has finished loading all the fonts it chooses to initially load.
>It must return the same future across multiple calls.  If, after
>resolving the future, the browser beings loading more fonts, it must
>create a new future to return from .ready(), and again resolve it when
>the browser stops loading fonts.  This addresses use-case #1,
>replacing notifyWhenFontsReady().

It's not clear to me whether "same future" refers to object identity and
if it does, why this would not return a new object on each invocation. I
am not sure from your proposal what the object would be "resolved" with,
and when.

>The loadFont() function has had its API reverted to be identical to
>checkFont, and it just returns a future which is resolved as soon as
>all the necessary requested fonts have loaded (which may be
>immediately, if all necessary fonts are already loaded).  This
>addresses use-case #2.

It seems you mean that you propose `checkFont` and `loadFont` to have
the same prototype (argument list), but otherwise they are not identical
at all.

>checkFont() is unchanged.
>
>To address use-case #3, the API has two pieces.  If you care about the
>loading status of individual fonts, look for the relevant Font object
>and call its ready() function to obtain a Future which is resolved
>when the font is done loading, or cancelled when the font load has an
>error.  This replaces the loadstart/load/error events.  The
>loading/loadingDone events are unchanged - they're useful for
>providing UI indicating whether fonts are loading or not, rather than
>a one-off "tell me when fonts are ready", which is what the .ready()
>future is for.

This sounds like you are proposing that load failures cannot be observed
through the Event APIs. If so, I am not sure what motivates that.

Overall, I think it would be good to have a common protocol for similar
APIs, and if "Futures" are such a protocol I think it makes sense to use
them for `loadFont`, but beyond that I am not really a fan of your pro-
posal, or the `FontLoader` so far.

One worry is that when you actually want to take measurements only when,
as far as the browser knows, final layout no longer depends on unknowns,
you have to wait for more than just fonts, there may also be images or
web components or other things that are not yet "ready", so binding to
font loads would be incorrect.

Another worry is the liveness of the FontList you propose; a "Future"
that encapsulates multiple "Future" objects is a common idiom, but you
usually would know what you are waiting for, and the typical libraries
do not appear to support "live" semantics; as an example, it bothers me
that `X.all(Array.from(document.fonts).map(x => x.ready()))` is quite
different from `document.fonts.ready()`, where `X.all` creates a Future
out of a list of Futures.

Yet another problem I see is that currently components tend to be poorly
isolated. You might have a third party script on your site that attempts
to use a font that fails to load, but you do not want your own code to
break because of that, so using `document.fonts.ready()` is a bad idea
for robust code. That is a problem that might go away if and when compo-
nents become better isolated, but right now it is a concern.
-- 
Björn Höhrmann · mailto:bjoern@hoehrmann.de · http://bjoern.hoehrmann.de
Am Badedeich 7 · Telefon: +49(0)160/4415681 · http://www.bjoernsworld.de
25899 Dagebüll · PGP Pub. KeyID: 0xA4357E78 · http://www.websitedev.de/ 
Received on Friday, 5 April 2013 00:29:54 UTC

This archive was generated by hypermail 2.3.1 : Friday, 5 April 2013 00:29:54 UTC