SVG 1.2 - 27 October 2004

Previous | Top | Next

8 Progressive rendering

When progressively downloading a document, a user agent conceptually builds a tree of nodes in various states. The possible states for these nodes are unresolved, resolved and error. After the startElement SAX event on a node, that node becomes part of the document tree in the unresolved state. When the node's dependencies are successfully resolved, then the node enters the resolved state. When the node's dependencies are found to be in error, then the node enters the error state.

Node dependencies include both children content (like the child elements on a g) and resources (like stylesheets or images referenced by an image) referenced from that node or from its children. Children become resolved when the endElement event occurs on an element. Resources become resolved (or found in error) by a user agent specific mechanism.

A user agent implementing progressive rendering must render the current document tree with the following rules:

Fonts are an exception to the above rules: startElement and endElement events on font element children ( font-face, hkern, vkern, missing-glyph, glyph ) do not cause an update of the document rendering. However, the endElement event on the font element does cause a document rendering as for other node types.

Example

<svg>
  <g externalResourcesRequired="true">
     <rect id="rect_1" .... />
      ...
     <rect id="rect_1000" ..../>
     <image xlink:href="myImage.png" externalResourcesRequired="true" ... />
     <rect id="rect_1001" ..../>
  </g>
</svg>

In this example, the g element rendering will start when the g closing tag has been parsed and processed and when all the resources needed by its children have been resolved. This means that the group's rendering will start when the group has been fully parsed and myImage.png has been successfully retrieved.

Forward reference of use element

<svg>
  <use xlink:href="#myRect" x="200" fill="green"/>
  <circle cx="450" cy="50" r="50" fill="yellow" />
  <g fill="red">
     <rect id="myRect" width="100" height="100" />
  </g>
</svg>

According to the proposal above, the various renderings will be (the rendering state follows the semi-colon):

  1. use.startElement : empty
  2. circle.startElement: yellow circle
  3. g.startElement: no update
  4. rect.startElement (use reference becomes resolved): green rect, yellow circle, red rect

Forward reference on use with eRR="true"

<svg>
  <use xlink:href="#myGroup" x="200" fill="green"
       externalResourcesRequired="true"/>
    <circle cx="450" cy="50" r="50" fill="yellow" />
    <g fill="red">
        <g id="myGroup">
            <rect id="myRect" width="100" height="100" />
            <use xlink:href="#myRect" x="50" fill="purple"/>
        </g>
    </g>
</svg>
  1. use.startElement : empty
  2. circle.startElement: empty use is unresolved & eRR=true, rendering is stopped at the use)
  3. g.startElement: no update
  4. g.myGroup.startElement: no update (use is resolved but eRR=true so rendering will no proceed until that reference enters the resolved state)
  5. rect.startElement: no update
  6. use.startElement: no update
  7. g.myGroup.endElement (#myGroup reference becomes resolved, rendering can proceed): green rect, purple rect, yellow circle, red rect, purple rect.

Forward reference with use to an element under a container with eRR="true"

<svg>
  <use xlink:href="#myRect" x="200" fill="green"/>
    <circle cx="250" cy="50" r="50" fill="pink" />
    <g fill="red" externalResourcesRequired="true">
        <circle cx="450" cy="50" r="50" fill="yellow" />
        <rect id="myRect" width="100" height="100" />
    </g>
</svg>
  1. use.startElement : empty
  2. pink.circle.startElement: pink circle
  3. g.startElement: no update (#myRect is resolved, but it has eRR set to true, so the referenced node is unresolved and rendering is stopped).
  4. yellow.circle.startElement: no update (rendering suspended because of use)
  5. myRect.rect.startElement: no update
  6. g.endElement. Resources referenced by use become resolved and can be rendered. Rendering can proceed: green rect, pink circle, yellow circle, red rect

Font Resolution Example

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.2"
     baseProfile="tiny" id="svg-root" width="100%" height="100%" viewBox="0 0 480 360">
 <text x="240" y="230" text-anchor="middle" font-size="120" 
    font-family="fontC, fontB, fontA">A</text>
 <defs>
   <font id="fontA" horiz-adv-x="224" >
     <font-face
        font-family="fontA"
        units-per-em="1000"
        panose-1="0 0 0 0 0 0 0 0 0 0"
        ascent="917"
        descent="-250"
        alphabetic="0" />
   <missing-glyph horiz-adv-x="800" d="..." />
   <glyph unicode="A" glyph-name="A" ... />
 </font>

 <font id="fontB" horiz-adv-x="224">
   <font-face
       font-family="fontB"
       units-per-em="1000"
       panose-1="0 0 0 0 0 0 0 0 0 0"
       ascent="917"
       descent="-250"
       alphabetic="0" />

   <missing-glyph ... />
   <glyph unicode="A" glyph-name="B" ... />

 </font>

 <font id="fontC" horiz-adv-x="224" >
   <font-face
       font-family="fontC"
       units-per-em="1000"
       panose-1="0 0 0 0 0 0 0 0 0 0"
       ascent="917"
       descent="-250"
       alphabetic="0" />
     <missing-glyph ... />
     <glyph unicode="A" glyph-name="C" ... />
   </font>
 </defs>
</svg>

Progressive rendering:

  1. text.startElement: 'A' rendered with the default font
  2. defs.startElement: no update
  3. fontA.font.startElement: no update
  4. fontA.font-face.startElement: no update
  5. fontA.missingGlyph.startElement: no update
  6. fontA.glyphA.startElement: no update
  7. fontA.font.endElement: 'A' rendered with fontB (represents current document state rendering)
  8. fontB.font.startElement: no update
  9. fontB.font-face.startElement: no update
  10. fontB.missingGlyph.startElement: no update
  11. fontB.glyphA.startElement: no update
  12. fontB.font.endElement: 'A' rendered with fontB (represents current document state rendering)
  13. fontC.font.startElement: no update
  14. fontC.font-face.startElement: no update
  15. fontC.missingGlyph.startElement: no update
  16. fontC.glyphA.startElement:
  17. fontC.font.endElement: 'A' rendered with fontC (represents current