W3C

CSS Font Load Events Module Level 3

Editor's Draft 22 February 2013

This version:
http://dev.w3.org/csswg/css-font-load-events-3/
Latest version:
http://www.w3.org/TR/css-font-load-events-3/
Latest editor's draft:
http://dev.w3.org/csswg/css-font-load-events-3/ (change log)
Issues List:
Feedback:
www-style@w3.org with subject line “[css-font-load-events] … message topic …” (archives)
Editor:
John Daggett (Mozilla)

Abstract

This CSS module describes events and interfaces used for dynamically loading font resources. The contents of this specification were previously contained in the CSS3 Fonts module.

Status of this document

This is a public copy of the editors' draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don't cite this document other than as work in progress.

The (archived) public mailing list www-style@w3.org (see instructions) is preferred for discussion of this specification. When sending e-mail, please put the text “css-font-load-events-3” in the subject, preferably like this: “[css-font-load-events-3] …summary of comment…

This document was produced by the CSS Working Group (part of the Style Activity).

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

Table of contents

1 Introduction

Wait until last call...

2 Font Load Events

Since fonts defined via @font-face rules are loaded on demand, pages may need to know precisely when fonts have completed downloading before measuring text elements on the page or to show some form of interim user interface state.

2.1 Extension to the document interface

To allow font loading to be tracked explicitly within content the following event target is added to the document of the page:

partial interface Document {
  readonly attribute FontLoader fontloader;
};

2.2 The FontLoader Interface

dictionary CSSFontFaceLoadEventInit : EventInit {
  CSSFontFaceRule fontface = null;
  DOMError error = null;
};

dictionary LoadFontParameters {
  DOMString font;
  DOMString text = " ";
  FontsReadyCallback success;
  FontsReadyCallback error;
};

[Constructor(DOMString type, optional CSSFontFaceLoadEventInit eventInitDict)]
interface CSSFontFaceLoadEvent : Event {
  readonly attribute CSSFontFaceRule fontface;
  readonly attribute DOMError? error = null;
}

callback FontsReadyCallback = void ();

interface FontLoader : EventTarget {

  // -- events for when loading state changes
  attribute EventHandler onloading;
  attribute EventHandler onloadingdone;

  // -- events for each individual font load
  attribute EventHandler onloadstart;
  attribute EventHandler onload;
  attribute EventHandler onerror;

  // check and start load if appropriate
  // and fire callback when all loads complete
  void loadFont(LoadFontParameters params);

  // return whether all fonts in the fontlist are loaded
  // (does not initiate load if not available)
  boolean checkFont(DOMString font, optional DOMString text = " ");

  // async notify upon completion, pending layout changes
  void notifyWhenFontsReady(FontsReadyCallback fontsReadyCallback);

  // loading state, true while one or more fonts loading, false otherwise
  readonly attribute boolean loading;
};

Because font families defined with @font-face rules are loaded only when they are used, content sometimes needs to understand when the loading of fonts occurs. Authors can use the events and methods defined here to allow greater control over actions that are dependent upon the availability of specific fonts.

The term font load is used below to indicate when the loading of content for a given @font-face rule completes. An @font-face rule may list multiple alternate resources within the ‘src’ descriptor, including references to local fonts, but the term font load only refers to the loading of the finally selected resource for a given rule, not to the loading of each individual resource.

Given that the FontLoader object is defined to be attached to the document, how will canvas worker threads load fonts?

Some FontLoader methods, in particular loadFont, seem like a good fit for DOMFuture, a spec that hopefully will be ready within the next month or so. Should FontLoader be based on that or at least some parts of that? Do we need to decide this now?

2.2.1 Events

Font load events are grouped into two general categories, events associated with a group of fonts loading (loading, loading) or finer-grained events associated with each individual font loaded (loadstart, load, error).

The following are the event handlers (and their corresponding event handler event types) that must be supported by FontLoader objects as IDL attributes:

Event handler Event handler event type
onloading loading
onloadingdone loadingdone
onloadstart loadstart
onload load
onerror error

