KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > bridge > SVGUtilities


1 /*
2
3    Copyright 2001-2004 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.bridge;
19
20 import java.awt.geom.AffineTransform JavaDoc;
21 import java.awt.geom.Point2D JavaDoc;
22 import java.awt.geom.Rectangle2D JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.LinkedList JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.StringTokenizer JavaDoc;
28
29 import org.apache.batik.css.engine.CSSEngine;
30 import org.apache.batik.dom.svg.SVGOMDocument;
31 import org.apache.batik.dom.util.XLinkSupport;
32 import org.apache.batik.dom.util.XMLSupport;
33 import org.apache.batik.gvt.GraphicsNode;
34 import org.apache.batik.parser.AWTTransformProducer;
35 import org.apache.batik.parser.ParseException;
36 import org.apache.batik.util.ParsedURL;
37 import org.apache.batik.util.SVG12Constants;
38 import org.apache.batik.util.SVGConstants;
39 import org.w3c.dom.Element JavaDoc;
40 import org.w3c.dom.Node JavaDoc;
41 import org.w3c.dom.svg.SVGDocument;
42 import org.w3c.dom.svg.SVGElement;
43 import org.w3c.dom.svg.SVGLangSpace;
44 import org.w3c.dom.svg.SVGNumberList;
45
46 /**
47  * A collection of utility methods for SVG.
48  *
49  * @author <a HREF="mailto:tkormann@apache.org">Thierry Kormann</a>
50  * @author <a HREF="mailto:stephane@hillion.org">Stephane Hillion</a>
51  * @version $Id: SVGUtilities.java,v 1.32 2005/03/27 08:58:30 cam Exp $
52  */

