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: import java.util.List;
023:
024: import org.apache.batik.anim.AbstractAnimation;
025: import org.apache.batik.anim.AnimationEngine;
026: import org.apache.batik.dom.anim.AnimationTarget;
027: import org.apache.batik.anim.SimpleAnimation;
028: import org.apache.batik.anim.values.AnimatableValue;
029: import org.apache.batik.util.SMILConstants;
030:
031: /**
032: * Bridge class for the 'animate' animation element.
033: *
034: * @author <a href="mailto:cam%40mcc%2eid%2eau">Cameron McCormack</a>
035: * @version $Id: SVGAnimateElementBridge.java 501922 2007-01-31 17:47:47Z dvholten $
036: */
037: public class SVGAnimateElementBridge extends SVGAnimationElementBridge {
038:
039: /**
040: * Returns 'animate'.
041: */
042: public String getLocalName() {
043: return SVG_ANIMATE_TAG;
044: }
045:
046: /**
047: * Returns a new instance of this bridge.
048: */
049: public Bridge getInstance() {
050: return new SVGAnimateElementBridge();
051: }
052:
053: /**
054: * Creates the animation object for the animation element.
055: */
056: protected AbstractAnimation createAnimation(AnimationTarget target) {
057: AnimatableValue from = parseAnimatableValue(SVG_FROM_ATTRIBUTE);
058: AnimatableValue to = parseAnimatableValue(SVG_TO_ATTRIBUTE);
059: AnimatableValue by = parseAnimatableValue(SVG_BY_ATTRIBUTE);
060: return new SimpleAnimation(timedElement, this , parseCalcMode(),
061: parseKeyTimes(), parseKeySplines(), parseAdditive(),
062: parseAccumulate(), parseValues(), from, to, by);
063: }
064:
065: /**
066: * Returns the parsed 'calcMode' attribute from the animation element.
067: */
068: protected int parseCalcMode() {
069: // If the attribute being animated has only non-additive values, take
070: // the animation as having calcMode="discrete".
071: if (animationType == AnimationEngine.ANIM_TYPE_CSS
072: && !targetElement
073: .isPropertyAdditive(attributeLocalName)
074: || animationType == AnimationEngine.ANIM_TYPE_XML
075: && !targetElement.isAttributeAdditive(
076: attributeNamespaceURI, attributeLocalName)) {
077: return SimpleAnimation.CALC_MODE_DISCRETE;
078: }
079:
080: String calcModeString = element.getAttributeNS(null,
081: SVG_CALC_MODE_ATTRIBUTE);
082: if (calcModeString.length() == 0) {
083: return getDefaultCalcMode();
084: } else if (calcModeString
085: .equals(SMILConstants.SMIL_LINEAR_VALUE)) {
086: return SimpleAnimation.CALC_MODE_LINEAR;
087: } else if (calcModeString
088: .equals(SMILConstants.SMIL_DISCRETE_VALUE)) {
089: return SimpleAnimation.CALC_MODE_DISCRETE;
090: } else if (calcModeString
091: .equals(SMILConstants.SMIL_PACED_VALUE)) {
092: return SimpleAnimation.CALC_MODE_PACED;
093: } else if (calcModeString
094: .equals(SMILConstants.SMIL_SPLINE_VALUE)) {
095: return SimpleAnimation.CALC_MODE_SPLINE;
096: }
097: throw new BridgeException(
098: ctx,
099: element,
100: ErrorConstants.ERR_ATTRIBUTE_VALUE_MALFORMED,
101: new Object[] { SVG_CALC_MODE_ATTRIBUTE, calcModeString });
102: }
103:
104: /**
105: * Returns the parsed 'additive' attribute from the animation element.
106: */
107: protected boolean parseAdditive() {
108: String additiveString = element.getAttributeNS(null,
109: SVG_ADDITIVE_ATTRIBUTE);
110: if (additiveString.length() == 0
111: || additiveString
112: .equals(SMILConstants.SMIL_REPLACE_VALUE)) {
113: return false;
114: } else if (additiveString.equals(SMILConstants.SMIL_SUM_VALUE)) {
115: return true;
116: }
117: throw new BridgeException(ctx, element,
118: ErrorConstants.ERR_ATTRIBUTE_VALUE_MALFORMED,
119: new Object[] { SVG_ADDITIVE_ATTRIBUTE, additiveString });
120: }
121:
122: /**
123: * Returns the parsed 'accumulate' attribute from the animation element.
124: */
125: protected boolean parseAccumulate() {
126: String accumulateString = element.getAttributeNS(null,
127: SVG_ACCUMULATE_ATTRIBUTE);
128: if (accumulateString.length() == 0
129: || accumulateString
130: .equals(SMILConstants.SMIL_NONE_VALUE)) {
131: return false;
132: } else if (accumulateString
133: .equals(SMILConstants.SMIL_SUM_VALUE)) {
134: return true;
135: }
136: throw new BridgeException(ctx, element,
137: ErrorConstants.ERR_ATTRIBUTE_VALUE_MALFORMED,
138: new Object[] { SVG_ACCUMULATE_ATTRIBUTE,
139: accumulateString });
140: }
141:
142: /**
143: * Returns the parsed 'values' attribute from the animation element.
144: */
145: protected AnimatableValue[] parseValues() {
146: boolean isCSS = animationType == AnimationEngine.ANIM_TYPE_CSS;
147: String valuesString = element.getAttributeNS(null,
148: SVG_VALUES_ATTRIBUTE);
149: int len = valuesString.length();
150: if (len == 0) {
151: return null;
152: }
153: ArrayList values = new ArrayList(7);
154: int i = 0, start = 0, end;
155: char c;
156: outer: while (i < len) {
157: while (valuesString.charAt(i) == ' ') {
158: i++;
159: if (i == len) {
160: break outer;
161: }
162: }
163: start = i++;
164: if (i != len) {
165: c = valuesString.charAt(i);
166: while (c != ';') {
167: i++;
168: if (i == len) {
169: break;
170: }
171: c = valuesString.charAt(i);
172: }
173: }
174: end = i++;
175: AnimatableValue val = eng.parseAnimatableValue(element,
176: animationTarget, attributeNamespaceURI,
177: attributeLocalName, isCSS, valuesString.substring(
178: start, end));
179: if (!checkValueType(val)) {
180: throw new BridgeException(ctx, element,
181: ErrorConstants.ERR_ATTRIBUTE_VALUE_MALFORMED,
182: new Object[] { SVG_VALUES_ATTRIBUTE,
183: valuesString });
184: }
185: values.add(val);
186: }
187: AnimatableValue[] ret = new AnimatableValue[values.size()];
188: return (AnimatableValue[]) values.toArray(ret);
189: }
190:
191: /**
192: * Returns the parsed 'keyTimes' attribute from the animation element.
193: */
194: protected float[] parseKeyTimes() {
195: String keyTimesString = element.getAttributeNS(null,
196: SVG_KEY_TIMES_ATTRIBUTE);
197: int len = keyTimesString.length();
198: if (len == 0) {
199: return null;
200: }
201: ArrayList keyTimes = new ArrayList(7);
202: int i = 0, start = 0, end;
203: char c;
204: outer: while (i < len) {
205: while (keyTimesString.charAt(i) == ' ') {
206: i++;
207: if (i == len) {
208: break outer;
209: }
210: }
211: start = i++;
212: if (i != len) {
213: c = keyTimesString.charAt(i);
214: while (c != ' ' && c != ';') {
215: i++;
216: if (i == len) {
217: break;
218: }
219: c = keyTimesString.charAt(i);
220: }
221: }
222: end = i++;
223: try {
224: float keyTime = Float.parseFloat(keyTimesString
225: .substring(start, end));
226: keyTimes.add(new Float(keyTime));
227: } catch (NumberFormatException nfEx) {
228: throw new BridgeException(ctx, element, nfEx,
229: ErrorConstants.ERR_ATTRIBUTE_VALUE_MALFORMED,
230: new Object[] { SVG_KEY_TIMES_ATTRIBUTE,
231: keyTimesString });
232: }
233: }
234: len = keyTimes.size();
235: float[] ret = new float[len];
236: for (int j = 0; j < len; j++) {
237: ret[j] = ((Float) keyTimes.get(j)).floatValue();
238: }
239: return ret;
240: }
241:
242: /**
243: * Returns the parsed 'keySplines' attribute from the animation element.
244: */
245: protected float[] parseKeySplines() {
246: String keySplinesString = element.getAttributeNS(null,
247: SVG_KEY_SPLINES_ATTRIBUTE);
248: int len = keySplinesString.length();
249: if (len == 0) {
250: return null;
251: }
252: List keySplines = new ArrayList(7);
253: int count = 0, i = 0, start = 0, end;
254: char c;
255: outer: while (i < len) {
256: while (keySplinesString.charAt(i) == ' ') {
257: i++;
258: if (i == len) {
259: break outer;
260: }
261: }
262: start = i++;
263: if (i != len) {
264: c = keySplinesString.charAt(i);
265: while (c != ' ' && c != ',' && c != ';') {
266: i++;
267: if (i == len) {
268: break;
269: }
270: c = keySplinesString.charAt(i);
271: }
272: end = i++;
273: if (c == ' ') {
274: do {
275: if (i == len) {
276: break;
277: }
278: c = keySplinesString.charAt(i++);
279: } while (c == ' ');
280: if (c != ';' && c != ',') {
281: i--;
282: }
283: }
284: if (c == ';') {
285: if (count == 3) {
286: count = 0;
287: } else {
288: throw new BridgeException(
289: ctx,
290: element,
291: ErrorConstants.ERR_ATTRIBUTE_VALUE_MALFORMED,
292: new Object[] {
293: SVG_KEY_SPLINES_ATTRIBUTE,
294: keySplinesString });
295: }
296: } else {
297: count++;
298: }
299: } else {
300: end = i++;
301: }
302: try {
303: float keySplineValue = Float
304: .parseFloat(keySplinesString.substring(start,
305: end));
306: keySplines.add(new Float(keySplineValue));
307: } catch (NumberFormatException nfEx) {
308: throw new BridgeException(ctx, element, nfEx,
309: ErrorConstants.ERR_ATTRIBUTE_VALUE_MALFORMED,
310: new Object[] { SVG_KEY_SPLINES_ATTRIBUTE,
311: keySplinesString });
312: }
313: }
314: len = keySplines.size();
315: float[] ret = new float[len];
316: for (int j = 0; j < len; j++) {
317: ret[j] = ((Float) keySplines.get(j)).floatValue();
318: }
319: return ret;
320: }
321:
322: /**
323: * Returns the calcMode that the animation defaults to if none is specified.
324: */
325: protected int getDefaultCalcMode() {
326: return SimpleAnimation.CALC_MODE_LINEAR;
327: }
328:
329: /**
330: * Returns whether the animation element being handled by this bridge can
331: * animate attributes of the specified type.
332: * @param type one of the TYPE_ constants defined in {@link org.apache.batik.util.SVGTypes}.
333: */
334: protected boolean canAnimateType(int type) {
335: return true;
336: }
337: }
|