Code

7569d0db7deadc3a3ee44c1ccf9cd296e3eb0255
[inkscape.git] / share / extensions / svg2fxg.xsl
1 <?xml version="1.0" encoding="UTF-8"?>
3 <!--
4 Authors:
5   Nicolas Dufour <nicoduf@yahoo.fr>
6   
7 Copyright (c) 2010 authors
9 Released under GNU GPL, read the file 'COPYING' for more information
10 -->
12 <xsl:stylesheet version="1.0"
13 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
14 xmlns:xlink="http://www.w3.org/1999/xlink"
15 xmlns:xs="http://www.w3.org/2001/XMLSchema"
16 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
17 xmlns="http://ns.adobe.com/fxg/2008"
18 xmlns:fxg="http://ns.adobe.com/fxg/2008"
19 xmlns:d="http://ns.adobe.com/fxg/2008/dt"
20 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
21 xmlns:exsl="http://exslt.org/common"
22 xmlns:math="http://exslt.org/math"
23 xmlns:libxslt="http://xmlsoft.org/XSLT/namespace"
24 xmlns:svg="http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd"
25 exclude-result-prefixes="rdf xlink xs exsl libxslt"
26 extension-element-prefixes="math">
28 <xsl:strip-space elements="*" />
29 <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
31 <!-- 
32   // Containers //
34   * Root templace
35   * Graphic attributes
36   * Groups
37 -->
39 <!-- 
40   // Root template //
41 -->
42 <xsl:template match="/">
43     <xsl:apply-templates mode="forward" />
44 </xsl:template>
45 <!--
46   // Graphic //
47   First SVG element is converted to Graphic
48 -->
49 <xsl:template mode="forward" match="/*[name(.) = 'svg']" priority="1">
50   <Graphic>
51     <xsl:attribute name="version">2.0</xsl:attribute>
52     <xsl:if test="@width and not(contains(@width, '%'))">
53       <xsl:attribute name="viewWidth">
54         <xsl:call-template name="convert_unit">
55           <xsl:with-param name="convert_value" select="@width" />
56         </xsl:call-template>
57       </xsl:attribute>
58     </xsl:if>
59     <xsl:if test="@height and not(contains(@height, '%'))">
60       <xsl:attribute name="viewHeight">
61         <xsl:call-template name="convert_unit">
62           <xsl:with-param name="convert_value" select="@height" />
63         </xsl:call-template>
64       </xsl:attribute>
65     </xsl:if>
66     <xsl:if test="@width and not(contains(@width, '%')) and @height and not(contains(@height, '%'))">
67       <mask>
68         <Group>
69           <Rect>
70             <xsl:attribute name="width">
71               <xsl:call-template name="convert_unit">
72                 <xsl:with-param name="convert_value" select="@width" />
73               </xsl:call-template>
74             </xsl:attribute>
75             <xsl:attribute name="height">
76               <xsl:call-template name="convert_unit">
77                 <xsl:with-param name="convert_value" select="@height" />
78               </xsl:call-template>
79             </xsl:attribute>
80             <fill>
81               <SolidColor color="#ffffff" alpha="1"/>
82             </fill>
83           </Rect>
84         </Group>
85       </mask>
86     </xsl:if>
87     <xsl:apply-templates mode="forward" />
88   </Graphic>
89 </xsl:template>
91 <!--
92   // inner SVG elements //
93   Converted to groups
94 -->
95 <xsl:template mode="forward" match="*[name(.) = 'svg']">
96   <Group>
97     <xsl:if test="@x">
98       <xsl:attribute name="x">
99           <xsl:call-template name="convert_unit">
100             <xsl:with-param name="convert_value" select="@x" />
101           </xsl:call-template>
102       </xsl:attribute>
103     </xsl:if>
104     <xsl:if test="@y">
105       <xsl:attribute name="y">
106         <xsl:call-template name="convert_unit">
107           <xsl:with-param name="convert_value" select="@y" />
108         </xsl:call-template>
109       </xsl:attribute>
110     </xsl:if>
111     <xsl:if test="@width and not(contains(@width, '%')) and @height and not(contains(@height, '%'))">
112       <xsl:attribute name="maskType"><xsl:value-of select="'clip'"/></xsl:attribute>
113       <mask>
114         <Group>
115           <Rect>
116             <xsl:attribute name="width">
117               <xsl:call-template name="convert_unit">
118                 <xsl:with-param name="convert_value" select="@width" />
119               </xsl:call-template>
120             </xsl:attribute>
121             <xsl:attribute name="height">
122               <xsl:call-template name="convert_unit">
123                 <xsl:with-param name="convert_value" select="@height" />
124               </xsl:call-template>
125             </xsl:attribute>
126             <fill>
127               <SolidColor color="#ffffff" alpha="1"/>
128             </fill>
129           </Rect>
130         </Group>
131       </mask>
132     </xsl:if>
133     <xsl:apply-templates mode="forward" />
134   </Group>
135 </xsl:template>
137 <!--
138   // Groups //
139   (including layers)
140   
141   FXG's Group doesn't support other elements attributes (such as font-size, etc.) 
142 -->
143 <xsl:template mode="forward" match="*[name(.) = 'g']">
144   <xsl:variable name="object">
145     <Group>
146       <xsl:if test="@style and contains(@style, 'display:none')">
147         <xsl:attribute name="Visibility">Collapsed</xsl:attribute>
148       </xsl:if>
149       <xsl:if test="@width and not(contains(@width, '%'))">
150         <xsl:attribute name="width">
151           <xsl:call-template name="convert_unit">
152             <xsl:with-param name="convert_value" select="@width" />
153           </xsl:call-template>
154         </xsl:attribute>
155       </xsl:if>
156       <xsl:if test="@height and not(contains(@height, '%'))">
157         <xsl:attribute name="height">
158           <xsl:call-template name="convert_unit">
159             <xsl:with-param name="convert_value" select="@height" />
160           </xsl:call-template>
161         </xsl:attribute>
162       </xsl:if>
163       <xsl:if test="@x">
164         <xsl:attribute name="x">
165             <xsl:call-template name="convert_unit">
166               <xsl:with-param name="convert_value" select="@x" />
167             </xsl:call-template>
168         </xsl:attribute>
169       </xsl:if>
170       <xsl:if test="@y">
171         <xsl:attribute name="y">
172           <xsl:call-template name="convert_unit">
173             <xsl:with-param name="convert_value" select="@y" />
174           </xsl:call-template>
175         </xsl:attribute>
176       </xsl:if>
177       <xsl:apply-templates mode="object_opacity" select="." />
178       <xsl:apply-templates mode="id" select="." />
179       
180       <xsl:apply-templates mode="layer_blend" select="." />
181       <xsl:apply-templates mode="filter_effect" select="." />
182       <xsl:apply-templates mode="forward" select="*" />
183     </Group>
184   </xsl:variable>
185   
186   <xsl:variable name="clipped_object">
187     <xsl:apply-templates mode="clip" select="." >
188       <xsl:with-param name="object" select="$object" />
189       <xsl:with-param name="clip_type" select="'clip'" />
190     </xsl:apply-templates>
191   </xsl:variable>
193   <xsl:variable name="masked_object">
194     <xsl:apply-templates mode="clip" select="." >
195       <xsl:with-param name="object" select="$clipped_object" />
196       <xsl:with-param name="clip_type" select="'mask'" />
197     </xsl:apply-templates>
198   </xsl:variable>
199   
200   <xsl:choose>
201     <xsl:when test="@transform">
202     <Group>
203       <xsl:call-template name="object_transform">
204         <xsl:with-param name="object" select="$masked_object" />
205         <xsl:with-param name="transform" select="@transform" />
206       </xsl:call-template>
207     </Group>
208     </xsl:when>
209     <xsl:otherwise>
210       <xsl:copy-of select="$masked_object" />
211     </xsl:otherwise>
212   </xsl:choose>
213 </xsl:template>
215 <!-- 
216   // Transforms //
217   All the matrix, translate, rotate... stuff.
218   * Parse objects transform
219   * Object transform
220   * Parse gradient transform  
221   * Gradient transform
222   
223   Not supported by FXG:
224   * Skew transform.
225   * Multiple values rotation.
226 -->
228 <!-- 
229   // Parse object transform //
230 -->
231 <xsl:template name="parse_object_transform">
232   <xsl:param name="input" />  
233     <xsl:choose>
234   <!-- Matrix transform -->
235     <xsl:when test="starts-with($input, 'matrix(')">
236       <transform>
237       <Transform>
238       <matrix>
239         <Matrix>
240           <xsl:variable name="matrix" select="normalize-space(translate(substring-before(substring-after($input, 'matrix('), ')'), ',', ' '))" />
241           <xsl:variable name="a" select="substring-before($matrix, ' ')"/>
242           <xsl:variable name="ra" select="substring-after($matrix, ' ')"/>
243           <xsl:variable name="b" select="substring-before($ra, ' ')"/>
244           <xsl:variable name="rb" select="substring-after($ra, ' ')"/>
245           <xsl:variable name="c" select="substring-before($rb, ' ')"/>
246           <xsl:variable name="rc" select="substring-after($rb, ' ')"/>
247           <xsl:variable name="d" select="substring-before($rc, ' ')"/>
248           <xsl:variable name="rd" select="substring-after($rc, ' ')"/>
249           <xsl:variable name="tx" select="substring-before($rd, ' ')"/>
250           <xsl:variable name="ty" select="substring-after($rd, ' ')"/>
251           <xsl:attribute name="a"><xsl:value-of select="$a" /></xsl:attribute>
252           <xsl:attribute name="b"><xsl:value-of select="$b" /></xsl:attribute>
253           <xsl:attribute name="c"><xsl:value-of select="$c" /></xsl:attribute>
254           <xsl:attribute name="d"><xsl:value-of select="$d" /></xsl:attribute>
255           <xsl:attribute name="tx"><xsl:value-of select='format-number($tx, "#.##")' /></xsl:attribute>
256           <xsl:attribute name="ty"><xsl:value-of select='format-number($ty, "#.##")' /></xsl:attribute>
257         </Matrix>
258       </matrix>
259       </Transform>
260       </transform>  
261     </xsl:when>
263   <!-- Scale transform -->
264     <xsl:when test="starts-with($input, 'scale(')">
265       <xsl:variable name="scale" select="normalize-space(translate(substring-before(substring-after($input, 'scale('), ')'), ',', ' '))" />
266       <xsl:choose>
267         <xsl:when test="contains($scale, ' ')">
268           <xsl:attribute name="scaleX">
269             <xsl:value-of select="substring-before($scale, ' ')" />
270           </xsl:attribute>
271           <xsl:attribute name="scaleY">
272             <xsl:value-of select="substring-after($scale, ' ')" />
273           </xsl:attribute>
274         </xsl:when>
275         <xsl:otherwise>
276           <xsl:attribute name="scaleX">
277             <xsl:value-of select="$scale" />
278           </xsl:attribute>
279           <xsl:attribute name="scaleY">
280             <xsl:value-of select="$scale" />
281           </xsl:attribute>
282         </xsl:otherwise>
283       </xsl:choose>
284     </xsl:when>
285   
286   <!-- Rotate transform -->
287     <xsl:when test="starts-with($input, 'rotate(')">
288       <xsl:variable name="rotate" select="normalize-space(translate(substring-before(substring-after($input, 'rotate('), ')'), ',', ' '))" />
289       <xsl:attribute name="rotation">
290         <xsl:choose>
291           <xsl:when test="contains($rotate, ' ')">
292             <xsl:value-of select="substring-before($rotate, ' ')" />
293           </xsl:when>
294           <xsl:otherwise>
295             <xsl:value-of select="$rotate" />
296           </xsl:otherwise>
297         </xsl:choose>
298       </xsl:attribute>
299       <xsl:if test="@rx">
300         <xsl:attribute name="CenterX">
301           <xsl:value-of select="@rx" />
302         </xsl:attribute>
303       </xsl:if>
304       <xsl:if test="@ry">
305         <xsl:attribute name="CenterY">
306           <xsl:value-of select="@ry" />
307         </xsl:attribute>
308       </xsl:if>
309     </xsl:when>
310   
311   <!-- Translate transform -->
312     <xsl:when test="starts-with($input, 'translate(')">
313       <xsl:variable name="translate" select="normalize-space(translate(substring-before(substring-after($input, 'translate('), ')'), ',', ' '))" />
314       <xsl:choose>
315         <xsl:when test="contains($translate, ' ')">
316           <xsl:attribute name="x">
317             <xsl:value-of select="substring-before($translate, ' ')" />
318           </xsl:attribute>
319           <xsl:attribute name="y">
320             <xsl:value-of select="substring-after($translate, ' ')" />
321           </xsl:attribute>
322         </xsl:when>
323         <xsl:otherwise>
324           <xsl:attribute name="x">
325             <xsl:value-of select="$translate" />
326           </xsl:attribute>
327         </xsl:otherwise>
328       </xsl:choose>
329     </xsl:when>
330   </xsl:choose>
331 </xsl:template>
333 <!-- 
334   // Object transform //
335   FXG needs a separate group for each transform type in the transform attribute (scale+translate != translate+scale)
336 -->
337 <xsl:template name="object_transform">
338   <xsl:param name="object" />  
339   <xsl:param name="transform" />
341   <xsl:variable name="values" select="normalize-space(translate($transform, ',', ' '))" />
342   <xsl:choose>
343     <xsl:when test="contains($values, ') ')">
344       <xsl:call-template name="parse_object_transform">
345         <xsl:with-param name="input" select="concat(substring-before($values, ') '), ')')" />
346       </xsl:call-template>
347       <xsl:variable name="values2" select="substring-after($values, ') ')" />
348       <Group>
349       <xsl:choose>
350         <xsl:when test="contains($values2, ') ')">
351           <xsl:call-template name="parse_object_transform">
352             <xsl:with-param name="input" select="concat(substring-before($values2, ') '), ')')" />
353           </xsl:call-template>
354           <xsl:variable name="values3" select="substring-after($values2, ') ')" />
355           <Group>
356             <xsl:call-template name="parse_object_transform">
357               <xsl:with-param name="input" select="concat($values3, ')')" />
358             </xsl:call-template>
359             <xsl:copy-of select="$object" />
360           </Group>
361         </xsl:when>
362         <xsl:otherwise>
363           <xsl:call-template name="parse_object_transform">
364             <xsl:with-param name="input" select="$values2" />
365           </xsl:call-template>
366           <xsl:copy-of select="$object" />
367         </xsl:otherwise>
368       </xsl:choose>
369       </Group>
370     </xsl:when>
371     <xsl:otherwise>
372       <xsl:call-template name="parse_object_transform">
373         <xsl:with-param name="input" select="$values" />
374       </xsl:call-template>
375       <xsl:copy-of select="$object" />
376     </xsl:otherwise>
377   </xsl:choose>
378 </xsl:template>
380 <!-- 
381   // Parse gradient transform //
382 -->
383 <xsl:template name="parse_gradient_transform">
384   <xsl:param name="input" />  
385   <xsl:param name="type" />
386   <xsl:choose>
387   <!-- Scale transform -->
388     <xsl:when test="starts-with($input, 'scale(')">
389       <xsl:variable name="scale" select="normalize-space(translate(substring-before(substring-after($input, 'scale('), ')'), ',', ' '))" />
390       <xsl:choose>
391         <xsl:when test="$type='radial'">
392           <xsl:choose>
393             <xsl:when test="contains($scale, ' ')">
394               <xsl:attribute name="scaleX">
395                 <xsl:value-of select="substring-before($scale, ' ')" />
396               </xsl:attribute>
397               <xsl:attribute name="scaleY">
398                 <xsl:value-of select="substring-after($scale, ' ')" />
399               </xsl:attribute>
400             </xsl:when>
401             <xsl:otherwise>
402               <xsl:attribute name="scaleX">
403                 <xsl:value-of select="$scale" />
404               </xsl:attribute>
405               <xsl:attribute name="scaleY">
406                 <xsl:value-of select="$scale" />
407               </xsl:attribute>
408             </xsl:otherwise>
409           </xsl:choose>
410         </xsl:when>
411         <xsl:otherwise>
412           <xsl:attribute name="scaleX">
413             <xsl:value-of select="$scale" />
414           </xsl:attribute>
415         </xsl:otherwise>
416       </xsl:choose>
417     </xsl:when>
418     
419   <!-- Rotate transform -->
420     <xsl:when test="starts-with($input, 'rotate(')">
421       <xsl:variable name="rotate" select="normalize-space(translate(substring-before(substring-after($input, 'rotate('), ')'), ',', ' '))" />
422       <xsl:attribute name="rotation">
423         <xsl:choose>
424           <xsl:when test="contains($rotate, ' ')">
425             <xsl:value-of select="substring-before($rotate, ' ')" />
426           </xsl:when>
427           <xsl:otherwise>
428             <xsl:value-of select="$rotate" />
429           </xsl:otherwise>
430         </xsl:choose>
431       </xsl:attribute>
432     </xsl:when>
433     
434   <!-- Translate transform -->
435     <xsl:when test="starts-with($input, 'translate(')">
436       <xsl:variable name="translate" select="normalize-space(translate(substring-before(substring-after($input, 'translate('), ')'), ',', ' '))" />
437       <xsl:choose>
438         <xsl:when test="contains($translate, ' ')">
439           <xsl:attribute name="x">
440             <xsl:value-of select="substring-before($translate, ' ')" />
441           </xsl:attribute>
442           <xsl:attribute name="y">
443             <xsl:value-of select="substring-after($translate, ' ')" />
444           </xsl:attribute>
445         </xsl:when>
446         <xsl:otherwise>
447           <xsl:attribute name="x">
448             <xsl:value-of select="$translate" />
449           </xsl:attribute>
450         </xsl:otherwise>
451       </xsl:choose>
452     </xsl:when>
453   </xsl:choose>
454 </xsl:template>
456 <!-- 
457   // Gradient transform //
458   Not implemented yet
459   Gradient positioning and tranformation are very different in FXG
460 -->
461 <xsl:template name="gradient_transform">
462   <xsl:param name="transform" />
463   <xsl:param name="type" />
464   
465   <xsl:if test="contains($transform, 'translate')">
466     <xsl:call-template name="parse_gradient_transform">
467       <xsl:with-param name="input" select="concat('translate(', substring-before(substring-after($transform, 'translate('), ')'), ')')" />
468       <xsl:with-param name="type" select="$type" />
469     </xsl:call-template>
470   </xsl:if>
471 </xsl:template>
473 <!--
474   // Resources (defs) //
476   * Resources ids
477   * Generic defs template
478   * Defs gradients
479   * Layers blend mode
480   * Generic filters template
481   * Filter effects
482   * Linked filter effects
483   * Linear gradients
484   * Radial gradients
485   * Gradient stops list
486   * Gradient stop
487   * Clipping
488 -->
490 <!-- 
491   // Resources ids //
492 -->
493 <xsl:template mode="resources" match="*">
494   <!-- should be in-depth -->
495   <xsl:if test="ancestor::*[name(.) = 'defs']"><xsl:attribute name="id"><xsl:value-of select="@id" /></xsl:attribute></xsl:if>
496 </xsl:template>
498 <!--
499   // Generic defs template //
500 -->
501 <xsl:template mode="forward" match="defs">
502 <!-- Ignoring defs, do nothing  
503   <xsl:apply-templates mode="forward" />
504 -->
505 </xsl:template>
507 <!--
508   // Defs gradients //
509   ignored
510 -->
511 <xsl:template mode="forward" match="*[name(.) = 'linearGradient' or name(.) = 'radialGradient']">
513 </xsl:template>
515 <!-- 
516   // Layers blend mode //
518   Partial support
519   Looks good with normal, multiply, and darken
520 -->
521 <xsl:template mode="layer_blend" match="*">
522   <xsl:if test="@inkscape:groupmode='layer' and @style and contains(@style, 'filter:url(#')">
523     <xsl:variable name="id" select="substring-before(substring-after(@style, 'filter:url(#'), ')')" />
524     <xsl:for-each select="//*[@id=$id]">
525       <xsl:if test="name(child::node()) = 'feBlend'">
526         <xsl:attribute name="blendMode">
527           <xsl:value-of select="child::node()/@mode"/>
528         </xsl:attribute>
529       </xsl:if>
530     </xsl:for-each>
531   </xsl:if>
532 </xsl:template>
534 <!--
535   // Generic filters template //
536   Limited to one filter (can be improved)
537 -->
538 <xsl:template mode="forward" match="*[name(.) = 'filter']">
539   <xsl:if test="count(*) = 1">
540     <xsl:apply-templates mode="forward" />
541   </xsl:if> 
542 </xsl:template>
544 <!--
545   // GaussianBlur filter effects //
546   Blur values approximated with d = floor(s * 3*sqrt(2*pi)/4 + 0.5) from:
547     http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement
548   Blur quality=2 recommended by the FXG specifications:
549     http://opensource.adobe.com/wiki/display/flexsdk/FXG+2.0+Specification#FXG2.0Specification-FilterEffects
550 -->
551 <xsl:template mode="forward" match="*[name(.) = 'feGaussianBlur']">
552   <xsl:if test="name(.)='feGaussianBlur'">
553     <filters>
554       <BlurFilter>
555         <xsl:attribute name="quality">2</xsl:attribute>
556         <xsl:if test="@stdDeviation">
557           <xsl:variable name="blur" select="normalize-space(translate(@stdDeviation, ',', ' '))" />
558           <xsl:choose>
559             <xsl:when test="not(contains($blur, ' '))">
560               <xsl:attribute name="blurX">
561                 <xsl:value-of select="floor($blur * 1.88 + 0.5)" />
562               </xsl:attribute>
563               <xsl:attribute name="blurY">
564                 <xsl:value-of select="floor($blur * 1.88 + 0.5)" />
565               </xsl:attribute>
566             </xsl:when>
567             <xsl:otherwise>
568               <xsl:attribute name="blurX">
569                 <xsl:value-of select="floor(substring-before($blur, ' ') * 1.88 + 0.5)" />
570               </xsl:attribute>
571               <xsl:attribute name="blurY">
572                 <xsl:value-of select="floor(substring-after($blur, ' ') * 1.88 + 0.5)" />
573               </xsl:attribute>
574             </xsl:otherwise>
575           </xsl:choose>          
576         </xsl:if>
577       </BlurFilter>
578     </filters>
579   </xsl:if>
580 </xsl:template>
582 <!--
583   // Linked filter effect //
584   Only supports blurs
585 -->
586 <xsl:template mode="filter_effect" match="*">
587   <xsl:variable name="id">
588     <xsl:choose>
589       <xsl:when test="@filter and starts-with(@filter, 'url(#')">
590         <xsl:value-of select="substring-before(substring-after(@filter, 'url(#'), ')')" />
591       </xsl:when>
592       <xsl:when test="@style and contains(@style, 'filter:url(#')">
593         <xsl:value-of select="substring-before(substring-after(@style, 'filter:url(#'), ')')" />
594       </xsl:when>
595     </xsl:choose>
596   </xsl:variable>
598   <xsl:for-each select="//*[@id=$id]">
599     <xsl:apply-templates mode="forward" />
600   </xsl:for-each>
601 </xsl:template>
603 <!--
604   // Linear gradient //
605   Full convertion to FXG would require some math.
606 -->
607 <xsl:template name="linearGradient">
608   <xsl:param name="id" />
609   <xsl:for-each select="//*[@id=$id]">
610     <xsl:if test="@id">
611       <xsl:attribute name="id">
612         <xsl:value-of select="@id" />
613       </xsl:attribute>
614     </xsl:if>
615     <xsl:if test="@spreadMethod">
616       <xsl:attribute name="spreadMethod">
617         <xsl:choose>
618           <xsl:when test="@spreadMethod = 'pad'">pad</xsl:when>
619           <xsl:when test="@spreadMethod = 'reflect'">reflect</xsl:when>
620           <xsl:when test="@spreadMethod = 'repeat'">repeat</xsl:when>
621         </xsl:choose>
622       </xsl:attribute>
623     </xsl:if>
624     <xsl:if test="@color-interpolation">
625       <xsl:attribute name="interpolationMethod">
626         <xsl:choose>
627           <xsl:when test="@color-interpolation = 'linearRGB'">linearRGB</xsl:when>
628           <xsl:otherwise>rgb</xsl:otherwise>
629         </xsl:choose>
630       </xsl:attribute>
631     </xsl:if>
632     <xsl:if test="@x1 and @x2 and @y1 and @y2 and function-available('math:atan')">
633       <xsl:attribute name="rotation">
634         <xsl:value-of select="57.3 * math:atan((@y2 - @y1) div (@x2 - @x1))" />
635       </xsl:attribute>
636     </xsl:if>
637     <xsl:if test="@gradientTransform">
638       <xsl:call-template name="gradient_transform">
639         <xsl:with-param name="transform" select="@gradientTransform" />
640         <xsl:with-param name="type" select="linear" />
641       </xsl:call-template>
642     </xsl:if> 
643     <xsl:choose>
644       <xsl:when test="@xlink:href">
645         <xsl:variable name="reference_id" select="@xlink:href" />
646         <xsl:call-template name="gradientStops" >
647           <xsl:with-param name="id">
648             <xsl:value-of select="substring-after($reference_id, '#')" />
649           </xsl:with-param>
650         </xsl:call-template>
651       </xsl:when>
652       <xsl:otherwise><xsl:apply-templates mode="forward" /></xsl:otherwise>
653     </xsl:choose>
654   </xsl:for-each>
655 </xsl:template>
657 <!--
658   // Radial gradient //
659     
660   Full convertion to FXG would require some math.
661 -->
662 <xsl:template name="radialGradient">
663   <xsl:param name="id" />
664   <xsl:for-each select="//*[@id=$id]">
665     <xsl:if test="@id">
666       <xsl:attribute name="id">
667         <xsl:value-of select="@id" />
668       </xsl:attribute>
669     </xsl:if>
670     <xsl:if test="@spreadMethod">
671       <xsl:attribute name="spreadMethod">
672         <xsl:choose>
673           <xsl:when test="@spreadMethod = 'pad'">pad</xsl:when>
674           <xsl:when test="@spreadMethod = 'reflect'">reflect</xsl:when>
675           <xsl:when test="@spreadMethod = 'repeat'">repeat</xsl:when>
676         </xsl:choose>
677       </xsl:attribute>
678     </xsl:if>
679     <xsl:if test="@color-interpolation">
680       <xsl:attribute name="interpolationMethod">
681         <xsl:choose>
682           <xsl:when test="@color-interpolation = 'linearRGB'">linearRGB</xsl:when>
683           <xsl:otherwise>rgb</xsl:otherwise>
684         </xsl:choose>
685       </xsl:attribute>
686     </xsl:if>
687     <xsl:if test="@gradientTransform">
688       <xsl:call-template name="gradient_transform">
689         <xsl:with-param name="transform" select="@gradientTransform" />
690         <xsl:with-param name="type" select="radial" />
691       </xsl:call-template>
692     </xsl:if>
693     <xsl:choose>
694       <xsl:when test="@xlink:href">
695         <xsl:variable name="reference_id" select="@xlink:href" />
696         <xsl:call-template name="gradientStops" >
697           <xsl:with-param name="id">
698             <xsl:value-of select="substring-after($reference_id, '#')" />
699           </xsl:with-param>
700         </xsl:call-template>
701       </xsl:when>
702       <xsl:otherwise><xsl:apply-templates mode="forward" /></xsl:otherwise>
703     </xsl:choose>
704   </xsl:for-each>
705 </xsl:template>
707 <!--
708   // Gradient stops list //
709   
710   TODO: Find a way to test the existence of the node-set
711 -->
712 <xsl:template name="gradientStops">
713   <xsl:param name="id" />
714   <xsl:variable name="stops">
715     <xsl:for-each select="//*[@id=$id]">
716       <xsl:apply-templates mode="forward" />
717     </xsl:for-each>
718   </xsl:variable>
719   <xsl:choose>
720     <xsl:when test="not($stops)">
721       <GradientEntry>
722         <xsl:attribute name="alpha">0</xsl:attribute>
723       </GradientEntry>
724     </xsl:when>
725     <xsl:otherwise><xsl:copy-of select="$stops" /></xsl:otherwise>
726   </xsl:choose>
727 </xsl:template>
729 <!--
730   // Gradient stop //
731 -->
732 <xsl:template mode="forward" match="*[name(.) = 'stop']">
733   <GradientEntry>
734     <!--xsl:apply-templates mode="stop_opacity" select="." /-->
735     <xsl:apply-templates mode="stop_color" select="." />
736     <xsl:apply-templates mode="offset" select="." />
737     <xsl:apply-templates mode="forward" />
738   </GradientEntry>
739 </xsl:template>
741 <!--
742   // Clipping and masking//
743 -->
744 <xsl:template mode="clip" match="*">
745   <xsl:param name="object" />
746   <xsl:param name="clip_type" />
748   <xsl:choose>
749     <xsl:when test="$clip_type='clip' and @clip-path and contains(@clip-path, 'url')">
750       <Group>
751         <xsl:attribute name="maskType"><xsl:value-of select="'clip'"/></xsl:attribute>
752         <mask>
753           <Group>
754             <xsl:variable name="clip_id" select="substring-before(substring-after(@clip-path, 'url(#'), ')')"/>
755             <xsl:for-each select="//*[@id=$clip_id]">
756               <xsl:if test="not(@clipPathUnits) or @clipPathUnits != 'objectBoundingBox'">
757                 <xsl:apply-templates mode="forward" />
758               </xsl:if>
759             </xsl:for-each>
760           </Group>
761         </mask>
762         <xsl:copy-of select="$object"/>
763       </Group>
764     </xsl:when>
765     <xsl:when test="$clip_type='mask' and @mask and contains(@mask, 'url')">
766       <Group>
767         <xsl:attribute name="maskType"><xsl:value-of select="'alpha'"/></xsl:attribute>
768         <mask>
769           <Group>
770             <xsl:variable name="mask_id" select="substring-before(substring-after(@mask, 'url(#'), ')')"/>
771             <xsl:for-each select="//*[@id=$mask_id]">
772               <xsl:if test="not(@maskUnits) or @maskUnits != 'objectBoundingBox'">
773                 <xsl:apply-templates mode="forward" />
774               </xsl:if>
775             </xsl:for-each>
776           </Group>
777         </mask>
778         <xsl:copy-of select="$object"/>
779       </Group>
780     </xsl:when>
781     <xsl:otherwise>
782       <xsl:copy-of select="$object" />
783     </xsl:otherwise>
784   </xsl:choose>
785 </xsl:template>
787 <!--
788   // Misc templates //
790   * Id converter
791   * Decimal to hexadecimal converter
792   * Unit to pixel converter
793   * Switch
794   * Unknows tags
795   * Object description (not supported)
796   * Title and description (not supported)
797   * Symbols (not supported)
798   * Use (not supported)
799   * RDF and foreign objects (not supported)
800   * Misc ignored stuff (markers, patterns, styles)
801 -->
803 <!--
804   // Id converter //
805   Removes "-" from the original id
806   (Not sure FXG really needs it)
807 -->
808 <xsl:template mode="id" match="*">
809   <xsl:if test="@id">
810     <xsl:attribute name="id"><xsl:value-of select="translate(@id, '- ', '')" /></xsl:attribute>
811   </xsl:if>
812 </xsl:template>
814 <!--
815   // Decimal to hexadecimal converter //
816 -->
817 <xsl:template name="to_hex">
818   <xsl:param name="convert" />
819   <xsl:value-of select="concat(substring('0123456789ABCDEF', 1 + floor(round($convert) div 16), 1), substring('0123456789ABCDEF', 1 + round($convert) mod 16, 1))" />
820 </xsl:template>
822 <!-- 
823   // Unit to pixel converter //
824   Values with units (except %) are converted to pixels and rounded.
825   Unknown units are kept.
826   em, ex and % not implemented
827 -->
828 <xsl:template name="convert_unit">
829   <xsl:param name="convert_value" />
830   <xsl:choose>
831     <xsl:when test="contains($convert_value, 'px')">
832       <xsl:value-of select="round(translate($convert_value, 'px', ''))" />
833     </xsl:when>
834     <xsl:when test="contains($convert_value, 'pt')">
835       <xsl:value-of select="round(translate($convert_value, 'pt', '') * 1.25)" />
836     </xsl:when>
837     <xsl:when test="contains($convert_value, 'pc')">
838       <xsl:value-of select="round(translate($convert_value, 'pc', '') * 15)" />
839     </xsl:when>
840     <xsl:when test="contains($convert_value, 'mm')">
841       <xsl:value-of select="round(translate($convert_value, 'mm', '') * 3.543307)" />
842     </xsl:when>
843     <xsl:when test="contains($convert_value, 'cm')">
844       <xsl:value-of select="round(translate($convert_value, 'cm', '') * 35.43307)" />
845     </xsl:when>
846     <xsl:when test="contains($convert_value, 'in')">
847       <xsl:value-of select="round(translate($convert_value, 'in', '') * 90)" />
848     </xsl:when>
849     <xsl:when test="contains($convert_value, 'ft')">
850       <xsl:value-of select="round(translate($convert_value, 'ft', '') * 1080)" />
851     </xsl:when>
852     <xsl:when test="not(string(number($convert_value))='NaN')">
853       <xsl:value-of select="round($convert_value)" />
854     </xsl:when>
855     <xsl:otherwise>
856       <xsl:value-of select="$convert_value" />
857     </xsl:otherwise>
858   </xsl:choose>
859 </xsl:template>
861 <!--
862   // Switch //
863 -->
864 <xsl:template mode="forward" match="*[name(.) = 'switch']">
865   <xsl:apply-templates mode="forward" />
866 </xsl:template>
868 <!-- 
869   // Unknown tags //
870   With generic and mode="forward" templates
871 -->
872 <xsl:template match="*">
873   <xsl:comment><xsl:value-of select="concat('Unknown tag: ', name(.))" /></xsl:comment>
874 </xsl:template>
876 <xsl:template mode="forward" match="*">
877   <xsl:comment><xsl:value-of select="concat('Unknown tag: ', name(.))" /></xsl:comment>
878 </xsl:template>
880 <!-- 
881   // Object description //
882 -->
883 <xsl:template mode="desc" match="*">
885 </xsl:template>
887 <!-- 
888   // Title and description //
889   Title is ignored and desc is converted to Tag in the mode="desc" template
890 -->
891 <xsl:template mode="forward" match="*[name(.) = 'title' or name(.) = 'desc']">
893 </xsl:template>
895 <!--
896   // Symbols //
897 -->
898 <xsl:template mode="forward" match="*[name(.) = 'symbol']">
900 </xsl:template>
902 <!--
903   // Use //
904   Could be implemented via librairies
905   (but since it is not supported by Inkscape, not implemented yet)
906 -->
907 <xsl:template mode="forward" match="*[name(.) = 'use']">
909 </xsl:template>
911 <!--
912   // RDF and foreign objects //
913 -->
914 <xsl:template mode="forward" match="rdf:RDF | *[name(.) = 'foreignObject']">
916 </xsl:template>
918 <!--
919   // Misc ignored stuff (markers, patterns, styles) //
920 -->
921 <xsl:template mode="forward" match="*[name(.) = 'marker' or name(.) = 'pattern' or name(.) = 'style']">
923 </xsl:template>
925 <!--
926   // Colors and patterns //
928   * Generic color template
929   * Object opacity
930   * Fill
931   * Fill opacity
932   * Fill rule
933   * Generic fill template
934   * Stroke
935   * Stroke opacity
936   * Generic stroke template
937   * Stroke width
938   * Stroke mitterlimit
939   * Stroke dasharray (not supported in FXG)
940   * Stroke dashoffset (not supported in FXG)
941   * Linejoin SVG to FxG converter
942   * Stroke linejoin
943   * Linecap SVG to FXG converter
944   * Stroke linecap
945   * Gradient stop
946   * Gradient stop opacity
947   * Gradient stop offset
948 -->
950 <!--
951   // Generic color template //
952 -->
953 <xsl:template name="template_color">
954   <xsl:param name="colorspec" />
955   <xsl:choose>
956     <xsl:when test="starts-with($colorspec, 'rgb(') and not(contains($colorspec , '%'))">
957       <xsl:value-of select="'#'" />
958       <xsl:call-template name="to_hex">
959         <xsl:with-param name="convert">
960           <xsl:value-of select="substring-before(substring-after($colorspec, 'rgb('), ',')" />
961         </xsl:with-param>
962       </xsl:call-template>
963       <xsl:call-template name="to_hex">
964         <xsl:with-param name="convert">
965           <xsl:value-of select="substring-before(substring-after(substring-after($colorspec, 'rgb('), ','), ',')" />
966         </xsl:with-param>
967       </xsl:call-template>
968       <xsl:call-template name="to_hex">
969         <xsl:with-param name="convert">
970           <xsl:value-of select="substring-before(substring-after(substring-after(substring-after($colorspec, 'rgb('), ','), ','), ')')" />
971         </xsl:with-param>
972       </xsl:call-template>
973     </xsl:when>
974     <xsl:when test="starts-with($colorspec, 'rgb(') and contains($colorspec , '%')">
975       <xsl:value-of select="'#'" />
976       <xsl:call-template name="to_hex">
977         <xsl:with-param name="convert">
978           <xsl:value-of select="number(substring-before(substring-after($colorspec, 'rgb('), '%,')) * 255 div 100" />
979         </xsl:with-param>
980       </xsl:call-template>
981       <xsl:call-template name="to_hex">
982         <xsl:with-param name="convert">
983           <xsl:value-of select="number(substring-before(substring-after(substring-after($colorspec, 'rgb('), ','), '%,')) * 255 div 100" />
984         </xsl:with-param>
985       </xsl:call-template>
986       <xsl:call-template name="to_hex">
987         <xsl:with-param name="convert">
988           <xsl:value-of select="number(substring-before(substring-after(substring-after(substring-after($colorspec, 'rgb('), ','), ','), '%)')) * 255 div 100" />
989         </xsl:with-param>
990       </xsl:call-template>
991     </xsl:when>
992     <xsl:when test="starts-with($colorspec, '#')">
993       <xsl:value-of select="'#'" />
994       <xsl:choose>
995         <xsl:when test="string-length(substring-after($colorspec, '#')) = 3">
996           <xsl:variable name="colorspec3">
997             <xsl:value-of select="translate(substring-after($colorspec, '#'), 'abcdefgh', 'ABCDEFGH')" />
998           </xsl:variable>
999           <xsl:value-of select="concat(substring($colorspec3, 1, 1), substring($colorspec3, 1, 1))" />
1000           <xsl:value-of select="concat(substring($colorspec3, 2, 1), substring($colorspec3, 2, 1))" />
1001           <xsl:value-of select="concat(substring($colorspec3, 3, 1), substring($colorspec3, 3, 1))" />
1002         </xsl:when>
1003         <xsl:otherwise>
1004           <xsl:value-of select="translate(substring-after($colorspec, '#'), 'abcdefgh', 'ABCDEFGH')" />
1005         </xsl:otherwise>
1006       </xsl:choose>
1007     </xsl:when>
1008     <xsl:otherwise>
1009       <xsl:variable name="named_color_hex" select="document('colors.xml')/colors/color[@name = translate($colorspec, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')]/@hex" />
1010       <xsl:choose>
1011         <xsl:when test="$named_color_hex and $named_color_hex != ''">
1012           <xsl:value-of select="'#'" />
1013           <xsl:value-of select="substring-after($named_color_hex, '#')" />
1014         </xsl:when>
1015         <xsl:otherwise>
1016           <xsl:value-of select="$colorspec" />
1017         </xsl:otherwise>
1018       </xsl:choose>
1019     </xsl:otherwise>
1020   </xsl:choose>
1021 </xsl:template>
1023 <!--
1024   // Object opacity //
1025 -->
1026 <xsl:template mode="object_opacity" match="*">
1027   <xsl:if test="@opacity or (@style and (contains(@style, ';opacity:') or starts-with(@style, 'opacity:')))">
1028     <xsl:variable name="value">
1029     <xsl:choose>
1030       <xsl:when test="@opacity">
1031         <xsl:value-of select="@opacity" />
1032       </xsl:when>
1033       <xsl:when test="@style and contains(@style, ';opacity:')">
1034         <xsl:variable name="Opacity" select="substring-after(@style, ';opacity:')" />
1035         <xsl:choose>
1036           <xsl:when test="contains($Opacity, ';')">
1037             <xsl:value-of select="substring-before($Opacity, ';')" />
1038           </xsl:when>
1039           <xsl:otherwise>
1040             <xsl:value-of select="$Opacity" />
1041           </xsl:otherwise>
1042         </xsl:choose>
1043       </xsl:when>
1044       <xsl:when test="@style and starts-with(@style, 'opacity:')">
1045         <xsl:variable name="Opacity" select="substring-after(@style, 'opacity:')" />
1046         <xsl:choose>
1047           <xsl:when test="contains($Opacity, ';')">
1048             <xsl:value-of select="substring-before($Opacity, ';')" />
1049           </xsl:when>
1050           <xsl:otherwise>
1051             <xsl:value-of select="$Opacity" />
1052           </xsl:otherwise>
1053         </xsl:choose>
1054       </xsl:when>
1055       <xsl:when test="name(..) = 'g' or name(..) = 'svg'">
1056         <xsl:apply-templates mode="object_opacity" select="parent::*" />
1057       </xsl:when>
1058       <xsl:otherwise>1</xsl:otherwise>
1059     </xsl:choose>
1060     </xsl:variable>
1061     <xsl:attribute name="alpha">
1062     <xsl:choose>
1063       <xsl:when test="$value &lt; 0">0</xsl:when>
1064       <xsl:when test="$value &gt; 1">1</xsl:when>
1065       <xsl:otherwise>
1066         <xsl:value-of select="$value" />
1067       </xsl:otherwise>
1068     </xsl:choose>
1069     </xsl:attribute>
1070   </xsl:if>
1071 </xsl:template>
1073 <!--
1074   // Fill //
1075 -->
1076 <xsl:template mode="fill" match="*">
1077   <xsl:variable name="value">
1078     <xsl:choose>
1079       <xsl:when test="@fill">
1080         <xsl:value-of select="@fill" />
1081       </xsl:when>
1082       <xsl:when test="@style and contains(@style, 'fill:')">
1083         <xsl:variable name="Fill" select="normalize-space(substring-after(@style, 'fill:'))" />
1084         <xsl:choose>
1085           <xsl:when test="contains($Fill, ';')">
1086             <xsl:value-of select="substring-before($Fill, ';')" />
1087           </xsl:when>
1088           <xsl:otherwise>
1089             <xsl:value-of select="$Fill" />
1090           </xsl:otherwise>
1091         </xsl:choose>
1092       </xsl:when>
1093       <xsl:when test="name(..) = 'g' or name(..) = 'svg'">
1094         <xsl:apply-templates mode="fill" select="parent::*"/>
1095       </xsl:when>
1096     </xsl:choose>
1097   </xsl:variable>
1098   <xsl:if test="$value">
1099     <!-- Removes unwanted characters in the color link (TODO: export to a specific template)-->
1100     <xsl:value-of select="normalize-space(translate($value, '&quot;', ''))" />
1101   </xsl:if>
1102 </xsl:template>
1104 <!--
1105   // Fill opacity //
1106 -->
1107 <xsl:template mode="fill_opacity" match="*">
1108   <xsl:variable name="value">
1109   <xsl:choose>
1110     <xsl:when test="@fill-opacity">
1111       <xsl:value-of select="@fill-opacity" />
1112     </xsl:when>
1113     <xsl:when test="@style and contains(@style, 'fill-opacity:')">
1114       <xsl:variable name="Opacity" select="substring-after(@style, 'fill-opacity:')" />
1115       <xsl:choose>
1116         <xsl:when test="contains($Opacity, ';')">
1117           <xsl:value-of select="substring-before($Opacity, ';')" />
1118         </xsl:when>
1119         <xsl:otherwise>
1120           <xsl:value-of select="$Opacity" />
1121         </xsl:otherwise>
1122       </xsl:choose>
1123     </xsl:when>
1124     <xsl:when test="name(..) = 'g' or name(..) = 'svg'">
1125       <xsl:apply-templates mode="fill_opacity" select="parent::*" />
1126     </xsl:when>
1127     <xsl:otherwise>1</xsl:otherwise>
1128   </xsl:choose>
1129   </xsl:variable>
1130   <xsl:choose>
1131     <xsl:when test="$value &lt; 0">0</xsl:when>
1132     <xsl:when test="$value &gt; 1">1</xsl:when>
1133     <xsl:otherwise>
1134       <xsl:value-of select="$value" />
1135     </xsl:otherwise>
1136   </xsl:choose>
1137 </xsl:template>
1139 <!--
1140   // Fill rule //
1141 -->
1142 <xsl:template mode="fill_rule" match="*">
1143   <xsl:choose>
1144     <xsl:when test="@fill-rule and (@fill-rule = 'nonzero' or @fill-rule = 'evenodd')">
1145       <xsl:if test="@fill-rule = 'nonzero'">
1146         <xsl:attribute name="winding">nonZero</xsl:attribute>
1147       </xsl:if>
1148       <xsl:if test="@fill-rule = 'evenodd'">
1149         <xsl:attribute name="winding">evenOdd</xsl:attribute>
1150       </xsl:if>
1151     </xsl:when>
1152     <xsl:when test="@style and contains(@style, 'fill-rule:')">
1153       <xsl:variable name="FillRule" select="normalize-space(substring-after(@style, 'fill-rule:'))" />
1154       <xsl:choose>
1155         <xsl:when test="contains($FillRule, ';')">
1156           <xsl:if test="substring-before($FillRule, ';') = 'nonzero'">
1157             <xsl:attribute name="winding">nonZero</xsl:attribute>
1158           </xsl:if>
1159           <xsl:if test="substring-before($FillRule, ';') = 'evenodd'">
1160             <xsl:attribute name="winding">evenOdd</xsl:attribute>
1161           </xsl:if>
1162         </xsl:when>
1163         <xsl:when test="$FillRule = 'nonzero'">
1164           <xsl:attribute name="winding">nonZero</xsl:attribute>
1165         </xsl:when>
1166         <xsl:when test=" $FillRule = 'evenodd'">
1167           <xsl:attribute name="winding">evenOdd</xsl:attribute>
1168         </xsl:when>
1169       </xsl:choose>
1170     </xsl:when>
1171     <xsl:when test="name(..) = 'g' or name(..) = 'svg'">
1172       <xsl:apply-templates mode="fill_rule" select="parent::*"/>
1173         </xsl:when>
1174     <xsl:otherwise>
1175       <xsl:attribute name="winding">nonZero</xsl:attribute>
1176     </xsl:otherwise>
1177   </xsl:choose>
1178 </xsl:template>
1180 <!--
1181   // Generic fill template //
1182 -->
1183 <xsl:template mode="template_fill" match="*">
1184   <xsl:variable name="fill"><xsl:apply-templates mode="fill" select="." /></xsl:variable>
1185   <xsl:variable name="fill_opacity"><xsl:apply-templates mode="fill_opacity" select="." /></xsl:variable>
1186     
1187   <xsl:choose>
1188     <xsl:when test="$fill != '' and $fill != 'none' and not(starts-with($fill, 'url(#'))">
1189     <!-- Solid color -->
1190       <fill>
1191         <SolidColor>
1192           <xsl:attribute name="color">
1193             <xsl:call-template name="template_color">
1194               <xsl:with-param name="colorspec">
1195                 <xsl:value-of select="$fill" />
1196               </xsl:with-param>
1197             </xsl:call-template>
1198           </xsl:attribute>
1199           <xsl:attribute name="alpha">
1200             <xsl:value-of select="$fill_opacity" />
1201           </xsl:attribute>
1202         </SolidColor>
1203       </fill>
1204     </xsl:when>
1205     <!-- Gradients -->
1206     <xsl:when test="starts-with($fill, 'url(#')">
1207       <xsl:for-each select="//*[@id=substring-before(substring-after($fill, 'url(#'), ')')]">
1208         <xsl:if test="name(.) = 'linearGradient'">
1209           <fill>
1210             <LinearGradient>
1211               <xsl:call-template name="linearGradient" >
1212                 <xsl:with-param name="id">
1213                   <xsl:value-of select="substring-before(substring-after($fill, 'url(#'), ')')" />
1214                 </xsl:with-param>
1215               </xsl:call-template>
1216             </LinearGradient>
1217           </fill>
1218         </xsl:if>
1219         <xsl:if test="name(.) = 'radialGradient'">
1220           <fill>
1221             <RadialGradient>
1222               <xsl:call-template name="radialGradient" >
1223                 <xsl:with-param name="id">
1224                   <xsl:value-of select="substring-before(substring-after($fill, 'url(#'), ')')" />
1225                 </xsl:with-param>
1226               </xsl:call-template>
1227             </RadialGradient>
1228           </fill>
1229         </xsl:if>
1230       </xsl:for-each>
1231     </xsl:when>
1232     <xsl:when test="$fill = 'none'">
1233     </xsl:when>
1234     <xsl:otherwise>
1235       <fill>
1236         <SolidColor color="#ffffff" alpha="1"/>
1237       </fill>
1238     </xsl:otherwise>
1239   </xsl:choose>
1240 </xsl:template>
1242 <!--
1243   // Stroke //
1244 -->
1245 <xsl:template mode="stroke" match="*">
1246   <xsl:choose>
1247     <xsl:when test="@stroke">
1248       <xsl:value-of select="@stroke" />
1249     </xsl:when>
1250     <xsl:when test="@style and contains(@style, 'stroke:')">
1251       <xsl:variable name="Stroke" select="normalize-space(substring-after(@style, 'stroke:'))" />
1252       <xsl:choose>
1253         <xsl:when test="contains($Stroke, ';')">
1254           <xsl:value-of select="substring-before($Stroke, ';')" />
1255         </xsl:when>
1256         <xsl:when test="$Stroke">
1257           <xsl:value-of select="$Stroke" />
1258         </xsl:when>
1259       </xsl:choose>
1260     </xsl:when>
1261     <xsl:when test="name(..) = 'g' or name(..) = 'svg'">
1262       <xsl:apply-templates mode="stroke" select="parent::*"/>
1263     </xsl:when>
1264   </xsl:choose>
1265 </xsl:template>
1267 <!--
1268   // Stroke opacity //
1269 -->
1270 <xsl:template mode="stroke_opacity" match="*">
1271   <xsl:variable name="value">
1272   <xsl:choose>
1273     <xsl:when test="@stroke-opacity"><xsl:value-of select="@stroke-opacity" /></xsl:when>
1274     <xsl:when test="@style and contains(@style, 'stroke-opacity:')">
1275       <xsl:variable name="Opacity" select="substring-after(@style, 'stroke-opacity:')" />
1276       <xsl:choose>
1277         <xsl:when test="contains($Opacity, ';')">
1278           <xsl:value-of select="substring-before($Opacity, ';')" />
1279         </xsl:when>
1280         <xsl:otherwise>
1281           <xsl:value-of select="$Opacity" />
1282         </xsl:otherwise>
1283       </xsl:choose>
1284     </xsl:when>
1285     <xsl:when test="name(..) = 'g' or name(..) = 'svg'">
1286       <xsl:apply-templates mode="stroke_opacity" select="parent::*" />
1287     </xsl:when>
1288     <xsl:otherwise>1</xsl:otherwise>
1289   </xsl:choose>
1290   </xsl:variable>
1291   <xsl:choose>
1292     <xsl:when test="$value &lt; 0">0</xsl:when>
1293     <xsl:when test="$value &gt; 1">1</xsl:when>
1294     <xsl:otherwise>
1295       <xsl:value-of select="$value" />
1296     </xsl:otherwise>
1297   </xsl:choose>
1298 </xsl:template>
1300 <!-- 
1301   // Generic stroke template //
1302   
1303   Not supported in FXG:
1304   * stroke-dasharray
1305   * stroke-dashoffset
1306   
1307  -->
1308 <xsl:template mode="template_stroke" match="*">
1309   <xsl:variable name="stroke"><xsl:apply-templates mode="stroke" select="." /></xsl:variable>
1310   <xsl:variable name="stroke_opacity"><xsl:apply-templates mode="stroke_opacity" select="." /></xsl:variable>
1311   <xsl:variable name="stroke_width"><xsl:apply-templates mode="stroke_width" select="." /></xsl:variable>
1312   <xsl:variable name="stroke_miterlimit"><xsl:apply-templates mode="stroke_miterlimit" select="." /></xsl:variable>
1313   <xsl:variable name="stroke_linejoin"><xsl:apply-templates mode="stroke_linejoin" select="." /></xsl:variable>
1314   <xsl:variable name="stroke_linecap"><xsl:apply-templates mode="stroke_linecap" select="." /></xsl:variable>
1316   <!-- Solid color -->
1317   <xsl:if  test="$stroke != '' and $stroke != 'none' and not(starts-with($stroke, 'url(#'))">
1318     <stroke>
1319       <SolidColorStroke>
1320         <xsl:attribute name="color">
1321           <xsl:call-template name="template_color">
1322             <xsl:with-param name="colorspec">
1323               <xsl:value-of select="$stroke" />
1324             </xsl:with-param>
1325           </xsl:call-template>
1326         </xsl:attribute>
1327         <xsl:attribute name="alpha">
1328           <xsl:value-of select="$stroke_opacity" />
1329         </xsl:attribute>
1330         <xsl:attribute name="weight">
1331           <xsl:value-of select="$stroke_width" />
1332         </xsl:attribute>
1333         <xsl:if test="$stroke_miterlimit != ''">
1334           <xsl:attribute name="miterLimit">
1335             <xsl:value-of select="$stroke_miterlimit" />
1336           </xsl:attribute>
1337         </xsl:if>
1338         <xsl:attribute name="joints">
1339           <xsl:value-of select="$stroke_linejoin" />
1340         </xsl:attribute>
1341         <xsl:attribute name="caps">
1342           <xsl:value-of select="$stroke_linecap" />
1343         </xsl:attribute>
1344       </SolidColorStroke>  
1345     </stroke>
1346   </xsl:if>
1347     
1348   <!-- Gradients -->
1349   <xsl:if test="starts-with($stroke, 'url(#')">
1350     <xsl:for-each select="//*[@id=substring-before(substring-after($stroke, 'url(#'), ')')]">
1351       <xsl:if test="name(.) = 'linearGradient'">
1352         <stroke>
1353           <LinearGradientStroke>
1354             <xsl:attribute name="weight">
1355               <xsl:value-of select="$stroke_width" />
1356             </xsl:attribute>
1357             <xsl:if test="$stroke_miterlimit != ''">
1358               <xsl:attribute name="miterLimit">
1359                 <xsl:value-of select="$stroke_miterlimit" />
1360               </xsl:attribute>
1361             </xsl:if>
1362             <xsl:attribute name="joints">
1363               <xsl:value-of select="$stroke_linejoin" />
1364             </xsl:attribute>
1365             <xsl:attribute name="caps">
1366               <xsl:value-of select="$stroke_linecap" />
1367             </xsl:attribute>
1368             <xsl:call-template name="linearGradient" >
1369               <xsl:with-param name="id">
1370                 <xsl:value-of select="substring-before(substring-after($stroke, 'url(#'), ')')" />
1371               </xsl:with-param>
1372             </xsl:call-template>
1373           </LinearGradientStroke>
1374         </stroke>
1375       </xsl:if>
1376       <xsl:if test="name(.) = 'radialGradient'">
1377         <stroke>
1378           <RadialGradientStroke>
1379             <xsl:attribute name="weight">
1380               <xsl:value-of select="$stroke_width" />
1381             </xsl:attribute>
1382             <xsl:if test="$stroke_miterlimit != ''">
1383               <xsl:attribute name="miterLimit">
1384                 <xsl:value-of select="$stroke_miterlimit" />
1385               </xsl:attribute>
1386             </xsl:if>
1387             <xsl:attribute name="joints">
1388               <xsl:value-of select="$stroke_linejoin" />
1389             </xsl:attribute>
1390             <xsl:attribute name="caps">
1391               <xsl:value-of select="$stroke_linecap" />
1392             </xsl:attribute>
1393             <xsl:call-template name="radialGradient" >
1394               <xsl:with-param name="id">
1395                 <xsl:value-of select="substring-before(substring-after($stroke, 'url(#'), ')')" />
1396               </xsl:with-param>
1397             </xsl:call-template>
1398           </RadialGradientStroke>
1399         </stroke>
1400       </xsl:if>
1401     </xsl:for-each>
1402   </xsl:if>
1403 </xsl:template>
1405 <!--
1406   // Stroke width //
1407 -->
1408 <xsl:template mode="stroke_width" match="*">
1409   <xsl:choose>
1410     <xsl:when test="@stroke-width">
1411       <xsl:call-template name="convert_unit">
1412         <xsl:with-param name="convert_value">
1413           <xsl:value-of select="@stroke-width" />
1414         </xsl:with-param>
1415       </xsl:call-template> 
1416     </xsl:when>
1417     <xsl:when test="@style and contains(@style, 'stroke-width:')">
1418       <xsl:call-template name="convert_unit">
1419         <xsl:with-param name="convert_value">
1420         <xsl:choose>
1421           <xsl:when test="contains(substring-after(@style, 'stroke-width:'), ';')">
1422             <xsl:value-of select="substring-before(substring-after(@style, 'stroke-width:'), ';')" />
1423           </xsl:when>
1424           <xsl:otherwise>
1425             <xsl:value-of select="substring-after(@style, 'stroke-width:')" />
1426           </xsl:otherwise>
1427         </xsl:choose>
1428         </xsl:with-param>
1429       </xsl:call-template> 
1430     </xsl:when>
1431     <xsl:when test="name(..) = 'g' or name(..) = 'svg'">
1432       <xsl:apply-templates mode="stroke_width" select="parent::*"/>
1433     </xsl:when>
1434     <xsl:otherwise>1</xsl:otherwise>
1435   </xsl:choose>
1436 </xsl:template>
1438 <!--
1439   // Stroke miterlimit //
1441   Probably not calculated the same way in SVG and FXG (same value but different result)
1442 -->
1443 <xsl:template mode="stroke_miterlimit" match="*">
1444   <xsl:choose>
1445     <xsl:when test="@stroke-miterlimit">
1446       <xsl:value-of select="@stroke-miterlimit" />
1447     </xsl:when>
1448     <xsl:when test="@style and contains(@style, 'stroke-miterlimit:')">
1449       <xsl:variable name="miterLimit" select="substring-after(@style, 'stroke-miterlimit:')" />
1450       <xsl:choose>
1451         <xsl:when test="contains($miterLimit, ';')">
1452           <xsl:value-of select="substring-before($miterLimit, ';')" />
1453         </xsl:when>
1454         <xsl:otherwise>
1455           <xsl:value-of select="$miterLimit" />
1456         </xsl:otherwise>
1457       </xsl:choose>
1458     </xsl:when>
1459     <xsl:when test="name(..) = 'g' or name(..) = 'svg'">
1460       <xsl:apply-templates mode="stroke_miterlimit" select="parent::*"/>
1461     </xsl:when>
1462   </xsl:choose>
1463 </xsl:template>
1465 <!-- 
1466   // Stroke dasharray //
1467   !! Not supported !!
1468 -->
1469 <xsl:template mode="stroke_dasharray" match="*">
1470   <xsl:comment>FXG does not support dasharrays</xsl:comment>
1471 </xsl:template>
1473 <!-- 
1474   // Stroke dashoffset //
1475   !! Not supported !!
1476 -->
1477 <xsl:template mode="stroke_dashoffset" match="*">
1478   <xsl:comment>FXG does not support dashoffsets</xsl:comment>
1479 </xsl:template>
1481 <!-- 
1482   // Linejoin SVG to FXG converter //
1483 -->
1484 <xsl:template name="linejoin_svg_to_fxg">
1485   <xsl:param name="linejoin" />
1486   <xsl:choose>
1487     <xsl:when test="$linejoin = 'bevel'">bevel</xsl:when>
1488     <xsl:when test="$linejoin = 'round'">round</xsl:when>
1489     <xsl:otherwise>miter</xsl:otherwise>
1490   </xsl:choose>
1491 </xsl:template>
1493 <!-- 
1494   // Stroke linejoin //
1495 -->
1496 <xsl:template mode="stroke_linejoin" match="*">
1497   <xsl:choose>
1498     <xsl:when test="@stroke-linejoin">
1499       <xsl:call-template name="linejoin_svg_to_fxg">
1500         <xsl:with-param name="linejoin">
1501           <xsl:value-of select="@stroke-linejoin" />
1502         </xsl:with-param>
1503       </xsl:call-template>
1504     </xsl:when>
1505     <xsl:when test="@style and contains(@style, 'stroke-linejoin:')">
1506       <xsl:variable name="joints" select="substring-after(@style, 'stroke-linejoin:')" />
1507       <xsl:choose>
1508         <xsl:when test="contains($joints, ';')">
1509           <xsl:call-template name="linejoin_svg_to_fxg">
1510             <xsl:with-param name="linejoin">
1511               <xsl:value-of select="substring-before($joints, ';')" />
1512             </xsl:with-param>
1513           </xsl:call-template>
1514         </xsl:when>
1515         <xsl:otherwise>
1516           <xsl:call-template name="linejoin_svg_to_fxg">
1517             <xsl:with-param name="linejoin">
1518               <xsl:value-of select="$joints" />
1519             </xsl:with-param>
1520           </xsl:call-template>
1521         </xsl:otherwise>
1522       </xsl:choose>
1523     </xsl:when>
1524     <xsl:when test="name(..) = 'g' or name(..) = 'svg'">
1525       <xsl:apply-templates mode="stroke_linejoin" select="parent::*"/>
1526     </xsl:when>
1527     <xsl:otherwise>miter</xsl:otherwise>
1528   </xsl:choose>
1529 </xsl:template>
1531 <!--
1532   // Linecap SVG to FXG converter //
1533   
1534   Not supported in FXG:
1535   * butt linecap
1536 -->
1537 <xsl:template name="linecap_svg_to_fxg">
1538   <xsl:param name="linecap" />
1539   <xsl:choose>
1540     <xsl:when test="$linecap = 'round'">round</xsl:when>
1541     <xsl:when test="$linecap = 'square'">square</xsl:when>
1542     <xsl:when test="$linecap = 'butt'">round</xsl:when>
1543     <xsl:otherwise>none</xsl:otherwise>
1544   </xsl:choose>
1545 </xsl:template>
1547 <!--
1548   // Stroke linecap //
1549 -->
1550 <xsl:template mode="stroke_linecap" match="*">
1551   <xsl:choose>
1552     <xsl:when test="@stroke-linecap">
1553       <xsl:call-template name="linecap_svg_to_fxg">
1554         <xsl:with-param name="linecap">
1555           <xsl:value-of select="@stroke-linecap" />
1556         </xsl:with-param>
1557       </xsl:call-template>
1558     </xsl:when>
1559     <xsl:when test="@style and contains(@style, 'stroke-linecap:')">
1560       <xsl:variable name="caps" select="substring-after(@style, 'stroke-linecap:')" />
1561       <xsl:choose>
1562         <xsl:when test="contains($caps, ';')">
1563           <xsl:call-template name="linecap_svg_to_fxg">
1564             <xsl:with-param name="linecap">
1565               <xsl:value-of select="substring-before($caps, ';')" />
1566             </xsl:with-param>
1567           </xsl:call-template>
1568         </xsl:when>
1569         <xsl:otherwise>
1570           <xsl:call-template name="linecap_svg_to_fxg">
1571             <xsl:with-param name="linecap">
1572               <xsl:value-of select="$caps" />
1573             </xsl:with-param>
1574           </xsl:call-template>
1575         </xsl:otherwise>
1576       </xsl:choose>
1577     </xsl:when>
1578     <xsl:when test="name(..) = 'g' or name(..) = 'svg'">
1579       <xsl:apply-templates mode="stroke_linecap" select="parent::*"/>
1580     </xsl:when>
1581     <xsl:otherwise>none</xsl:otherwise>
1582   </xsl:choose>
1583 </xsl:template>
1585 <!-- 
1586   // Gradient stops //
1587 -->
1588 <xsl:template mode="stop_color" match="*">
1589   <xsl:variable name="Opacity">
1590     <xsl:choose>
1591       <xsl:when test="@stop-opacity">
1592         <xsl:value-of select="@stop-opacity" />
1593       </xsl:when>
1594       <xsl:when test="@style and contains(@style, 'stop-opacity:')">
1595         <xsl:variable name="temp_opacity" select="substring-after(@style, 'stop-opacity:')" />
1596         <xsl:choose>
1597           <xsl:when test="contains($temp_opacity, ';')">
1598             <xsl:value-of select="substring-before($temp_opacity, ';')" />
1599           </xsl:when>
1600           <xsl:otherwise>
1601             <xsl:value-of select="$temp_opacity" />
1602           </xsl:otherwise>
1603         </xsl:choose>
1604       </xsl:when>
1605       <xsl:otherwise><xsl:value-of select="''" /></xsl:otherwise>
1606     </xsl:choose>
1607   </xsl:variable>
1608   <xsl:variable name="hex_opacity">
1609     <xsl:choose>
1610       <xsl:when test="$Opacity != ''">
1611         <xsl:call-template name="to_hex">
1612           <xsl:with-param name="convert">
1613             <xsl:value-of select="number($Opacity) * 255" />
1614           </xsl:with-param>
1615         </xsl:call-template>
1616       </xsl:when>
1617       <xsl:otherwise>
1618         <xsl:value-of select="$Opacity" />
1619       </xsl:otherwise>
1620     </xsl:choose>
1621   </xsl:variable>
1622   <xsl:variable name="stopcolor">
1623     <xsl:choose>
1624       <xsl:when test="@stop-color">
1625         <xsl:call-template name="template_color">
1626           <xsl:with-param name="colorspec">
1627             <xsl:value-of select="@stop-color" />
1628           </xsl:with-param>
1629         </xsl:call-template>
1630       </xsl:when>
1631       <xsl:when test="@style and contains(@style, 'stop-color:')">
1632         <xsl:variable name="Color" select="normalize-space(substring-after(@style, 'stop-color:'))" />
1633         <xsl:choose>
1634           <xsl:when test="contains($Color, ';')">
1635             <xsl:call-template name="template_color">
1636               <xsl:with-param name="colorspec">
1637                 <xsl:value-of select="substring-before($Color, ';')" />
1638               </xsl:with-param>
1639             </xsl:call-template>
1640           </xsl:when>
1641           <xsl:otherwise>
1642             <xsl:call-template name="template_color">
1643               <xsl:with-param name="colorspec">
1644                 <xsl:value-of select="$Color" />
1645               </xsl:with-param>
1646             </xsl:call-template>
1647           </xsl:otherwise>
1648         </xsl:choose>
1649       </xsl:when>
1650       <xsl:when test="name(..) = 'g' or name(..) = 'svg'">
1651         <xsl:apply-templates mode="stop_color" select="parent::*"/>
1652       </xsl:when>
1653       <xsl:otherwise>#000</xsl:otherwise>
1654     </xsl:choose>
1655   </xsl:variable>
1656   <xsl:attribute name="color">
1657     <xsl:value-of select="$stopcolor" />
1658   </xsl:attribute>
1659   <xsl:if test="$Opacity != ''">
1660     <xsl:attribute name="alpha">
1661       <xsl:value-of select="$Opacity" />
1662     </xsl:attribute>
1663   </xsl:if>
1664 </xsl:template>
1666 <!--
1667   // Gradient stop opacity //
1668 -->
1669 <xsl:template mode="stop_opacity" match="*">
1670   <xsl:choose>
1671     <xsl:when test="@stop-opacity">
1672       <xsl:attribute name="Opacity">
1673         <xsl:value-of select="@stop-opacity" />
1674       </xsl:attribute>
1675     </xsl:when>
1676     <xsl:when test="@style and contains(@style, 'stop-opacity:')">
1677       <xsl:variable name="Opacity" select="substring-after(@style, 'stop-opacity:')" />
1678       <xsl:attribute name="opacity">
1679         <xsl:choose>
1680           <xsl:when test="contains($Opacity, ';')">
1681             <xsl:value-of select="substring-before($Opacity, ';')" />
1682           </xsl:when>
1683           <xsl:otherwise>
1684             <xsl:value-of select="$Opacity" />
1685           </xsl:otherwise>
1686         </xsl:choose>
1687       </xsl:attribute>
1688     </xsl:when>
1689     <xsl:when test="name(..) = 'g' or name(..) = 'svg'">
1690       <xsl:apply-templates mode="stop_opacity" select="parent::*"/>
1691     </xsl:when>
1692   </xsl:choose>
1693 </xsl:template>
1695 <!--
1696   // Gradient stop offset //
1697 -->
1698 <xsl:template mode="offset" match="*">
1699   <xsl:choose>
1700     <xsl:when test="@offset">
1701       <xsl:attribute name="ratio">
1702         <xsl:choose>
1703           <xsl:when test="contains(@offset, '%')">
1704             <xsl:value-of select="number(substring-before(@offset, '%')) div 100" />
1705           </xsl:when>
1706           <xsl:otherwise>
1707             <xsl:value-of select="@offset" />
1708           </xsl:otherwise>
1709         </xsl:choose>
1710       </xsl:attribute>
1711     </xsl:when>
1712     <xsl:when test="@style and contains(@style, 'offset:')">
1713       <xsl:variable name="Offset" select="substring-after(@style, 'offset:')" />
1714       <xsl:attribute name="ratio">
1715         <xsl:choose>
1716           <xsl:when test="contains($Offset, '%')">
1717             <xsl:value-of select="number(substring-before($Offset, '%')) div 100" />
1718           </xsl:when>    
1719           <xsl:when test="contains($Offset, ';')">
1720             <xsl:value-of select="substring-before($Offset, ';')" />
1721           </xsl:when>
1722           <xsl:otherwise>
1723             <xsl:value-of select="$Offset" />
1724           </xsl:otherwise>
1725         </xsl:choose>
1726       </xsl:attribute>
1727     </xsl:when>
1728     <xsl:when test="name(..) = 'g' or name(..) = 'svg'">
1729       <xsl:apply-templates mode="stop_offset" select="parent::*"/>
1730     </xsl:when>
1731   </xsl:choose>
1732 </xsl:template>
1734 <!-- 
1735   // Text specific templates //
1737   * Text tspan
1738   * Text flowPara
1739   * Text flowRegion (text frame)
1740   * Font size
1741   * Font weight
1742   * Font family
1743   * Font style
1744   * Baseline shift
1745   * Line height
1746   * Writing mode
1747   * Text decoration
1748   * Text fill
1749   * Text direction
1750   * Text size
1751   * Text position
1752   * Text object
1753   * FlowRoot object
1754 -->
1756  <!-- 
1757   // Text span //
1758   SVG: tspan, flowSpan, FXG: span
1759   
1760   Not supported in FXG:
1761   * span position
1762 -->
1763 <xsl:template mode="forward" match="*[name(.) = 'tspan'  or name(.) = 'flowSpan']">
1764   <span>
1765     <xsl:if test="../@xml:space='preserve'">
1766       <xsl:attribute name="whiteSpaceCollapse">preserve</xsl:attribute>
1767     </xsl:if>
1768     <xsl:variable name="fill">
1769       <xsl:apply-templates mode="fill" select="." />
1770     </xsl:variable>
1771     <xsl:variable name="fill_opacity">
1772       <xsl:apply-templates mode="fill_opacity" select="." />
1773     </xsl:variable>
1774     <xsl:if test="starts-with($fill, '#') or (not(starts-with($fill, 'url')) and $fill != '' and $fill != 'none')">
1775       <xsl:attribute name="color">
1776         <xsl:call-template name="template_color">
1777           <xsl:with-param name="colorspec">
1778             <xsl:value-of select="$fill" />
1779           </xsl:with-param>
1780         </xsl:call-template>
1781       </xsl:attribute>
1782       <xsl:attribute name="textAlpha">
1783         <xsl:value-of select="$fill_opacity" />
1784       </xsl:attribute>
1785     </xsl:if>
1786     <xsl:apply-templates mode="font_size" select="." />
1787     <xsl:apply-templates mode="font_weight" select="." />
1788     <xsl:apply-templates mode="font_family" select="." />
1789     <xsl:apply-templates mode="font_style" select="." />
1790     <xsl:apply-templates mode="text_fill" select="." />
1791     <xsl:apply-templates mode="text_decoration" select="." />
1792     <xsl:apply-templates mode="line_height" select="." />
1793     <xsl:apply-templates mode="baseline_shift" select="." />
1794     
1795     <xsl:if test="text()">
1796       <xsl:value-of select="text()" />
1797     </xsl:if>
1798   </span>
1799 </xsl:template>
1801  <!-- 
1802   // Text flowPara //
1803   SVG: flowPara, flowDiv FXG: p
1804   
1805   Not supported in FXG:
1806   * paragraph position
1807 -->
1808 <xsl:template mode="forward" match="*[name(.) = 'flowPara' or name(.) = 'flowDiv']">
1809   <p>
1810     <xsl:if test="../@xml:space='preserve'">
1811       <xsl:attribute name="whiteSpaceCollapse">preserve</xsl:attribute>
1812     </xsl:if>
1813     <xsl:variable name="fill">
1814       <xsl:apply-templates mode="fill" select="." />
1815     </xsl:variable>
1816     <xsl:variable name="fill_opacity">
1817       <xsl:apply-templates mode="fill_opacity" select="." />
1818     </xsl:variable>
1819     <xsl:if test="starts-with($fill, '#') or (not(starts-with($fill, 'url')) and $fill != '' and $fill != 'none')">
1820       <xsl:attribute name="color">
1821         <xsl:call-template name="template_color">
1822           <xsl:with-param name="colorspec">
1823             <xsl:value-of select="$fill" />
1824           </xsl:with-param>
1825         </xsl:call-template>
1826       </xsl:attribute>
1827       <xsl:attribute name="textAlpha">
1828         <xsl:value-of select="$fill_opacity" />
1829       </xsl:attribute>
1830     </xsl:if>
1831     <xsl:apply-templates mode="font_size" select="." />
1832     <xsl:apply-templates mode="font_weight" select="." />
1833     <xsl:apply-templates mode="font_family" select="." />
1834     <xsl:apply-templates mode="font_style" select="." />
1835     <xsl:apply-templates mode="text_fill" select="." />
1836     <xsl:apply-templates mode="text_decoration" select="." />
1837     <xsl:apply-templates mode="line_height" select="." />
1838     <xsl:apply-templates mode="baseline_shift" select="." />
1840     <xsl:choose>
1841       <xsl:when test="*[name(.) = 'flowSpan']/text()">
1842         <xsl:apply-templates mode="forward" />
1843       </xsl:when>
1844       <xsl:otherwise>
1845         <xsl:choose>
1846           <xsl:when test="@xml:space='preserve'">
1847             <xsl:copy-of select="translate(text(), '&#x9;&#xA;&#xD;', ' ')" />
1848           </xsl:when>
1849           <xsl:otherwise>
1850             <xsl:copy-of select="normalize-space(translate(text(), '&#x9;&#xA;&#xD;', ' '))" />
1851           </xsl:otherwise>
1852         </xsl:choose>  
1853       </xsl:otherwise>
1854     </xsl:choose>
1855   </p>
1856 </xsl:template>
1859  <!-- 
1860   // Text flowRegion //
1861 -->
1862 <xsl:template mode="flow_region" match="*">
1863   <xsl:apply-templates mode="text_size" select="." />
1864   <xsl:apply-templates mode="text_position" select="." />
1865 </xsl:template>
1867 <!-- 
1868   // Text font size //
1869   SVG: font-size, FXG: fontSize
1870 -->
1871 <xsl:template mode="font_size" match="*">
1872   <xsl:variable name="value">
1873     <xsl:if test="@font-size">
1874       <xsl:value-of select="@font-size" />
1875     </xsl:if>
1876     <xsl:if test="@style and contains(@style, 'font-size:')">
1877       <xsl:variable name="font_size" select="normalize-space(substring-after(@style, 'font-size:'))" />
1878       <xsl:choose>
1879         <xsl:when test="contains($font_size, ';')">
1880           <xsl:value-of select="substring-before($font_size, ';')" />
1881         </xsl:when>
1882         <xsl:otherwise>
1883           <xsl:value-of select="$font_size" />
1884         </xsl:otherwise>
1885       </xsl:choose>
1886     </xsl:if>
1887   </xsl:variable>
1888   <xsl:if test="$value != ''">
1889     <xsl:attribute name="fontSize">
1890       <xsl:call-template name="convert_unit">
1891         <xsl:with-param name="convert_value" select="$value" />
1892       </xsl:call-template>
1893     </xsl:attribute>
1894   </xsl:if>
1895 </xsl:template>
1897 <!-- 
1898   // Text font weight //
1899   SVG: font-weight, FXG: fontWeight
1900 -->
1901 <xsl:template mode="font_weight" match="*">
1902   <xsl:variable name="value">
1903     <xsl:if test="@font-weight">
1904       <xsl:value-of select="@font-weight" />
1905     </xsl:if>
1906     <xsl:if test="@style and contains(@style, 'font-weight:')">
1907       <xsl:variable name="font_weight" select="normalize-space(substring-after(@style, 'font-weight:'))" />
1908       <xsl:choose>
1909         <xsl:when test="contains($font_weight, ';')">
1910           <xsl:value-of select="substring-before($font_weight, ';')" />
1911         </xsl:when>
1912         <xsl:otherwise>
1913           <xsl:value-of select="$font_weight" />
1914         </xsl:otherwise>
1915       </xsl:choose>
1916     </xsl:if>
1917   </xsl:variable>
1918   <xsl:if test="$value != ''">
1919     <xsl:attribute name="fontWeight">
1920       <xsl:choose>
1921         <xsl:when test="$value='normal' or $value='bold'">
1922           <xsl:value-of select="$value" />
1923         </xsl:when>
1924         <xsl:when test="$value &lt; 500 or $value = 'lighter'">normal</xsl:when>
1925         <xsl:when test="$value &gt; 499 or $value = 'bolder'">bold</xsl:when>
1926         <xsl:otherwise>normal</xsl:otherwise>
1927       </xsl:choose>
1928     </xsl:attribute>
1929   </xsl:if>
1930 </xsl:template>
1932 <!-- 
1933   // Text font family //
1934   SVG: font-family, FXG: fontFamily
1935 -->
1936 <xsl:template mode="font_family" match="*">
1937   <xsl:variable name="value">
1938     <xsl:if test="@font-family">
1939       <xsl:value-of select="translate(@font-family, &quot;'&quot;, '')" />
1940     </xsl:if>
1941     <xsl:if test="@style and contains(@style, 'font-family:')">
1942       <xsl:variable name="font_family" select="normalize-space(substring-after(@style, 'font-family:'))" />
1943       <xsl:choose>
1944         <xsl:when test="contains($font_family, ';')">
1945           <xsl:value-of select="translate(substring-before($font_family, ';'), &quot;'&quot;, '')" />
1946         </xsl:when>
1947         <xsl:otherwise>
1948           <xsl:value-of select="translate($font_family, &quot;'&quot;, '')" />
1949         </xsl:otherwise>
1950       </xsl:choose>
1951     </xsl:if>
1952   </xsl:variable>
1953   <xsl:if test="$value != ''">
1954     <xsl:attribute name="fontFamily">
1955       <xsl:choose>
1956         <xsl:when test="$value='Sans'">Arial</xsl:when>
1957         <xsl:otherwise>
1958           <xsl:value-of select="$value" />
1959         </xsl:otherwise>
1960       </xsl:choose>
1961     </xsl:attribute>
1962   </xsl:if>
1963 </xsl:template>
1965 <!-- 
1966   // Text font style //
1967   SVG: font-style, FXG: fontStyle
1968 -->
1969 <xsl:template mode="font_style" match="*">
1970   <xsl:variable name="value">
1971     <xsl:if test="@font-style">
1972       <xsl:value-of select="@font-style" />
1973     </xsl:if>
1974     <xsl:if test="@style and contains(@style, 'font-style:')">
1975       <xsl:variable name="font_style" select="normalize-space(substring-after(@style, 'font-style:'))" />
1976       <xsl:choose>
1977         <xsl:when test="contains($font_style, ';')">
1978           <xsl:value-of select="substring-before($font_style, ';')" />
1979         </xsl:when>
1980         <xsl:otherwise>
1981           <xsl:value-of select="$font_style" />
1982         </xsl:otherwise>
1983       </xsl:choose>
1984     </xsl:if>
1985   </xsl:variable>
1986   <xsl:if test="$value != ''">
1987     <xsl:attribute name="fontStyle">
1988       <xsl:value-of select="$value" />
1989     </xsl:attribute>
1990   </xsl:if>
1991 </xsl:template>
1993 <!-- 
1994   // Text baseline shift //
1995   SVG: baseline-shift, FXG: baselineShift
1996 -->
1997 <xsl:template mode="baseline_shift" match="*">
1998   <xsl:variable name="value">
1999     <xsl:if test="@baseline-shift">
2000       <xsl:value-of select="@baseline-shift" />
2001     </xsl:if>
2002     <xsl:if test="@style and contains(@style, 'baseline-shift:') and not(contains(substring-after(@style, 'baseline-shift:'), ';'))">
2003       <xsl:value-of select="substring-after(@style, 'baseline-shift:')" />
2004     </xsl:if>
2005     <xsl:if test="@style and contains(@style, 'baseline-shift:') and contains(substring-after(@style, 'baseline-shift:'), ';')">
2006       <xsl:value-of select="substring-before(substring-after(@style, 'baseline-shift:'), ';')" />
2007     </xsl:if>   
2008   </xsl:variable>
2009   <xsl:if test="$value != ''">
2010     <xsl:attribute name="baselineShift">  
2011       <xsl:choose>
2012         <xsl:when test="$value='baseline'">0</xsl:when>
2013         <xsl:when test="$value='super'">superscript</xsl:when>
2014         <xsl:when test="$value='sub'">subscript</xsl:when>
2015         <xsl:when test="translate($value, '%', '') &lt; -1000">-1000</xsl:when>
2016         <xsl:when test="translate($value, '%', '') &gt; 1000">1000</xsl:when>
2017         <xsl:otherwise>
2018           <xsl:value-of select="translate($value, '%', '')" />
2019         </xsl:otherwise>
2020       </xsl:choose>  
2021       <xsl:if test="contains($value, '%')">%</xsl:if>
2022     </xsl:attribute>
2023   </xsl:if>
2024 </xsl:template>
2026 <!-- 
2027   // Text line height //
2028   SVG: line-height, FXG: lineHeight
2029 -->
2030 <xsl:template mode="line_height" match="*">
2031   <xsl:variable name="value">
2032     <xsl:if test="@line-height">
2033       <xsl:value-of select="@line-height" />
2034     </xsl:if>
2035     <xsl:if test="@style and contains(@style, 'line-height:')">
2036       <xsl:variable name="line_height" select="normalize-space(substring-after(@style, 'line-height:'))" />
2037       <xsl:choose>
2038         <xsl:when test="contains($line_height, ';')">
2039           <xsl:value-of select="substring-before($line_height, ';')" />
2040         </xsl:when>
2041         <xsl:otherwise>
2042           <xsl:value-of select="$line_height" />
2043         </xsl:otherwise>
2044       </xsl:choose>
2045     </xsl:if>
2046   </xsl:variable>
2047   <xsl:if test="$value != ''">
2048     <xsl:attribute name="lineHeight">
2049       <xsl:call-template name="convert_unit">
2050         <xsl:with-param name="convert_value" select="$value" />
2051       </xsl:call-template>
2052     </xsl:attribute>
2053   </xsl:if>
2054 </xsl:template>
2056 <!-- 
2057   // Text writing mode //
2058   SVG: writing-mode, FXG: blockProgression 
2059   
2060   Values inverted in FXG...
2061 -->
2062 <xsl:template mode="writing_mode" match="*">
2063   <xsl:variable name="value">
2064     <xsl:if test="@writing-mode">
2065       <xsl:value-of select="@writing-mode" />
2066     </xsl:if>
2067     <xsl:if test="@style and contains(@style, 'writing-mode:') and not(contains(substring-after(@style, 'writing-mode:'), ';'))">
2068       <xsl:value-of select="substring-after(@style, 'writing-mode:')" />
2069     </xsl:if>
2070     <xsl:if test="@style and contains(@style, 'writing-mode:') and contains(substring-after(@style, 'writing-mode:'), ';')">
2071       <xsl:value-of select="substring-before(substring-after(@style, 'writing-mode:'), ';')" />
2072     </xsl:if>   
2073   </xsl:variable>
2074   <xsl:if test="$value != ''">
2075     <xsl:attribute name="blockProgression">  
2076       <xsl:choose>
2077         <xsl:when test="$value='tb'">rl</xsl:when>
2078         <xsl:otherwise>tb</xsl:otherwise>
2079       </xsl:choose>  
2080     </xsl:attribute>
2081     <xsl:if test="$value='tb'">
2082       <xsl:attribute name="textRotation">rotate270</xsl:attribute>
2083     </xsl:if>  
2084   </xsl:if>
2085 </xsl:template>
2086   
2087 <!-- 
2088   // Text decoration //
2089   SVG: text-decoration, FXG: textDecoration, lineThrough 
2090 -->
2091 <xsl:template mode="text_decoration" match="*">
2092   <xsl:variable name="value">
2093     <xsl:if test="@text-decoration">
2094       <xsl:value-of select="@text-decoration" />
2095     </xsl:if>
2096     <xsl:if test="@style and contains(@style, 'text-decoration:') and not(contains(substring-after(@style, 'text-decoration:'), ';'))">
2097       <xsl:value-of select="substring-after(@style, 'text-decoration:')" />
2098     </xsl:if>
2099     <xsl:if test="@style and contains(@style, 'text-decoration:') and contains(substring-after(@style, 'text-decoration:'), ';')">
2100       <xsl:value-of select="substring-before(substring-after(@style, 'text-decoration:'), ';')" />
2101     </xsl:if>   
2102   </xsl:variable>
2103   <xsl:if test="$value != ''">  
2104     <xsl:choose>
2105       <xsl:when test="$value='underline'">
2106         <xsl:attribute name="textDecoration">underline</xsl:attribute>
2107       </xsl:when>
2108       <xsl:when test="$value='line-through'">
2109         <xsl:attribute name="lineThrough">true</xsl:attribute>
2110       </xsl:when>
2111     </xsl:choose>  
2112   </xsl:if>
2113 </xsl:template>
2115 <!-- 
2116   // Text fill //
2117   SVG: fill, fill-opacity, FXG: color, textAlpha
2118 -->
2119 <xsl:template mode="text_fill" match="*">
2120   <xsl:variable name="fill">
2121     <xsl:apply-templates mode="fill" select="." />
2122   </xsl:variable>
2123   <xsl:variable name="fill_opacity">
2124     <xsl:apply-templates mode="fill_opacity" select="." />
2125   </xsl:variable>
2126   <xsl:if test="starts-with($fill, '#') or (not(starts-with($fill, 'url')) and $fill != '' and $fill != 'none')">
2127     <xsl:attribute name="color">
2128       <xsl:call-template name="template_color">
2129         <xsl:with-param name="colorspec">
2130           <xsl:value-of select="$fill" />
2131         </xsl:with-param>
2132       </xsl:call-template>
2133     </xsl:attribute>
2134     <xsl:attribute name="textAlpha">
2135       <xsl:value-of select="$fill_opacity" />
2136     </xsl:attribute>
2137   </xsl:if>
2138 </xsl:template>
2140 <!-- 
2141   // Text direction //
2142   SVG: direction, unicode-bidi, FXG: direction
2143 -->
2144 <xsl:template mode="direction" match="*">
2145   <xsl:variable name="value">
2146     <xsl:if test="@direction">
2147       <xsl:value-of select="@direction" />
2148     </xsl:if>
2149     <xsl:if test="@style and contains(@style, 'direction:') and not(contains(substring-after(@style, 'direction:'), ';'))">
2150       <xsl:value-of select="substring-after(@style, 'direction:')" />
2151     </xsl:if>
2152     <xsl:if test="@style and contains(@style, 'direction:') and contains(substring-after(@style, 'direction:'), ';')">
2153       <xsl:value-of select="substring-before(substring-after(@style, 'direction:'), ';')" />
2154     </xsl:if>   
2155   </xsl:variable>
2156   <xsl:variable name="bidi">
2157     <xsl:if test="@unicode-bidi">
2158       <xsl:value-of select="@unicode-bidi" />
2159     </xsl:if>
2160     <xsl:if test="@style and contains(@style, 'unicode-bidi:') and not(contains(substring-after(@style, 'unicode-bidi:'), ';'))">
2161       <xsl:value-of select="substring-after(@style, 'unicode-bidi:')" />
2162     </xsl:if>
2163     <xsl:if test="@style and contains(@style, 'unicode-bidi:') and contains(substring-after(@style, 'unicode-bidi:'), ';')">
2164       <xsl:value-of select="substring-before(substring-after(@style, 'unicode-bidi:'), ';')" />
2165     </xsl:if>   
2166   </xsl:variable>
2168   <xsl:if test="$value != '' and ($bidi='embed' or $bidi='bidi-override')">  
2169     <xsl:attribute name="direction">
2170       <xsl:choose>
2171         <xsl:when test="$value='ltr'">ltr</xsl:when>
2172         <xsl:when test="$value='rtl'">rtl</xsl:when>
2173       </xsl:choose>  
2174     </xsl:attribute>
2175   </xsl:if>
2176 </xsl:template>
2178  <!-- 
2179   // Text size //
2180 -->
2181 <xsl:template mode="text_size" match="*">
2182   <xsl:if test="@width">
2183     <xsl:attribute name="width">
2184       <xsl:call-template name="convert_unit">
2185         <xsl:with-param name="convert_value" select="@width" />
2186       </xsl:call-template>
2187     </xsl:attribute>
2188   </xsl:if>
2189   <xsl:if test="@height">
2190     <xsl:attribute name="height">
2191       <xsl:call-template name="convert_unit">
2192         <xsl:with-param name="convert_value" select="@height" />
2193       </xsl:call-template>
2194     </xsl:attribute>
2195   </xsl:if>
2196 </xsl:template>
2198  <!-- 
2199   // Text position //
2200 -->
2201 <xsl:template mode="text_position" match="*">
2202   <!-- Keep the first x value only -->
2203   <xsl:if test="@x">
2204     <xsl:attribute name="x">
2205       <xsl:choose>
2206         <xsl:when test="contains(@x, ' ')">
2207           <xsl:call-template name="convert_unit">
2208             <xsl:with-param name="convert_value" select="substring-before(@x, ' ')" />
2209           </xsl:call-template>   
2210           </xsl:when>
2211           <xsl:otherwise>
2212           <xsl:call-template name="convert_unit">
2213             <xsl:with-param name="convert_value" select="@x" />
2214           </xsl:call-template>  
2215         </xsl:otherwise>
2216       </xsl:choose>
2217     </xsl:attribute>
2218   </xsl:if>
2219   <!-- Keep the first y value only -->
2220   <xsl:if test="@y">
2221     <xsl:attribute name="y">
2222       <xsl:choose>
2223         <xsl:when test="contains(@y, ' ')">
2224           <xsl:call-template name="convert_unit">
2225             <xsl:with-param name="convert_value" select="substring-before(@y, ' ')" />
2226           </xsl:call-template>   
2227           </xsl:when>
2228           <xsl:otherwise>
2229           <xsl:call-template name="convert_unit">
2230             <xsl:with-param name="convert_value" select="@y" />
2231           </xsl:call-template>  
2232         </xsl:otherwise>
2233       </xsl:choose>
2234     </xsl:attribute>
2235   </xsl:if>
2236 </xsl:template>
2239 <!-- 
2240   // Text objects //
2241   SVG: text, FXG: RichText
2243   Not supported by FXG:
2244   * Generic fonts.
2245   * Embedded fonts (in defs).
2246   * Character rotation.
2247   * Character positionning (x and y).
2248   * Text-anchor.
2249   * Text stroke.
2250   
2251   Partial support:
2252   * Text rotation (0, 90, 180 and 270 degrees only) -> not implemented.
2253   * Font weight (normal and bold only) -> values under 500 are considered normal, the others bold.
2254   * Whitespace handling, issues with xml:whitespace='preserve'.
2255 -->
2256 <xsl:template mode="forward" match="*[name(.) = 'text']">
2257   <xsl:variable name="object">
2258     <RichText>
2259       <!-- Force default baseline to "ascent" -->
2260       <xsl:attribute name="alignmentBaseline">ascent</xsl:attribute>
2261       
2262       <xsl:apply-templates mode="font_size" select="." />
2263       <xsl:apply-templates mode="font_weight" select="." />
2264       <xsl:apply-templates mode="font_family" select="." />
2265       <xsl:apply-templates mode="font_style" select="." />
2266       <xsl:apply-templates mode="text_fill" select="." />
2267       <xsl:apply-templates mode="text_decoration" select="." />
2268       <xsl:apply-templates mode="line_height" select="." />
2269       <xsl:apply-templates mode="text_size" select="." />
2270       <xsl:apply-templates mode="text_position" select="." />
2271       <xsl:apply-templates mode="direction" select="." />
2272       <xsl:apply-templates mode="writing_mode" select="." />
2273       <xsl:apply-templates mode="id" select="." />
2275       <xsl:if test="not(*[name(.) = 'tspan']/text())">
2276         <xsl:attribute name="whiteSpaceCollapse">preserve</xsl:attribute>
2277       </xsl:if>
2278       
2279       <xsl:apply-templates mode="filter_effect" select="." />
2280       <xsl:apply-templates mode="desc" select="." />
2282       <!--xsl:apply-templates mode="forward" /-->
2283       <content>
2284         <xsl:choose>
2285           <xsl:when test="*[name(.) = 'tspan']/text()">
2286             <xsl:apply-templates mode="forward" />
2287           </xsl:when>
2288           <xsl:otherwise>
2289             <xsl:choose>
2290               <xsl:when test="@xml:space='preserve'">
2291                 <xsl:copy-of select="translate(text(), '&#x9;&#xA;&#xD;', ' ')" />
2292               </xsl:when>
2293               <xsl:otherwise>
2294                 <xsl:copy-of select="normalize-space(translate(text(), '&#x9;&#xA;&#xD;', ' '))" />
2295               </xsl:otherwise>
2296             </xsl:choose>  
2297           </xsl:otherwise>
2298         </xsl:choose>
2299       </content>
2300     </RichText>
2301   </xsl:variable>
2303   <xsl:variable name="clipped_object">
2304     <xsl:apply-templates mode="clip" select="." >
2305       <xsl:with-param name="object" select="$object" />
2306       <xsl:with-param name="clip_type" select="'clip'" />
2307     </xsl:apply-templates>
2308   </xsl:variable>
2310   <xsl:variable name="masked_object">
2311     <xsl:apply-templates mode="clip" select="." >
2312       <xsl:with-param name="object" select="$clipped_object" />
2313       <xsl:with-param name="clip_type" select="'mask'" />
2314     </xsl:apply-templates>
2315   </xsl:variable>
2316   
2317   <xsl:choose>
2318     <xsl:when test="@transform">
2319     <Group>
2320       <xsl:call-template name="object_transform">
2321         <xsl:with-param name="object" select="$masked_object" />
2322         <xsl:with-param name="transform" select="@transform" />
2323       </xsl:call-template>
2324     </Group>
2325     </xsl:when>
2326     <xsl:otherwise>
2327       <xsl:copy-of select="$masked_object" />
2328     </xsl:otherwise>
2329   </xsl:choose>
2330 </xsl:template>
2331  
2332  <!-- 
2333   // FlowRoot objects //
2334   SVG: flowRoot, FXG: RichText
2336   Not supported by FXG:
2337   * See text objects
2338 -->
2339 <xsl:template mode="forward" match="*[name(.) = 'flowRoot']">
2340   <xsl:variable name="object">
2341     <RichText>
2342       <!-- Force default baseline to "ascent" -->
2343       <xsl:attribute name="alignmentBaseline">ascent</xsl:attribute>
2344       
2345       <xsl:apply-templates mode="font_size" select="." />
2346       <xsl:apply-templates mode="font_weight" select="." />
2347       <xsl:apply-templates mode="font_family" select="." />
2348       <xsl:apply-templates mode="font_style" select="." />
2349       <xsl:apply-templates mode="text_fill" select="." />
2350       <xsl:apply-templates mode="text_decoration" select="." />
2351       <xsl:apply-templates mode="line_height" select="." />
2352       <xsl:apply-templates mode="direction" select="." />
2353       <xsl:apply-templates mode="writing_mode" select="." />
2354       <xsl:apply-templates mode="id" select="." />
2355       <xsl:apply-templates mode="flow_region" select="*[name(.) = 'flowRegion']/child::node()" />
2356       
2357       <xsl:apply-templates mode="filter_effect" select="." />
2358       <xsl:apply-templates mode="desc" select="." />
2360       <content>
2361         <xsl:choose>
2362           <xsl:when test="*[name(.) = 'flowPara' or name(.) = 'flowDiv']/text()">
2363             <xsl:apply-templates mode="forward" />
2364           </xsl:when>
2365           <xsl:otherwise>
2366             <xsl:choose>
2367               <xsl:when test="@xml:space='preserve'">
2368                 <xsl:copy-of select="translate(text(), '&#x9;&#xA;&#xD;', ' ')" />
2369               </xsl:when>
2370               <xsl:otherwise>
2371                 <xsl:copy-of select="normalize-space(translate(text(), '&#x9;&#xA;&#xD;', ' '))" />
2372               </xsl:otherwise>
2373             </xsl:choose>  
2374           </xsl:otherwise>
2375         </xsl:choose>
2376       </content>
2377     </RichText>
2378   </xsl:variable>
2380   <xsl:variable name="clipped_object">
2381     <xsl:apply-templates mode="clip" select="." >
2382       <xsl:with-param name="object" select="$object" />
2383       <xsl:with-param name="clip_type" select="'clip'" />
2384     </xsl:apply-templates>
2385   </xsl:variable>
2387   <xsl:variable name="masked_object">
2388     <xsl:apply-templates mode="clip" select="." >
2389       <xsl:with-param name="object" select="$clipped_object" />
2390       <xsl:with-param name="clip_type" select="'mask'" />
2391     </xsl:apply-templates>
2392   </xsl:variable>
2393   
2394   <xsl:choose>
2395     <xsl:when test="@transform">
2396     <Group>
2397       <xsl:call-template name="object_transform">
2398         <xsl:with-param name="object" select="$masked_object" />
2399         <xsl:with-param name="transform" select="@transform" />
2400       </xsl:call-template>
2401     </Group>
2402     </xsl:when>
2403     <xsl:otherwise>
2404       <xsl:copy-of select="$masked_object" />
2405     </xsl:otherwise>
2406   </xsl:choose>
2407 </xsl:template>
2409 <!-- 
2410   // Shapes //
2411   
2412   * Lines
2413   * Rectangle
2414   * Path
2415   * Ellipse
2416   * Circle
2417   * Image
2418   * Polygon (not supported)
2419   * Polyline (not supported)
2420 -->
2422 <!-- 
2423   // Line object //
2424   SVG: line, FXG: Line
2425 -->
2426 <xsl:template mode="forward" match="*[name(.) = 'line']">
2427   <xsl:variable name="object">
2428     <Line>
2429       <xsl:if test="@x1">
2430         <xsl:attribute name="xFrom">
2431           <xsl:call-template name="convert_unit">
2432             <xsl:with-param name="convert_value" select="@x1" />
2433           </xsl:call-template>
2434         </xsl:attribute>
2435       </xsl:if>
2436       <xsl:if test="@y1">
2437         <xsl:attribute name="yFrom">
2438           <xsl:call-template name="convert_unit">
2439             <xsl:with-param name="convert_value" select="@y1" />
2440           </xsl:call-template>
2441         </xsl:attribute>
2442       </xsl:if>
2443       <xsl:if test="@x2">
2444         <xsl:attribute name="xTo">
2445           <xsl:call-template name="convert_unit">
2446             <xsl:with-param name="convert_value" select="@x2" />
2447           </xsl:call-template>
2448         </xsl:attribute>
2449       </xsl:if>
2450       <xsl:if test="@y2">
2451         <xsl:attribute name="yTo">
2452           <xsl:call-template name="convert_unit">
2453             <xsl:with-param name="convert_value" select="@y2" />
2454           </xsl:call-template>
2455         </xsl:attribute>
2456       </xsl:if>
2457       <xsl:apply-templates mode="object_opacity" select="." />
2458       <xsl:apply-templates mode="id" select="." />
2460       <xsl:apply-templates mode="template_fill" select="." />
2461       <xsl:apply-templates mode="template_stroke" select="." />
2462       <xsl:apply-templates mode="filter_effect" select="." />
2463       <xsl:apply-templates mode="desc" select="." />   
2465       <xsl:apply-templates mode="forward" />
2466     </Line>
2467   </xsl:variable>
2469   <xsl:variable name="clipped_object">
2470     <xsl:apply-templates mode="clip" select="." >
2471       <xsl:with-param name="object" select="$object" />
2472       <xsl:with-param name="clip_type" select="'clip'" />
2473     </xsl:apply-templates>
2474   </xsl:variable>
2476   <xsl:variable name="masked_object">
2477     <xsl:apply-templates mode="clip" select="." >
2478       <xsl:with-param name="object" select="$clipped_object" />
2479       <xsl:with-param name="clip_type" select="'mask'" />
2480     </xsl:apply-templates>
2481   </xsl:variable>
2482   
2483   <xsl:choose>
2484     <xsl:when test="@transform">
2485     <Group>
2486       <xsl:call-template name="object_transform">
2487         <xsl:with-param name="object" select="$masked_object" />
2488         <xsl:with-param name="transform" select="@transform" />
2489       </xsl:call-template>
2490     </Group>
2491     </xsl:when>
2492     <xsl:otherwise>
2493       <xsl:copy-of select="$masked_object" />
2494     </xsl:otherwise>
2495   </xsl:choose>
2496 </xsl:template>
2498 <!-- 
2499   // Rectangle object //
2500   SVG: rect, FXG: Rect
2501 -->
2502 <xsl:template mode="forward" match="*[name(.) = 'rect']">
2503   <xsl:variable name="object">
2504     <Rect>
2505       <xsl:if test="@x">
2506         <xsl:attribute name="x">
2507           <xsl:call-template name="convert_unit">
2508             <xsl:with-param name="convert_value" select="@x" />
2509           </xsl:call-template>
2510         </xsl:attribute>
2511       </xsl:if>
2512       <xsl:if test="@y">
2513         <xsl:attribute name="y">
2514           <xsl:call-template name="convert_unit">
2515             <xsl:with-param name="convert_value" select="@y" />
2516           </xsl:call-template>
2517         </xsl:attribute>
2518       </xsl:if>
2519       <xsl:if test="@width">
2520         <xsl:attribute name="width">
2521           <xsl:call-template name="convert_unit">
2522             <xsl:with-param name="convert_value" select="@width" />
2523           </xsl:call-template>
2524         </xsl:attribute>
2525       </xsl:if>
2526       <xsl:if test="@height">
2527         <xsl:attribute name="height">
2528           <xsl:call-template name="convert_unit">
2529             <xsl:with-param name="convert_value" select="@height" />
2530           </xsl:call-template>
2531         </xsl:attribute>
2532       </xsl:if>
2533       <xsl:if test="@rx">
2534         <xsl:attribute name="radiusX">
2535           <xsl:value-of select="@rx" />
2536         </xsl:attribute>
2537       </xsl:if>
2538       <xsl:if test="@ry">
2539         <xsl:attribute name="radiusY">
2540           <xsl:value-of select="@ry" />
2541         </xsl:attribute>
2542       </xsl:if>
2543       <xsl:if test="@rx and not(@ry)">
2544         <xsl:attribute name="radiusX">
2545           <xsl:value-of select="@rx" />
2546         </xsl:attribute>
2547         <xsl:attribute name="radiusY">
2548           <xsl:value-of select="@rx" />
2549         </xsl:attribute>
2550       </xsl:if>
2551       <xsl:if test="@ry and not(@rx)">
2552         <xsl:attribute name="radiusX">
2553           <xsl:value-of select="@ry" />
2554         </xsl:attribute>
2555         <xsl:attribute name="radiusY">
2556           <xsl:value-of select="@ry" />
2557         </xsl:attribute>
2558       </xsl:if>
2559       <xsl:apply-templates mode="object_opacity" select="." />
2560       <xsl:apply-templates mode="id" select="." />
2562       <xsl:apply-templates mode="template_fill" select="." />
2563       <xsl:apply-templates mode="template_stroke" select="." />
2564       <xsl:apply-templates mode="filter_effect" select="." />
2565       <!--  <xsl:apply-templates mode="resources" select="." /> -->
2566       <xsl:apply-templates mode="desc" select="." />
2568       <xsl:apply-templates mode="forward" />
2569     </Rect>
2570   </xsl:variable>
2572   <xsl:variable name="clipped_object">
2573     <xsl:apply-templates mode="clip" select="." >
2574       <xsl:with-param name="object" select="$object" />
2575       <xsl:with-param name="clip_type" select="'clip'" />
2576     </xsl:apply-templates>
2577   </xsl:variable>
2579   <xsl:variable name="masked_object">
2580     <xsl:apply-templates mode="clip" select="." >
2581       <xsl:with-param name="object" select="$clipped_object" />
2582       <xsl:with-param name="clip_type" select="'mask'" />
2583     </xsl:apply-templates>
2584   </xsl:variable>
2585   
2586   <xsl:choose>
2587     <xsl:when test="@transform">
2588     <Group>
2589       <xsl:call-template name="object_transform">
2590         <xsl:with-param name="object" select="$masked_object" />
2591         <xsl:with-param name="transform" select="@transform" />
2592       </xsl:call-template>
2593     </Group>
2594     </xsl:when>
2595     <xsl:otherwise>
2596       <xsl:copy-of select="$masked_object" />
2597     </xsl:otherwise>
2598   </xsl:choose>
2599 </xsl:template>
2601 <!-- 
2602   // Path //
2603   SVG: path, FXG: Path
2604   
2605   Not supported by FXG:
2606   * elliptical arc curve commands (workaround: convert to path first)
2607   TODO:
2608   * Implement an arc to curve convertor
2609 -->
2610 <xsl:template mode="forward" match="*[name(.) = 'path']">
2611   <xsl:variable name="object">
2612     <Path>
2613       <!-- Path element -->
2614       <!-- Exclude arcs in order to prevent the mxml compiler from failing -->
2615       <xsl:if test="@d and not(contains(@d, 'a') or contains(@d, 'A'))">
2616         <xsl:attribute name="data">
2617           <xsl:value-of select="normalize-space(translate(@d , ',', ' '))" />
2618         </xsl:attribute>
2619       </xsl:if>
2620       <xsl:apply-templates mode="fill_rule" select="." />
2621       <xsl:apply-templates mode="object_opacity" select="." />
2622       <xsl:apply-templates mode="id" select="." />
2624       <!-- Child elements -->
2625       <xsl:apply-templates mode="template_fill" select="." />
2626       <xsl:apply-templates mode="template_stroke" select="." />
2627       <xsl:apply-templates mode="filter_effect" select="." />
2628       <xsl:apply-templates mode="desc" select="." />
2630       <xsl:apply-templates mode="forward" />
2631     </Path>
2632   </xsl:variable>
2633   
2634   <xsl:variable name="clipped_object">
2635     <xsl:apply-templates mode="clip" select="." >
2636       <xsl:with-param name="object" select="$object" />
2637       <xsl:with-param name="clip_type" select="'clip'" />
2638     </xsl:apply-templates>
2639   </xsl:variable>
2641   <xsl:variable name="masked_object">
2642     <xsl:apply-templates mode="clip" select="." >
2643       <xsl:with-param name="object" select="$clipped_object" />
2644       <xsl:with-param name="clip_type" select="'mask'" />
2645     </xsl:apply-templates>
2646   </xsl:variable>
2647   
2648   <xsl:choose>
2649     <xsl:when test="@transform">
2650     <Group>
2651       <xsl:call-template name="object_transform">
2652         <xsl:with-param name="object" select="$masked_object" />
2653         <xsl:with-param name="transform" select="@transform" />
2654       </xsl:call-template>
2655     </Group>
2656     </xsl:when>
2657     <xsl:otherwise>
2658       <xsl:copy-of select="$masked_object" />
2659     </xsl:otherwise>
2660   </xsl:choose>
2661   <xsl:if test="contains(@d, 'a') or contains(@d, 'A')">
2662     <xsl:comment><xsl:value-of select="'Elliptic arc command in path data not supported, please convert to path (arcs are thus converted to curves) before exporting.'" /></xsl:comment>
2663   </xsl:if> 
2664 </xsl:template>
2666 <!-- 
2667   // Ellipse object //
2668   SVG: ellipse, FXG: Ellipse
2669 -->
2670 <xsl:template mode="forward" match="*[name(.) = 'ellipse']">
2671   <xsl:variable name="object">
2672     <Ellipse>
2673       <xsl:variable name="cx">
2674         <xsl:choose>
2675           <xsl:when test="@cx">
2676             <xsl:call-template name="convert_unit">
2677               <xsl:with-param name="convert_value" select="@cx" />
2678             </xsl:call-template>
2679           </xsl:when>
2680           <xsl:otherwise>0</xsl:otherwise>
2681         </xsl:choose>
2682       </xsl:variable>
2683       <xsl:variable name="cy">
2684         <xsl:choose>
2685           <xsl:when test="@cy">
2686             <xsl:call-template name="convert_unit">
2687               <xsl:with-param name="convert_value" select="@cy" />
2688             </xsl:call-template>
2689           </xsl:when>
2690           <xsl:otherwise>0</xsl:otherwise>
2691         </xsl:choose>
2692       </xsl:variable>
2693       <xsl:variable name="rx">
2694         <xsl:choose>
2695           <xsl:when test="@rx">
2696             <xsl:call-template name="convert_unit">
2697               <xsl:with-param name="convert_value" select="@rx" />
2698             </xsl:call-template>
2699           </xsl:when>
2700           <xsl:otherwise>0</xsl:otherwise>
2701         </xsl:choose>
2702       </xsl:variable>
2703       <xsl:variable name="ry">
2704         <xsl:choose>
2705           <xsl:when test="@ry">
2706             <xsl:call-template name="convert_unit">
2707               <xsl:with-param name="convert_value" select="@ry" />
2708             </xsl:call-template>
2709           </xsl:when>
2710           <xsl:otherwise>0</xsl:otherwise>
2711         </xsl:choose>
2712       </xsl:variable>
2714       <xsl:choose>
2715         <xsl:when test="$rx != 0">
2716           <xsl:attribute name="x">
2717             <xsl:value-of select='format-number($cx - $rx, "#.#")' />
2718           </xsl:attribute>
2719           <xsl:attribute name="width">
2720             <xsl:value-of select='format-number(2 * $rx, "#.#")' />
2721           </xsl:attribute>
2722         </xsl:when>
2723         <xsl:otherwise>
2724           <xsl:attribute name="x">
2725             <xsl:value-of select='format-number($cx, "#.#")' />
2726           </xsl:attribute>
2727           <xsl:attribute name="width">0</xsl:attribute>
2728         </xsl:otherwise>
2729       </xsl:choose>
2730       <xsl:choose>
2731         <xsl:when test="$ry != 0">
2732           <xsl:attribute name="y">
2733             <xsl:value-of select='format-number($cy - $ry, "#.#")' />
2734           </xsl:attribute>
2735           <xsl:attribute name="height">
2736             <xsl:value-of select='format-number(2 * $ry, "#.#")' />
2737           </xsl:attribute>
2738         </xsl:when>
2739         <xsl:otherwise>
2740           <xsl:attribute name="y">
2741             <xsl:value-of select='format-number($cy, "#.#")' />
2742           </xsl:attribute>
2743           <xsl:attribute name="height">0</xsl:attribute>
2744         </xsl:otherwise>
2745       </xsl:choose>
2746       <xsl:apply-templates mode="object_opacity" select="." />
2747       <xsl:apply-templates mode="id" select="." />
2749       <!-- Child elements -->
2750       <xsl:apply-templates mode="template_fill" select="." />
2751       <xsl:apply-templates mode="template_stroke" select="." />
2752       <xsl:apply-templates mode="filter_effect" select="." />
2753       <xsl:apply-templates mode="desc" select="." />
2755       <xsl:apply-templates mode="forward" />
2756     </Ellipse>
2757   </xsl:variable>
2759   <xsl:variable name="clipped_object">
2760     <xsl:apply-templates mode="clip" select="." >
2761       <xsl:with-param name="object" select="$object" />
2762       <xsl:with-param name="clip_type" select="'clip'" />
2763     </xsl:apply-templates>
2764   </xsl:variable>
2766   <xsl:variable name="masked_object">
2767     <xsl:apply-templates mode="clip" select="." >
2768       <xsl:with-param name="object" select="$clipped_object" />
2769       <xsl:with-param name="clip_type" select="'mask'" />
2770     </xsl:apply-templates>
2771   </xsl:variable>
2772   
2773   <xsl:choose>
2774     <xsl:when test="@transform">
2775     <Group>
2776       <xsl:call-template name="object_transform">
2777         <xsl:with-param name="object" select="$masked_object" />
2778         <xsl:with-param name="transform" select="@transform" />
2779       </xsl:call-template>
2780     </Group>
2781     </xsl:when>
2782     <xsl:otherwise>
2783       <xsl:copy-of select="$masked_object" />
2784     </xsl:otherwise>
2785   </xsl:choose>
2786 </xsl:template>
2788 <!-- 
2789   // Circle object //
2790   SVG: circle, FXG: Ellipse
2791 -->
2792 <xsl:template mode="forward" match="*[name(.) = 'circle']">
2793   <xsl:variable name="object">
2794     <Ellipse>
2795       <xsl:variable name="cx">
2796         <xsl:choose>
2797           <xsl:when test="@cx">
2798             <xsl:call-template name="convert_unit">
2799               <xsl:with-param name="convert_value" select="@cx" />
2800             </xsl:call-template>
2801           </xsl:when>
2802           <xsl:otherwise>0</xsl:otherwise>
2803         </xsl:choose>
2804       </xsl:variable>
2805       <xsl:variable name="cy">
2806         <xsl:choose>
2807           <xsl:when test="@cy">
2808             <xsl:call-template name="convert_unit">
2809               <xsl:with-param name="convert_value" select="@cy" />
2810             </xsl:call-template>
2811           </xsl:when>
2812           <xsl:otherwise>0</xsl:otherwise>
2813         </xsl:choose>
2814       </xsl:variable>
2815       <xsl:variable name="r">
2816         <xsl:choose>
2817           <xsl:when test="@r">
2818             <xsl:call-template name="convert_unit">
2819               <xsl:with-param name="convert_value" select="@r" />
2820             </xsl:call-template>
2821           </xsl:when>
2822           <xsl:otherwise>0</xsl:otherwise>
2823         </xsl:choose>
2824       </xsl:variable>
2825       
2826       <xsl:choose>
2827         <xsl:when test="$r != 0">
2828           <xsl:attribute name="x">
2829             <xsl:value-of select='format-number($cx - $r, "#.#")' />
2830           </xsl:attribute>
2831           <xsl:attribute name="y">
2832             <xsl:value-of select='format-number($cy - $r, "#.#")' />
2833           </xsl:attribute>
2834           <xsl:attribute name="width">
2835             <xsl:value-of select='format-number(2 * $r, "#.#")' />
2836           </xsl:attribute>
2837           <xsl:attribute name="height">
2838             <xsl:value-of select='format-number(2 * $r, "#.#")' />
2839           </xsl:attribute>
2840         </xsl:when>
2841         <xsl:otherwise>
2842           <xsl:attribute name="x">
2843             <xsl:value-of select='format-number($cx, "#.#")' />
2844           </xsl:attribute>
2845           <xsl:attribute name="y">
2846             <xsl:value-of select='format-number($cy, "#.#")' />
2847           </xsl:attribute>
2848           <xsl:attribute name="width">0</xsl:attribute>
2849           <xsl:attribute name="height">0</xsl:attribute>
2850         </xsl:otherwise>
2851       </xsl:choose>
2852       <xsl:apply-templates mode="object_opacity" select="." />
2853       <xsl:apply-templates mode="id" select="." />
2855       <!-- Child elements -->
2856       <xsl:apply-templates mode="template_fill" select="." />
2857       <xsl:apply-templates mode="template_stroke" select="." />
2858       <xsl:apply-templates mode="filter_effect" select="." />
2859       <xsl:apply-templates mode="desc" select="." />
2861       <xsl:apply-templates mode="forward" />
2862     </Ellipse>
2863   </xsl:variable>
2865   <xsl:variable name="clipped_object">
2866     <xsl:apply-templates mode="clip" select="." >
2867       <xsl:with-param name="object" select="$object" />
2868       <xsl:with-param name="clip_type" select="'clip'" />
2869     </xsl:apply-templates>
2870   </xsl:variable>
2872   <xsl:variable name="masked_object">
2873     <xsl:apply-templates mode="clip" select="." >
2874       <xsl:with-param name="object" select="$clipped_object" />
2875       <xsl:with-param name="clip_type" select="'mask'" />
2876     </xsl:apply-templates>
2877   </xsl:variable>
2878   
2879   <xsl:choose>
2880     <xsl:when test="@transform">
2881     <Group>
2882       <xsl:call-template name="object_transform">
2883         <xsl:with-param name="object" select="$masked_object" />
2884         <xsl:with-param name="transform" select="@transform" />
2885       </xsl:call-template>
2886     </Group>
2887     </xsl:when>
2888     <xsl:otherwise>
2889       <xsl:copy-of select="$masked_object" />
2890     </xsl:otherwise>
2891   </xsl:choose>
2892 </xsl:template>
2894 <!-- 
2895   // Image objects //
2896   SVG: image, FXG: Rect+BitmapFill
2897   
2898   Not supported by FXG:
2899   * Embedded images (base64).
2900   * Preserve ratio.
2901 -->
2902 <xsl:template mode="forward" match="*[name(.) = 'image']">
2903   <xsl:variable name="object">
2904     <Rect>
2905       <xsl:if test="@x">
2906         <xsl:attribute name="x">
2907           <xsl:call-template name="convert_unit">
2908             <xsl:with-param name="convert_value" select="@x" />
2909           </xsl:call-template>
2910         </xsl:attribute>
2911       </xsl:if>
2912       <xsl:if test="@y">
2913         <xsl:attribute name="y">
2914           <xsl:call-template name="convert_unit">
2915             <xsl:with-param name="convert_value" select="@y" />
2916           </xsl:call-template>
2917         </xsl:attribute>
2918       </xsl:if>
2919       <xsl:if test="@width">
2920         <xsl:attribute name="width">
2921           <xsl:call-template name="convert_unit">
2922             <xsl:with-param name="convert_value" select="@width" />
2923           </xsl:call-template>
2924         </xsl:attribute>
2925       </xsl:if>
2926       <xsl:if test="@height">
2927         <xsl:attribute name="height">
2928           <xsl:call-template name="convert_unit">
2929             <xsl:with-param name="convert_value" select="@height" />
2930           </xsl:call-template>
2931         </xsl:attribute>
2932       </xsl:if>
2933       <xsl:apply-templates mode="object_opacity" select="." />
2934       <xsl:apply-templates mode="id" select="." />
2935       
2936       <xsl:apply-templates mode="desc" select="." />
2937       
2938       <xsl:if test="@xlink:href">
2939         <fill>
2940           <BitmapFill>
2941             <xsl:attribute name="source">@Embed('<xsl:value-of select="@xlink:href"/>')</xsl:attribute>
2942           </BitmapFill>
2943         </fill> 
2944       </xsl:if>
2945       
2946       <xsl:apply-templates mode="forward" />
2947     </Rect>
2948   </xsl:variable>
2950   <xsl:variable name="clipped_object">
2951     <xsl:apply-templates mode="clip" select="." >
2952       <xsl:with-param name="object" select="$object" />
2953       <xsl:with-param name="clip_type" select="'clip'" />
2954     </xsl:apply-templates>
2955   </xsl:variable>
2957   <xsl:variable name="masked_object">
2958     <xsl:apply-templates mode="clip" select="." >
2959       <xsl:with-param name="object" select="$clipped_object" />
2960       <xsl:with-param name="clip_type" select="'mask'" />
2961     </xsl:apply-templates>
2962   </xsl:variable>
2963   
2964   <xsl:choose>
2965     <xsl:when test="@transform">
2966     <Group>
2967       <xsl:call-template name="object_transform">
2968         <xsl:with-param name="object" select="$masked_object" />
2969         <xsl:with-param name="transform" select="@transform" />
2970       </xsl:call-template>
2971     </Group>
2972     </xsl:when>
2973     <xsl:otherwise>
2974       <xsl:copy-of select="$masked_object" />
2975     </xsl:otherwise>
2976   </xsl:choose>
2977 </xsl:template>
2979 <!-- 
2980   // Polygon object //
2981   !! Not supported !!
2982 -->
2983 <xsl:template mode="forward" match="*[name(.) = 'polygon']">
2984   <xsl:comment>FXG does not support polygons</xsl:comment>
2985 </xsl:template>
2987 <!-- 
2988   // Polyline object //
2989   !! Not supported !!
2990 -->
2991 <xsl:template mode="forward" match="*[name(.) = 'polyline']">
2992   <xsl:comment>FXG does not support polylines</xsl:comment>
2993 </xsl:template>
2995 </xsl:stylesheet>