Re: [css-font-loading] replacing [[ReadyPromise]]

On 01/07/14 07:53, Tab Atkins Jr. wrote:
>> First, I notice  that it says "fulfilled" rather than "settled". Although
>> the spec never rejects [[ReadyPromise]], script could.  Is it worth making
>> document.fonts.ready resilient to that?
>
> How can script reject the [[ReadyPromise]]?  It doesn't have access to
> the promise's reject handler.

Of course, good.

>> Second, detecting if [[ReadyPromise]] holds a fulfilled promise is not
>> really something you can do with the Promise API.  Well, you could do this
>> (maybe?):
>>
>>    var fulfilled = false;
>>    readyPromise.then(function() { fulfilled = true; });
>>    setTimeout(function() {
>>      if (fulfilled) {
>>        readyPromise = new Promise(...);
>>      }
>>    }, 0);
>>
>> but I'm not really sure if this is an idiomatic use of Promises.
>
> It's easier than this.  The UA already maintains counters of loading
> fonts, for the purpose of firing the events.  (This can be done
> non-magically, since the actual load machinery is UA-controlled, so it
> can go increment/decrement some hidden state to communicate this
> information.)  It can use the same counters to keep track of the
> promise states.

OK, yes, should have thought of that. :-)

I've just noticed there is one issue with the way [[ReadyPromise]] is 
initialized with a pending promise when the FontFaceSet is first created 
and replaced whenever we transition from "no fonts loading" to "some 
fonts loading".  It allows authors to write code that "works" if they 
are tracking the very first set of fonts loading and "doesn't work" with 
the same code pattern for subsequent font loads.

For example:

   // Assume document.fonts is empty and has been empty since the
   // document was created.
   var face = new FontFace(...);
   document.fonts.ready.then(function() { alert("loaded"); });
   document.fonts.load(face);

This will alert once the font loads, because document.fonts is not 
replaced when with a new Promise object as soon as the FontFace starts 
loading.

   // Now continue on once |face| has been loaded and the
   // [[ReadyPromise]] has been replaced.
   var face2 = new FontFace(...);
   document.fonts.ready.then(function() { alert("loaded"); });
   document.fonts.load(face2);

This will alert before face2 loads, because document.fonts.ready is the 
already-fulfilled Promise representing the first FontFace's load.

We could avoid this by having the FontFaceSet initialized 
[[ReadyPromise]] to a Promise that is already resolved with the FontFaceSet.

Received on Thursday, 3 July 2014 04:16:31 UTC