Copyright © 2003 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability, trademark, document use and software licensing rules apply.
This document specifies version 1.2 of the Scalable Vector Graphics (SVG) Language, a modularized language for describing two-dimensional vector and mixed vector/raster graphics in XML.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.
This document is the fourth public working draft of the SVG 1.2 specification. It lists the areas of new work in version 1.2 of SVG and is not a complete language description. The SVG Working Group consider the feature set of SVG 1.2 to be approaching stability. However, there are some cases where the descriptions in this document are incomplete and simply show the current thoughts of the SVG Working Group on the feature, or list the open issues. Therefore, this document should not be considered stable.
This version does not include the complete implementations of SVG 1.2 in either DTD or XML Schema form. Those will be included in subsequent versions, once the content of the SVG 1.2 language stabilizes. This document references a draft RelaxNG schema for SVG 1.1.
This document has been produced by the W3C SVG Working Group as part of the W3C Graphics Activity within the Interaction Domain.
We explicitly invite comments on this specification. Please send them to www-svg@w3.org: the public email list for issues related to vector graphics on the Web. This list is archived and acceptance of this archiving policy is requested automatically upon first post. To subscribe to this list send an email to www-svg-request@w3.org with the word subscribe in the subject line.
The latest information regarding patent disclosures related to this document is available on the Web. As of this publication, the SVG Working Group are not aware of any royalty-bearing patents they believe to be essential to SVG.
Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This draft of SVG 1.2 is a snapshot of a work-in-progress. The SVG Working Group believe the most of the features here are complete and stable enough for implementors to begin work and provide feedback. Some features already have multiple implementations.
This is not a complete specification of the SVG 1.2 language. Rather it is a list of features that are under consideration for SVG 1.2. In many cases the reader will have to be familiar with the SVG 1.1 language.
The main purpose of this document is to encourage public feedback. The best way to give feedback is by sending an email to www-svg@w3.org. Please include some kind of keyword that identifies the area of the specification the comment is referring to in the subject line of your message (e.g "1.2 compositing" or "1.2 audio and video formats"). If you have comments on multiple areas of this document, then it is probably best to split those comments into multiple messages.
The public are welcome to comment on any aspect in this document, but there are a few areas in which the SVG Working Group are explicitly requesting feedback. These areas are noted in place within this document. There are also a few areas related to the specification that are listed here:
The SVG Working Group is chartered to develop a language that best addresses the needs of its user community. After carefully examining the past and present use of SVG as well as researching the expected future uses of SVG, the SVG Working Group can see two broad usage themes:
SVG Tiny 1.1 is an example of this theme.
An SVG 1.1 document that uses scripting to build a user interface is an example of this theme.
There has been much discussion within the SVG Working Group on how to best accomodate the two different usage themes. Some Working Group members have expressed concerns regarding potential incompatibility of the two themes, especially in the area of graphical authoring tools. Other members believe some of the new features of SVG 1.2 directly address these incompatibilities.
There are a number of choices that the SVG Working Group could take on this issue. Here are some examples:
The SVG Working Group is seeking feedback on this matter from both users and implementers. Which changes, if any, should the Working Group be making to ensure a good user experience when using SVG for both of the usage themes described above.
It is worth noting that the SVG Working Group have a strong desire to keep the number of SVG profiles to a minimum.
This section describes the currently favored choice of the SVG Working Group: separating the SVG language into two themes.
Separating the language into two themes does not add any new features, nor does it create two new languages. Rather it better distinguishes the two broad usages of the SVG language. SVG Core files will be interoperable between all compliant user agents and authoring tools. SVG Extended files will be interoperable between all compliant extended user agents and potentially between authoring tools.
It is expected that the SVG specification will continue as a single document, but will be separated into a number of sub-documents. For example, the SVG Core features, the SVG Extended features and the SVG DOM may be available as separate files.
The SVG Working Group is considering many different methods of identifying the SVG themes, taking into account the existing SVG content. One proposed solution is to have an attribute on the root svg element that identifies an SVG Core document. By default the attribute is set to identify the document as SVG Extended. Also, there will be clarifications in the conformance criteria.
During the evolution of this solution, the SVG Working Group considered a number of other potential identification techniques, such as:
SVG 1.2 enables a block of text to be rendered inside a shape, while automatically wrapping the text into lines, using the flowText element. The idea is to mirror, as far as practical, the existing SVG text elements.
The flowText element specifies a block of text to be rendered. It contains at least one flowRegion element, defining regions in which the child flowDiv element of the flowText should be flowed into.
The following is an extract of an XML Schema that describes the flowText element.
<xs:element name="flowText">
<xs:complexType>
<xs:sequence>
<xs:element ref="flowRegion"/>
<xs:element ref="flowRegionExclude"/>
<xs:element ref="flowDiv"/>
</xs:sequence>
<xs:attributeGroup ref="PresentationAttrs"/>
<xs:attributeGroup ref="StyleAttrs"/>
</xs:complexType>
</xs:element>
The flowRegion element contains a set of shapes and exclusion regions in which the text content of a parent flowText element is drawn into. A flowRegion element has basic shapes and path elements as children, as well as a flowRegionExclude element. The children of a flowRegion element are inserted into the rendering tree before the text is drawn, and have the same rendering behavior as if they were children of a g element.
The child elements create a sequence of shapes in which the text content for the parent flowText will be drawn into. Once the text fills a shape it flows into the next shape. The flowRegionExclude child describes a set of regions in which text will not be drawn into, such as a cutout from a rectangular block of text.
The child elements of a flowRegion can be transformed as usual, but the text is always laid out in the coordinate system of the flowText element. For example, a rect child with a 45 degree rotation transformation will appear as a diamond, but the text will be axis aligned.
The following is an extract of an XML Schema that describes the flowRegion element.
<xs:element name="flowRegion">
<xs:complexType>
<xs:sequence>
<xs:choice>
<xs:group ref="ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="use" minOccurs="0" maxOccurs="unbounded"/>
<xs:group ref="flowRegionExclude" minOccurs="0" maxOccurs="unbounded"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
</xs:element>
The flowRegionExclude element contains a set of shapes defining regions in which flowed text is not drawn. It can be used to create exclusion regions from within a region of text.
If flowRegionExclude is a child of a flowRegion then it describes an exclusion region for that particular flowRegion. If it is a child of flowText then it describes exclusion regions for all flowRegion children of the flowText.
The following is an extract of an XML Schema that describes the flowRegionExclude element.
<xs:element name="flowRegionExclude">
<xs:complexType>
<xs:sequence>
<xs:group ref="ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="use" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
The flowDiv element specifies a block of text to be inserted into the text layout, and marks it as a division of related text. The children of the flowDiv element will be rendered as a block: offset before and after from their parent's siblings. By separating the logical order of text (in successive flowDiv elements) from the physical layout (in regions, which can be presented anywhere on the canvas) the SVG document structure encourages creation of a default, meaningful linear reading order while preserving artistic freedom for layout. This enhances accessibility.
The following is an extract of an XML Schema that describes the flowtext element.
<xs:element name="flowDiv">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="flowPara"/>
<xs:element ref="flowRegionBreak"/>
</xs:choice>
<xs:attributeGroup ref="PresentationAttrs"/>
<xs:attributeGroup ref="StyleAttrs"/>
</xs:complexType>
</xs:element>
The flowPara element marks a block of text as a logical paragraph.
The following is an extract of an XML Schema that describes the flowPara element.
<xs:element name="flowPara">
<xs:complexType mixed="true">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="flowRegionBreak"/>
<xs:element ref="flowLine"/>
<xs:element ref="flowTref"/>
<xs:element ref="flowSpan"/>
<xs:element ref="flowImage"/>
</xs:choice>
<xs:attributeGroup ref="PresentationAttrs"/>
<xs:attributeGroup ref="StyleAttrs"/>
</xs:complexType>
</xs:element>
The flowSpan element specifies a block of text to be rendered inline, and marks the text as a related span of words. The flowSpan element is typically used to allow a subset of the text block, of which it is a child, to be rendered in a different style, or to mark it as being in a different language.
The following is an extract of an XML Schema that describes the flowSpan element.
<xs:element name="flowSpan">
<xs:complexType mixed="true">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="flowSpan"/>
<xs:element ref="flowLine"/>
<xs:element ref="flowImage"/>
<xs:element ref="flowRegionBreak"/>
</xs:choice>
<xs:attributeGroup ref="PresentationAttrs"/>
<xs:attributeGroup ref="StyleAttrs"/>
</xs:complexType>
</xs:element>
When the flowRegionBreak element is inserted into the text stream it causes the text to stop flowing into the current region at that point. The text after the flowRegionBreak element begins in the next region. If there is no next region, then the text will stop being rendered at the point of the flowRegionBreak.
The following is an extract of an XML Schema that describes the flowRegionBreak element.
<xs:element name="flowRegionBreak"> <xs:complexType/> </xs:element>
The flowLine element is used to force a line break in the text flow. The content following the end of a flowLine element will be placed on the next available strip in the flowRegion that does not already contain text. This happens even if the flowLine element has no children.
Note that if there are no printing characters between the end of multiple flowLine elements the second and greater flowLine elements have no effect as the current line does not contain any text when they are processed.
In all other aspects, the flowLine element is functionally equivalent to the flowSpan element.
The following is an extract of an XML Schema that describes the flowLine element.
<xs:element name="flowLine">
<xs:complexType mixed="true">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="flowSpan"/>
<xs:element ref="flowLine"/>
<xs:element ref="flowImage"/>
<xs:element ref="flowRegionBreak"/>
</xs:choice>
<xs:attributeGroup ref="PresentationAttrs"/>
<xs:attributeGroup ref="StyleAttrs"/>
</xs:complexType>
</xs:element>
The flowTref element is used to insert the child text content of a referenced element. It's effect is analogous to the tref element.
The following is an extract of an XML Schema that describes the flowTref element.
<xs:element name="flowTref">
<xs:complexType>
<xs:attribute ref="href" use="required"
namespace="http://www.w3.org/1999/xlink"/>
<xs:attributeGroup ref="PresentationAttrs"/>
<xs:attributeGroup ref="StyleAttrs"/>
</xs:complexType>
</xs:element>
The flowRef element references a flowRegionElement. It causes the referenced element's geometry to be drawn in the current user coordinate system along with the text that was flowed into the region.
The following is an extract of an XML Schema that describes the flowRef element.
<xs:element name="flowRef">
<xs:complexType>
<xs:attribute ref="href" use="required"
namespace="http://www.w3.org/1999/xlink"/>
<xs:attributeGroup ref="PresentationAttrs"/>
<xs:attributeGroup ref="StyleAttrs"/>
</xs:complexType>
</xs:element>
The flowImage element defines a container for graphics which are to be rendered inline in the text layout. It can be used to insert images or any other graphic object that will then flow inline with the text flows.
The flowImage element establishes a new viewport for contained graphic elements. If flowImage specifies an absolute size, that size is used as the bounding rectangle for the flowImage region. If flowImage specifies a percentage as its size, the percentage is represented as a percentage of the current viewport.
In the absence of either width or height on the flowImage element, no new viewport is established. Any contained graphic elements are sized relative to the current viewport. In that case, the bounds of the flowImage element are calculated from the bounding box of any contained child graphic elements.
The following is an extract of an XML Schema that describes the flowImage element.
<xs:element name="flowImage">
<xs:complexType mixed="true">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="image"/>
<xs:group ref="ShapeElements"/>
<xs:element ref="g"/>
</xs:choice>
<xs:attribute name="width" type="CoordinateType" use="optional"/>
<xs:attribute name="height" type="CoordinateType" use="optional"/>
</xs:complexType>
</xs:element>
Text flow is defined as a post processing step to the standard text layout model of SVG. At a high level the steps for flowing text are as follows:
When a word is added the line height may increase, it can never decrease from the first word. An increase in the line height can only reduce the space available for text placement in the span.
The span will have the maximum possible number of words.
To determine the placement of a strip the Glyph Groups from first word is used. The initial position for the strip is calculated, taking into account the end (in non text progression direction) of the previous strip and the appropriate margin properties.
The line-box is calculated using the initial position as the top/right edge of the line-box, and the line-height of the first word. The 'bottom/right' edge of the line-box must be checked against the margin properties, if it lies within the margin then processing moves to the next flow region.
Once the line-box is calculated the Strip and it's associated Text Regions are calculated (see: Calculating Text Regions). If the first word can be placed in the text regions of this Strip then this location is used for the next line of text. If the first word does not fit then the top/right edge is shifted by 'line-advance' and the new line-box is checked. This proceeds until the word fits or end of the flow region is reached at which point processing moves to the next flow region.
In order to flow text into arbitrary regions it is necessary to calculate what areas of the arbitrary region are available for text placement. SVG uses a fairly simple algorithm to do this.
In summary you intersect the flow region geometry with the current line-box. The result of this intersection is referred to as the strip. The strip is then split into text regions where ever a piece of geometry from the flow region 'intrudes'. It is important to ignore edges & points that are co-incident with the top or bottom of the line-box.
The diagram below shows the text strips used on a given shape.
The following is the algorithm with more detail:
The current flow region and any applicable exclude regions must be combined into one piece of geometry, simply concatenating the geometry is sufficient as this entire algorithm deals simply with segments of the paths and does not use directionality information until the inclusion tests at the end. The result of the concatenation of the geometry is referred to as the flow geometry.
Next the line-box is calculated, from the top/right edge of the line, the line-height and the bounding box of the flow region. This line-box is intersection with the flow geometry, clipping the flow geometry segments to the line box.
The bounding box is then calculated separately for each of the segments in the intersection.
The left and right (top and bottom respectively for vertical text) edges of the bounding boxes are sorted in increasing coordinate order (x for horizontal text, y for vertical text), for edges at the same location the left/top (or opening) edge is considered less than right/bottom (or closing) edges. The following pseudo code then generates the list of open areas for the current line:
Edge [] segs = ...; // The sorted list of edges.
Edge edge = segs[0];
int count = 1;
double start = 0;
for (i=1; i<segs.length; i++) {
edge = segs[i];
if (edge.open) {
// 'open' is true, this is the start of a block out region.
if (count == 0) {
// End of an open region so record it.
rgns.add(new TextRegion(start, edge.loc));
}
count++;
} else {
// 'open' is false, this edge is the end of a block out region.
count--;
if (count == 0) {
// start of an open area remember it.
start = edge.loc;
}
}
}
This gives the regions of the strip that are unobstructed by any flow geometry (from either exclusion or flow regions), however those regions may be outside the flow region (such as in a hole, such as the middle of an 'O'), or inside an exclusion region. Thus the center of each rectangle should be checked first to see if it lies inside any exclusion region if so the rectangle is removed from the list. Second it must be checked for inclusion in the flow region, if it is inside the flow region then the rectangle is available for text placement and becomes a text region for the current strip.
Once all the text regions for a strip are located left and right Margins for horizontal text (top and bottom margins for vertical) as well as indent are applied. Margins are applied to each text region. For the first span in a paragraph (flowPara for flowRegionBreak) the indent is added to the appropriate margin of the first text region. For left to right text this is the left margin of the left most text region, for right to left text this is the right margin of the right most text region, and for vertical text is the top margin of the top most text region.
this is applying margins to every Text Region we could just apply them to the first/last text regions. Perhaps have a separate property for 'internal' margins and the 'external' margins?.
If the left/right (top/bottom) edges of a text region pass each other due to the application of margins (or indent) the text region is removed from the list. If the text region removed had indent applied the indent is not applied to the next text region in text progression direction it is simply ignored.
We could have the indent move but it isn't clear that this would always be correct. The above is simpler and for the cases where indent is most commonly used, simple rectangles, it doesn't matter.
Should we restrict indent's range such that it can be no more negative than the margin it is applied to? Our feeling is no. If the user wants to shift the boxes out they should be able to - the only complication this adds is that the geometry may no longer define the bounding box of the text.
Below is an example of the flowing text capabilities:
<svg xmlns:svg="http://www.w3.org/2000/svg" version="1.2"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%" height="100%" viewBox="0 0 300 310">
<title>Basic textflow</title>
<rect x="0" y="0" width="100%" height="100%" fill="yellow"/>
<flow font-size="16">
<flowRegion>
<path d="M100,50L50,300L250,300L300,50z"/>
</flowRegion>
<flowDiv>
<flowPara>Tomorrow, and tomorrow, and tomorrow; creeps in this
petty pace from day to day, until the last syllable of recorded time.
And all our yesterdays have lighted fools the way to dusty death.
</flowPara>
</flowDiv>
</flow>
<path d="M90,40L40,270L260,270L210,40z" fill="none" stroke="black" stroke-width="5"/>
</svg>
View this image as SVG (SVG-enabled browsers only)
A more complicated example is show below. It is not included inline. Please see the SVG file for the source.
View this image as SVG (SVG-enabled browsers only)
There are many SVG use cases where textual input is a requirement. Implementing such a feature in SVG 1.1 with the DOM is nearly impossible without restricting functionality, such as only allowing latin left-to-right text.
SVG 1.2 introduces editable text fields, moving the burden of text input and editing to the user agent, which has access to system text libraries.
The text and flowDiv elements have an editable attribute which defines if the contents of the elements can be edited in place.
If set to "false" the contents of the text element are not editable in place through the user agent. If set to "true", the user agent must provide a way for the user to edit the content of the text element and all contained subelements which are not hidden (with visibility="hidden") or disabled (through the switch element or display="none"). The user agent must also provide a way to cut the selected text from the element and to paste text from the clipboard into the element. If no value is given for this attribute, the default value is "false". Animatable: Yes.
In general, user agents should allow for the inline WYSIWYG editing of text with a caret that identifies current position.
For WYSIWYG editing the following functionality must be made available:
For devices without keyboard access, the equivalent system input methods should be used wherever possible to provide the functionality described above.
The content of the DOM nodes that are being edited should be live at all times and reflect the current state of the edited string as it being edited (except for the state associated with an Input Method Editor window).
SVG 1.2 adds the ability to associate behavior or extensions with arbitrary XML markup within an SVG file. This feature is referred to as Rendering Custom Content (RCC).
The extensionDefs element registers a set of custom elements, all of which are in the same namespace.
The extensionsDefs element can be used in either of two ways. First, the custom elements can be defined within the content of the extensionDefs element, most significantly via elementDef child elements. Here is an example which defines two custom elements, equilateral-triangle and rhombus, in the "http://example.org" namespace:
<extensionDefs namespace="http://example.org"> <elementDef name="equilateral-triangle">...</elementDef> <elementDef name="rhombus">...</elementDef> </extensionDefs>
Alternatively, the extensionDefs element can include an xlink:href attribute (i.e., an href attribute in the XLink namespace) which specifies an XPointer value to a different extensionDefs element, most often located in a different file or resource.
Here is a snippet from the SVG file which will get displayed:
<extensionDefs xlink:href="http://example.org/cool/cool.svg#CoolExtensions"/> <g xmlns:cool="http://example.org/cool"> <cool:bellbottoms x="20" y="60" width="40" height="200"/> <cool:leisuresuit x="80" y="60" width="40" height="200"/> </g>
Here is a snippet from the referenced SVG file which defines the extensions:
<extensionDefs id="CoolExtensions" namespace="http://example.org/cool"> <elementDef name="bellbottoms">...</elementDef> <elementDef name="leisuresuit">...</elementDef> </extensionDefs>
The following is a schema snippet which defines the extensionDefs element:
<xs:element name='extensionDefs'>
<xs:complexType>
<xs:choice minOccurs='0' maxOccurs='unbounded'>
<xs:element ref='elementDef'/>
<xs:element ref='defs'/>
<xs:element ref='script'/>
</xs:choice>
<xs:attributeGroup ref='PresentationAttrs'/>
<xs:attributeGroup ref='StyleAttrs'/>
<xs:attribute ref='xlink:href'/>
<xs:attribute name='namespace' type='anyURI'/>
</xs:complexType>
</xs:element>
The above schema may need to be modified to constrain the grammar such that there can be either an xlink:href attribute which points to the real definition of the extensions (probably in a separate file) or a combination of namespace attribute and content, which would be required if xlink:href is not present.
Attributes:
The elementDef element is used to define a custom element. It encapsulates all information about the element. Also, all event listeners for this element are implicitly attached to the custom elements that it defines. That makes it convenient to put handler elements with XMLEvent ev:type attribute as its children or use event attributes (e.g., onactivate or onmousemove).
The most essential function of the elementDef element is to control the definition of the shadow tree for the given custom element. The shadow tree is built from automatic cloning of the contents of the prototype child element or copying the tree generated by the XML transformer referenced by the transformer element, as well as DOM manipulation of the shadow tree via scripting.
The shadow tree can include instances of other custom elements, in which case elementDef processing happens recursively.
The following is a schema snippet which defines the elementDef element:
<xs:element name="elementDef">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<!-- xsd:group ref="svg:desc-title-metadata"/>
<xs:element ref="defs"/>
<xs:choice minOccurs="0" maxOccurs="1">
<xs:element ref="prototype"/>
<xs:element ref="transformer"/>
</xs:choice>
<xs:element ref="script"/>
</xs:choice>
<xs:attributeGroup ref="PresentationAttrs"/>
<xs:attributeGroup ref="StyleAttrs"/>
<xs:attribute name="name" type="NCName" use="required" />
<!-- anything else??? -->
</xs:complexType>
</xs:element>
The name attribute specifies the name of the element being defined.
The above schema may need to be modified to constrain the grammar so that only one prototype or transformer element can be specified.
An attribute which prevents initial shadow tree generation may be added to the elementDef element.
This is the standard SVG defs element. Its purpose as a child of elementDef is to be a container for the various resource elements that might be referenced by other elements within the elementDef. The defs is most commonly used to define referenced objects such gradients, filters or symbols, but there are no restrictions for the contents with the defs.
This element is used to define an initial shadow tree for the custom element defined by its parent. The contents of the prototype element are copied onto the 'shadowTree' DOM property for the custom element.
The prototype element is optional. If not present, there is no automatic cloning into the shadow tree. However, even without a prototype element, the shadow tree can still contain contents due to the possibility of DOM manipulation via other means such as scripting.
Because shadow trees can contain instances of other custom elements, it is allowed that a prototype element contains other custom elements.
An XML transformer is something that takes XML as input, and produces XML as output, like an XSLT stylesheet. The transformerelement provides the ability to run a specified XML transformer with specified parameter values, and place the results onto the 'shadowTree' DOM property for the custom element. It is equivalent to the output of the transformation being placed as the literal content of a prototype element. In particular, if the XML transformer's output includes refContent or custom element output, then further shadow tree references are implicit in the output, just as they would be within a prototype element.
Suppose an elementDef is defined for a custom element, and that elementDef has a transformer child. If the custom element has an svg:input attribute (where the 'svg:' prefix is bound to the SVG namespace), then the input for the XML transformer is the XML tree specified by the svg:input attribute value, which is a URI. For example, this URI can point to:
If the custom element does not have an svg:input attribute then it behaves as if the svg:input attribute has a default value pointing to the custom element in question, meaning that the input for the XML transformer is the branch of the DOM rooted at this custom element.
When a custom element's shadow tree includes a refContent element, this refers to the shadow trees of the descendants of the custom element in question, regardless of whether the shadow tree was generated by a transformer element and regardless of whether the custom element has an svg:input attribute pointing elsewhere. The refContent mechanism is not used to recurse on the XML trees of external resources.
This idea of running a script or other process on a branch of an XML tree to produce a generated SVG sub-tree is not specific to XSLT, so it should be possible, in theory, to specify the MIME type of the script file to be something else like XQuery, Java, or ECMAScript. Initially, we'll only deal with XSLT as the default and as top priority for implementers.
There is discussion of using an element like in or source rather than an attribute to provide the functionality of the svg:input attribute.
An attribute which prevents the svg:input from being usable with a particular custom element may added to the elementDef element.
The example below demonstrates a trivial use of the transformer element that draws red diamonds.
<svg width="10cm" height="3cm" viewBox="0 0 100 30" version="1.2"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<extensionDefs id="shapes" namespace="http://foo.example.org/shapes">
<xsl:stylesheet id="diamond" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:foo="http://foo.example.org/shapes"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="foo:diamond">
<svg x="{@x}" y="{@y}" width="{@width}" height="{@height}"
viewBox="0 0 100 100">
<rect transform="rotate(44,50%,50%)"
fill="red"
width="100%"
height="100%"/>
</svg>
</xsl:template>
</xsl:stylesheet>
<elementDef name="diamond">
<transformer xlink:href="#diamond" type="text/xsl"/>
<elementDef>
</extensionDefs>
<foo:diamond x="10" y="10" width="30" height="30"/>
<foo:diamond x="50" y="15" width="25" height="25"/>
<foo:diamond x="5" y="20" width="25" height="10"/>
</svg>
The following is a schema snippet which defines the transformer element:
<element name="transformer">
<complexType>
<choice minOccurs="0" maxOccurs="unbounded">
<element ref="svg:param"/>
<!-- <group ref="svg:desc-title-metadata"/> -->
</choice>
<attribute ref="xlink:href" use="required"/>
<attribute name="type" type="string"/>
</complexType>
</element>
Attributes:
Mechanics for XSLT, which is the initial focus, are clear. URI syntax and invocation mechanics may also be added for Java and ECMAScript.
The param element passes string information to the XML transformer (such as XSLT), mimicking the information that could be passed on the command line to the XML transformer.
The name of the param element is not finalized. Other candidate names include with-param and withParam.
The example below demonstrates a trivial use of the param element.
<svg width="7cm" height="5cm" viewBox="0 0 70 50" version="1.2"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<extensionDefs id="shapes" namespace="http://foo.example.org/shapes">
<xsl:stylesheet id="light" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:foo="http://foo.example.org/shapes"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="lightcolor">
<xsl:template match="foo:description">
<!-- Strip out descriptions -->
</xsl:template>
<xsl:template match="foo:light">
<xsl:variable name="x" select="../@x" />
<xsl:variable name="y" select="../@y" />
<xsl:variable name="width" select="../@width" />
<xsl:variable name="height" select="../@height" />
<svg x="{$x}" y="{$y}" width="{$width}" height="{$height}"
viewBox="0 0 100 100">
<rect transform="rotate(44,50%,50%)"
stroke="black"
stroke-width="1"
width="100%"
height="100%"/>
<circle stroke="none" fill="{$lightcolor"}
cx="50%"
cy="50%"
r="25%"/>
</svg>
</xsl:template>
</xsl:stylesheet>
<elementDef name="stop">
<transformer xlink:href="#light" type="text/xsl">
<param name="lightcolor" value="red"/>
</transformer>
<elementDef>
<elementDef name="go">
<transformer xlink:href="#light" type="text/xsl">
<param name="lightcolor" value="green"/>
</transformer>
<elementDef>
<elementDef name="gofast">
<transformer xlink:href="#light" type="text/xsl">
<param name="lightcolor" value="yellow"/>
</transformer>
<elementDef>
</extensionDefs>
<foo:stop x="10" y="10" width="30" height="30" >
<foo:description>A "stop" with a light</foo:description>
<foo:light/>
</foo:stop>
<foo:gofast x="50" y="15" width="25" height="25" >
<foo:description>A "gofast" with a light</foo:description>
<foo:light/>
</foo:gofast>
<foo:go x="5" y="20" width="25" height="10" >
<foo:description>A "go" with a light</foo:description>
<foo:light/>
</foo:go>
</svg>
The following is a schema snippet which defines the param element:
<element name="param">
<complexType>
<attribute name="name" type="NMTOKEN" />
<attribute name="value" type="string" use="required"/>
</complexType>
</element>
Attribute definitions:
The param element binding with XSLT is fairly clear. The binding for Java and perhaps also ECMAScript needs to be specified.
The refContent element is often an essential feature when the content developer requires a custom container element. One example of a custom container element is a custom scrollArea element where the contents should render normally except with customized translations and clipping due the special container element behavior.
With refContent, the contents of the container do not get cloned into the shadow DOM; instead, the shadow DOM refers back into the custom element's DOM (the original DOM) for some of the graphics to be rendered. In addition to allowing an effective subclassing of SVG's container elements such as g, refContent offers potential performance and memory-saving benefits by preventing duplication of the DOM when such duplication is unnecessary or undesirable.
The refContent element acts as a virtual grouping element within the shadow DOM for a set of referenced elements in the custom element's DOM. The effect in terms of rendering and behavior is as if the referenced elements had been moved into the shadow DOM temporarily in order to accomplish the necessary rendering operations and behaviors (e.g., hit testing).
Using the optional select attribute, refContent can specified a subset of the custom element's descendants.
It is legal to have multiple refContent elements in the shadow subtree, but the subsets of the children that they select must not intersect.
In the example below, a ui:scrollArea custom element establishes a scrollable region onto which any SVG content can be rendered:
<extensionDefs...>
<elementDef name="scrollArea">
<prototype>
<svg ...>
<refContent/>
</svg>
<!-- assume a scrollbar custom element is defined elsewhere -->
<ui:scrollbar.../>
</prototype>
<!-- etc. -->
</elementDef>
</extensionDefs>
<ui:scrollArea>
<image .../>
<path ... />
<text...>...</...>
<!-- etc. -->
</ui:scrollArea>
In the simple flowchart example provided earlier, the flowchart custom element itself is a container for other flowcharting custom elements such as processNode and terminalNode. The implementation of the flowchart custom element takes advantage of refContent to simply refer to the custom element's (i.e., the flowchart element's) original content (i.e., a list of processNode and terminalNode custom elements):
<extensionDefs...>
<elementDef name="flowchart">
<prototype><refContent/></prototype>
<!-- etc. -->
</elementDef>
</extensionDefs>
<flowchart xmlns="http://example.org/rcc-flowcharts"...>
<terminalNode>Start</terminalNode>
<processNode>Step 1</processNode>
<processNode>Step 2</processNode>
<terminalNode>End</terminalNode>
</flowchart>
The refContent element is defined as follows:
<xs:element name="refContent">
<xs:complexType>
<xs:sequence>
<!-- xsd:group ref="svg:desc-title-metadata" minOccurs="0" maxOccurs="unbounded"/>
<xs:attributeGroup ref="PresentationAttrs"/>
<xs:attributeGroup ref="StyleAttrs"/>
<xs:attribute name="select" type="???" use="optional" />
<xs:attribute name="transform" type="???" use="optional" />
<!-- event attributes??? overflow/clip??? -->
<!-- anything else??? -->
</xs:sequence>
</xs:complexType>
</xs:element>
The select attribute defines an XPath selector for the node set that should be connected here. Only a small subset of XPath is allowed: "*", "name", "*[#]", "name[#]" where name is any identifier and # is a number
Shadow tree generation occurs initially when the document is loaded. Shadow tree generation also occurs when a custom element is added to the SVG document via DOM.
Subsequent regeneration of shadow tree for particular elements may be triggered by a declaratively specified set of events.
Declarative syntax for specifying the set of events that cause a particular element's shadow tree to be regenerated hasn't yet been developed. It may be a SMIL like list of events (the "begin" and "end" animation timing attributes can take an event list) or use some sort of XML event listener syntax.
The default (perhaps empty) set of events that cause shadow tree regeneration is to be determined.
In addition an attribute may be set that causes the UA to regenerate shadow trees every time there is a modification to the DOM that may affect the shadow tree.
Declarative syntax for specifying the above attribute hasn't yet been developed. It's default value is to be determined. In addition, what "a modification to the DOM that may affect the shadow tree" means needs to be tightly specified.
In addition, there is a DOM call "rebind()" that causes regeneration of the shadow tree for a particular element.
On the DOM level, all custom elements have a shadowTree attribute that points to an SVGShadowElement.
If this attribute is null (which it normally is), then an element "behaves normally". For example, normal behavior for foreign namespace elements is that they don't get rendered. However, if this attribute is not null, all rendering and interactive behavior is determined by the content of this attribute. This affects all behavioral aspects of the element (rendering, hit testing, layout, UI events etc.), but not its "DOM" aspects (Core DOM calls, document events, mutation events, etc.)
The node which is attached to an element through an 'shadowTree' DOM property is said to belong to the "Shadow DOM". It remains a normal Node in all respects, though. A Node can be attached only to one element at a time and it must not have a parentNode. From the Core DOM point of view, it is not attached to the document tree (which is perfectly legal). It is legal for a Node owned by one document to be attached to the element from another document as well. And it is also legal for the "Shadow DOM" Nodes to have their own "shadow" subtrees attached (through their nested own 'shadowTree' DOM properties).
The SVG DOM should provide a method to set the 'shadowTree' of an element. With such a method, RCC DOM can be used even without an associated syntax. Also there should be a method to obtain an element given its shadow DOM root. Here is an initial proposal, which introduces new interfaces SVGShadowElement and SVGShadowable:
interface SVGShadowElement : Element {
Element getShadowOwnerElement() raises ... ;
void rebind() raises ... ;
}
interface SVGShadowable {
readonly attribute SVGShadow Element shadowTree ;
void setShadowTree (in SVGShadow Element newShadow) raises ...;
}
All unknown elements (generally, all elements in a different namespace) implement interface SVGShadowable.
Two new events are defined to support the RCC feature set: SVGBindBegin and SVGBindEnd. SVGBindBegin is fired before the user agent creates the shadow tree for a custom element. SVGBindEnd is fired when the user agent has finished adding the element's shadow tree to the element and after any custom elements in the shadow tree have been processed.
Initial processing of custom elements is done in document order (preorder depth first traversal of the tree). This means that initially, a custom element's SVGBindBegin must be fired before the element's descendants shadow trees have been created and therefore before any of the descendants' SVGBindBegin and SVGBindEnd events have been fired. For progressive rendering, a custom element's SVGBindBegin may not be fired until the custom element's end tag has been read.
Regeneration of a custom element's shadow tree causes SVGBindBegin and SVGBindEnd events to be fired.
The two new event types extend dom::Event. The event target is the custom element.
In order to ensure interoperability:
Any script elements inside of extensionDefs elements get evaluated once at the time the script elements contents have been added to the DOM tree. (The result of evaluation often adds function definitions to the scripting environment, and these function are available indefinitely.) Any handler elements inside of extensionDefs elements which have an ev:event attribute get evaluated every time the given event occurs, similar to how event attributes such as onclick get re-evaluated every time the user clicks on the given element.
Circular references within the definitions of custom elements must raise an error. The shadow tree for a custom element must not contain the same custom element directly or indirectly. An example of illegal indirection would be where custom element A includes an instance of custom element B, which is OK, but then custom element B in turn includes an instance of custom element A, which is an indirect circular reference and must raise an error.
Here are some of the open issues that have been raised regarding potential RCC features that allow for transformation of semantically rich arbitrary XML into presentation-rich alternative SVG.
Some of the arguments against shadow trees:
Resolution: alternate generated SVG goes onto a shadow tree in the form of a DOM attribute off of the custom element.
Resolution: regeneration of shadow tree is triggered via event handling/listener which is manually established using XML event listeners.
Resolution: the feature will use XML events for event handling.
Resolution: the current approach seems to cover most situations in both cases.
Resolution: the working group is still working on the relationship of the arbitrary XML features in RCC with the arbitrary XML features in XForms. There is an example earlier which shows how XForms might work with RCC. Certainly, there are templating aspects to RCC, but it more like an extensibility mechanism that maps XML namespaces into presentation+behavior than just a templating facility.
The working group is still working on this aspect of the feature.
The working group is still working on this aspect of the feature. We'll know more after users try out the feature and send in their reports.
The working group is still working on this aspect of the feature.
The working group is still working on this aspect of the feature.
Resolution: no, we aren't just going to add new options to the use element.
The working group is still working on this aspect of the feature.
Current thinking in the working group is that RCC is required in both Full and Basic. The working group is studying approaches where a subset of features could be made available in Tiny. The big problem with SVG 1.1 Tiny is that scripting is not part of Tiny, and the current design generally requires scripting support.
Suggested resolution: no, shadow tree elements are owned by document with the custom element, not the document with the custom element's elementDefs
Suggested resolution: no.
Below is a simple example of the Rendering Custom Content feature. In the example, the SVG file references a set of custom elements for flowcharting using the extensionDefs element, and then uses the custom elements to draw the flowchart. Note that the document below is semantically more meaningful due to the use of the custom elements than it would have been if the file had contained just the low-level visual presentation elements (i.e., circle, rect, path and text):
<svg width="12cm" height="3cm"
xmlns="http://www.w3.org/2000/svg" version="1.2">
<desc>Example rcc01 - simple flowchart example using RCC</desc>
<!-- XPointer reference to the location for the flowchart extensions -->
<extensionDefs xlink:href="rcc01-flowchart-exts.svg#flowcharts"/>
<!-- Use the flowchart extensions. As a result of using the extensions,
a shadow tree of low-level SVG (circle, rect, path elements)
is added to the SVG DOM. The user agent renders the shadow tree. -->
<flowchart xmlns="http://example.org/rcc-flowcharts"
x="0%" y="0%" width="100%" height="100%">
<terminalNode>Start</terminalNode>
<processNode>Step 1</processNode>
<processNode>Step 2</processNode>
<terminalNode>End</terminalNode>
</flowchart>
</svg>
View this image as SVG (SVG-enabled browsers only)
Here is the file which defines the simple flowcharting extensions used in the example above:
<svg xmlns="http://www.w3.org/2000/svg" version="1.2"
xmlns:ev="http://www.w3.org/2001/xml-events">
<desc>Supplemental file for example rcc01.svg -
contains definition of simple flowchart extension elements.</desc>
<extensionDefs id="flowcharts" namespace="http://example.org/rcc-flowcharts">
<!-- Example needs to be upgraded to show handling of mutation events -->
<defs>
<symbol id="connectorline">
<path transform="translate(0 50)" stroke="black" stroke-width="3" fill="black"
d="M 0,0 L 90,0 L 90,-10 L 100,0 L 90,10 L 90,0"/>
</symbol>
</defs>
<elementDef name="terminalNode">
<prototype>
<g>
<circle stroke="#008" stroke-width="5" fill="none" cx="50" cy="50" r="50"/>
<text x="50" y="57" font-size="25" text-anchor="middle"><refContent/></text>
</g>
</prototype>
</elementDef>
<elementDef name="processNode">
<prototype>
<g>
<rect stroke="#080" stroke-width="5" fill="none" width="150" height="100" rx="10"/>
<text x="75" y="57" font-size="25" text-anchor="middle"><refContent/></text>
</g>
</prototype>
</elementDef>
<elementDef name="flowchart">
<prototype>
<svg><refContent/></svg>
</prototype>
<handler ev:event="SVGBindEnd" type="text/ecmascript"><![CDATA[
var svgns = "http://www.w3.org/2000/svg";
var xlinkns = "http://www.w3.org/1999/xlink";
var flowchartns = "http://example.org/rcc-flowcharts";
var ELEMENT_NODE = 1;
var SIDE_INDENT = 50;
var PROCESSNODE_WIDTH = 150;
var TERMINALNODE_WIDTH = 100;
var CONNECTOR_WIDTH = 100;
var YPOS = 50;
var flowchartelement = evt.target;
var ap = flowchartelement.shadowTree;
var svgElm = ap.firstChild;
svgElm.setAttributeNS(null, "x", flowchartelement.getAttribute("x"));
svgElm.setAttributeNS(null, "y", flowchartelement.getAttribute("y"));
svgElm.setAttributeNS(null, "width", flowchartelement.getAttribute("width"));
svgElm.setAttributeNS(null, "height", flowchartelement.getAttribute("height"));
// Determine total width needed and set viewBox attribute appropriately.
var totalWidth = 0;
var nodeCount = 0;
for( var node = flowchartelement.firstChild ; node != null ; node = node.nextSibling )
{
// only process elements in flowchart ns
if( node.nodeType == ELEMENT_NODE && node.namespaceURI == flowchartns) {
nodeCount++;
if (node.localName == "processNode")
totalWidth += PROCESSNODE_WIDTH;
else if (node.localName == "terminalNode")
totalWidth += TERMINALNODE_WIDTH;
}
}
totalWidth += (nodeCount-1)*CONNECTOR_WIDTH + 2*SIDE_INDENT;
svgElm.setAttributeNS(null, "viewBox", "0 0 "+totalWidth+" 200");
var xtrans = 50;
// Position all of the nodes and draw the connectors.
var xpos = SIDE_INDENT;
var nodeNum = 0;
for( var node = flowchartelement.firstChild ; node != null ; node = node.nextSibling )
{
// only process elements in flowchart ns
if( node.nodeType == ELEMENT_NODE && node.namespaceURI == flowchartns) {
node.shadowTree.setAttributeNS(null, "transform", "translate("+xpos+" "+YPOS+")");
var nodeWidth;
if (node.localName == "processNode") {
nodeWidth = PROCESSNODE_WIDTH;
} else if (node.localName == "terminalNode") {
nodeWidth = TERMINALNODE_WIDTH;
}
xpos += nodeWidth;
// Add connector line to end of flowchart node's shadowTree.
if (nodeNum < (nodeCount-1)) {
var useElement = document.createElementNS(svgns, "use");
useElement.setAttributeNS(xlinkns, "xlink:href", "#connectorline");
useElement.setAttributeNS(null, "transform", "translate("+nodeWidth+" 0)");
node.shadowTree.appendChild(useElement);
xpos += CONNECTOR_WIDTH;
}
nodeNum++;
}
}
]]></handler>
</elementDef>
</extensionDefs>
</svg>
The next example takes sample code from section 4.6 from the Geography Markup Language (GML) specification, version 2.1.2. The 'extensionDefs' element would effect a client-side transformation from original XML/GML into final-form SVG rendering.
<svg width="12cm" height="3cm"
xmlns="http://www.w3.org/2000/svg" version="1.2">
<desc>Example rcc-gml-01 - GML and RCC</desc>
<!-- XPointer reference to the location for the GML extensions -->
<extensionDefs xlink:href="rcc-gml-01-exts.svg#gml"/>
<CityModel xmlns="http://www.opengis.net/examples"
xmlns:gml="http://www.opengis.net/gml"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/examples city.xsd">
<gml:name>Cambridge</gml:name>
<gml:boundedBy>
<gml:Box srsName="http://www.opengis.net/gml/srs/epsg.xml#4326">
<gml:coord><gml:X>0.0</gml:X><gml:Y>0.0</gml:Y></gml:coord>
<gml:coord><gml:X>100.0</gml:X><gml:Y>100.0</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>
<cityMember>
<River>
<gml:description>The river that runs through Cambridge.</gml:description>
<gml:name>Cam</gml:name>
<gml:centerLineOf>
<gml:LineString srsName="http://www.opengis.net/gml/srs/epsg.xml#4326">
<gml:coord><gml:X>0</gml:X><gml:Y>50</gml:Y></gml:coord>
<gml:coord><gml:X>70</gml:X><gml:Y>60</gml:Y></gml:coord>
<gml:coord><gml:X>100</gml:X><gml:Y>50</gml:Y></gml:coord>
</gml:LineString>
</gml:centerLineOf>
</River>
</cityMember>
<dateCreated>2000-11</dateCreated>
</CityModel>
</svg>
The next example takes sample code from [Appendix G of the XForms specification | http://www.w3.org/TR/xforms/sliceG.html ] . The extensionDefs element would effect a client-side transformation from original XForms elements into final-form SVG rendering. In this example, the assumption is that the extension would implement all or at least a large part of the XForms specification via DOM/scripting.
<svg width="12cm" height="3cm"
xmlns="http://www.w3.org/2000/svg" version="1.2"
xmlns:xforms="http://www.w3.org/2002/xforms/cr"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:my="http://commerce.example.com/payment">
<desc>Example rcc-xforms-01 - using RCC within a combined XForms+SVG user agent</desc>
<title xml:lang="fr">XForms en SVG</title>
<!-- XPointer reference to the location for the XForms extensions to SVG.
The extensions convert the XForms UI elements into low-level SVG
interactive graphics and also provide high-level features,
such as client-side validation and the XForms event model. -->
<extensionDefs xlink:href="rcc-xforms-01-exts.svg#xforms"/>
<rx:renderXForms xmlns:rx="http://example.org/rcc-xforms"
xmlns="http://www.w3.org/2002/xforms/cr">
<model schema="payschema.xsd">
<instance>
<my:payment as="credit">
<my:cc />
<my:exp />
</my:payment>
</instance>
<submission action="http://www.example.com/buy.rb" method="post" id="s00" />
<bind nodeset="my:cc" relevant="../@as='credit'" required="true()" />
<bind nodeset="my:exp" relevant="../@as='credit'" required="true()" />
</model>
<group xmlns="http://www.w3.org/2002/xforms/cr">
<trigger>
<label>Francais</label>
<toggle case="fr" ev:event="xforms-activate" />
</trigger>
<trigger>
<label>English</label>
<toggle case="en" ev:event="xforms-activate" />
</trigger>
</group>
<input ref="my:cc">
<label xml:lang="fr">Numero de carte bancaire</label>
<alert xml:lang="fr">Saississez un numro de carte bancaire en cours
(sparez par un espace ou un trait d'union chaque groupe de chiffres)</alert>
</input>
<input ref="my:exp">
<label xml:lang="fr">Date d'chance</label>
</input>
<submit submission="s00">
<label xml:lang="fr">Achetez</label>
</submit>
</svg>
The next example supplements the XForms example above with the following simple example which shows a set of extension elements ui:menubar, ui:menu, ui:menuitem) which present a menubar and a scrolling area for graphics.
<svg width="525" height="575"
xmlns="http://www.w3.org/2000/svg" version="1.2"
xmlns:ui="http://example.org/rcc-ui">
<desc>Example rcc-ui-01 - using rcc for UI elements</desc>
<title>UI in SVG</title>
<!-- XPointer reference to the location for the UI extensions to SVG.
The extensions convert the UI elements into low-level SVG. -->
<extensionDefs xlink:href="rcc-ui-01-exts.svg#ui"/>
<ui:menubar x="25" y="25" width="500" height="20" font-size="14">
<ui:menu title=File>
<ui:menuitem title=New op="newdoc(evt)">
<ui:menuitem title=Open op="opendoc(evt)">
</ui:menu>
<ui:menu title=Edit>
<ui:menuitem title=Copy op="copy(evt)">
<ui:menuitem title=Past op="paste(evt)">
</ui:menu>
</ui:menubar>
<ui:scrollArea x="25" y="50" width="500" height="400">
<image xlink:href="..." ... />
<path d="..." ... />
<text transform="..." font-size="...">...</text>
</ui:scrollArea>
</svg>
The last example shows RCC being used for custom container elements that perform layout, in this case a magazine layout.
<svg>
...
<!-- XPointer reference to the location for the widgets extensions to SVG.
The extensions convert the widget elements into low-level SVG. -->
<extensionDefs xlink:href="rcc-dynlayout-01-exts.svg#dynlayout" />
<foo:DynamicPageLayout>
<foo:articles>
<foo:article>
<foo:title>Major war erupts</foo:title>
<foo:para>War broke out around the world today...</foo:para>
</foo:article>
<foo:article>
<foo:title>Two headed-chicken born</foo:title>
<foo:para>The sleepy town of Frostbite Falls is excited about...</foo:para>
</foo:article>
</foo:articles>
</foo:DynamicPageLayout>
...
</svg>
Live Templates is the name of an alternate proposal to the Rendering Custom Content feature. The SVG Working Group is currently in the process of reconciling Live Templates with RCC. Some of this has been included above in the RCC section, but the following Live Template details have not been updated. Therefore there will be some inconsistencies in the description below.
The objective of Live Templates is to improve SVG's usability as a front-end for fully interactive Web applications. In classical UI, the data model is in any appropriate XML grammar, the view is SVG, and there is the ability to view (transform the XML to SVG), edit (manipulate the view via DOM or post instructions to a server that would change the XML), and update the view (incrementally change only those parts of the SVG that are affected by changes in the XML, thereby avoiding a complete screen refresh).
There are three main uses of Live Templates:
Refer also to the design objectives and requirements of the RCC, they apply to Live Templates as well.
Live Templates provides the ability to run a specified XML transformer on a specified XML file or branch of the DOM with specified parameter values, and place the results as a generated SVG sub-tree in a specified location in the SVG. An XML transformer is something that takes XML as input, and produces XML as output, like an XSLT stylesheet.
The newly generated SVG subtree could be placed either directly in the DOM or as a shadow tree accessible as a separate DOM tree by calling a method on the element that generates this shadow tree .
Live Templates also provides ability to re-run the XSLT/XML transformer at any time to replace just the generated results, while leaving the rest of the SVG untouched.
This idea of running a script or other process on an input file to produce a generated SVG sub-tree is not specific to XSLT, or to XML input, so it should be possible, in theory, to specify the MIME type of the script file to be something else like XQuery, Java, or ECMAScript. Let's make XSLT the default and a priority for implementers.
The generateContent element allows an XML transformer such as an XSLT stylesheet to be run on a specified template XML file or fragment and the results inserted as a shadow tree of the generateContent element. The shadow tree is accessible via a DOM call on the generateContent element.
The generateContent, like the use element, has optional attributes x, y, width and height which are used to map the generated graphical contents onto a rectangular region within the current coordinate system.
Should the 'generateContent' to have similar viewport establishing attributes and behavior as the 'use' element or the 'svg' element?
A DOM method is provided so that script writers may regenerate the shadow tree from template XML at any time. The shadow tree is only generated at two possible times:
A generateContent element has the same visual effect as if the generateContent element was replaced by the shadow tree it generates.
General discussion of shadow tree inheritance, DOM access, and event model should be referenced from here.
We may want to fire an event before the shadow tree is generated and afterwords for script writers. An argument can be made against this, as it encourages doing a lot of rendering "fix-up" in a non-declarative manner with ECMAScript.
The specified XML transformer is run with the XML file as input.
The specified XML transformer is run with a constructed document rooted at the referenced element. The DTD of the constructed document is derivable from the DTD of the original document.
The specified XML transformer is run with a document constructed from the current DOM state, rooted at the referenced element. The DTD of the constructed document is derivable from the DTD of the current document.
This behavior is intended for both templating of SVG itself (a more general 'use') and the ability to store current user state information in an XML model which can be easily transformed to graphics. Separate files would be used for cases in which an external, server-based data model is being maintained
There is an interoperability argument to be made for not allowing this coding style, and enforcing the use of separate files. Keeping custom markup in a separate file would prevent any confusion about what markup is SVG and what markup is custom.
Example Use01 below has a simple 'generateContent' referencing an external template for a simple shape and an XML transformer that creates the SVG for the shape.
<svg width="10cm" height="3cm" viewBox="0 0 100 30" version="1.2"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<generateContent
x="10" y="10" width="30" height="30"
transformer="shapes.xsl"
type="text/xsl"
input="diamondInstance.xml" />
</svg>
The referenced template file:
diamond xmlns="http://foo.example.org/shapes" />
The referenced XML transformer file:
<xsl:stylesheet version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:foo="http://foo.example.org/shapes" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="foo:diamond"> <rect transform="rotate(44,50%,50%)" fill="red" width="100%" height="100%"/> </xsl:template> </xsl:stylesheet>
The visual effect would be equivalent to the following document:
<svg width="10cm" height="3cm" viewBox="0 0 100 30" version="1.2"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g transform="translate(10,10)">
<svg width="30" height="30" >
<rect transform="rotate(44,50%,50%)"
fill="red"
width="100%"
height="100%"/>
</svg >
</g >
</svg>
Example Use02 below has a generateContent referencing an external template for a simple button and an XML transformer that creates the SVG for the button.
<svg width="10cm" height="3cm" viewBox="0 0 100 30" version="1.2"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style type="text/css"<>![CDATA[
.pushButton {
fill: green;
stroke: black;
stroke-width: 3
}
]]<>/style>
<script type="text/ecmascript"< <![CDATA[
var angle = 0;
function myCallback(evt) {
var document = evt.target.ownerDocument;
var elem = document.getElementById( "message" )
// set rotation transform attribute on text.
angle = angle + 10;
var transform = "rotate(" + angle + " 100,20 )";
elem.setAttribute( "transform", transform );
}
]]> </script>
<text id="message" x="20" y="20" font-size="10">Below is a button, please press it</text>
<generateContent
x="10" y="10" width="30" height="30"
transformer="buttons.xsl"
type="text/xsl"
input="buttonInstance.xml" />
</svg>
The referenced template file:
<pushButton xmlns="http://bar.example.org/buttons" action="myCallback(evt)"/>
The referenced XML transformer file:
<xsl:stylesheet version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:bar="http://bar.example.org/buttons"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="bar:pushButton">
<xsl:variable name="action" select="./@action"/>
<g class="pushButton" fill="blue" onclick="{$action}" >
<rect width="100%" height="100%"/>
<svg x="10%" y="10%" width="80%" height="80%">
<xsl:apply-templates select="./*"/>
</svg>
</g>
</xsl:template>
</xsl:stylesheet>
The effect would be equivalent to the following document:
<svg width="10cm" height="3cm" viewBox="0 0 100 30" version="1.2"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style type="text/css"<>![CDATA[
.pushButton {
fill: green;
stroke: black;
stroke-width: 3
}
]]<>/style>
<script type="text/ecmascript"< <![CDATA[
var angle = 0;
function myCallback(evt) {
var document = evt.target.ownerDocument;
var elem = document.getElementById( "message" )
// set rotation transform attribute on text.
angle = angle + 10;
var transform = "rotate(" + angle + " 100,20 )";
elem.setAttribute( "transform", transform );
}
]]> </script>
<text id="message" x="20" y="20" font-size="10">Below is a button, please press it</text>
<g transform="translate(10,10)">
<svg width="30" height="30" >
<g class="pushButton" fill="blue" onclick="myCallback(evt)" >
<rect width="100%" height="100%"/>
<svg x="10%" y="10%" width="80%" height="80%"/>
</g>
</svg >
</g >
</svg>
Example Use03 below has a generateContent combining the two above examples to put the diamond on the button as a label.
<svg width="10cm" height="3cm" viewBox="0 0 100 30" version="1.2"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style type="text/css"<>![CDATA[
.pushButton {
fill: green;
stroke: black;
stroke-width: 3
}
]]<>/style>
<script type="text/ecmascript"< <![CDATA[
var angle = 0;
function myCallback(evt) {
var document = evt.target.ownerDocument;
var elem = document.getElementById( "message" )
// set rotation transform attribute on text.
angle = angle + 10;
var transform = "rotate(" + angle + " 100,20 )";
elem.setAttribute( "transform", transform );
}
]]> </script>
<text id="message" x="20" y="20" font-size="10">Below is a button, please press it</text>
<generateContent
x="10" y="10" width="30" height="30"
transformer="shapesAndButtons.xsl"
type="text/xsl"
input="diamondButtonInstance.xml" />
</svg>
The referenced template file:
<bar:pushButton xmlns:bar="http://bar.example.org/buttons"
action="myCallback(evt)">
<foo:diamond xmlns:foo="http://foo.example.org/shapes" />
</bar:pushButton>
The referenced XML transformer file:
<xsl:stylesheet version="1.1"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="buttons.xsl"/>
<xsl:import href="shapes.xsl"/>
</xsl:stylesheet>
The effect would be equivalent to the following document:
<svg width="10cm" height="3cm" viewBox="0 0 100 30" version="1.2"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style type="text/css"<>![CDATA[
.pushButton {
fill: green;
stroke: black;
stroke-width: 3
}
]]<>/style>
<script type="text/ecmascript"< <![CDATA[
var angle = 0;
function myCallback(evt) {
var document = evt.target.ownerDocument;
var elem = document.getElementById( "message" )
// set rotation transform attribute on text.
angle = angle + 10;
var transform = "rotate(" + angle + " 100,20 )";
elem.setAttribute( "transform", transform );
}
]]> </script>
<text id="message" x="20" y="20" font-size="10">Below is a button, please press it</text>
<g transform="translate(10,10)">
<svg width="30" height="30" >
<g class="pushButton" fill="blue" onclick="myCallback(evt)" >
<rect width="100%" height="100%"/>
<svg x="10%" y="10%" width="80%" height="80%">
<rect transform="rotate(44,50%,50%)"
fill="red"
width="100%"
height="100%"/>
</svg >
</g>
</svg >
</g >
</svg>
Example Use04 below has a generateContent transformer and input xml in the same file.
<svg width="10cm" height="3cm" viewBox="0 0 100 30" version="1.2"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<script id="diamond" type="text/xsl"<
<xsl:stylesheet version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:foo="http://foo.example.org/shapes"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="foo:diamond">
<rect transform="rotate(44,50%,50%)"
fill="red"
width="100%"
height="100%"/>
</xsl:template>
</xsl:stylesheet>
</script>
<generateContent
x="10" y="10" width="30" height="30"
transformer="#diamond"
type="text/xsl"
input="#diamondInstance" />
<metadata>
<diamond id="diamondInstance" xmlns="http://foo.example.org/shapes" />
</metadata>
</svg>
Example Use05 below has a generateContent referencing an XML transformer that allows binding SVG events to generated content.
The referenced template file:
<foo:teleportCircle
xmlns="http://www.w3.org/2000/svg"
xmlns:foo="http://foo.example.org/teleport"
foo:url="http://www.w3c.org"
cx="100" cy="100" r="30" fill="red" onmouseover="myCallback(evt)">
</foo:teleportCircle>
The referenced XML transformer file:
<xsl:stylesheet version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:foo="http://foo.example.org/teleport"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="foo:teleportCircle">
<xsl:variable name="url" select="./@foo:url"/>
<a xlink:href="{$url}">
<circle>
<xsl:for-each select="./@*[name() != 'onclick' and name() != 'foo:url']">
<xsl:variable name="attrName" select="name()"/>
<xsl:attribute name="{$attrName}"><xsl:value-of select="."/></xsl:attribute>
</xsl:for-each>
</circle>
</a>
</xsl:template>
</xsl:stylesheet>
The effect would be equivalent to the following document:
<svg width="10cm" height="3cm" viewBox="0 0 100 30" version="1.2"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style type="text/css"><![CDATA[
.pushButton {
fill: green;
stroke: black;
stroke-width: 3
}
]]></style>
<script type="text/ecmascript"> <![CDATA[
var angle = 0;
function myCallback(evt) {
var document = evt.target.ownerDocument;
var elem = document.getElementById( "message" )
// set rotation transform attribute on text.
angle = angle + 10;
var transform = "rotate(" + angle + " 100,20 )";
elem.setAttribute( "transform", transform );
}
]]> </script>
<text id="message" x="20" y="20" font-size="10">Below is a teleporter</text>
<a xlink:href="http://www.w3c.org">
<circle cx="100" cy="100" r="30" fill="red" onmouseover="myCallback(evt)"/>
</a>
</svg>
TODO: a DTD or schema fragment.
Attribute definitions:
The param element passes string information to the XML transformer (such as XSLT), mimicking the information that could be passed on the command line to the XML transformer.
Example Use06 below has two generateContent elements that use the 'param' element to pass parameters to the XML transformer.
<svg width="10cm" height="10cm" viewBox="0 0 100 100" version="1.2"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style type="text/css"><![CDATA[
.pushButton {
fill: green;
stroke: black;
stroke-width: 3
}
]]></style>
<script type="text/ecmascript"> <![CDATA[
var angle = 0;
function rotatePlus(evt) {
var document = evt.target.ownerDocument;
var elem = document.getElementById( "message" )
// set rotation transform attribute on text.
angle = angle + 10;
var transform = "rotate(" + angle + " 100,20 )";
elem.setAttribute( "transform", transform );
}
function rotateMinus(evt) {
var document = evt.target.ownerDocument;
var elem = document.getElementById( "message" )
// set rotation transform attribute on text.
angle = angle - 10;
var transform = "rotate(" + angle + " 100,20 )";
elem.setAttribute( "transform", transform );
}
]]> </script>
<text id="message" x="20" y="20" font-size="10">Below are buttons, please press them</text>
<generateContent
x="10" y="100" height="30" width="30"
type="text/xsl" input="paramButtonInstance.xml" transformer="paramButtons.xsl">
<param name="action" value="rotatePlus(evt)"/>
</generateContent>
<generateContent
x="100" y="100" height="30" width="30"
type="text/xsl" input="paramButtonInstance.xml" transformer="paramButtons.xsl">
<param name="action" value="rotateMinus(evt)"/>
</generateContent>
</svg>
The referenced template file:
<pushButton xmlns="http://bar.example.org/buttons" fill="blue"/>
The referenced XML transformer file:
<xsl:stylesheet version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:bar="http://bar.example.org/buttons"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="action" />
<xsl:template match="bar:pushButton">
<xsl:variable name="fill" select="./@fill"/>
<g class="pushButton" fill="blue" onclick="{$action}" >
<rect width="100%" height="100%"/>
<svg width="100%" height="100%" viewBox="0 0 100 100">
<xsl:apply-templates select="./*"/>
</svg>
</g>
</xsl:template>
</xsl:stylesheet>
The effect would be equivalent to the following document:
<svg width="10cm" height="10cm" viewBox="0 0 100 100" version="1.2"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style type="text/css"><![CDATA[
.pushButton {
fill: green;
stroke: black;
stroke-width: 3
}
]]></style>
<script type="text/ecmascript"> <![CDATA[
var angle = 0;
function rotatePlus(evt) {
var document = evt.target.ownerDocument;
var elem = document.getElementById( "message" )
// set rotation transform attribute on text.
angle = angle + 10;
var transform = "rotate(" + angle + " 100,20 )";
elem.setAttribute( "transform", transform );
}
function rotateMinus(evt) {
var document = evt.target.ownerDocument;
var elem = document.getElementById( "message" )
// set rotation transform attribute on text.
angle = angle - 10;
var transform = "rotate(" + angle + " 100,20 )";
elem.setAttribute( "transform", transform );
}
]]> </script>
<text id="message" x="20" y="20" font-size="10">Below are buttons, please press them</text>
<g transform="translate(10,100)">
<svg width="30" height="30" >
<g class="pushButton" fill="blue" onclick="rotatePlus(evt)">
<rect width="100%" height="100%"/>
</g>
</svg>
</g>
<g transform="translate(100,100)">
<svg width="30" height="30" >
<g class="pushButton" fill="blue" onclick="rotateMinus(evt)">
<rect width="100%" height="100%"/>
</g>
</svg>
</g>
</svg>
TODO: Schema or DTD fragment
Attribute definitions:
The following interfaces will be defined below: GenerateContentElement and ParamsElement.
These interfaces are not yet ready.
For the GenerateContentElement interface, the important methods to define are:
XForms is a technology for describing forms in XML. It separates the model, or the information that is to be sent as the result of the form, from the abstract controls that will be used to get information from the person using the form. XForms deliberately says nothing about presentation of form controls; this is left to a styling or transformation language, to generate the actual visual (or indeed, audio) form widgets. XForms cannot be used by itself; it is designed to be integrated into a host language, such as SVG. This provides the host language with an abstract definition of form content and leaves the rendering to the host. SVG is well suited to hosting XForms, since it provides powerful rendering and interactivity APIs.
Furthermore, a generic set of user interface components has been a common request from the SVG community. By describing how SVG and XForms can be integrated that request can be answered while providing more functionality if required. For example, the tight integration with a data model of a form should allow an