001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.bridge;
020:
021: import java.awt.Shape;
022: import java.awt.geom.GeneralPath;
023: import java.awt.geom.Point2D;
024:
025: import org.apache.batik.css.engine.SVGCSSEngine;
026: import org.apache.batik.dom.svg.AnimatedLiveAttributeValue;
027: import org.apache.batik.dom.svg.LiveAttributeException;
028: import org.apache.batik.dom.svg.SVGAnimatedPathDataSupport;
029: import org.apache.batik.dom.svg.SVGOMPathElement;
030: import org.apache.batik.dom.svg.SVGPathContext;
031: import org.apache.batik.ext.awt.geom.PathLength;
032: import org.apache.batik.gvt.ShapeNode;
033: import org.apache.batik.parser.AWTPathProducer;
034:
035: import org.w3c.dom.Element;
036: import org.w3c.dom.svg.SVGPathSegList;
037:
038: /**
039: * Bridge class for the <path> element.
040: *
041: * @author <a href="mailto:tkormann@apache.org">Thierry Kormann</a>
042: * @version $Id: SVGPathElementBridge.java 475477 2006-11-15 22:44:28Z cam $
043: */
044: public class SVGPathElementBridge extends
045: SVGDecoratedShapeElementBridge implements SVGPathContext {
046:
047: /**
048: * default shape for the update of 'd' when
049: * the value is the empty string.
050: */
051: protected static final Shape DEFAULT_SHAPE = new GeneralPath();
052:
053: /**
054: * Constructs a new bridge for the <path> element.
055: */
056: public SVGPathElementBridge() {
057: }
058:
059: /**
060: * Returns 'path'.
061: */
062: public String getLocalName() {
063: return SVG_PATH_TAG;
064: }
065:
066: /**
067: * Returns a new instance of this bridge.
068: */
069: public Bridge getInstance() {
070: return new SVGPathElementBridge();
071: }
072:
073: /**
074: * Constructs a path according to the specified parameters.
075: *
076: * @param ctx the bridge context to use
077: * @param e the element that describes a rect element
078: * @param shapeNode the shape node to initialize
079: */
080: protected void buildShape(BridgeContext ctx, Element e,
081: ShapeNode shapeNode) {
082:
083: SVGOMPathElement pe = (SVGOMPathElement) e;
084: AWTPathProducer app = new AWTPathProducer();
085: try {
086: // 'd' attribute - required
087: SVGPathSegList p = pe.getAnimatedPathSegList();
088: app.setWindingRule(CSSUtilities.convertFillRule(e));
089: SVGAnimatedPathDataSupport.handlePathSegList(p, app);
090: } catch (LiveAttributeException ex) {
091: throw new BridgeException(ctx, ex);
092: } finally {
093: shapeNode.setShape(app.getShape());
094: }
095: }
096:
097: // BridgeUpdateHandler implementation //////////////////////////////////
098:
099: /**
100: * Invoked when the animated value of an animatable attribute has changed.
101: */
102: public void handleAnimatedAttributeChanged(
103: AnimatedLiveAttributeValue alav) {
104: if (alav.getNamespaceURI() == null
105: && alav.getLocalName().equals(SVG_D_ATTRIBUTE)) {
106: buildShape(ctx, e, (ShapeNode) node);
107: handleGeometryChanged();
108: } else {
109: super .handleAnimatedAttributeChanged(alav);
110: }
111: }
112:
113: protected void handleCSSPropertyChanged(int property) {
114: switch (property) {
115: case SVGCSSEngine.FILL_RULE_INDEX:
116: buildShape(ctx, e, (ShapeNode) node);
117: handleGeometryChanged();
118: break;
119: default:
120: super .handleCSSPropertyChanged(property);
121: }
122: }
123:
124: // SVGPathContext ////////////////////////////////////////////////////////
125:
126: /**
127: * The cached Shape used for computing the path length.
128: */
129: protected Shape pathLengthShape;
130:
131: /**
132: * The cached PathLength object used for computing the path length.
133: */
134: protected PathLength pathLength;
135:
136: /**
137: * Returns the PathLength object that tracks the length of the path.
138: */
139: protected PathLength getPathLengthObj() {
140: Shape s = ((ShapeNode) node).getShape();
141: if (pathLengthShape != s) {
142: pathLength = new PathLength(s);
143: pathLengthShape = s;
144: }
145: return pathLength;
146: }
147:
148: /**
149: * Returns the total length of the path.
150: */
151: public float getTotalLength() {
152: PathLength pl = getPathLengthObj();
153: return pl.lengthOfPath();
154: }
155:
156: /**
157: * Returns the point at the given distance along the path.
158: */
159: public Point2D getPointAtLength(float distance) {
160: PathLength pl = getPathLengthObj();
161: return pl.pointAtLength(distance);
162: }
163:
164: /**
165: * Returns the index of the path segment at the given distance along the
166: * path.
167: */
168: public int getPathSegAtLength(float distance) {
169: PathLength pl = getPathLengthObj();
170: return pl.segmentAtLength(distance);
171: }
172: }
|