53 public abstract class SVGUtilities implements SVGConstants, ErrorConstants {
54
55     /**
56      * No instance of this class is required.
57      */

58     protected SVGUtilities() {}
59
60     ////////////////////////////////////////////////////////////////////////
61
// common methods
62
////////////////////////////////////////////////////////////////////////
63

64     /**
65      * Returns the node imported by the given node, or null.
66      */

67     public static Node getImportedChild(Node n) {
68         return CSSEngine.getImportedChild(n);
69     }
70
71     /**
72      * Returns the logical parent element of the given element.
73      * The parent element of a used element is the &lt;use> element
74      * which reference it.
75      */

76     public static Element JavaDoc getParentElement(Element JavaDoc elt) {
77         return CSSEngine.getParentElement(elt);
78     }
79
80     /**
81      * Converts an SVGNumberList into a float array.
82      * @param l the list to convert
83      */

84     public static float[] convertSVGNumberList(SVGNumberList l) {
85         int n = l.getNumberOfItems();
86         if (n == 0) {
87             return null;
88         }
89         float fl[] = new float[n];
90         for (int i=0; i < n; i++) {
91             fl[i] = l.getItem(i).getValue();
92         }
93         return fl;
94     }
95
96     /**
97      * Converts a string into a float.
98      * @param s the float representation to convert
99      */

100     public static float convertSVGNumber(String JavaDoc s) {
101         return Float.parseFloat(s);
102     }
103
104     /**
105      * Converts a string into an integer.
106      * @param s the integer representation to convert
107      */

108     public static int convertSVGInteger(String JavaDoc s) {
109         return Integer.parseInt(s);
110     }
111
112     /**
113      * Converts the specified ratio to float number.
114      * @param v the ratio value to convert
115      * @exception NumberFormatException if the ratio is not a valid
116      * number or percentage
117      */

118     public static float convertRatio(String JavaDoc v) {
119         float d = 1;
120         if (v.endsWith("%")) {
121             v = v.substring(0, v.length() - 1);
122             d = 100;
123         }
124         float r = Float.parseFloat(v)/d;
125         if (r < 0) {
126             r = 0;
127         } else if (r > 1) {
128             r = 1;
129         }
130         return r;
131     }
132
133     /**
134      * Returns the content of the 'desc' child of the given element.
135      */

136     public static String JavaDoc getDescription(SVGElement elt) {
137         String JavaDoc result = "";
138         boolean preserve = false;
139         Node n = elt.getFirstChild();
140         if (n != null && n.getNodeType() == Node.ELEMENT_NODE) {
141             String JavaDoc name =
142                 (n.getPrefix() == null) ? n.getNodeName() : n.getLocalName();
143             if (name.equals(SVG_DESC_TAG)) {
144                 preserve = ((SVGLangSpace)n).getXMLspace().equals
145                     (SVG_PRESERVE_VALUE);
146                 for (n = n.getFirstChild();
147                      n != null;
148                      n = n.getNextSibling()) {
149                     if (n.getNodeType() == Node.TEXT_NODE) {
150                         result += n.getNodeValue();
151                     }
152                 }
153             }
154         }
155         return (preserve)
156             ? XMLSupport.preserveXMLSpace(result)
157             : XMLSupport.defaultXMLSpace(result);
158     }
159
160     /**
161      * Tests whether or not the given element match a specified user agent.
162      *
163      * @param elt the element to check
164      * @param ua the user agent
165      */

166     public static boolean matchUserAgent(Element JavaDoc elt, UserAgent ua) {
167         test: if (elt.hasAttributeNS(null, SVG_SYSTEM_LANGUAGE_ATTRIBUTE)) {
168             // Tests the system languages.
169
String JavaDoc sl = elt.getAttributeNS(null,
170                                            SVG_SYSTEM_LANGUAGE_ATTRIBUTE);
171             if (sl.length() == 0) // SVG spec says empty returns false
172
return false;
173             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(sl, ", ");
174             while (st.hasMoreTokens()) {
175                 String JavaDoc s = st.nextToken();
176                 if (matchUserLanguage(s, ua.getLanguages())) {
177                     break test;
178                 }
179             }
180             return false;
181         }
182         if (elt.hasAttributeNS(null, SVG_REQUIRED_FEATURES_ATTRIBUTE)) {
183             // Tests the system features.
184
String JavaDoc rf = elt.getAttributeNS(null,
185                                            SVG_REQUIRED_FEATURES_ATTRIBUTE);
186             if (rf.length() == 0) // SVG spec says empty returns false
187
return false;
188             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(rf, " ");
189             while (st.hasMoreTokens()) {
190                 String JavaDoc s = st.nextToken();
191                 if (!ua.hasFeature(s)) {
192                     return false;
193                 }
194             }
195         }
196         if (elt.hasAttributeNS(null, SVG_REQUIRED_EXTENSIONS_ATTRIBUTE)) {
197             // Tests the system features.
198
String JavaDoc re = elt.getAttributeNS(null,
199                                            SVG_REQUIRED_EXTENSIONS_ATTRIBUTE);
200             if (re.length() == 0) // SVG spec says empty returns false
201
return false;
202             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(re, " ");
203             while (st.hasMoreTokens()) {
204                 String JavaDoc s = st.nextToken();
205                 if (!ua.supportExtension(s)) {
206                     return false;
207                 }
208             }
209         }
210         return true;
211     }
212
213     /**
214      * Tests whether or not the specified language specification matches
215      * the user preferences.
216      *
217      * @param s the langage to check
218      * @param userLanguages the user langages
219      */

220     protected static boolean matchUserLanguage(String JavaDoc s,
221                                                String JavaDoc userLanguages) {
222         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(userLanguages, ", ");
223         while (st.hasMoreTokens()) {
224             String JavaDoc t = st.nextToken();
225             if (s.startsWith(t)) {
226                 if (s.length() > t.length()) {
227                     return (s.charAt(t.length()) == '-');
228                 }
229                 return true;
230             }
231         }
232         return false;
233     }
234
235     /**
236      * Returns the value of the specified attribute specified on the
237      * specified element or one of its ancestor. Ancestors are found
238      * using the xlink:href attribute.
239      *
240      * @param element the element to start with
241      * @param namespaceURI the namespace URI of the attribute to return
242      * @param attrName the name of the attribute to search
243      * @param ctx the bridge context
244      * @return the value of the attribute or an empty string if not defined
245      */

246     public static String JavaDoc getChainableAttributeNS(Element JavaDoc element,
247                                                  String JavaDoc namespaceURI,
248                                                  String JavaDoc attrName,
249                                                  BridgeContext ctx) {
250
251         DocumentLoader loader = ctx.getDocumentLoader();
252         Element JavaDoc e = element;
253         List JavaDoc refs = new LinkedList JavaDoc();
254         for (;;) {
255             String JavaDoc v = e.getAttributeNS(namespaceURI, attrName);
256             if (v.length() > 0) { // exit if attribute defined
257
return v;
258             }
259             String JavaDoc uriStr = XLinkSupport.getXLinkHref(e);
260             if (uriStr.length() == 0) { // exit if no more xlink:href
261
return "";
262             }
263             SVGDocument svgDoc = (SVGDocument)e.getOwnerDocument();
264             String JavaDoc baseURI = ((SVGOMDocument)svgDoc).getURL();
265
266             ParsedURL purl = new ParsedURL(baseURI, uriStr);
267             if (!purl.complete())
268                 throw new BridgeException(e, ERR_URI_MALFORMED,
269                                           new Object JavaDoc[] {uriStr});
270
271             Iterator JavaDoc iter = refs.iterator();
272             while (iter.hasNext()) {
273                 if (purl.equals(iter.next()))
274                     throw new BridgeException
275                         (e, ERR_XLINK_HREF_CIRCULAR_DEPENDENCIES,
276                          new Object JavaDoc[] {uriStr});
277             }
278
279             try {
280                 URIResolver resolver = new URIResolver(svgDoc, loader);
281                 e = resolver.getElement(purl.toString(), e);
282                 refs.add(purl);
283             } catch(IOException JavaDoc ex) {
284                 throw new BridgeException(e, ERR_URI_IO,
285                                           new Object JavaDoc[] {uriStr});
286             } catch(SecurityException JavaDoc ex) {
287                 throw new BridgeException(e, ERR_URI_UNSECURE,
288                                           new Object JavaDoc[] {uriStr});
289             }
290         }
291     }
292
293     /////////////////////////////////////////////////////////////////////////
294
// <linearGradient> and <radialGradient>
295
/////////////////////////////////////////////////////////////////////////
296

297     /**
298      * Returns a Point2D in user units according to the specified parameters.
299      *
300      * @param xStr the x coordinate
301      * @param xAttr the name of the attribute that represents the x coordinate
302      * @param yStr the y coordinate
303      * @param yAttr the name of the attribute that represents the y coordinate
304      * @param unitsType the coordinate system (OBJECT_BOUNDING_BOX |
305      * USER_SPACE_ON_USE)
306      * @param uctx the unit processor context
307      */

308     public static Point2D JavaDoc convertPoint(String JavaDoc xStr,
309                                        String JavaDoc xAttr,
310                                        String JavaDoc yStr,
311                                        String JavaDoc yAttr,
312                                        short unitsType,
313                                        UnitProcessor.Context uctx) {
314         float x, y;
315         switch (unitsType) {
316         case OBJECT_BOUNDING_BOX:
317             x = UnitProcessor.svgHorizontalCoordinateToObjectBoundingBox
318                 (xStr, xAttr, uctx);
319             y = UnitProcessor.svgVerticalCoordinateToObjectBoundingBox
320                 (yStr, yAttr, uctx);
321             break;
322         case USER_SPACE_ON_USE:
323             x = UnitProcessor.svgHorizontalCoordinateToUserSpace
324                 (xStr, xAttr, uctx);
325             y = UnitProcessor.svgVerticalCoordinateToUserSpace
326                 (yStr, yAttr, uctx);
327             break;
328         default:
329             throw new Error JavaDoc(); // can't be reached
330
}
331         return new Point2D.Float JavaDoc(x, y);
332     }
333
334     /**
335      * Returns a float in user units according to the specified parameters.
336      *
337      * @param length the length
338      * @param attr the name of the attribute that represents the length
339      * @param unitsType the coordinate system (OBJECT_BOUNDING_BOX |
340      * USER_SPACE_ON_USE)
341      * @param uctx the unit processor context
342      */

343     public static float convertLength(String JavaDoc length,
344                                       String JavaDoc attr,
345                                       short unitsType,
346                                       UnitProcessor.Context uctx) {
347         switch (unitsType) {
348         case OBJECT_BOUNDING_BOX:
349             return UnitProcessor.svgOtherLengthToObjectBoundingBox
350                 (length, attr, uctx);
351         case USER_SPACE_ON_USE:
352             return UnitProcessor.svgOtherLengthToUserSpace(length, attr, uctx);
353         default:
354             throw new Error JavaDoc(); // can't be reached
355
}
356     }
357
358     /////////////////////////////////////////////////////////////////////////
359
// <mask> region
360
/////////////////////////////////////////////////////////////////////////
361

362     /**
363      * Returns the mask region according to the x, y, width, height,
364      * and maskUnits attributes.
365      *
366      * @param maskElement the mask element that defines the various attributes
367      * @param maskedElement the element referencing the mask
368      * @param maskedNode the graphics node to mask (objectBoundingBox)
369      * @param ctx the bridge context
370      */

371     public static Rectangle2D JavaDoc convertMaskRegion(Element JavaDoc maskElement,
372                                                 Element JavaDoc maskedElement,
373                                                 GraphicsNode maskedNode,
374                                                 BridgeContext ctx) {
375
376         // 'x' attribute - default is -10%
377
String JavaDoc xStr = maskElement.getAttributeNS(null, SVG_X_ATTRIBUTE);
378         if (xStr.length() == 0) {
379             xStr = SVG_MASK_X_DEFAULT_VALUE;
380         }
381         // 'y' attribute - default is -10%
382
String JavaDoc yStr = maskElement.getAttributeNS(null, SVG_Y_ATTRIBUTE);
383         if (yStr.length() == 0) {
384             yStr = SVG_MASK_Y_DEFAULT_VALUE;
385         }
386         // 'width' attribute - default is 120%
387
String JavaDoc wStr = maskElement.getAttributeNS(null, SVG_WIDTH_ATTRIBUTE);
388         if (wStr.length() == 0) {
389             wStr = SVG_MASK_WIDTH_DEFAULT_VALUE;
390         }
391         // 'height' attribute - default is 120%
392
String JavaDoc hStr = maskElement.getAttributeNS(null, SVG_HEIGHT_ATTRIBUTE);
393         if (hStr.length() == 0) {
394             hStr = SVG_MASK_HEIGHT_DEFAULT_VALUE;
395         }
396         // 'maskUnits' attribute - default is 'objectBoundingBox'
397
short unitsType;
398         String JavaDoc units =
399             maskElement.getAttributeNS(null, SVG_MASK_UNITS_ATTRIBUTE);
400         if (units.length() == 0) {
401             unitsType = OBJECT_BOUNDING_BOX;
402         } else {
403             unitsType = parseCoordinateSystem
404                 (maskElement, SVG_MASK_UNITS_ATTRIBUTE, units);
405         }
406
407         // resolve units in the (referenced) maskedElement's coordinate system
408
UnitProcessor.Context uctx
409             = UnitProcessor.createContext(ctx, maskedElement);
410
411         return convertRegion(xStr,
412                              yStr,
413                              wStr,
414                              hStr,
415                              unitsType,
416                              maskedNode,
417                              uctx);
418     }
419
420     /////////////////////////////////////////////////////////////////////////
421
// <pattern> region
422
/////////////////////////////////////////////////////////////////////////
423

424     /**
425      * Returns the pattern region according to the x, y, width, height,
426      * and patternUnits attributes.
427      *
428      * @param patternElement the pattern element that defines the attributes
429      * @param paintedElement the element referencing the pattern
430      * @param paintedNode the graphics node to paint (objectBoundingBox)
431      * @param ctx the bridge context
432      */

433     public static Rectangle2D JavaDoc convertPatternRegion(Element JavaDoc patternElement,
434                                                    Element JavaDoc paintedElement,
435                                                    GraphicsNode paintedNode,
436                                                    BridgeContext ctx) {
437
438         // 'x' attribute - default is 0%
439
String JavaDoc xStr = getChainableAttributeNS
440             (patternElement, null, SVG_X_ATTRIBUTE, ctx);
441         if (xStr.length() == 0) {
442             xStr = SVG_PATTERN_X_DEFAULT_VALUE;
443         }
444         // 'y' attribute - default is 0%
445
String JavaDoc yStr = getChainableAttributeNS
446             (patternElement, null, SVG_Y_ATTRIBUTE, ctx);
447         if (yStr.length() == 0) {
448             yStr = SVG_PATTERN_Y_DEFAULT_VALUE;
449         }
450         // 'width' attribute - required
451
String JavaDoc wStr = getChainableAttributeNS
452             (patternElement, null, SVG_WIDTH_ATTRIBUTE, ctx);
453         if (wStr.length() == 0) {
454             throw new BridgeException(patternElement, ERR_ATTRIBUTE_MISSING,
455                                       new Object JavaDoc[] {SVG_WIDTH_ATTRIBUTE});
456         }
457         // 'height' attribute - required
458
String JavaDoc hStr = getChainableAttributeNS
459             (patternElement, null, SVG_HEIGHT_ATTRIBUTE, ctx);
460         if (hStr.length() == 0) {
461             throw new BridgeException(patternElement, ERR_ATTRIBUTE_MISSING,
462                                       new Object JavaDoc[] {SVG_HEIGHT_ATTRIBUTE});
463         }
464         // 'patternUnits' attribute - default is 'objectBoundingBox'
465
short unitsType;
466         String JavaDoc units = getChainableAttributeNS
467             (patternElement, null, SVG_PATTERN_UNITS_ATTRIBUTE, ctx);
468         if (units.length() == 0) {
469             unitsType = OBJECT_BOUNDING_BOX;
470         } else {
471             unitsType = parseCoordinateSystem
472                 (patternElement, SVG_PATTERN_UNITS_ATTRIBUTE, units);
473         }
474
475         // resolve units in the (referenced) paintedElement's coordinate system
476
UnitProcessor.Context uctx
477             = UnitProcessor.createContext(ctx, paintedElement);
478
479         return convertRegion(xStr,
480                              yStr,
481                              wStr,
482                              hStr,
483                              unitsType,
484                              paintedNode,
485                              uctx);
486     }
487
488     /////////////////////////////////////////////////////////////////////////
489
// <filter> and filter primitive
490
/////////////////////////////////////////////////////////////////////////
491

492     /**
493      * Returns an array of 2 float numbers that describes the filter
494      * resolution of the specified filter element.
495      *
496      * @param filterElement the filter element
497      * @param ctx the bridge context
498      */

499     public static
500         float [] convertFilterRes(Element JavaDoc filterElement, BridgeContext ctx) {
501
502         float [] filterRes = new float[2];
503         String JavaDoc s = getChainableAttributeNS
504             (filterElement, null, SVG_FILTER_RES_ATTRIBUTE, ctx);
505         Float JavaDoc [] vals = convertSVGNumberOptionalNumber
506             (filterElement, SVG_FILTER_RES_ATTRIBUTE, s);
507
508         if (filterRes[0] < 0 || filterRes[1] < 0) {
509             throw new BridgeException
510                 (filterElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
511                  new Object JavaDoc[] {SVG_FILTER_RES_ATTRIBUTE, s});
512         }
513         
514         if (vals[0] == null)
515             filterRes[0] = -1;
516         else {
517             filterRes[0] = vals[0].floatValue();
518             if (filterRes[0] < 0)
519                 throw new BridgeException
520                     (filterElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
521                      new Object JavaDoc[] {SVG_FILTER_RES_ATTRIBUTE, s});
522         }
523
524         if (vals[1] == null)
525             filterRes[1] = filterRes[0];
526         else {
527             filterRes[1] = vals[1].floatValue();
528             if (filterRes[1] < 0)
529                 throw new BridgeException
530                     (filterElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
531                      new Object JavaDoc[] {SVG_FILTER_RES_ATTRIBUTE, s});
532         }
533         return filterRes;
534     }
535
536     /**
537      * This function parses attrValue for a number followed by an optional
538      * second Number. It always returns an array of two Floats. If either
539      * or both values are not provided the entries are set to null
540      */

541     public static Float JavaDoc []
542         convertSVGNumberOptionalNumber(Element JavaDoc elem,
543                                        String JavaDoc attrName,
544                                        String JavaDoc attrValue) {
545
546         Float JavaDoc [] ret = new Float JavaDoc[2];
547         if (attrValue.length() == 0)
548             return ret;
549
550         try {
551             StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(attrValue, " ");
552             ret[0] = new Float JavaDoc(Float.parseFloat(tokens.nextToken()));
553             if (tokens.hasMoreTokens()) {
554                 ret[1] = new Float JavaDoc(Float.parseFloat(tokens.nextToken()));
555             }
556
557             if (tokens.hasMoreTokens()) {
558                 throw new BridgeException
559                     (elem, ERR_ATTRIBUTE_VALUE_MALFORMED,
560                      new Object JavaDoc[] {attrName, attrValue});
561             }
562         } catch (NumberFormatException JavaDoc ex) {
563             throw new BridgeException
564                 (elem, ERR_ATTRIBUTE_VALUE_MALFORMED,
565                  new Object JavaDoc[] {attrName, attrValue, ex});
566         }
567         return ret;
568     }
569
570
571    /**
572     * Returns the filter region according to the x, y, width, height,
573     * dx, dy, dw, dh and filterUnits attributes.
574     *
575     * @param filterElement the filter element that defines the attributes
576     * @param filteredElement the element referencing the filter
577     * @param filteredNode the graphics node to filter (objectBoundingBox)
578     * @param ctx the bridge context
579     */

580    public static
581        Rectangle2D JavaDoc convertFilterChainRegion(Element JavaDoc filterElement,
582                                             Element JavaDoc filteredElement,
583                                             GraphicsNode filteredNode,
584                                             BridgeContext ctx) {
585
586        // 'x' attribute - default is -10%
587
String JavaDoc xStr = getChainableAttributeNS
588            (filterElement, null, SVG_X_ATTRIBUTE, ctx);
589        if (xStr.length() == 0) {
590            xStr = SVG_FILTER_X_DEFAULT_VALUE;
591        }
592        // 'y' attribute - default is -10%
593
String JavaDoc yStr = getChainableAttributeNS
594            (filterElement, null, SVG_Y_ATTRIBUTE, ctx);
595        if (yStr.length() == 0) {
596            yStr = SVG_FILTER_Y_DEFAULT_VALUE;
597        }
598        // 'width' attribute - default is 120%
599
String JavaDoc wStr = getChainableAttributeNS
600            (filterElement, null, SVG_WIDTH_ATTRIBUTE, ctx);
601        if (wStr.length() == 0) {
602            wStr = SVG_FILTER_WIDTH_DEFAULT_VALUE;
603        }
604        // 'height' attribute - default is 120%
605
String JavaDoc hStr = getChainableAttributeNS
606            (filterElement, null, SVG_HEIGHT_ATTRIBUTE, ctx);
607        if (hStr.length() == 0) {
608            hStr = SVG_FILTER_HEIGHT_DEFAULT_VALUE;
609        }
610        // 'filterUnits' attribute - default is 'objectBoundingBox'
611
short unitsType;
612        String JavaDoc units = getChainableAttributeNS
613            (filterElement, null, SVG_FILTER_UNITS_ATTRIBUTE, ctx);
614        if (units.length() == 0) {
615            unitsType = OBJECT_BOUNDING_BOX;
616        } else {
617            unitsType = parseCoordinateSystem
618                (filterElement, SVG_FILTER_UNITS_ATTRIBUTE, units);
619        }
620
621        // resolve units in the (referenced) filteredElement's
622
// coordinate system
623
UnitProcessor.Context uctx
624            = UnitProcessor.createContext(ctx, filteredElement);
625
626        Rectangle2D JavaDoc region = convertRegion(xStr,
627                                           yStr,
628                                           wStr,
629                                           hStr,
630                                           unitsType,
631                                           filteredNode,
632                                           uctx);
633        //
634
// Account for region padding
635
//
636
units = getChainableAttributeNS
637            (filterElement, null,
638             SVG12Constants.SVG_FILTER_MARGINS_UNITS_ATTRIBUTE, ctx);
639        if (units.length() == 0) {
640            // Default to user space on use for margins, not objectBoundingBox
641
unitsType = USER_SPACE_ON_USE;
642        } else {
643            unitsType = parseCoordinateSystem
644                (filterElement,
645                 SVG12Constants.SVG_FILTER_MARGINS_UNITS_ATTRIBUTE, units);
646        }
647
648        // 'batik:dx' attribute - default is 0
649
String JavaDoc dxStr = filterElement.getAttributeNS(null,
650                                                    SVG12Constants.SVG_MX_ATRIBUTE);
651        if (dxStr.length() == 0) {
652            dxStr = SVG12Constants.SVG_FILTER_MX_DEFAULT_VALUE;
653        }
654        // 'batik:dy' attribute - default is 0
655
String JavaDoc dyStr = filterElement.getAttributeNS(null, SVG12Constants.SVG_MY_ATRIBUTE);
656        if (dyStr.length() == 0) {
657            dyStr = SVG12Constants.SVG_FILTER_MY_DEFAULT_VALUE;
658        }
659        // 'batik:dw' attribute - default is 0
660
String JavaDoc dwStr = filterElement.getAttributeNS(null, SVG12Constants.SVG_MW_ATRIBUTE);
661        if (dwStr.length() == 0) {
662            dwStr = SVG12Constants.SVG_FILTER_MW_DEFAULT_VALUE;
663        }
664        // 'batik:dh' attribute - default is 0
665
String JavaDoc dhStr = filterElement.getAttributeNS(null, SVG12Constants.SVG_MH_ATRIBUTE);
666        if (dhStr.length() == 0) {
667            dhStr = SVG12Constants.SVG_FILTER_MH_DEFAULT_VALUE;
668        }
669        
670        return extendRegion(dxStr,
671                            dyStr,
672                            dwStr,
673                            dhStr,
674                            unitsType,
675                            filteredNode,
676                            region,
677                            uctx);
678    }
679     
680    /**
681     * Returns a rectangle that represents the region extended by the
682     * specified differential coordinates.
683     *
684     * @param dxStr the differential x coordinate of the region
685     * @param dyStr the differential y coordinate of the region
686     * @param dwStr the differential width of the region
687     * @param dhStr the differential height of the region
688     * @param unitsType specifies whether the values are in userSpaceOnUse
689     * or objectBoundingBox space
690     * @param region the region to extend
691     * @param uctx the unit processor context (needed for userSpaceOnUse)
692     */

693     protected static Rectangle2D JavaDoc extendRegion(String JavaDoc dxStr,
694                                               String JavaDoc dyStr,
695                                               String JavaDoc dwStr,
696                                               String JavaDoc dhStr,
697                                               short unitsType,
698                                               GraphicsNode filteredNode,
699                                               Rectangle2D JavaDoc region,
700