To fire a font load event named e at a FontLoader target means to fire a simple event named e using the CSSFontFaceLoadEvent interface that also meets these conditions:

  1. The fontface attribute is initialized to the given font face rule.
  2. The error attribute is initialized to the given error, if one occurred during the font load.

When the user agent determines that one or more fonts defined via @font-face rules in a document doc need to be loaded, it must run the following steps:

  1. Let font loader be the value of the fontloader attribute of doc.
  2. Set the loading attribute of font loader to true.
  3. Fire a font load event named "loading" at font loader with fontface set to the first @font-face rule.
  4. When the user agent begins loading the first resource for a given @font-face rule, it must fire a font load event named "loadstart" at font loader with fontface set to the given @font-face rule.

These steps imply that if fonts are loaded concurrently, the loading event will fire just once, while the loadstart event will be fired once for each @font-face rule whose load is initiated. User agents must only set the error attribute of a font load event to a non-null value in the cases noted in this section.

The term “font load” covers any of the resources listed in the ‘src’ descriptor, including local fonts. When multiple resources are listed, the “font load” is the first resource in the list to successfully load or the error that occurs on the last resource for which a load is attempted.

When the user agent completes each font load for a document doc, it must run the following steps:

  1. Let font loader be the value of the fontloader attribute of doc.
  2. If a font data was successfully loaded and activated, fire a font load event named "load" at font loader with fontface set to the @font-face rule for which the font data was loaded.
  3. Otherwise, fire a font load event named "error" at font loader with fontface set to the @font-face rule for which the error occurred. If the font data can't be loaded error is set to one of the standard DOMError types (e.g. NotFoundError, NetworkError). If the font data was downloaded but invalid, then error is set to "InvalidFontDataError". If several resources are listed in the src descriptor, the error that caused the last font resource in the list to fail must be used.

When the user agent completes the final font load for document doc, after all pending layout operations that might affect font selection have completed and no font loads are pending, it must run the following steps:

  1. Let font loader be the value of the fontloader attribute of doc.
  2. Set the loading attribute of font loader to false.
  3. Fire a font load event named "loadingdone" at font loader with fontface set to the @font-face rule of the last font loaded.

For example, if three fonts are loaded at the same time, a "loading" event followed by three "loadstart" events and three "load" or "error" events, followed by a "loadingdone" event will occur.

Errors will go "unreported" when using the general category of font load events (i.e. "loading" and "loadingdone"). This seems fine but need to confirm this.

2.2.2 Methods

The methods loadFont and checkFont must determine whether all fonts in the given font list have been loaded and are available. If all fonts are available, checkFont must return true, false if one or more fonts are not available. In the case of loadFont, if any fonts are downloadable fonts and have not already been loaded, the user agent must initiate the load of each of these fonts.

The loadFont(params) method must use these steps:

  1. Parse the value of the font member of params, using the CSS value syntax of the ‘font’ property.
  2. If a syntax error occurs, return.
  3. Otherwise, let font family list be the set of families and font style be the other font style attributes.
  4. For each family in font family list, use the font matching rules to select the font faces that match the font style. In the case where these are font faces defined via @font-face rules, the use of ‘unicode-range’ means that this may be more than just a single font face.
  5. Remove from the set of font faces all faces that have defined ‘unicode-range’ values that don't intersect the range of character values in the text member of params and set this to be the font load list.
  6. For all of the font faces in the font load list, initiate the load of any font that has not already been loaded and return.
  7. When all fonts in the font load list have been loaded, fire the appropriate callback handler. If all fonts loaded successfully, call the callback specified by the success member of params. If an error occurred with any one of the fonts in the font load list or if the list is empty, call the callback specified by the error member of params.

Callbacks for loadFont fire in addition to the callbacks that fire due to font event handlers.

