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.dom.svg;
020:
021: import java.util.Iterator;
022: import java.util.LinkedList;
023:
024: import org.apache.batik.dom.anim.AnimationTarget;
025: import org.apache.batik.dom.anim.AnimationTargetListener;
026: import org.apache.batik.anim.values.AnimatableNumberOptionalNumberValue;
027: import org.apache.batik.anim.values.AnimatableValue;
028: import org.apache.batik.css.engine.CSSEngine;
029: import org.apache.batik.css.engine.CSSNavigableNode;
030: import org.apache.batik.css.engine.value.ShorthandManager;
031: import org.apache.batik.css.engine.value.ValueManager;
032: import org.apache.batik.dom.AbstractDocument;
033: import org.apache.batik.dom.AbstractStylableDocument;
034: import org.apache.batik.dom.util.DoublyIndexedTable;
035: import org.apache.batik.dom.util.DOMUtilities;
036: import org.apache.batik.parser.UnitProcessor;
037: import org.apache.batik.util.CSSConstants;
038: import org.apache.batik.util.ParsedURL;
039: import org.apache.batik.util.SVGConstants;
040: import org.apache.batik.util.SVGTypes;
041:
042: import org.w3c.dom.Attr;
043: import org.w3c.dom.DOMException;
044: import org.w3c.dom.Element;
045: import org.w3c.dom.Node;
046: import org.w3c.dom.svg.SVGAnimatedInteger;
047: import org.w3c.dom.svg.SVGAnimatedNumber;
048: import org.w3c.dom.svg.SVGElement;
049: import org.w3c.dom.svg.SVGException;
050: import org.w3c.dom.svg.SVGFitToViewBox;
051: import org.w3c.dom.svg.SVGLength;
052: import org.w3c.dom.svg.SVGSVGElement;
053:
054: /**
055: * This class implements the {@link SVGElement} interface.
056: *
057: * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
058: * @version $Id: SVGOMElement.java 491178 2006-12-30 06:18:34Z cam $
059: */
060: public abstract class SVGOMElement extends AbstractElement implements
061: SVGElement, SVGConstants, ExtendedTraitAccess, AnimationTarget {
062:
063: /**
064: * Table mapping XML attribute names to TraitInformation objects.
065: */
066: protected static DoublyIndexedTable xmlTraitInformation;
067: static {
068: DoublyIndexedTable t = new DoublyIndexedTable();
069: t.put(null, SVG_ID_ATTRIBUTE, new TraitInformation(false,
070: SVGTypes.TYPE_CDATA));
071: t.put(XML_NAMESPACE_URI, XML_BASE_ATTRIBUTE,
072: new TraitInformation(false, SVGTypes.TYPE_URI));
073: t.put(XML_NAMESPACE_URI, XML_SPACE_ATTRIBUTE,
074: new TraitInformation(false, SVGTypes.TYPE_IDENT));
075: t.put(XML_NAMESPACE_URI, XML_ID_ATTRIBUTE,
076: new TraitInformation(false, SVGTypes.TYPE_CDATA));
077: t.put(XML_NAMESPACE_URI, XML_LANG_ATTRIBUTE,
078: new TraitInformation(false, SVGTypes.TYPE_LANG));
079: xmlTraitInformation = t;
080: }
081:
082: /**
083: * Is this element immutable?
084: */
085: protected transient boolean readonly;
086:
087: /**
088: * The element prefix.
089: */
090: protected String prefix;
091:
092: /**
093: * The SVG context to get SVG specific informations.
094: */
095: protected transient SVGContext svgContext;
096:
097: /**
098: * Table mapping namespaceURI/local name pairs to {@link LinkedList}s
099: * of {@link AnimationTargetListener}s.
100: */
101: protected DoublyIndexedTable targetListeners;
102:
103: /**
104: * The context used to resolve the units.
105: */
106: protected UnitProcessor.Context unitContext;
107:
108: /**
109: * Creates a new Element object.
110: */
111: protected SVGOMElement() {
112: }
113:
114: /**
115: * Creates a new Element object.
116: * @param prefix The namespace prefix.
117: * @param owner The owner document.
118: */
119: protected SVGOMElement(String prefix, AbstractDocument owner) {
120: super (prefix, owner);
121: // initializeLiveAttributes();
122: }
123:
124: /**
125: * Initializes all live attributes for this element.
126: */
127: protected void initializeAllLiveAttributes() {
128: // initializeLiveAttributes();
129: }
130:
131: // /**
132: // * Initializes the live attribute values of this element.
133: // */
134: // private void initializeLiveAttributes() {
135: // // If live attributes are added here, make sure to uncomment the
136: // // call to initializeLiveAttributes in the constructor and
137: // // initializeAllLiveAttributes method above.
138: // }
139:
140: /**
141: * <b>DOM</b>: Implements {@link SVGElement#getId()}.
142: */
143: public String getId() {
144: return super .getId();
145: }
146:
147: /**
148: * <b>DOM</b>: Implements {@link SVGElement#setId(String)}.
149: */
150: public void setId(String id) {
151: Attr a = getIdAttribute();
152: if (a == null) {
153: setAttributeNS(null, "id", id);
154: } else {
155: a.setNodeValue(id);
156: }
157: }
158:
159: /**
160: * <b>DOM</b>: Implements {@link SVGElement#getXMLbase()}.
161: */
162: public String getXMLbase() {
163: return getAttributeNS(XML_NAMESPACE_URI, XML_BASE_ATTRIBUTE);
164: }
165:
166: /**
167: * <b>DOM</b>: Implements {@link SVGElement#setXMLbase(String)}.
168: */
169: public void setXMLbase(String xmlbase) throws DOMException {
170: setAttributeNS(XML_NAMESPACE_URI, XML_BASE_QNAME, xmlbase);
171: }
172:
173: /**
174: * <b>DOM</b>: Implements {@link SVGElement#getOwnerSVGElement()}.
175: */
176: public SVGSVGElement getOwnerSVGElement() {
177: for (Element e = CSSEngine.getParentCSSStylableElement(this ); e != null; e = CSSEngine
178: .getParentCSSStylableElement(e)) {
179: if (e instanceof SVGSVGElement) {
180: return (SVGSVGElement) e;
181: }
182: }
183: return null;
184: }
185:
186: /**
187: * <b>DOM</b>: Implements {@link SVGElement#getViewportElement()}.
188: */
189: public SVGElement getViewportElement() {
190: for (Element e = CSSEngine.getParentCSSStylableElement(this ); e != null; e = CSSEngine
191: .getParentCSSStylableElement(e)) {
192: if (e instanceof SVGFitToViewBox) {
193: return (SVGElement) e;
194: }
195: }
196: return null;
197: }
198:
199: /**
200: * <b>DOM</b>: Implements {@link Node#getNodeName()}.
201: */
202: public String getNodeName() {
203: if (prefix == null || prefix.equals("")) {
204: return getLocalName();
205: }
206:
207: return prefix + ':' + getLocalName();
208: }
209:
210: /**
211: * <b>DOM</b>: Implements {@link Node#getNamespaceURI()}.
212: */
213: public String getNamespaceURI() {
214: return SVGDOMImplementation.SVG_NAMESPACE_URI;
215: }
216:
217: /**
218: * <b>DOM</b>: Implements {@link Node#setPrefix(String)}.
219: */
220: public void setPrefix(String prefix) throws DOMException {
221: if (isReadonly()) {
222: throw createDOMException(
223: DOMException.NO_MODIFICATION_ALLOWED_ERR,
224: "readonly.node", new Object[] {
225: new Integer(getNodeType()), getNodeName() });
226: }
227: if (prefix != null && !prefix.equals("")
228: && !DOMUtilities.isValidName(prefix)) {
229: throw createDOMException(
230: DOMException.INVALID_CHARACTER_ERR, "prefix",
231: new Object[] { new Integer(getNodeType()),
232: getNodeName(), prefix });
233: }
234: this .prefix = prefix;
235: }
236:
237: /**
238: * Returns the xml:base attribute value of the given element,
239: * resolving any dependency on parent bases if needed.
240: * Follows shadow trees when moving to parent nodes.
241: */
242: protected String getCascadedXMLBase(Node node) {
243: String base = null;
244: Node n = node.getParentNode();
245: while (n != null) {
246: if (n.getNodeType() == Node.ELEMENT_NODE) {
247: base = getCascadedXMLBase((Element) n);
248: break;
249: }
250: if (n instanceof CSSNavigableNode) {
251: n = ((CSSNavigableNode) n).getCSSParentNode();
252: } else {
253: n = n.getParentNode();
254: }
255: }
256: if (base == null) {
257: AbstractDocument doc;
258: if (node.getNodeType() == Node.DOCUMENT_NODE) {
259: doc = (AbstractDocument) node;
260: } else {
261: doc = (AbstractDocument) node.getOwnerDocument();
262: }
263: base = doc.getDocumentURI();
264: }
265: while (node != null && node.getNodeType() != Node.ELEMENT_NODE) {
266: node = node.getParentNode();
267: }
268: if (node == null) {
269: return base;
270: }
271: Element e = (Element) node;
272: Attr attr = e.getAttributeNodeNS(XML_NAMESPACE_URI,
273: XML_BASE_ATTRIBUTE);
274: if (attr != null) {
275: if (base == null) {
276: base = attr.getNodeValue();
277: } else {
278: base = new ParsedURL(base, attr.getNodeValue())
279: .toString();
280: }
281: }
282: return base;
283: }
284:
285: // SVGContext ////////////////////////////////////////////////////
286:
287: /**
288: * Sets the SVG context to use to get SVG specific informations.
289: *
290: * @param ctx the SVG context
291: */
292: public void setSVGContext(SVGContext ctx) {
293: svgContext = ctx;
294: }
295:
296: /**
297: * Returns the SVG context used to get SVG specific informations.
298: */
299: public SVGContext getSVGContext() {
300: return svgContext;
301: }
302:
303: // ExtendedNode //////////////////////////////////////////////////
304:
305: /**
306: * Creates an SVGException with the appropriate error message.
307: */
308: public SVGException createSVGException(short type, String key,
309: Object[] args) {
310: try {
311: return new SVGOMException(type, getCurrentDocument()
312: .formatMessage(key, args));
313: } catch (Exception e) {
314: return new SVGOMException(type, key);
315: }
316: }
317:
318: /**
319: * Tests whether this node is readonly.
320: */
321: public boolean isReadonly() {
322: return readonly;
323: }
324:
325: /**
326: * Sets this node readonly attribute.
327: */
328: public void setReadonly(boolean v) {
329: readonly = v;
330: }
331:
332: /**
333: * Returns the table of TraitInformation objects for this element.
334: */
335: protected DoublyIndexedTable getTraitInformationTable() {
336: return xmlTraitInformation;
337: }
338:
339: /**
340: * Creates a new {@link SVGOMAnimatedTransformList} and stores it in
341: * this element's LiveAttributeValue table.
342: */
343: protected SVGOMAnimatedTransformList createLiveAnimatedTransformList(
344: String ns, String ln, String def) {
345: SVGOMAnimatedTransformList v = new SVGOMAnimatedTransformList(
346: this , ns, ln, def);
347: liveAttributeValues.put(ns, ln, v);
348: v.addAnimatedAttributeListener(((SVGOMDocument) ownerDocument)
349: .getAnimatedAttributeListener());
350: return v;
351: }
352:
353: /**
354: * Creates a new {@link SVGOMAnimatedBoolean} and stores it in
355: * this element's LiveAttributeValue table.
356: */
357: protected SVGOMAnimatedBoolean createLiveAnimatedBoolean(String ns,
358: String ln, boolean def) {
359: SVGOMAnimatedBoolean v = new SVGOMAnimatedBoolean(this , ns, ln,
360: def);
361: liveAttributeValues.put(ns, ln, v);
362: v.addAnimatedAttributeListener(((SVGOMDocument) ownerDocument)
363: .getAnimatedAttributeListener());
364: return v;
365: }
366:
367: /**
368: * Creates a new {@link SVGOMAnimatedString} and stores it in
369: * this element's LiveAttributeValue table.
370: */
371: protected SVGOMAnimatedString createLiveAnimatedString(String ns,
372: String ln) {
373: SVGOMAnimatedString v = new SVGOMAnimatedString(this , ns, ln);
374: liveAttributeValues.put(ns, ln, v);
375: v.addAnimatedAttributeListener(((SVGOMDocument) ownerDocument)
376: .getAnimatedAttributeListener());
377: return v;
378: }
379:
380: /**
381: * Creates a new {@link SVGOMAnimatedPreserveAspectRatio} and stores it in
382: * this element's LiveAttributeValue table.
383: */
384: protected SVGOMAnimatedPreserveAspectRatio createLiveAnimatedPreserveAspectRatio() {
385: SVGOMAnimatedPreserveAspectRatio v = new SVGOMAnimatedPreserveAspectRatio(
386: this );
387: liveAttributeValues.put(null,
388: SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE, v);
389: v.addAnimatedAttributeListener(((SVGOMDocument) ownerDocument)
390: .getAnimatedAttributeListener());
391: return v;
392: }
393:
394: /**
395: * Creates a new {@link SVGOMAnimatedMarkerOrientValue} and stores it in
396: * this element's LiveAttributeValue table.
397: */
398: protected SVGOMAnimatedMarkerOrientValue createLiveAnimatedMarkerOrientValue(
399: String ns, String ln) {
400: SVGOMAnimatedMarkerOrientValue v = new SVGOMAnimatedMarkerOrientValue(
401: this , ns, ln);
402: liveAttributeValues.put(ns, ln, v);
403: v.addAnimatedAttributeListener(((SVGOMDocument) ownerDocument)
404: .getAnimatedAttributeListener());
405: return v;
406: }
407:
408: /**
409: * Creates a new {@link SVGOMAnimatedPathData} and stores it in
410: * this element's LiveAttributeValue table.
411: */
412: protected SVGOMAnimatedPathData createLiveAnimatedPathData(
413: String ns, String ln, String def) {
414: SVGOMAnimatedPathData v = new SVGOMAnimatedPathData(this , ns,
415: ln, def);
416: liveAttributeValues.put(ns, ln, v);
417: v.addAnimatedAttributeListener(((SVGOMDocument) ownerDocument)
418: .getAnimatedAttributeListener());
419: return v;
420: }
421:
422: /**
423: * Creates a new {@link SVGOMAnimatedNumber} and stores it in
424: * this element's LiveAttributeValue table.
425: */
426: protected SVGOMAnimatedNumber createLiveAnimatedNumber(String ns,
427: String ln, float def) {
428: return createLiveAnimatedNumber(ns, ln, def, false);
429: }
430:
431: /**
432: * Creates a new {@link SVGOMAnimatedNumber} that can be parsed as a
433: * percentage and stores it in this element's LiveAttributeValue table.
434: */
435: protected SVGOMAnimatedNumber createLiveAnimatedNumber(String ns,
436: String ln, float def, boolean allowPercentage) {
437: SVGOMAnimatedNumber v = new SVGOMAnimatedNumber(this , ns, ln,
438: def, allowPercentage);
439: liveAttributeValues.put(ns, ln, v);
440: v.addAnimatedAttributeListener(((SVGOMDocument) ownerDocument)
441: .getAnimatedAttributeListener());
442: return v;
443: }
444:
445: /**
446: * Creates a new {@link SVGOMAnimatedNumberList} and stores it in
447: * this element's LiveAttributeValue table.
448: */
449: protected SVGOMAnimatedNumberList createLiveAnimatedNumberList(
450: String ns, String ln, String def, boolean canEmpty) {
451: SVGOMAnimatedNumberList v = new SVGOMAnimatedNumberList(this ,
452: ns, ln, def, canEmpty);
453: liveAttributeValues.put(ns, ln, v);
454: v.addAnimatedAttributeListener(((SVGOMDocument) ownerDocument)
455: .getAnimatedAttributeListener());
456: return v;
457: }
458:
459: /**
460: * Creates a new {@link SVGOMAnimatedPoints} and stores it in
461: * this element's LiveAttributeValue table.
462: */
463: protected SVGOMAnimatedPoints createLiveAnimatedPoints(String ns,
464: String ln, String def) {
465: SVGOMAnimatedPoints v = new SVGOMAnimatedPoints(this , ns, ln,
466: def);
467: liveAttributeValues.put(ns, ln, v);
468: v.addAnimatedAttributeListener(((SVGOMDocument) ownerDocument)
469: .getAnimatedAttributeListener());
470: return v;
471: }
472:
473: /**
474: * Creates a new {@link SVGOMAnimatedLengthList} and stores it in
475: * this element's LiveAttributeValue table.
476: */
477: protected SVGOMAnimatedLengthList createLiveAnimatedLengthList(
478: String ns, String ln, String def, boolean emptyAllowed,
479: short dir) {
480: SVGOMAnimatedLengthList v = new SVGOMAnimatedLengthList(this ,
481: ns, ln, def, emptyAllowed, dir);
482: liveAttributeValues.put(ns, ln, v);
483: v.addAnimatedAttributeListener(((SVGOMDocument) ownerDocument)
484: .getAnimatedAttributeListener());
485: return v;
486: }
487:
488: /**
489: * Creates a new {@link SVGOMAnimatedInteger} and stores it in
490: * this element's LiveAttributeValue table.
491: */
492: protected SVGOMAnimatedInteger createLiveAnimatedInteger(String ns,
493: String ln, int def) {
494: SVGOMAnimatedInteger v = new SVGOMAnimatedInteger(this , ns, ln,
495: def);
496: liveAttributeValues.put(ns, ln, v);
497: v.addAnimatedAttributeListener(((SVGOMDocument) ownerDocument)
498: .getAnimatedAttributeListener());
499: return v;
500: }
501:
502: /**
503: * Creates a new {@link SVGOMAnimatedEnumeration} and stores it in
504: * this element's LiveAttributeValue table.
505: */
506: protected SVGOMAnimatedEnumeration createLiveAnimatedEnumeration(
507: String ns, String ln, String[] val, short def) {
508: SVGOMAnimatedEnumeration v = new SVGOMAnimatedEnumeration(this ,
509: ns, ln, val, def);
510: liveAttributeValues.put(ns, ln, v);
511: v.addAnimatedAttributeListener(((SVGOMDocument) ownerDocument)
512: .getAnimatedAttributeListener());
513: return v;
514: }
515:
516: /**
517: * Creates a new {@link SVGOMAnimatedLength} and stores it in
518: * this element's LiveAttributeValue table.
519: */
520: protected SVGOMAnimatedLength createLiveAnimatedLength(String ns,
521: String ln, String val, short dir, boolean nonneg) {
522: SVGOMAnimatedLength v = new SVGOMAnimatedLength(this , ns, ln,
523: val, dir, nonneg);
524: liveAttributeValues.put(ns, ln, v);
525: v.addAnimatedAttributeListener(((SVGOMDocument) ownerDocument)
526: .getAnimatedAttributeListener());
527: return v;
528: }
529:
530: // ExtendedTraitAccess ///////////////////////////////////////////////////
531:
532: /**
533: * Returns whether the given CSS property is available on this element.
534: */
535: public boolean hasProperty(String pn) {
536: AbstractStylableDocument doc = (AbstractStylableDocument) ownerDocument;
537: CSSEngine eng = doc.getCSSEngine();
538: return eng.getPropertyIndex(pn) != -1
539: || eng.getShorthandIndex(pn) != -1;
540: }
541:
542: /**
543: * Returns whether the given trait is available on this element.
544: */
545: public boolean hasTrait(String ns, String ln) {
546: // XXX no traits yet
547: return false;
548: }
549:
550: /**
551: * Returns whether the given CSS property is animatable.
552: */
553: public boolean isPropertyAnimatable(String pn) {
554: AbstractStylableDocument doc = (AbstractStylableDocument) ownerDocument;
555: CSSEngine eng = doc.getCSSEngine();
556: int idx = eng.getPropertyIndex(pn);
557: if (idx != -1) {
558: ValueManager[] vms = eng.getValueManagers();
559: return vms[idx].isAnimatableProperty();
560: }
561: idx = eng.getShorthandIndex(pn);
562: if (idx != -1) {
563: ShorthandManager[] sms = eng.getShorthandManagers();
564: return sms[idx].isAnimatableProperty();
565: }
566: return false;
567: }
568:
569: /**
570: * Returns whether the given XML attribute is animatable.
571: */
572: public final boolean isAttributeAnimatable(String ns, String ln) {
573: DoublyIndexedTable t = getTraitInformationTable();
574: TraitInformation ti = (TraitInformation) t.get(ns, ln);
575: if (ti != null) {
576: return ti.isAnimatable();
577: }
578: return false;
579: }
580:
581: /**
582: * Returns whether the given CSS property is additive.
583: */
584: public boolean isPropertyAdditive(String pn) {
585: AbstractStylableDocument doc = (AbstractStylableDocument) ownerDocument;
586: CSSEngine eng = doc.getCSSEngine();
587: int idx = eng.getPropertyIndex(pn);
588: if (idx != -1) {
589: ValueManager[] vms = eng.getValueManagers();
590: return vms[idx].isAdditiveProperty();
591: }
592: idx = eng.getShorthandIndex(pn);
593: if (idx != -1) {
594: ShorthandManager[] sms = eng.getShorthandManagers();
595: return sms[idx].isAdditiveProperty();
596: }
597: return false;
598: }
599:
600: /**
601: * Returns whether the given XML attribute is additive.
602: */
603: public boolean isAttributeAdditive(String ns, String ln) {
604: return true;
605: }
606:
607: /**
608: * Returns whether the given trait is animatable.
609: */
610: public boolean isTraitAnimatable(String ns, String tn) {
611: // XXX no traits yet
612: return false;
613: }
614:
615: /**
616: * Returns whether the given trait is additive.
617: */
618: public boolean isTraitAdditive(String ns, String tn) {
619: // XXX no traits yet
620: return false;
621: }
622:
623: /**
624: * Returns the type of the given property.
625: */
626: public int getPropertyType(String pn) {
627: AbstractStylableDocument doc = (AbstractStylableDocument) ownerDocument;
628: CSSEngine eng = doc.getCSSEngine();
629: int idx = eng.getPropertyIndex(pn);
630: if (idx != -1) {
631: ValueManager[] vms = eng.getValueManagers();
632: return vms[idx].getPropertyType();
633: }
634: return SVGTypes.TYPE_UNKNOWN;
635: }
636:
637: /**
638: * Returns the type of the given attribute.
639: */
640: public final int getAttributeType(String ns, String ln) {
641: DoublyIndexedTable t = getTraitInformationTable();
642: TraitInformation ti = (TraitInformation) t.get(ns, ln);
643: if (ti != null) {
644: return ti.getType();
645: }
646: return SVGTypes.TYPE_UNKNOWN;
647: }
648:
649: // AnimationTarget ///////////////////////////////////////////////////////
650:
651: /**
652: * Returns the element.
653: */
654: public Element getElement() {
655: return this ;
656: }
657:
658: /**
659: * Updates a property value in this target. Ignored for non-stylable
660: * elements. Overridden in {@link SVGStylableElement} to actually update
661: * properties.
662: */
663: public void updatePropertyValue(String pn, AnimatableValue val) {
664: }
665:
666: /**
667: * Updates an attribute value in this target.
668: */
669: public void updateAttributeValue(String ns, String ln,
670: AnimatableValue val) {
671: LiveAttributeValue a = getLiveAttributeValue(ns, ln);
672: ((AbstractSVGAnimatedValue) a).updateAnimatedValue(val);
673: // XXX Override this for NumberOptionalNumber values
674: }
675:
676: /**
677: * Updates a 'other' animation value in this target.
678: */
679: public void updateOtherValue(String type, AnimatableValue val) {
680: }
681:
682: /**
683: * Returns the underlying value of an animatable XML attribute.
684: */
685: public AnimatableValue getUnderlyingValue(String ns, String ln) {
686: LiveAttributeValue a = getLiveAttributeValue(ns, ln);
687: if (!(a instanceof AnimatedLiveAttributeValue)) {
688: return null;
689: }
690: return ((AnimatedLiveAttributeValue) a)
691: .getUnderlyingValue(this );
692: // XXX Override this for NumberOptionalNumber values
693: }
694:
695: /**
696: * Returns an AnimatableNumberOptionalNumberValue for the base value of
697: * the given two SVGAnimatedIntegers.
698: */
699: protected AnimatableValue getBaseValue(SVGAnimatedInteger n,
700: SVGAnimatedInteger on) {
701: return new AnimatableNumberOptionalNumberValue(this , n
702: .getBaseVal(), on.getBaseVal());
703: }
704:
705: /**
706: * Returns an AnimatableNumberOptionalNumberValue for the base value of
707: * the given two SVGAnimatedNumbers.
708: */
709: protected AnimatableValue getBaseValue(SVGAnimatedNumber n,
710: SVGAnimatedNumber on) {
711: return new AnimatableNumberOptionalNumberValue(this , n
712: .getBaseVal(), on.getBaseVal());
713: }
714:
715: /**
716: * Gets how percentage values are interpreted by the given attribute
717: * or property.
718: */
719: public short getPercentageInterpretation(String ns, String an,
720: boolean isCSS) {
721: if (isCSS || ns == null) {
722: if (an.equals(CSSConstants.CSS_BASELINE_SHIFT_PROPERTY)
723: || an.equals(CSSConstants.CSS_FONT_SIZE_PROPERTY)) {
724: return PERCENTAGE_FONT_SIZE;
725: }
726: }
727: if (!isCSS) {
728: DoublyIndexedTable t = getTraitInformationTable();
729: TraitInformation ti = (TraitInformation) t.get(ns, an);
730: if (ti != null) {
731: return ti.getPercentageInterpretation();
732: }
733: return PERCENTAGE_VIEWPORT_SIZE;
734: }
735: // Default for properties.
736: return PERCENTAGE_VIEWPORT_SIZE;
737: }
738:
739: /**
740: * Gets how percentage values are interpreted by the given attribute.
741: */
742: protected final short getAttributePercentageInterpretation(
743: String ns, String ln) {
744: return PERCENTAGE_VIEWPORT_SIZE;
745: }
746:
747: /**
748: * Returns whether color interpolations should be done in linear RGB
749: * color space rather than sRGB. Overriden in {@link SVGStylableElement}
750: * to actually look up the 'color-interpolation' property.
751: */
752: public boolean useLinearRGBColorInterpolation() {
753: return false;
754: }
755:
756: /**
757: * Converts the given SVG length into user units.
758: * @param v the SVG length value
759: * @param type the SVG length units (one of the
760: * {@link SVGLength}.SVG_LENGTH_* constants)
761: * @param pcInterp how to interpretet percentage values (one of the
762: * {@link SVGContext}.PERCENTAGE_* constants)
763: * @return the SVG value in user units
764: */
765: public float svgToUserSpace(float v, short type, short pcInterp) {
766: if (unitContext == null) {
767: unitContext = new UnitContext();
768: }
769: if (pcInterp == PERCENTAGE_FONT_SIZE
770: && type == SVGLength.SVG_LENGTHTYPE_PERCENTAGE) {
771: // XXX
772: return 0f;
773: } else {
774: return UnitProcessor.svgToUserSpace(v, type,
775: (short) (3 - pcInterp), unitContext);
776: }
777: }
778:
779: /**
780: * Adds a listener for changes to the given attribute value.
781: */
782: public void addTargetListener(String ns, String an, boolean isCSS,
783: AnimationTargetListener l) {
784: if (!isCSS) {
785: if (targetListeners == null) {
786: targetListeners = new DoublyIndexedTable();
787: }
788: LinkedList ll = (LinkedList) targetListeners.get(ns, an);
789: if (ll == null) {
790: ll = new LinkedList();
791: targetListeners.put(ns, an, ll);
792: }
793: ll.add(l);
794: }
795: }
796:
797: /**
798: * Removes a listener for changes to the given attribute value.
799: */
800: public void removeTargetListener(String ns, String an,
801: boolean isCSS, AnimationTargetListener l) {
802: if (!isCSS) {
803: LinkedList ll = (LinkedList) targetListeners.get(ns, an);
804: ll.remove(l);
805: }
806: }
807:
808: /**
809: * Fires the listeners registered for changes to the base value of the
810: * given attribute.
811: */
812: void fireBaseAttributeListeners(String ns, String ln) {
813: if (targetListeners != null) {
814: LinkedList ll = (LinkedList) targetListeners.get(ns, ln);
815: Iterator it = ll.iterator();
816: while (it.hasNext()) {
817: AnimationTargetListener l = (AnimationTargetListener) it
818: .next();
819: l.baseValueChanged(this , ns, ln, false);
820: }
821: }
822: }
823:
824: // Importation/Cloning ///////////////////////////////////////////
825:
826: /**
827: * Exports this node to the given document.
828: */
829: protected Node export(Node n, AbstractDocument d) {
830: super .export(n, d);
831: SVGOMElement e = (SVGOMElement) n;
832: e.prefix = prefix;
833: e.initializeAllLiveAttributes();
834: return n;
835: }
836:
837: /**
838: * Deeply exports this node to the given document.
839: */
840: protected Node deepExport(Node n, AbstractDocument d) {
841: super .deepExport(n, d);
842: SVGOMElement e = (SVGOMElement) n;
843: e.prefix = prefix;
844: e.initializeAllLiveAttributes();
845: return n;
846: }
847:
848: /**
849: * Copy the fields of the current node into the given node.
850: * @param n a node of the type of this.
851: */
852: protected Node copyInto(Node n) {
853: super .copyInto(n);
854: SVGOMElement e = (SVGOMElement) n;
855: e.prefix = prefix;
856: e.initializeAllLiveAttributes();
857: return n;
858: }
859:
860: /**
861: * Deeply copy the fields of the current node into the given node.
862: * @param n a node of the type of this.
863: */
864: protected Node deepCopyInto(Node n) {
865: super .deepCopyInto(n);
866: SVGOMElement e = (SVGOMElement) n;
867: e.prefix = prefix;
868: e.initializeAllLiveAttributes();
869: return n;
870: }
871:
872: /**
873: * To resolve the units.
874: */
875: protected class UnitContext implements UnitProcessor.Context {
876:
877: /**
878: * Returns the element.
879: */
880: public Element getElement() {
881: return SVGOMElement.this ;
882: }
883:
884: /**
885: * Returns the size of a px CSS unit in millimeters.
886: */
887: public float getPixelUnitToMillimeter() {
888: return getSVGContext().getPixelUnitToMillimeter();
889: }
890:
891: /**
892: * Returns the size of a px CSS unit in millimeters.
893: * This will be removed after next release.
894: * @see #getPixelUnitToMillimeter()
895: */
896: public float getPixelToMM() {
897: return getPixelUnitToMillimeter();
898: }
899:
900: /**
901: * Returns the font-size value.
902: */
903: public float getFontSize() {
904: return getSVGContext().getFontSize();
905: }
906:
907: /**
908: * Returns the x-height value.
909: */
910: public float getXHeight() {
911: return 0.5f;
912: }
913:
914: /**
915: * Returns the viewport width used to compute units.
916: */
917: public float getViewportWidth() {
918: return getSVGContext().getViewportWidth();
919: }
920:
921: /**
922: * Returns the viewport height used to compute units.
923: */
924: public float getViewportHeight() {
925: return getSVGContext().getViewportHeight();
926: }
927: }
928: }
|