KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Copyright 2001-2003 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
24 import org.apache.batik.css.engine.SVGCSSEngine;
25 import org.apache.batik.css.engine.value.Value;
26 import org.apache.batik.ext.awt.image.renderable.ClipRable8Bit;
27 import org.apache.batik.ext.awt.image.renderable.Filter;
28 import org.apache.batik.gvt.CompositeGraphicsNode;
29 import org.apache.batik.gvt.GraphicsNode;
30 import org.apache.batik.gvt.Marker;
31 import org.w3c.dom.Element JavaDoc;
32 import org.w3c.dom.Node JavaDoc;
33
34 /**
35  * Bridge class for the <marker> element.
36  *
37  * @author <a HREF="mailto:tkormann@apache.org">Thierry Kormann</a>
38  * @version $Id: SVGMarkerElementBridge.java,v 1.19 2004/08/18 07:12:35 vhardy Exp $
39  */

40 public class SVGMarkerElementBridge extends AbstractSVGBridge
41     implements MarkerBridge, ErrorConstants {
42
43     /**
44      * Constructs a new bridge for the &lt;marker> element.
45      */

46     protected SVGMarkerElementBridge() {}
47
48     /**
49      * Returns 'marker'.
50      */

51     public String JavaDoc getLocalName() {
52         return SVG_MARKER_TAG;
53     }
54
55     /**
56      * Creates a <tt>Marker</tt> according to the specified parameters.
57      *
58      * @param ctx the bridge context to use
59      * @param markerElement the element that represents the marker
60      * @param paintedElement the element that references the marker element
61      */

62     public Marker createMarker(BridgeContext ctx,
63                                Element JavaDoc markerElement,
64                                Element JavaDoc paintedElement) {
65
66         GVTBuilder builder = ctx.getGVTBuilder();
67
68         CompositeGraphicsNode markerContentNode
69             = new CompositeGraphicsNode();
70
71         // build the GVT tree that represents the marker
72
boolean hasChildren = false;
73         for(Node n = markerElement.getFirstChild();
74             n != null;
75             n = n.getNextSibling()) {
76
77             // check if the node is a valid Element
78
if (n.getNodeType() != Node.ELEMENT_NODE) {
79                 continue;
80             }
81             Element JavaDoc child = (Element JavaDoc)n;
82             GraphicsNode markerNode = builder.build(ctx, child) ;
83             // check if a GVT node has been created
84
if (markerNode == null) {
85                 continue; // skip element as <marker> can contain <defs>...
86
}
87             hasChildren = true;
88             markerContentNode.getChildren().add(markerNode);
89         }
90         if (!hasChildren) {
91             return null; // no marker content defined
92
}
93
94         String JavaDoc s;
95         UnitProcessor.Context uctx
96             = UnitProcessor.createContext(ctx, paintedElement);
97
98         // 'markerWidth' attribute - default is 3
99
float markerWidth = 3;
100         s = markerElement.getAttributeNS(null, SVG_MARKER_WIDTH_ATTRIBUTE);
101         if (s.length() != 0) {
102             markerWidth = UnitProcessor.svgHorizontalLengthToUserSpace
103                 (s, SVG_MARKER_WIDTH_ATTRIBUTE, uctx);
104         }
105         if (markerWidth == 0) {
106             // A value of zero disables rendering of the element.
107
return null;
108         }
109
110         // 'markerHeight' attribute - default is 3
111
float markerHeight = 3;
112         s = markerElement.getAttributeNS(null, SVG_MARKER_HEIGHT_ATTRIBUTE);
113         if (s.length() != 0) {
114             markerHeight = UnitProcessor.svgVerticalLengthToUserSpace
115                 (s, SVG_MARKER_HEIGHT_ATTRIBUTE, uctx);
116         }
117         if (markerHeight == 0) {
118             // A value of zero disables rendering of the element.
119
return null;
120         }
121
122         // 'orient' attribute - default is '0'
123
double orient;
124         s = markerElement.getAttributeNS(null, SVG_ORIENT_ATTRIBUTE);
125         if (s.length() == 0) {
126             orient = 0;
127         } else if (SVG_AUTO_VALUE.equals(s)) {
128             orient = Double.NaN;
129         } else {
130             try {
131                 orient = SVGUtilities.convertSVGNumber(s);
132             } catch (NumberFormatException JavaDoc ex) {
133                 throw new BridgeException
134                     (markerElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
135                      new Object JavaDoc [] {SVG_ORIENT_ATTRIBUTE, s});
136             }
137         }
138
139         // 'stroke-width' property
140
Value val = CSSUtilities.getComputedStyle
141             (paintedElement, SVGCSSEngine.STROKE_WIDTH_INDEX);
142         float strokeWidth = val.getFloatValue();
143
144         // 'markerUnits' attribute - default is 'strokeWidth'
145
short unitsType;
146         s = markerElement.getAttributeNS(null, SVG_MARKER_UNITS_ATTRIBUTE);
147         if (s.length() == 0) {
148             unitsType = SVGUtilities.STROKE_WIDTH;
149         } else {
150             unitsType = SVGUtilities.parseMarkerCoordinateSystem
151                 (markerElement, SVG_MARKER_UNITS_ATTRIBUTE, s);
152         }
153
154         //
155
//
156
//
157

158         // compute an additional transform for 'strokeWidth' coordinate system
159
AffineTransform JavaDoc markerTxf;
160         if (unitsType == SVGUtilities.STROKE_WIDTH) {
161             markerTxf = new AffineTransform JavaDoc();
162             markerTxf.scale(strokeWidth, strokeWidth);
163         } else {
164             markerTxf = new AffineTransform JavaDoc();
165         }
166
167         // 'viewBox' and 'preserveAspectRatio' attributes
168
// viewBox -> viewport(0, 0, markerWidth, markerHeight)
169
AffineTransform JavaDoc preserveAspectRatioTransform
170             = ViewBox.getPreserveAspectRatioTransform(markerElement,
171                                                       markerWidth,
172                                                       markerHeight);
173         if (preserveAspectRatioTransform == null) {
174             // disable the rendering of the element
175
return null;
176         } else {
177             markerTxf.concatenate(preserveAspectRatioTransform);
178         }
179         // now we can set the transform to the 'markerContentNode'
180
markerContentNode.setTransform(markerTxf);
181
182         // 'overflow' property
183
if (CSSUtilities.convertOverflow(markerElement)) { // overflow:hidden
184
Rectangle2D JavaDoc markerClip;
185             float [] offsets = CSSUtilities.convertClip(markerElement);
186             if (offsets == null) { // clip:auto
187
markerClip
188                     = new Rectangle2D.Float JavaDoc(0,
189                                             0,
190                                             strokeWidth * markerWidth,
191                                             strokeWidth * markerHeight);
192             } else { // clip:rect(<x>, <y>, <w>, <h>)
193
// offsets[0] = top
194
// offsets[1] = right
195
// offsets[2] = bottom
196
// offsets[3] = left
197
markerClip = new Rectangle2D.Float JavaDoc
198                     (offsets[3],
199                      offsets[0],
200                      strokeWidth * markerWidth - offsets[1] - offsets[3],
201                      strokeWidth * markerHeight - offsets[2] - offsets[0]);
202             }
203
204             CompositeGraphicsNode comp = new CompositeGraphicsNode();
205             comp.getChildren().add(markerContentNode);
206             Filter clipSrc = comp.getGraphicsNodeRable(true);
207             comp.setClip(new ClipRable8Bit(clipSrc, markerClip));
208             markerContentNode = comp;
209         }
210
211         // 'refX' attribute - default is 0
212
float refX = 0;
213         s = markerElement.getAttributeNS(null, SVG_REF_X_ATTRIBUTE);
214         if (s.length() != 0) {
215             refX = UnitProcessor.svgHorizontalCoordinateToUserSpace
216                 (s, SVG_REF_X_ATTRIBUTE, uctx);
217         }
218
219         // 'refY' attribute - default is 0
220
float refY = 0;
221         s = markerElement.getAttributeNS(null, SVG_REF_Y_ATTRIBUTE);
222         if (s.length() != 0) {
223             refY = UnitProcessor.svgVerticalCoordinateToUserSpace
224                 (s, SVG_REF_Y_ATTRIBUTE, uctx);
225         }
226
227         // TK: Warning at this time, refX and refY are relative to the
228
// paintedElement's coordinate system. We need to move the
229
// reference point to the marker's coordinate system
230

231         // Watch out: the reference point is defined a little weirdly in the
232
// SVG spec., but the bottom line is that the marker content should
233
// not be translated. Rather, the reference point should be computed
234
// in viewport space (this is what the following transform
235
// does) and used when placing the marker.
236
//
237
float ref[] = {refX, refY};
238         markerTxf.transform(ref, 0, ref, 0, 1);
239         Marker marker = new Marker(markerContentNode,
240                                    new Point2D.Float JavaDoc(ref[0], ref[1]),
241                                    orient);
242
243         return marker;
244     }
245 }
246
Popular Tags