- From: John Daggett <jdaggett@mozilla.com>
- Date: Thu, 30 Oct 2014 01:43:50 -0700 (PDT)
- To: www-style list <www-style@w3.org>
Ilya Grigorik wrote: > > As defined, the 'optional' keyword would always be effectively > > determined by whether a font had been loaded by a previous page, > > since layout initiates font loads and paint follows shortly after > > layout. So 'optional' in practice would be equivalent to "use the > > the font if it's already been cached". > > > > The fact that a resource may be in a local cache does not mean it is > instantly available: you need to hit your spinning rust / flash, and you > (likely) need to hop between I/O and render threads. We have telemetry data > showing that even with flash, some disk accesses are in high double and > even triple digits of milliseconds, and on top of that you have thread > hops, which can also add non trivial amounts of overhead (although, often > less due to hops and instead due to contention between main thread being > busy and events accumulating in the queue). > > Cache lookups are not free or instant, and from first hand experience in > Chrome, we can't count on font being available in time just because its > "cached"... There are cases where network fetches are faster than cache > lookups -- crazy, I know. With 'optional', the font generally won't be available the first time it's referenced, it'll only be *possibly* available on subsequent pages, subject to all the lovely browser internals you describe. > > The Font Loading API gives authors complete control over when fonts > > are loaded, precisely when they are used, and how the "swap" occurs. > > Loads are not instant. Yes, we can kick off a .load() with Font Events API, > but that doesn't mean it'll complete in time for layout+paint. The Font ****Loading**** API allows you to kick off the load. Fonts can be loaded without being added to the FontFaceSet, so they will be unavailable to layout. Authors can hide elements until a font is available. On a timer, script can determine whether the font is loaded or not and choose to use the fallback font at that point. Or it can wait until the font is loaded and decide the most effective way to handle the transition to the newly loaded font. Fonts are needed for layout, so there aren't any separate decisions to be made at paint time. > However, even with the JS event, defining this behavior would still require > quite a bit of JS work on behalf of developer. Personally, I'd still like > to see this as a CSS property. Text rendering (aka, communicating actual > information on the page) is the bread and butter of the web... It would > sure be nice to make delivering a performant text rendering experience > simple. Just to be clear, what's been proposed doesn't actually affect text rendering *performance* in any way. It's simply trying to ameliorate the effects of poor load performance for fonts on the dynamic layout of the page. > > That said, I think trying to spec behavior on "first layout" is > > really tricky since the precise timing of this depends on the > > incremental layout algorithm used by a browser and that's going to > > vary across user agents/devices. > > I don't think variability is the problem... I'd kick off my font request as > soon as possible, and then run a "is font ready" check in each element > layout callback to see if I can/should apply it or not. The variability of incremental layout algorithms will certainly be a problem for authors using this property, since user agents that start laying out a page earlier will be much more likely to hit the key "first layout" point before a font is loaded. > The behavior we're proposing here is not tweaking fetch parameters > in any way. To deliver the optimal experience you'd use this > alongside Font Events API to kick off an early fetch (from network > or cache), and then use these CSS properties to control behavior > of text rendering at first layout+paint of each element based on > state of the font request. > > - Font Events API allows me to start the font request sooner > - Browser is now racing font request and layout+paint work > - Browser gets to layout+paint and uses font-rendering to determine which > text rendering strategy it should apply > -- if request has finished, it applies the font and moves on > -- if request is still in flight, it applies specified strategy I should point out here that the ability to set timeout-sensitive behavior on elements is fraught with problems. Consider the example of a large document (think HTML5 spec) that uses a downloadable font for headings: @font-face { font-family: myfont; src: url(myfont.woff); } h4 { font-family: myfont, fallback-serif; font-rendering: swap 3s; } The user agent starts the font load and lays out the first section of the document. Headings appear in the fallback font. Because it's a large document the font load takes more than 3 seconds, so headings in the first section remain in the fallback font. But as later sections are laid out, the font *is* available so in those sections headings appear in the downloadable font. But scroll back up and the headings remain in the fallback font. >From an implementation viewpoint, you'd need to track this "timed out" state for those elements to prevent them switching to the fallback font. So when running font matching on reflows you'd need to keep track of font availability from the first layout. Ick. This doesn't sound like a way of providing performant text rendering. > > Ilya, you need to define what the default behavior is. If you don't > > want a single, standard behavior, then an 'auto' value is needed > > here, which would allow user agents to vary. > > Personally, I'm ok with allowing UAs to customize own defaults. As Tab > noted: > > FF and Chrome/Opera currently have a default of "mandatory 3s". IE > has a default of "mandatory 0s". Safari has a default of "mandatory > <infinite-time-value>". CSS properties have an initial value which is the same across browsers. The descriptors of the @font-face value have default values which are the same across browsers. So you need to define an initial value of the 'font-rendering' property and a default value for the 'font-rendering' descriptor within @font-face rules. In fact, to implement what you've described you need slightly different values for the property, since I think you want the default value for the descriptor to be "whatever the user agent timeout policy is" and for the *property* you want an initial value of 'auto' to mean "decide based on the 'font-rendering' descriptor value of the font". But this is just CSS mechanics, the important thing to decide here is whether you're proposing a single browser default timeout behavior or not. I actually think requiring some form of timeout would be a good idea. I'm guessing the 'mandatory <infinite>' for Safari is just a bug not really a feature. I think the additions proposed don't really address the underlying problem (font loads happening late or taking too long) and have some unfortunate side effects. I think the Font Loading API provides a lot of ways authors can address problems associated with slow font loading. I'm not really convinced that twiddling timeout behavior via CSS is the right solution here. Cheers, John Daggett Mozilla Japan
Received on Thursday, 30 October 2014 08:44:22 UTC