The checkFont(font, text) method must use these steps:

  1. Parse the value of the font parameter, using the CSS value syntax of the ‘font’ property.
  2. If a syntax error occurs, return false.
  3. Otherwise, let font family list be the set of families and font style be the other font style attributes.
  4. For each family in font family list, use the font matching rules to select the font faces that match the font style. In the case where these are font faces defined via @font-face rules, the use of ‘unicode-range’ means that this may be more than just a single font face.
  5. Remove from the set of font faces all faces that have defined ‘unicode-range’ values that don't intersect the range of character values in the text parameter and set this to be the font load list.
  6. If the font load list contains no font faces, return false.
  7. If all fonts in the font load list have already successfully been loaded, return true. Otherwise, return false.

The font parameter of checkFont and the font member of params parameter of loadFont both specify the list of fonts to load. These values must be parsed using the same syntax as values for the CSS ‘font’ property, the same way the font attribute of the CanvasRenderingContext2D is interpreted. [HTML5] This yields a list of font families along with font style attributes.

Because the number of fonts loaded depends on the how many fonts are used for a given piece of text, in some cases whether fonts need to be loaded or not may not be known. The notifyWhenFontsReady method provides a way for authors to avoid having to keep track of which fonts have or haven't been loaded before examining content affected by which font is used.

The notifyWhenFontsReady(fontsReadyCallback) method must use these steps:

  1. Let font loader be the value of the fontloader attribute of doc.
  2. Add the value of the fontsReadyCallback parameter to the notify callback list of the font loader and return.
  3. Once all pending layout operations have completed, determine whether font resources need to be loaded.
  4. If no loads are in progress, copy the contents of the notify callback list to the notify pending list of the font loader and clear out the notify list. After the "loadingdone" event fires, call each of the callbacks in the notify pending list and clear out the notify pending list.
  5. Otherwise, after all font loads complete and subsequent layout operations finish, again check whether loads are in progress. If no loads are in progress, execute the previous step. If fonts are still loading, continue waiting until those loads complete and repeat this step.

Authors should note here that the callback only fires once, the method needs to be called again when further font loads might occur. This method is similar to the callback function of the "loadingdone" event handler, except that in this case the callback will always get called, even when no font loads occur because the fonts in question are already loaded. It's a simple, easy way to sync code to font loads without the need to keep track of what fonts are needed and precisely when they load.

Note that the user agent may need to iterate over multiple font loads before the notify callback is called. This can occur with font fallback situations, where one font in the fontlist is loaded but doesn't contain a particular glyph and other fonts in the fontlist need to be loaded. The notify callback only fires after layout operations complete and no additional font loads are necessary.

2.3 Font load event examples

To show content only after all font loads complete:

  document.fontloader.onloadingdone = function() {
    var content = document.getElementById("content");
    content.style.visibility = "visible";
  }

Drawing text in a canvas with a downloadable font, explicitly initiating the font download and drawing upon completion:

  function drawStuff() {
    var ctx = document.getElementById("c").getContext("2d");

    ctx.fillStyle = "red";
    ctx.font = "50px MyDownloadableFont";
    ctx.fillText("Hello!", 100, 100);
  }

  document.fontloader.loadFont({font: "50px MyDownloadableFont",
                                success: drawStuff, 
                                error: handleError});

A rich text editing application may need to measure text elements after editing operations have taken place. Since style changes may or may not require additional fonts to be downloaded, or the fonts may already have been downloaded, the measurement procedures need to occur after those font loads complete:

  function measureTextElements() {
    // contents can now be measured using the metrics of
    // the downloadable font(s)
  }

  function doEditing() {
    // content/layout operations that may cause additional font loads
    document.fontloader.notifyWhenFontsReady(measureTextElements);
  }

Unlike the per-font load events, the "loadingdone" event only fires after all font related loads have completed and text has been laid out without causing additional font loads:

  @font-face {
    font-family: latin-serif;
    src: url(latinserif.woff) format("woff"); /* contains no kanji/kana */
  }

  @font-face {
    font-family: jpn-mincho;
    src: url(mincho.woff) format("woff");
  }

  body { font-family: latin-serif, jpn-mincho; }

  <p>納豆はいかがでしょうか</p>

