PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/batik-1.8/sources/org/apache/batik/bridge/SVGAnimateMotionElementBridge.java

#
Java | 339 lines | 260 code | 19 blank | 60 comment | 47 complexity | 40e663b18801be185b52e5bf23cf756e MD5 | raw file
Possible License(s): Apache-2.0, GPL-2.0, IPL-1.0
  1. /*
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. */
  15. package org.apache.batik.bridge;
  16. import java.util.ArrayList;
  17. import java.util.List;
  18. import org.apache.batik.anim.AbstractAnimation;
  19. import org.apache.batik.anim.AnimationEngine;
  20. import org.apache.batik.dom.anim.AnimationTarget;
  21. import org.apache.batik.anim.MotionAnimation;
  22. import org.apache.batik.anim.values.AnimatableMotionPointValue;
  23. import org.apache.batik.anim.values.AnimatableValue;
  24. import org.apache.batik.ext.awt.geom.ExtendedGeneralPath;
  25. import org.apache.batik.dom.svg.SVGAnimatedPathDataSupport;
  26. import org.apache.batik.dom.svg.SVGOMElement;
  27. import org.apache.batik.dom.svg.SVGOMPathElement;
  28. import org.apache.batik.dom.util.XLinkSupport;
  29. import org.apache.batik.parser.AWTPathProducer;
  30. import org.apache.batik.parser.AngleHandler;
  31. import org.apache.batik.parser.AngleParser;
  32. import org.apache.batik.parser.LengthArrayProducer;
  33. import org.apache.batik.parser.LengthPairListParser;
  34. import org.apache.batik.parser.PathParser;
  35. import org.apache.batik.parser.ParseException;
  36. import org.w3c.dom.Element;
  37. import org.w3c.dom.Node;
  38. import org.w3c.dom.svg.SVGAngle;
  39. /**
  40. * Bridge class for the 'animateMotion' animation element.
  41. *
  42. * @author <a href="mailto:cam%40mcc%2eid%2eau">Cameron McCormack</a>
  43. * @version $Id: SVGAnimateMotionElementBridge.java 501922 2007-01-31 17:47:47Z dvholten $
  44. */
  45. public class SVGAnimateMotionElementBridge extends SVGAnimateElementBridge {
  46. /**
  47. * Returns 'animateMotion'.
  48. */
  49. public String getLocalName() {
  50. return SVG_ANIMATE_MOTION_TAG;
  51. }
  52. /**
  53. * Returns a new instance of this bridge.
  54. */
  55. public Bridge getInstance() {
  56. return new SVGAnimateMotionElementBridge();
  57. }
  58. /**
  59. * Creates the animation object for the animation element.
  60. */
  61. protected AbstractAnimation createAnimation(AnimationTarget target) {
  62. animationType = AnimationEngine.ANIM_TYPE_OTHER;
  63. attributeLocalName = "motion";
  64. AnimatableValue from = parseLengthPair(SVG_FROM_ATTRIBUTE);
  65. AnimatableValue to = parseLengthPair(SVG_TO_ATTRIBUTE);
  66. AnimatableValue by = parseLengthPair(SVG_BY_ATTRIBUTE);
  67. boolean rotateAuto = false, rotateAutoReverse = false;
  68. float rotateAngle = 0;
  69. short rotateAngleUnit = SVGAngle.SVG_ANGLETYPE_UNKNOWN;
  70. String rotateString = element.getAttributeNS(null,
  71. SVG_ROTATE_ATTRIBUTE);
  72. if (rotateString.length() != 0) {
  73. if (rotateString.equals("auto")) {
  74. rotateAuto = true;
  75. } else if (rotateString.equals("auto-reverse")) {
  76. rotateAuto = true;
  77. rotateAutoReverse = true;
  78. } else {
  79. class Handler implements AngleHandler {
  80. float theAngle;
  81. short theUnit = SVGAngle.SVG_ANGLETYPE_UNSPECIFIED;
  82. public void startAngle() throws ParseException {
  83. }
  84. public void angleValue(float v) throws ParseException {
  85. theAngle = v;
  86. }
  87. public void deg() throws ParseException {
  88. theUnit = SVGAngle.SVG_ANGLETYPE_DEG;
  89. }
  90. public void grad() throws ParseException {
  91. theUnit = SVGAngle.SVG_ANGLETYPE_GRAD;
  92. }
  93. public void rad() throws ParseException {
  94. theUnit = SVGAngle.SVG_ANGLETYPE_RAD;
  95. }
  96. public void endAngle() throws ParseException {
  97. }
  98. }
  99. AngleParser ap = new AngleParser();
  100. Handler h = new Handler();
  101. ap.setAngleHandler(h);
  102. try {
  103. ap.parse(rotateString);
  104. } catch (ParseException pEx ) {
  105. throw new BridgeException
  106. (ctx, element,
  107. pEx, ErrorConstants.ERR_ATTRIBUTE_VALUE_MALFORMED,
  108. new Object[] { SVG_ROTATE_ATTRIBUTE, rotateString });
  109. }
  110. rotateAngle = h.theAngle;
  111. rotateAngleUnit = h.theUnit;
  112. }
  113. }
  114. return new MotionAnimation(timedElement,
  115. this,
  116. parseCalcMode(),
  117. parseKeyTimes(),
  118. parseKeySplines(),
  119. parseAdditive(),
  120. parseAccumulate(),
  121. parseValues(),
  122. from,
  123. to,
  124. by,
  125. parsePath(),
  126. parseKeyPoints(),
  127. rotateAuto,
  128. rotateAutoReverse,
  129. rotateAngle,
  130. rotateAngleUnit);
  131. }
  132. /**
  133. * Returns the parsed 'path' attribute (or the path from a referencing
  134. * 'mpath') from the animation element.
  135. */
  136. protected ExtendedGeneralPath parsePath() {
  137. Node n = element.getFirstChild();
  138. while (n != null) {
  139. if (n.getNodeType() == Node.ELEMENT_NODE
  140. && SVG_NAMESPACE_URI.equals(n.getNamespaceURI())
  141. && SVG_MPATH_TAG.equals(n.getLocalName())) {
  142. String uri = XLinkSupport.getXLinkHref((Element) n);
  143. Element path = ctx.getReferencedElement(element, uri);
  144. if (!SVG_NAMESPACE_URI.equals(path.getNamespaceURI())
  145. || !SVG_PATH_TAG.equals(path.getLocalName())) {
  146. throw new BridgeException
  147. (ctx, element, ErrorConstants.ERR_URI_BAD_TARGET,
  148. new Object[] { uri });
  149. }
  150. SVGOMPathElement pathElt = (SVGOMPathElement) path;
  151. AWTPathProducer app = new AWTPathProducer();
  152. SVGAnimatedPathDataSupport.handlePathSegList
  153. (pathElt.getPathSegList(), app);
  154. return (ExtendedGeneralPath) app.getShape();
  155. }
  156. n = n.getNextSibling();
  157. }
  158. String pathString = element.getAttributeNS(null, SVG_PATH_ATTRIBUTE);
  159. if (pathString.length() == 0) {
  160. return null;
  161. }
  162. try {
  163. AWTPathProducer app = new AWTPathProducer();
  164. PathParser pp = new PathParser();
  165. pp.setPathHandler(app);
  166. pp.parse(pathString);
  167. return (ExtendedGeneralPath) app.getShape();
  168. } catch (ParseException pEx ) {
  169. throw new BridgeException
  170. (ctx, element, pEx, ErrorConstants.ERR_ATTRIBUTE_VALUE_MALFORMED,
  171. new Object[] { SVG_PATH_ATTRIBUTE, pathString });
  172. }
  173. }
  174. /**
  175. * Returns the parsed 'keyPoints' attribute from the animation element.
  176. */
  177. protected float[] parseKeyPoints() {
  178. String keyPointsString =
  179. element.getAttributeNS(null, SVG_KEY_POINTS_ATTRIBUTE);
  180. int len = keyPointsString.length();
  181. if (len == 0) {
  182. return null;
  183. }
  184. List keyPoints = new ArrayList(7);
  185. int i = 0, start = 0, end;
  186. char c;
  187. outer: while (i < len) {
  188. while (keyPointsString.charAt(i) == ' ') {
  189. i++;
  190. if (i == len) {
  191. break outer;
  192. }
  193. }
  194. start = i++;
  195. if (i != len) {
  196. c = keyPointsString.charAt(i);
  197. while (c != ' ' && c != ';' && c != ',') {
  198. i++;
  199. if (i == len) {
  200. break;
  201. }
  202. c = keyPointsString.charAt(i);
  203. }
  204. }
  205. end = i++;
  206. try {
  207. float keyPointCoord =
  208. Float.parseFloat(keyPointsString.substring(start, end));
  209. keyPoints.add(new Float(keyPointCoord));
  210. } catch (NumberFormatException nfEx ) {
  211. throw new BridgeException
  212. (ctx, element, nfEx, ErrorConstants.ERR_ATTRIBUTE_VALUE_MALFORMED,
  213. new Object[] { SVG_KEY_POINTS_ATTRIBUTE, keyPointsString });
  214. }
  215. }
  216. len = keyPoints.size();
  217. float[] ret = new float[len];
  218. for (int j = 0; j < len; j++) {
  219. ret[j] = ((Float) keyPoints.get(j)).floatValue();
  220. }
  221. return ret;
  222. }
  223. /**
  224. * Returns the calcMode that the animation defaults to if none is specified.
  225. */
  226. protected int getDefaultCalcMode() {
  227. return MotionAnimation.CALC_MODE_PACED;
  228. }
  229. /**
  230. * Returns the parsed 'values' attribute from the animation element.
  231. */
  232. protected AnimatableValue[] parseValues() {
  233. String valuesString = element.getAttributeNS(null,
  234. SVG_VALUES_ATTRIBUTE);
  235. int len = valuesString.length();
  236. if (len == 0) {
  237. return null;
  238. }
  239. return parseValues(valuesString);
  240. }
  241. protected AnimatableValue[] parseValues(String s) {
  242. try {
  243. LengthPairListParser lplp = new LengthPairListParser();
  244. LengthArrayProducer lap = new LengthArrayProducer();
  245. lplp.setLengthListHandler(lap);
  246. lplp.parse(s);
  247. short[] types = lap.getLengthTypeArray();
  248. float[] values = lap.getLengthValueArray();
  249. AnimatableValue[] ret = new AnimatableValue[types.length / 2];
  250. for (int i = 0; i < types.length; i += 2) {
  251. float x = animationTarget.svgToUserSpace
  252. (values[i], types[i], AnimationTarget.PERCENTAGE_VIEWPORT_WIDTH);
  253. float y = animationTarget.svgToUserSpace
  254. (values[i + 1], types[i + 1], AnimationTarget.PERCENTAGE_VIEWPORT_HEIGHT);
  255. ret[i / 2] = new AnimatableMotionPointValue(animationTarget, x, y, 0);
  256. }
  257. return ret;
  258. } catch (ParseException pEx ) {
  259. throw new BridgeException
  260. (ctx, element, pEx, ErrorConstants.ERR_ATTRIBUTE_VALUE_MALFORMED,
  261. new Object[] { SVG_VALUES_ATTRIBUTE, s });
  262. }
  263. }
  264. /**
  265. * Parses a single comma-separated length pair.
  266. */
  267. protected AnimatableValue parseLengthPair(String ln) {
  268. String s = element.getAttributeNS(null, ln);
  269. if (s.length() == 0) {
  270. return null;
  271. }
  272. return parseValues(s)[0];
  273. }
  274. // AnimatableElement /////////////////////////////////////////////////////
  275. /**
  276. * Returns the underlying value of the animated attribute. Used for
  277. * composition of additive animations.
  278. */
  279. public AnimatableValue getUnderlyingValue() {
  280. return new AnimatableMotionPointValue(animationTarget, 0f, 0f, 0f);
  281. }
  282. /**
  283. * Parses the animation element's target attributes and adds it to the
  284. * document's AnimationEngine.
  285. */
  286. protected void initializeAnimation() {
  287. // Determine the target element.
  288. String uri = XLinkSupport.getXLinkHref(element);
  289. Node t;
  290. if (uri.length() == 0) {
  291. t = element.getParentNode();
  292. } else {
  293. t = ctx.getReferencedElement(element, uri);
  294. if (t.getOwnerDocument() != element.getOwnerDocument()) {
  295. throw new BridgeException
  296. (ctx, element, ErrorConstants.ERR_URI_BAD_TARGET,
  297. new Object[] { uri });
  298. }
  299. }
  300. animationTarget = null;
  301. if (t instanceof SVGOMElement) {
  302. targetElement = (SVGOMElement) t;
  303. animationTarget = targetElement;
  304. }
  305. if (animationTarget == null) {
  306. throw new BridgeException
  307. (ctx, element, ErrorConstants.ERR_URI_BAD_TARGET,
  308. new Object[] { uri });
  309. }
  310. // Add the animation.
  311. timedElement = createTimedElement();
  312. animation = createAnimation(animationTarget);
  313. eng.addAnimation(animationTarget, AnimationEngine.ANIM_TYPE_OTHER,
  314. attributeNamespaceURI, attributeLocalName, animation);
  315. }
  316. }