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.util.ArrayList;
022:
023: import org.apache.batik.anim.AbstractAnimation;
024: import org.apache.batik.dom.anim.AnimationTarget;
025: import org.apache.batik.anim.TransformAnimation;
026: import org.apache.batik.anim.values.AnimatableValue;
027: import org.apache.batik.anim.values.AnimatableTransformListValue;
028: import org.apache.batik.dom.svg.SVGOMTransform;
029: import org.apache.batik.util.SVGTypes;
030:
031: import org.w3c.dom.svg.SVGTransform;
032:
033: /**
034: * Bridge class for the 'animateTransform' animation element.
035: *
036: * @author <a href="mailto:cam%40mcc%2eid%2eau">Cameron McCormack</a>
037: * @version $Id: SVGAnimateTransformElementBridge.java 496029 2007-01-14 04:00:34Z cam $
038: */
039: public class SVGAnimateTransformElementBridge extends
040: SVGAnimateElementBridge {
041:
042: /**
043: * Returns 'animateTransform'.
044: */
045: public String getLocalName() {
046: return SVG_ANIMATE_TRANSFORM_TAG;
047: }
048:
049: /**
050: * Returns a new instance of this bridge.
051: */
052: public Bridge getInstance() {
053: return new SVGAnimateTransformElementBridge();
054: }
055:
056: /**
057: * Creates the animation object for the animation element.
058: */
059: protected AbstractAnimation createAnimation(AnimationTarget target) {
060: short type = parseType();
061: AnimatableValue from = null, to = null, by = null;
062: if (element.hasAttributeNS(null, SVG_FROM_ATTRIBUTE)) {
063: from = parseValue(element.getAttributeNS(null,
064: SVG_FROM_ATTRIBUTE), type, target);
065: }
066: if (element.hasAttributeNS(null, SVG_TO_ATTRIBUTE)) {
067: to = parseValue(element.getAttributeNS(null,
068: SVG_TO_ATTRIBUTE), type, target);
069: }
070: if (element.hasAttributeNS(null, SVG_BY_ATTRIBUTE)) {
071: by = parseValue(element.getAttributeNS(null,
072: SVG_BY_ATTRIBUTE), type, target);
073: }
074: return new TransformAnimation(timedElement, this ,
075: parseCalcMode(), parseKeyTimes(), parseKeySplines(),
076: parseAdditive(), parseAccumulate(), parseValues(type,
077: target), from, to, by, type);
078: }
079:
080: /**
081: * Returns the parsed 'type' attribute from the animation element.
082: */
083: protected short parseType() {
084: String typeString = element.getAttributeNS(null,
085: SVG_TYPE_ATTRIBUTE);
086: if (typeString.equals("translate")) {
087: return SVGTransform.SVG_TRANSFORM_TRANSLATE;
088: } else if (typeString.equals("scale")) {
089: return SVGTransform.SVG_TRANSFORM_SCALE;
090: } else if (typeString.equals("rotate")) {
091: return SVGTransform.SVG_TRANSFORM_ROTATE;
092: } else if (typeString.equals("skewX")) {
093: return SVGTransform.SVG_TRANSFORM_SKEWX;
094: } else if (typeString.equals("skewY")) {
095: return SVGTransform.SVG_TRANSFORM_SKEWY;
096: }
097: throw new BridgeException(ctx, element,
098: ErrorConstants.ERR_ATTRIBUTE_VALUE_MALFORMED,
099: new Object[] { SVG_TYPE_ATTRIBUTE, typeString });
100: }
101:
102: /**
103: * Parses a transform value.
104: */
105: protected AnimatableValue parseValue(String s, short type,
106: AnimationTarget target) {
107: float val1, val2 = 0, val3 = 0;
108: int i = 0;
109: char c = ',';
110: int len = s.length();
111: while (i < len) {
112: c = s.charAt(i);
113: if (c == ' ' || c == ',') {
114: break;
115: }
116: i++;
117: }
118: val1 = Float.parseFloat(s.substring(0, i));
119: if (i < len) {
120: i++;
121: }
122: int count = 1;
123: if (i < len && c == ' ') {
124: while (i < len) {
125: c = s.charAt(i);
126: if (c != ' ') {
127: break;
128: }
129: i++;
130: }
131: if (c == ',') {
132: i++;
133: }
134: }
135: while (i < len && s.charAt(i) == ' ') {
136: i++;
137: }
138: int j = i;
139: if (i < len && type != SVGTransform.SVG_TRANSFORM_SKEWX
140: && type != SVGTransform.SVG_TRANSFORM_SKEWY) {
141: while (i < len) {
142: c = s.charAt(i);
143: if (c == ' ' || c == ',') {
144: break;
145: }
146: i++;
147: }
148: val2 = Float.parseFloat(s.substring(j, i));
149: if (i < len) {
150: i++;
151: }
152: count++;
153: if (i < len && c == ' ') {
154: while (i < len) {
155: c = s.charAt(i);
156: if (c != ' ') {
157: break;
158: }
159: i++;
160: }
161: if (c == ',') {
162: i++;
163: }
164: }
165: while (i < len && s.charAt(i) == ' ') {
166: i++;
167: }
168: j = i;
169: if (i < len && type == SVGTransform.SVG_TRANSFORM_ROTATE) {
170: while (i < len) {
171: c = s.charAt(i);
172: if (c == ',' || c == ' ') {
173: break;
174: }
175: i++;
176: }
177: val3 = Float.parseFloat(s.substring(j, i));
178: if (i < len) {
179: i++;
180: }
181: count++;
182: while (i < len && s.charAt(i) == ' ') {
183: i++;
184: }
185: }
186: }
187:
188: if (i != len) {
189: return null;
190: }
191:
192: SVGOMTransform t = new SVGOMTransform();
193: switch (type) {
194: case SVGTransform.SVG_TRANSFORM_TRANSLATE:
195: if (count == 2) {
196: t.setTranslate(val1, val2);
197: } else {
198: t.setTranslate(val1, 0f);
199: }
200: break;
201: case SVGTransform.SVG_TRANSFORM_SCALE:
202: if (count == 2) {
203: t.setScale(val1, val2);
204: } else {
205: t.setScale(val1, val1);
206: }
207: break;
208: case SVGTransform.SVG_TRANSFORM_ROTATE:
209: if (count == 3) {
210: t.setRotate(val1, val2, val3);
211: } else {
212: t.setRotate(val1, 0f, 0f);
213: }
214: break;
215: case SVGTransform.SVG_TRANSFORM_SKEWX:
216: t.setSkewX(val1);
217: break;
218: case SVGTransform.SVG_TRANSFORM_SKEWY:
219: t.setSkewY(val1);
220: break;
221: }
222: return new AnimatableTransformListValue(target, t);
223: }
224:
225: /**
226: * Returns the parsed 'values' attribute from the animation element.
227: */
228: protected AnimatableValue[] parseValues(short type,
229: AnimationTarget target) {
230: String valuesString = element.getAttributeNS(null,
231: SVG_VALUES_ATTRIBUTE);
232: int len = valuesString.length();
233: if (len == 0) {
234: return null;
235: }
236: ArrayList values = new ArrayList(7);
237: int i = 0, start = 0, end;
238: char c;
239: outer: while (i < len) {
240: while (valuesString.charAt(i) == ' ') {
241: i++;
242: if (i == len) {
243: break outer;
244: }
245: }
246: start = i++;
247: if (i < len) {
248: c = valuesString.charAt(i);
249: while (c != ';') {
250: i++;
251: if (i == len) {
252: break;
253: }
254: c = valuesString.charAt(i);
255: }
256: }
257: end = i++;
258: String valueString = valuesString.substring(start, end);
259: AnimatableValue value = parseValue(valueString, type,
260: target);
261: if (value == null) {
262: throw new BridgeException(ctx, element,
263: ErrorConstants.ERR_ATTRIBUTE_VALUE_MALFORMED,
264: new Object[] { SVG_VALUES_ATTRIBUTE,
265: valuesString });
266: }
267: values.add(value);
268: }
269: AnimatableValue[] ret = new AnimatableValue[values.size()];
270: return (AnimatableValue[]) values.toArray(ret);
271: }
272:
273: /**
274: * Returns whether the animation element being handled by this bridge can
275: * animate attributes of the specified type.
276: * @param type one of the TYPE_ constants defined in {@link SVGTypes}.
277: */
278: protected boolean canAnimateType(int type) {
279: return type == SVGTypes.TYPE_TRANSFORM_LIST;
280: }
281: }
|