In this situation, the user agent first downloads ‘latinserif.woff’ and then tries to use this to draw the Japanese text. But because no Japanese glyphs are present in that font, fallback occurs and the font ‘mincho.woff’ is downloaded. Only after the second font is downloaded and the Japanese text laid out does the "loadingdone" event fire.

Changes

Changes from the February 2013 CSS3 Fonts Working Draft

Major changes include:

Acknowledgments

Several members of the Google Fonts team provided helpful feedback on font load events, as did Boris Zbarsky, Jonas Sicking and ms2ger.

Conformance

Document Conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Conformance Classes

Conformance to CSS Font Load Events Level 3 Module is defined for three conformance classes:

style sheet
A CSS style sheet.
renderer
A UA that interprets the semantics of a style sheet and renders documents that use them.
authoring tool
A UA that writes a style sheet.

A style sheet is conformant to CSS Font Load Events Level 3 Module if all of its declarations that use properties defined in this module have values that are valid according to the generic CSS grammar and the individual grammars of each property as given in this module.

A renderer is conformant to CSS Font Load Events Level 3 Module if, in addition to interpreting the style sheet as defined by the appropriate specifications, it supports all the features defined by CSS Font Load Events Level 3 Module by parsing them correctly and rendering the document accordingly. However, the inability of a UA to correctly render a document due to limitations of the device does not make the UA non-conformant. (For example, a UA is not required to render color on a monochrome monitor.)

An authoring tool is conformant to CSS Font Load Events Level 3 Module if it writes style sheets that are syntactically correct according to the generic CSS grammar and the individual grammars of each feature in this module, and meet all other conformance requirements of style sheets as described in this module.

Partial Implementations

So that authors can exploit the forward-compatible parsing rules to assign fallback values, CSS renderers must treat as invalid (and ignore as appropriate) any at-rules, properties, property values, keywords, and other syntactic constructs for which they have no usable level of support. In particular, user agents must not selectively ignore unsupported component values and honor supported values in a single multi-value property declaration: if any value is considered invalid (as unsupported values must be), CSS requires that the entire declaration be ignored.

Experimental Implementations

To avoid clashes with future CSS features, the CSS2.1 specification reserves a prefixed syntax for proprietary and experimental extensions to CSS.

Prior to a specification reaching the Candidate Recommendation stage in the W3C process, all implementations of a CSS feature are considered experimental. The CSS Working Group recommends that implementations use a vendor-prefixed syntax for such features, including those in W3C Working Drafts. This avoids incompatibilities with future changes in the draft.

Non-Experimental Implementations

Once a specification reaches the Candidate Recommendation stage, non-experimental implementations are possible, and implementors should release an unprefixed implementation of any CR-level feature they can demonstrate to be correctly implemented according to spec.

To establish and maintain the interoperability of CSS across implementations, the CSS Working Group requests that non-experimental CSS renderers submit an implementation report (and, if necessary, the testcases used for that implementation report) to the W3C before releasing an unprefixed implementation of any CSS features. Testcases submitted to W3C are subject to review and correction by the CSS Working Group.

Further information on submitting testcases and implementation reports can be found from on the CSS Working Group's website at http://www.w3.org/Style/CSS/Test/. Questions should be directed to the public-css-testsuite@w3.org mailing list.

References

Normative References

[CSS3-FONTS]
John Daggett. CSS Fonts Module Level 3. 11 December 2012. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2012/WD-css3-fonts-20121211/
[DOM]
Anne van Kesteren; et al. DOM4. 6 December 2012. W3C Working Draft. (Work in progress.) URL: http://www.w3.org/TR/2012/WD-dom-20121206/
[HTML5]
Ian Hickson. HTML5. 17 December 2012. W3C Candidate Recommendation. (Work in progress.) URL: http://www.w3.org/TR/2012/CR-html5-20121217/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. Internet RFC 2119. URL: http://www.ietf.org/rfc/rfc2119.txt

Index