0001: /*
0002: *
0003: *
0004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: */
0026: package com.sun.perseus.model;
0027:
0028: import com.sun.perseus.platform.MathSupport;
0029:
0030: import com.sun.perseus.util.SimpleTokenizer;
0031: import com.sun.perseus.util.SVGConstants;
0032: import com.sun.perseus.parser.Length;
0033:
0034: import org.w3c.dom.DOMException;
0035: import org.w3c.dom.Element;
0036: import org.w3c.dom.Node;
0037:
0038: import org.w3c.dom.events.EventListener;
0039:
0040: import org.w3c.dom.svg.SVGElement;
0041: import org.w3c.dom.svg.SVGLocatableElement;
0042: import org.w3c.dom.svg.SVGMatrix;
0043: import org.w3c.dom.svg.SVGPath;
0044: import org.w3c.dom.svg.SVGRect;
0045: import org.w3c.dom.svg.SVGRGBColor;
0046:
0047: import java.util.Hashtable;
0048: import java.util.Vector;
0049:
0050: import com.sun.perseus.j2d.RGB;
0051: import com.sun.perseus.j2d.Path;
0052: import com.sun.perseus.j2d.PaintDef;
0053: import com.sun.perseus.j2d.PaintTarget;
0054: import com.sun.perseus.j2d.PaintServer;
0055: import com.sun.perseus.j2d.Transform;
0056: import com.sun.perseus.j2d.Box;
0057:
0058: /**
0059: * <code>ElementNode</code> models <code>ModelNodes</code which
0060: * cna have children.
0061: *
0062: * <p>A <code>ElementNode</code> can have either <code>ElementNode</code>
0063: * children and text content children
0064: * (see the {@link #appendTextChild} appendTextChild} method).</p>
0065: *
0066: * <p>In addition, <code>Element</code>s can have proxies (see
0067: * {@link com.sun.perseus.model.ElementNodeProxy ElementNodeProxy}).
0068: * The proxies are used for implementing the behavior of the
0069: * <code><use></code> element and the <code><text></code>
0070: * element. The <code>buildProxy</code> and <code>removeProxy</code>
0071: * methods are used to add or remove proxies from a node.</p>
0072: *
0073: * <p>Finally, the <code>ElementNode</code> class provides support
0074: * for the common XML attributes supported by elements, such as
0075: * the <code>id</code>, <code>uriBase</code> and conditional attributes.</p>
0076: *
0077: * @version $Id: ElementNode.java,v 1.27 2006/06/29 10:47:30 ln156897 Exp $
0078: */
0079: public abstract class ElementNode extends CompositeNode implements
0080: SVGElement {
0081: /*
0082: * Constants for trait types.
0083: */
0084:
0085: /**
0086: * String trait type.
0087: */
0088: static final String TRAIT_TYPE_STRING = "string";
0089:
0090: /**
0091: * Float trait type.
0092: */
0093: static final String TRAIT_TYPE_FLOAT = "float";
0094:
0095: /**
0096: * SVGMatrix trait type.
0097: */
0098: static final String TRAIT_TYPE_SVG_MATRIX = "SVGMatrix";
0099:
0100: /**
0101: * SVGPath trait type.
0102: */
0103: static final String TRAIT_TYPE_SVG_PATH = "SVGPath";
0104:
0105: /**
0106: * SVGRect trait type
0107: */
0108: static final String TRAIT_TYPE_SVG_RECT = "SVGRect";
0109:
0110: /**
0111: * SVGRGBColor trait type.
0112: */
0113: static final String TRAIT_TYPE_SVG_RGB_COLOR = "SVGRGBColor";
0114:
0115: /**
0116: * See the SVG 1.1 specification
0117: */
0118: public static final int XML_SPACE_PRESERVE = 0;
0119:
0120: /**
0121: * See the SVG 1.1 specification
0122: */
0123: public static final int XML_SPACE_DEFAULT = 1;
0124:
0125: /**
0126: * Use the parent node's xml:space setting
0127: */
0128: public static final int XML_SPACE_INHERIT = 2;
0129:
0130: /**
0131: * Constant used to identify the per-element partition
0132: * (sometimes called anonymous) namespace.
0133: */
0134: static final String NULL_NS = "#!null/ns@!";
0135:
0136: /**
0137: * This node's id
0138: */
0139: protected String id = null;
0140:
0141: /**
0142: * This node's URI base
0143: */
0144: protected String uriBase = null;
0145:
0146: /**
0147: * This node's conditional attributes.
0148: */
0149: protected String[][] conditionalAttributes;
0150:
0151: /**
0152: * Index for requiredFeatures in conditionalAttributes.
0153: */
0154: public static final int REQUIRED_FEATURES_INDEX = 0;
0155:
0156: /**
0157: * Index for requiredExtensions in conditionalAttributes
0158: */
0159: public static final int REQUIRED_EXTENSIONS_INDEX = 1;
0160:
0161: /**
0162: * Index for systemLanguage in conditionalAttributes
0163: */
0164: public static final int SYSTEM_LANGUAGE_INDEX = 2;
0165:
0166: /**
0167: * Number of conditional attributes.
0168: */
0169: public static final int CONDITIONAl_ATTRIBUTES_LENGTH = 3;
0170:
0171: /**
0172: * The node's text white space handling policy
0173: */
0174: protected int xmlSpace = XML_SPACE_INHERIT;
0175:
0176: /**
0177: * Controls whether or not the node needs to be fully loaded
0178: * before it can be painted.
0179: */
0180: protected boolean paintNeedsLoad = false;
0181:
0182: /**
0183: * First node proxy. May be null.
0184: */
0185: protected ElementNodeProxy firstProxy;
0186:
0187: /**
0188: * Last node proxy. May be null.
0189: */
0190: protected ElementNodeProxy lastProxy;
0191:
0192: /**
0193: * Used to detect circular references when building
0194: * proxy chains.
0195: */
0196: protected boolean buildingProxy = false;
0197:
0198: /**
0199: * Maps namespaces to a map of (localName, TraitAnim)
0200: */
0201: protected Hashtable traitAnimsNS = null;
0202:
0203: /**
0204: * Only constructor.
0205: *
0206: * @param ownerDocument the document this node belongs to.
0207: * @throws IllegalArgumentException if the input ownerDocument is null
0208: */
0209: public ElementNode(final DocumentNode ownerDocument) {
0210:
0211: if (ownerDocument == null) {
0212: throw new IllegalArgumentException();
0213: }
0214:
0215: this .ownerDocument = ownerDocument;
0216: }
0217:
0218: /**
0219: * Returns the <code>ModelNode</code>, if any, hit by the
0220: * point at coordinate x/y in the proxy tree starting at
0221: * proxy.
0222: *
0223: * @param pt the x/y coordinate. Should never be null and be
0224: * of size two. If not, the behavior is unspecified.
0225: * The coordinates are in viewport space.
0226: * @param proxy the root of the proxy tree to test.
0227: * @return the <tt>ModelNode</tt> hit at the given point or null
0228: * if none was hit.
0229: */
0230: ModelNode proxyNodeHitAt(final float[] pt,
0231: final ElementNodeProxy proxy) {
0232: return null;
0233: }
0234:
0235: /**
0236: * Recomputes the transform cache on proxy nodes.
0237: */
0238: protected void recomputeProxyTransformState() {
0239: ElementNodeProxy proxy = firstProxy;
0240: while (proxy != null) {
0241: proxy.recomputeTransformState();
0242: proxy = proxy.nextProxy;
0243: }
0244: }
0245:
0246: /**
0247: * Invoked before an element is added to the document tree, to let the
0248: * element perform any validation it needs. For example, the use element
0249: * overrides this method to check that its reference is resolved.
0250: *
0251: * Note that the validate() method defined in some element implementations
0252: * is meant to perform validation after the nodes has been inserted into the
0253: * document tree.
0254: */
0255: protected void preValidate() {
0256: // By default, do nothing.
0257: }
0258:
0259: /**
0260: * By default, an <code>ElementNode</code> has no expanded content, so this
0261: * returns null.
0262: *
0263: * @return a reference to the node's first expanded child, or null if there
0264: * are no expanded children. This forces the computation of expanded
0265: * content if needed.
0266: */
0267: ModelNode getFirstExpandedChild() {
0268: return null;
0269: }
0270:
0271: /**
0272: * Some node types (such as <code>ElementNodeProxy</code>) have
0273: * expanded children that they compute in some specific
0274: * way depending on the implementation.
0275: *
0276: * @return a reference to the node's first expanded child, or null if there
0277: * are no expanded children.
0278: */
0279: public ModelNode getFirstComputedExpandedChild() {
0280: return null;
0281: }
0282:
0283: /**
0284: * By default, an <code>ElementNode</code> has no expanded content, so this
0285: * returns null.
0286: *
0287: * @return a reference to the node's last expanded child, or null if there
0288: * are no expanded children. This forces the computation of expanded
0289: * content if needed.
0290: */
0291: ModelNode getLastExpandedChild() {
0292: return null;
0293: }
0294:
0295: /**
0296: * Utility method. Unhooks the expanded content.
0297: */
0298: protected void unhookExpandedQuiet() {
0299: // No expanded content by default.
0300: }
0301:
0302: /**
0303: * Utility method. Unhooks the children.
0304: */
0305: protected void unhookChildrenQuiet() {
0306: super .unhookChildrenQuiet();
0307:
0308: // Need to clear the expanded content on proxies
0309: ElementNodeProxy proxy = firstProxy;
0310: while (proxy != null) {
0311: proxy.unhookExpandedQuiet();
0312: proxy = proxy.nextProxy;
0313: }
0314: }
0315:
0316: /**
0317: * By default, appending a text child does not do anything.
0318: *
0319: * @param text the text child to append to this node.
0320: */
0321: public void appendTextChild(final String text) {
0322: }
0323:
0324: /**
0325: * Adds a proxy to this node. When this node is modified, the
0326: * <code>ElementNodeProxy</code>'s corresponding modification
0327: * methods will be called so that modifications also gets reported
0328: * on the proxy.
0329: *
0330: * @param proxy new <code>ElementNodeProxy</code>
0331: * @throws NullPointerException if the input proxy is null.
0332: *
0333: * @see UpdateListener#modifiedNode
0334: * @see UpdateListener#modifyingNode
0335: * @see UpdateListener#nodeInserted
0336: */
0337: protected void addProxy(final ElementNodeProxy proxy) {
0338:
0339: if (proxy == null) {
0340: throw new NullPointerException();
0341: }
0342:
0343: if (firstProxy == null) {
0344: firstProxy = proxy;
0345: lastProxy = proxy;
0346: } else {
0347: lastProxy.nextProxy = proxy;
0348: proxy.prevProxy = lastProxy;
0349: lastProxy = proxy;
0350: }
0351: }
0352:
0353: /**
0354: * Removes a proxy from this node. If the input proxy is null,
0355: * or is not an existing proxy, this does nothing.
0356: *
0357: * @param proxy the <code>ElementNodeProxy</code> to remove.
0358: *
0359: * @see #addProxy
0360: */
0361: void removeProxy(final ElementNodeProxy proxy) {
0362: if (proxy == null || firstProxy == null) {
0363: return;
0364: }
0365:
0366: // The proxy may be the first one, the last
0367: // one, or in the middle
0368: if (proxy == firstProxy) {
0369: firstProxy = proxy.nextProxy;
0370: }
0371: if (proxy == lastProxy) {
0372: lastProxy = proxy.prevProxy;
0373: }
0374: if (proxy.prevProxy != null) {
0375: proxy.prevProxy.nextProxy = proxy.nextProxy;
0376: }
0377: if (proxy.nextProxy != null) {
0378: proxy.nextProxy.prevProxy = proxy.prevProxy;
0379: }
0380: }
0381:
0382: /**
0383: * Used to notify the <code>UpdateListener</code>, if any, of
0384: * an upcoming node modification
0385: *
0386: */
0387: protected void modifyingNode() {
0388: UpdateListener updateListener = getUpdateListener();
0389: if (updateListener != null) {
0390: updateListener.modifyingNode(this );
0391: }
0392:
0393: // During progressive rendering, a proxy may be hooked into
0394: // the tree while the referenced node is not. This is why we
0395: // need to notify proxies even if the node is not hooked into
0396: // the tree yet.
0397: ElementNodeProxy proxy = firstProxy;
0398: while (proxy != null) {
0399: proxy.modifyingProxied();
0400: proxy = proxy.nextProxy;
0401: }
0402: }
0403:
0404: /**
0405: * Used to notify the <code>UpdateListener</code>, if any, of
0406: * a completed node modification
0407: *
0408: */
0409: protected void modifiedNode() {
0410: UpdateListener updateListener = getUpdateListener();
0411: if (updateListener != null) {
0412: updateListener.modifiedNode(this );
0413: }
0414:
0415: // See comment in #modifyingNode.
0416: ElementNodeProxy proxy = firstProxy;
0417: while (proxy != null) {
0418: proxy.modifiedProxied();
0419: proxy = proxy.nextProxy;
0420: }
0421: }
0422:
0423: /**
0424: * Appends an element at the end of the list
0425: *
0426: * @param element the node to add to this <tt>CompositeNode</tt>
0427: * @throws NullPointerException if the input argument is null.
0428: */
0429: public void add(final ElementNode element) {
0430: super .add(element);
0431:
0432: ElementNodeProxy proxy = firstProxy;
0433: while (proxy != null) {
0434: proxy.proxiedChildAdded(element);
0435: proxy = proxy.nextProxy;
0436: }
0437: }
0438:
0439: /**
0440: * @return an adequate <code>ElementNodeProxy</code> for this node.
0441: */
0442: ElementNodeProxy buildProxy() {
0443: return new ElementNodeProxy(this );
0444: }
0445:
0446: /**
0447: * @return an adequate <code>ElementNodeProxy</code> for this node and
0448: * makes sure the content is expanded before returning.
0449: */
0450: protected ElementNodeProxy buildExpandedProxy() {
0451: if (buildingProxy) {
0452: // We ran into a circular reference.
0453: throw new IllegalStateException();
0454: }
0455: buildingProxy = true;
0456: ElementNodeProxy proxy = buildProxy();
0457: proxy.expand();
0458: buildingProxy = false;
0459: return proxy;
0460: }
0461:
0462: /**
0463: * @return the node's identifier
0464: */
0465: public String getId() {
0466: return id;
0467: }
0468:
0469: /**
0470: * @param newId the node's identifier
0471: *
0472: * @throws DOMException - with error code NO_MODIFICATION_ALLOWED_ERR is
0473: * raised if an attempt is made to change an existing Id.
0474: * @throws DOMException - with error code INVALID_ACCESS_ERR is raised if
0475: * the Id is not unique i.e. if this Id already exists in the document.
0476: *
0477: * @throws java.lang.NullPointerException - if Id is null.
0478: */
0479: public void setId(final String newId) {
0480: // Null ids are disallowed.
0481: if (newId == null) {
0482: throw new NullPointerException();
0483: }
0484:
0485: // If the id was already set, we cannot let it be modified.
0486: if (id != null) {
0487: throw new DOMException(
0488: DOMException.NO_MODIFICATION_ALLOWED_ERR, Messages
0489: .formatMessage(
0490: Messages.ERROR_CANNOT_MODIFY_ID,
0491: new String[] { newId, id,
0492: getLocalName(),
0493: getNamespaceURI() }));
0494: }
0495:
0496: // Now, check if there is any element with that id already.
0497: if (ownerDocument.getElementByIdAll(newId) != null) {
0498: ElementNode duplicateElement = (ElementNode) ownerDocument
0499: .getElementByIdAll(newId);
0500: throw new DOMException(
0501: DOMException.INVALID_ACCESS_ERR,
0502: Messages
0503: .formatMessage(
0504: Messages.ERROR_DUPLICATE_ID_VALUE,
0505: new String[] {
0506: newId,
0507: getLocalName(),
0508: getNamespaceURI(),
0509: duplicateElement
0510: .getLocalName(),
0511: duplicateElement
0512: .getNamespaceURI() }));
0513: }
0514:
0515: modifyingNode();
0516: id = newId;
0517:
0518: // We only declare the id in the global document
0519: // scope, i.e., we only consider the id to be
0520: // resolved, once the element is loaded, i.e., ready
0521: // to render. If the element is not loaded,
0522: // see the buildComplete method: it adds the element
0523: // to the list of identified nodes when loaded is
0524: // set to true.
0525: if (loaded && isInDocumentTree()) {
0526: ownerDocument.addIdentifiedNode(this );
0527: } else {
0528: ownerDocument.reserveId(this );
0529: }
0530: modifiedNode();
0531: }
0532:
0533: /**
0534: * When an Element is hooked into the document tree, it needs
0535: * to register as an identified node if it does have an id.
0536: */
0537: void nodeHookedInDocumentTree() {
0538: super .nodeHookedInDocumentTree();
0539:
0540: if (id != null) {
0541: ownerDocument.addIdentifiedNode(this );
0542: }
0543: }
0544:
0545: /**
0546: * The node's URI base to use to resolve URI references
0547: * If a URI base value was set on this node, then that value
0548: * is returned. Otherwise, this method returns the parent's
0549: * URI base.
0550: *
0551: * @return the node's URI base to use to resolve relative URI references.
0552: */
0553: public String getURIBase() {
0554: if (uriBase == null) {
0555: if (parent != null) {
0556: return parent.getURIBase();
0557: }
0558: return null;
0559: } else {
0560: if (uriBase.indexOf(":") != -1 || parent == null) {
0561: // This is not a relative URI, we can return this
0562: // value
0563: // - or -
0564: // There is no parent, return this relative URI
0565: // as the baseURI
0566: return uriBase;
0567: } else {
0568: // There is no scheme in this node's uri base.
0569: // We concatenate the uriBase to the one of the
0570: // parent.
0571: // This is done according to RFC 2396
0572: // (http://www.faqs.org/rfcs/rfc2396.html)
0573: String parentURIBase = parent.getURIBase();
0574: if (parentURIBase != null) {
0575: int lastSlashIndex = parentURIBase.lastIndexOf('/');
0576: if (lastSlashIndex != -1) {
0577: parentURIBase = parentURIBase.substring(0,
0578: lastSlashIndex);
0579: }
0580: return parentURIBase + '/' + uriBase;
0581: } else {
0582: return uriBase;
0583: }
0584: }
0585: }
0586: }
0587:
0588: /**
0589: * @param newUriBase the node's new URI base. The uriBase is used
0590: * to resolve relative URIs
0591: */
0592: public void setURIBase(final String newUriBase) {
0593: if (equal(newUriBase, uriBase)) {
0594: return;
0595: }
0596: modifyingNode();
0597: uriBase = newUriBase;
0598: modifiedNode();
0599: }
0600:
0601: /**
0602: * Controls how the node handles white spaces
0603: *
0604: * @param newXmlSpace should be one of XML_SPACE_DEFAULT,
0605: * XML_SPACE_PRESERVE, or XML_SPACE_INHERIT. Otherwise, an
0606: * IllegalArgumentException is thrown.
0607: */
0608: public void setXMLSpace(final int newXmlSpace) {
0609: if (newXmlSpace == xmlSpace) {
0610: return;
0611: }
0612: switch (newXmlSpace) {
0613: case XML_SPACE_DEFAULT:
0614: case XML_SPACE_PRESERVE:
0615: case XML_SPACE_INHERIT:
0616: modifyingNode();
0617: xmlSpace = newXmlSpace;
0618: modifiedNode();
0619: break;
0620: default:
0621: throw new IllegalArgumentException();
0622: }
0623: }
0624:
0625: /**
0626: * Defines how the node handles white spaces. Note that
0627: * if the value is set to null, the node should return
0628: * the value of its parent, as the xml:space attribute is
0629: * inherited.
0630: *
0631: * @return one of XML_SPACE_DEFAULT, XML_SPACE_PRESERVE
0632: */
0633: public int getXMLSpace() {
0634: if (xmlSpace != XML_SPACE_INHERIT) {
0635: return xmlSpace;
0636: } else {
0637: ModelNode ancestor = parent;
0638: while (ancestor != null) {
0639: if (ancestor instanceof ElementNode) {
0640: return ((ElementNode) parent).getXMLSpace();
0641: }
0642: ancestor = ancestor.parent;
0643: }
0644: return XML_SPACE_DEFAULT;
0645: }
0646: }
0647:
0648: /**
0649: * Returns true if the condition at the given index is equal to the input
0650: * value.
0651: */
0652: final boolean conditionEquals(final int index,
0653: final String[] conditionValue) {
0654: if (conditionValue == null) {
0655: return (conditionalAttributes == null)
0656: || (conditionalAttributes[index] == null);
0657: } else {
0658: return (conditionalAttributes != null)
0659: && (equal(conditionalAttributes[index],
0660: conditionValue));
0661: }
0662: }
0663:
0664: /**
0665: * The node will only render if the requiredFeatures string
0666: * evaluates to true. A null value will evaluate to true.
0667: *
0668: * @param newRequiredFeatures the set of features required for rendering
0669: * this node.
0670: */
0671: public void setRequiredFeatures(final String[] newRequiredFeatures) {
0672: setConditionalAttribute(REQUIRED_FEATURES_INDEX,
0673: newRequiredFeatures);
0674: }
0675:
0676: /**
0677: * Sets the new value for the given conditional attribute.
0678: *
0679: * @param index the conditional attribute index.
0680: * @param value the new conditional attribute value.
0681: */
0682: void setConditionalAttribute(final int index,
0683: final String[] newValue) {
0684: if (conditionEquals(index, newValue)) {
0685: return;
0686: }
0687: modifyingNode();
0688:
0689: if (newValue == null) {
0690: if (conditionalAttributes != null) {
0691: conditionalAttributes[index] = null;
0692: }
0693: } else {
0694: if (conditionalAttributes == null) {
0695: conditionalAttributes = new String[CONDITIONAl_ATTRIBUTES_LENGTH][];
0696: }
0697: conditionalAttributes[index] = newValue;
0698: }
0699:
0700: switch (index) {
0701: case REQUIRED_FEATURES_INDEX: {
0702: computeCanRenderRequiredFeaturesBit(newValue);
0703: ElementNodeProxy p = firstProxy;
0704: while (p != null) {
0705: p.computeCanRenderRequiredFeaturesBit(newValue);
0706: p = p.nextProxy;
0707: }
0708: }
0709: break;
0710: case REQUIRED_EXTENSIONS_INDEX: {
0711: computeCanRenderRequiredExtensionsBit(newValue);
0712: ElementNodeProxy p = firstProxy;
0713: while (p != null) {
0714: p.computeCanRenderRequiredExtensionsBit(newValue);
0715: p = p.nextProxy;
0716: }
0717: }
0718: break;
0719: default: {
0720: computeCanRenderSystemLanguageBit(newValue);
0721: ElementNodeProxy p = firstProxy;
0722: while (p != null) {
0723: p.computeCanRenderSystemLanguageBit(newValue);
0724: p = p.nextProxy;
0725: }
0726: }
0727: break;
0728: }
0729:
0730: modifiedNode();
0731: }
0732:
0733: /**
0734: * The node will only render if the required feature is
0735: * supported by Perseus.
0736: *
0737: * @return the array of features required for this node to
0738: * render.
0739: * @see #setRequiredFeatures
0740: */
0741: public String[] getRequiredFeatures() {
0742: return getConditionalAttribute(REQUIRED_FEATURES_INDEX);
0743: }
0744:
0745: /**
0746: * Returns the value of the conditional attribute with the given
0747: * index.
0748: *
0749: * @param index the conditional attribute index.
0750: * @return the conditional attribute value.
0751: */
0752: String[] getConditionalAttribute(final int index) {
0753: if (conditionalAttributes != null) {
0754: return conditionalAttributes[index];
0755: } else {
0756: return null;
0757: }
0758: }
0759:
0760: /**
0761: * The node will only render if the requiredExtensions string
0762: * evaluates to true. A null value evaluates to true.
0763: *
0764: * @param newRequiredExtensions the extensions which will be considered
0765: * a match for any document required extension.
0766: * @see #getRequiredExtensions
0767: */
0768: public void setRequiredExtensions(
0769: final String[] newRequiredExtensions) {
0770: setConditionalAttribute(REQUIRED_EXTENSIONS_INDEX,
0771: newRequiredExtensions);
0772: }
0773:
0774: /**
0775: * The node will only render if the required extension is supported
0776: * by Perseus.
0777: *
0778: * @return the extensions required to render this node
0779: * @see #setRequiredExtensions
0780: */
0781: public String[] getRequiredExtensions() {
0782: return getConditionalAttribute(REQUIRED_EXTENSIONS_INDEX);
0783: }
0784:
0785: /**
0786: * The node will only render if the Perseus user language matches
0787: * one of the values in this comma separated list. A null value is
0788: * a match.
0789: *
0790: * @param newSystemLanguage an array of languages which will be matched
0791: * against any document system language value
0792: */
0793: public void setSystemLanguage(final String[] newSystemLanguage) {
0794: setConditionalAttribute(SYSTEM_LANGUAGE_INDEX,
0795: newSystemLanguage);
0796: }
0797:
0798: /**
0799: * The node will only render if the Perseus user language matches
0800: * one of the values in this comma separated list. A null value is a
0801: * match.
0802: * @return the set of system languages.
0803: * @see #setSystemLanguage
0804: */
0805: public String[] getSystemLanguage() {
0806: return getConditionalAttribute(SYSTEM_LANGUAGE_INDEX);
0807: }
0808:
0809: /**
0810: * @return true if the node needs to be fully loaded before it
0811: * can be painted
0812: */
0813: public boolean getPaintNeedsLoad() {
0814: return paintNeedsLoad;
0815: }
0816:
0817: /**
0818: * @param paintNeedsLoad if true, the node can only be painted after its
0819: * children have been loaded. This can be used by a renderer
0820: * implementing progressive rendering of an SVG document.
0821: */
0822: public void setPreferedPaintNeedsLoad(final boolean paintNeedsLoad) {
0823: this .paintNeedsLoad = paintNeedsLoad;
0824: }
0825:
0826: /**
0827: * @return the namespace URI of the Node. By default, this returns
0828: * SVGConstants.SVG_NAMESPACE_URI.
0829: */
0830: public String getNamespaceURI() {
0831: return SVGConstants.SVG_NAMESPACE_URI;
0832: }
0833:
0834: /**
0835: * Returns the parent <code>Node</code> of this <code>Node</code>.
0836: *
0837: * @return the parent node or null if there is no parent (i.e. if a node has
0838: * just been created and not yet added to the tree, or if it has been
0839: * removed from the tree, this is null).
0840: * @throws SecurityException if the application does not have the necessary
0841: * privilege rights to access this (SVG) content.
0842: */
0843: public Node getParentNode() {
0844: return (Node) parent;
0845: }
0846:
0847: /**
0848: * Used by <code>DocumentNode</code> to create a new instance from
0849: * a prototype <code>ElementNode</code>.
0850: *
0851: * @param doc the <code>DocumentNode</code> for which a new node is
0852: * should be created.
0853: * @return a new <code>ElementNode</code> for the requested document.
0854: */
0855: public abstract ElementNode newInstance(final DocumentNode doc);
0856:
0857: /**
0858: * @return the first child element node of this element. <code>null</code>
0859: * if this element has no child elements.
0860: */
0861: public Element getFirstElementChild() {
0862: return (Element) firstChild;
0863: }
0864:
0865: /**
0866: * @return the next sibling element node of this element. <code>null</code>
0867: * if this element has no element sibling nodes that come after this one in
0868: * the document tree.
0869: */
0870: public Element getNextElementSibling() {
0871: // Casting is safe here because ElementNodes can only have ElementNode
0872: // siblings.
0873: return (Element) nextSibling;
0874: }
0875:
0876: /**
0877: * @return the previous sibling element node of this element. null if this
0878: * element has no element sibling nodes that come before this one in the
0879: * document tree.
0880: */
0881: public Element getPreviousElementSibling() {
0882: // Casting is safe here because ElementNodes can only have ElementNode
0883: // siblings.
0884: return (Element) prevSibling;
0885: }
0886:
0887: /**
0888: * @return the last child element node of this element. null if this element
0889: * has no child elements.
0890: */
0891: public Element getLastElementChild() {
0892: return (Element) lastChild;
0893: }
0894:
0895: /**
0896: * @param traitName the name of the trait which the element may support.
0897: * @return true if this element supports the given trait in one of the
0898: * trait accessor methods (such as <code>getTrait</code> or
0899: * <code>setFloatTrait</code>.
0900: */
0901: boolean supportsTrait(final String traitName) {
0902: if (SVGConstants.SVG_ID_ATTRIBUTE == traitName
0903: || SVGConstants.SVG_REQUIRED_FEATURES_ATTRIBUTE == traitName
0904: || SVGConstants.SVG_REQUIRED_EXTENSIONS_ATTRIBUTE == traitName
0905: || SVGConstants.SVG_SYSTEM_LANGUAGE_ATTRIBUTE == traitName) {
0906: return true;
0907: }
0908:
0909: return false;
0910: }
0911:
0912: /**
0913: * Checks if the input trait name is valid and throws a DOMException
0914: * with error code NOT_SUPPORTED_ERR if not.
0915: *
0916: * @param name the name whose syntax should be checked.
0917: * @throws DOMException with error code NOT_SUPPORTED_ERR if the
0918: * trait name is syntactically incorrect (e.g., null or containing
0919: * characters not conforming to the Namespaces in XML specification.
0920: *
0921: * @see http://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-NCName
0922: */
0923: final void checkNCName(final String name) throws DOMException {
0924: if (name == null || name.length() == 0) {
0925: throw unsupportedTrait(name);
0926: }
0927:
0928: // We should really validate that the name has the conforming syntax
0929: // But this slows down the load time considerably.
0930: //
0931: // NCName ::= (Letter | '_') (NCNameChar)*
0932: // NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar
0933: // | Extender
0934: }
0935:
0936: /**
0937: * @param traitNamespace the namespace of the trait for which a TraitAnim
0938: * is requested.
0939: * @param traitName the trait for which there may be a TraitAnimation.
0940: * @return the TraitAnim for the requested trait name.
0941: */
0942: TraitAnim getSafeTraitAnimNS(final String traitNamespace,
0943: final String traitName) {
0944: TraitAnim traitAnim = getTraitAnimNS(traitNamespace, traitName);
0945: if (traitAnim == null) {
0946: traitAnim = createTraitAnimNS(traitNamespace, traitName);
0947: }
0948:
0949: return traitAnim;
0950: }
0951:
0952: /**
0953: * @param traitNamespace the namespace of the trait for which a TraitAnim
0954: * is requested.
0955: * @param traitName the trait for which there may be a TraitAnimation.
0956: * @return the TraitAnim for the requested trait name.
0957: */
0958: TraitAnim getTraitAnimNS(String traitNamespace,
0959: final String traitName) {
0960: if (traitName == null) {
0961: throw new NullPointerException();
0962: }
0963:
0964: if (traitAnimsNS == null) {
0965: return null;
0966: }
0967:
0968: if (traitNamespace == null || traitNamespace.length() == 0) {
0969: traitNamespace = NULL_NS;
0970: }
0971:
0972: Hashtable nsTraitAnims = (Hashtable) traitAnimsNS
0973: .get(traitNamespace);
0974: if (nsTraitAnims != null) {
0975: return (TraitAnim) nsTraitAnims.get(traitName);
0976: }
0977: return null;
0978: }
0979:
0980: /**
0981: * @return an array of traits that are required by this element.
0982: */
0983: public String[] getRequiredTraits() {
0984: return null;
0985: }
0986:
0987: /**
0988: * @return an array of namespaceURI, localName trait pairs required by
0989: * this element.
0990: */
0991: public String[][] getRequiredTraitsNS() {
0992: return null;
0993: }
0994:
0995: /**
0996: * @return an array of trait default values, used if this element
0997: * requires that the default trait value be explicitly
0998: * set through a setTrait call. This happens, for example,
0999: * with the begin trait value on animation elements.
1000: */
1001: public String[][] getDefaultTraits() {
1002: return null;
1003: }
1004:
1005: /**
1006: * @return an array of trait aliases. These are used when the
1007: * value of a trait can be used to set the value of another trait.
1008: * For example, on a <rect>, if the rx trait is not specified in the
1009: * original XML document, the value fot eh ry trait should be used.
1010: */
1011: public String[][] getTraitAliases() {
1012: return null;
1013: }
1014:
1015: /**
1016: * Validates the input trait value.
1017: *
1018: * @param namespaceURI the trait's namespace URI.
1019: * @param traitName the name of the trait to be validated.
1020: * @param value the value to be validated
1021: * @param reqNamespaceURI the namespace of the element requesting
1022: * validation.
1023: * @param reqLocalName the local name of the element requesting validation.
1024: * @param reqTraitNamespace the namespace of the trait which has the values
1025: * value on the requesting element.
1026: * @param reqTraitName the name of the trait which has the values value on
1027: * the requesting element.
1028: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
1029: * value is incompatible with the given trait.
1030: *
1031: * @return the computed trait value.
1032: */
1033: String validateTraitNS(final String namespaceURI,
1034: final String traitName, final String value,
1035: final String reqNamespaceURI, final String reqLocalName,
1036: final String reqTraitNamespace, final String reqTraitName)
1037: throws DOMException {
1038: /*
1039: throw new InternalError(
1040: "Trying to validate unknown trait: " +
1041: "namespaceURI : " + namespaceURI + "\n" +
1042: "traitName : " + traitName + "\n" +
1043: "value : " + value + "\n" +
1044: "reqNamespaceURI : " + reqNamespaceURI + "\n" +
1045: "reqLocalName : " + reqLocalName + "\n" +
1046: "reqTraitNamespace : " + reqTraitNamespace + "\n" +
1047: "reqTraitName : " + reqTraitName);
1048: */
1049: return value;
1050: }
1051:
1052: /**
1053: * Validates the input trait value.
1054: *
1055: * @param traitName the name of the trait to be validated.
1056: * @param value the value to be validated
1057: * @param reqNamespaceURI the namespace of the element requesting
1058: * validation.
1059: * @param reqLocalName the local name of the element requesting validation.
1060: * @param reqTraitNamespace the namespace of the trait which has the values
1061: * value on the requesting element.
1062: * @param reqTraitName the name of the trait which has the values value on
1063: * the requesting element.
1064: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
1065: * value is incompatible with the given trait.
1066: */
1067: float[][] validateFloatArrayTrait(final String traitName,
1068: final String value, final String reqNamespaceURI,
1069: final String reqLocalName, final String reqTraitNamespace,
1070: final String reqTraitName) throws DOMException {
1071: // Throw an error because this should _never_ happen, as a float
1072: // array anim should only happen on a known trait. If validation is
1073: // requested, the element implementation should know the trait.
1074: throw new Error();
1075: }
1076:
1077: /**
1078: * @param namespaceURI the trait's namespace URI.
1079: * @param traitName the name of the trait which the element may support.
1080: * @return true if this element supports the given trait in one of the
1081: * trait accessor methods.
1082: */
1083: boolean supportsTraitNS(final String namespaceURI,
1084: final String traitName) {
1085: if (SVGConstants.PERSEUS_NAMESPACE_URI == namespaceURI
1086: && SVGConstants.PERSEUS_CHILDREN_REQUIRED_ATTRIBUTE == traitName) {
1087: return true;
1088: } else if (SVGConstants.XML_NAMESPACE_URI == namespaceURI
1089: && (SVGConstants.XML_BASE_ATTRIBUTE_LOCAL_NAME == traitName || SVGConstants.XML_SPACE_ATTRIBUTE_LOCAL_NAME == traitName)) {
1090: return true;
1091: }
1092:
1093: if (namespaceURI == null) {
1094: return supportsTrait(traitName);
1095: } else {
1096: return false;
1097: }
1098: }
1099:
1100: /**
1101: * The traits supported by default are: externalResourcesRequired,
1102: * xml:base, xml:space, requiredFeatures, requiredExtensions and
1103: * systemLanguage.
1104: *
1105: * Returns the trait value as String. In SVG Tiny only certain traits can be
1106: * obtained as a String value. Syntax of the returned String matches the
1107: * syntax of the corresponding attribute. This element is exactly equivalent
1108: * to {@link org.w3c.dom.svg.SVGElement#getTraitNS getTraitNS} with
1109: * namespaceURI set to null.
1110: *
1111: * The method is meant to be overridden by derived classes. The
1112: * implementation pattern is that derived classes will override the method
1113: * and call their super class' implementation. If the ElementNode
1114: * implementation is called, it means that the trait is either not supported
1115: * or that it cannot be seen as a String.
1116: *
1117: * @param name the requested trait name.
1118: * @return the trait value.
1119: *
1120: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1121: * trait is not supported on this element or null.
1122: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1123: * trait's computed value cannot be converted to a String (SVG Tiny only).
1124: */
1125: public final String getTrait(String traitName) throws DOMException {
1126: traitName = intern(traitName);
1127:
1128: if (!supportsTrait(traitName)) {
1129: throw unsupportedTrait(traitName);
1130: }
1131:
1132: TraitAnim anim = getTraitAnimNS(NULL_NS, traitName);
1133: if (anim == null || !anim.active) {
1134: return getTraitImpl(traitName);
1135: }
1136:
1137: // Get the computed trait value from the trait animation.
1138: return anim.getTrait(TRAIT_TYPE_STRING);
1139: }
1140:
1141: /**
1142: * Returns the specified trait value as String. In SVG Tiny only certain
1143: * traits can be obtained as a String value. Syntax of the returned String
1144: * matches the syntax of the corresponding attribute. This element is
1145: * exactly equivalent to {@link org.w3c.dom.svg.SVGElement#getTraitNS
1146: * getTraitNS} with namespaceURI set to null.
1147: *
1148: * The method is meant to be overridden by derived classes. The
1149: * implementation pattern is that derived classes will override the method
1150: * and call their super class' implementation. If the ElementNode
1151: * implementation is called, it means that the trait is either not supported
1152: * or that it cannot be seen as a String.
1153: *
1154: * @param traitNamespace the requested trait's namespace.
1155: * @param traitName the requested trait name.
1156: * @return the trait value.
1157: *
1158: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1159: * trait is not supported on this element or null.
1160: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1161: * trait's computed value cannot be converted to a String (SVG Tiny only).
1162: */
1163: String getSpecifiedTraitNSImpl(final String traitNamespace,
1164: final String traitName) throws DOMException {
1165: if (traitNamespace == null || traitNamespace == NULL_NS) {
1166: return getSpecifiedTraitImpl(traitName);
1167: }
1168:
1169: // Only xml:base behaves differently because the computed value
1170: // may be different from the specified value.
1171: if (SVGConstants.XML_NAMESPACE_URI == traitNamespace
1172: && SVGConstants.XML_BASE_ATTRIBUTE_LOCAL_NAME == traitName) {
1173: return uriBase;
1174: }
1175:
1176: return getTraitNSImpl(traitNamespace, traitName);
1177: }
1178:
1179: /**
1180: * Returns the specified trait value as String. In SVG Tiny only certain
1181: * traits can be obtained as a String value. Syntax of the returned String
1182: * matches the syntax of the corresponding attribute. This element is
1183: * exactly equivalent to {@link org.w3c.dom.svg.SVGElement#getTraitNS
1184: * getTraitNS} with namespaceURI set to null.
1185: *
1186: * The method is meant to be overridden by derived classes. The
1187: * implementation pattern is that derived classes will override the method
1188: * and call their super class' implementation. If the ElementNode
1189: * implementation is called, it means that the trait is either not supported
1190: * or that it cannot be seen as a String.
1191: *
1192: * @param traitName the requested trait name.
1193: * @return the trait value.
1194: *
1195: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1196: * trait is not supported on this element or null.
1197: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1198: * trait's computed value cannot be converted to a String (SVG Tiny only).
1199: */
1200: String getSpecifiedTraitImpl(final String traitName)
1201: throws DOMException {
1202: return getTraitImpl(traitName);
1203: }
1204:
1205: /**
1206: * The traits supported by default are: externalResourcesRequired,
1207: * xml:base, xml:space, requiredFeatures, requiredExtensions and
1208: * systemLanguage.
1209: *
1210: * Returns the trait value as String. In SVG Tiny only certain traits can be
1211: * obtained as a String value. Syntax of the returned String matches the
1212: * syntax of the corresponding attribute. This element is exactly equivalent
1213: * to {@link org.w3c.dom.svg.SVGElement#getTraitNS getTraitNS} with
1214: * namespaceURI set to null.
1215: *
1216: * The method is meant to be overridden by derived classes. The
1217: * implementation pattern is that derived classes will override the method
1218: * and call their super class' implementation. If the ElementNode
1219: * implementation is called, it means that the trait is either not supported
1220: * or that it cannot be seen as a String.
1221: *
1222: * @param name the requested trait name.
1223: * @return the trait value.
1224: *
1225: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1226: * trait is not supported on this element or null.
1227: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1228: * trait's computed value cannot be converted to a String (SVG Tiny only).
1229: */
1230: public String getTraitImpl(final String name) throws DOMException {
1231: if (SVGConstants.SVG_ID_ATTRIBUTE == name) {
1232: return getId();
1233: } else if (SVGConstants.SVG_REQUIRED_FEATURES_ATTRIBUTE == name) {
1234: return toStringTrait(getRequiredFeatures(), " ");
1235: } else if (SVGConstants.SVG_REQUIRED_EXTENSIONS_ATTRIBUTE == name) {
1236: return toStringTrait(getRequiredExtensions(), " ");
1237: } else if (SVGConstants.SVG_SYSTEM_LANGUAGE_ATTRIBUTE == name) {
1238: return toStringTrait(getSystemLanguage(), ",");
1239: } else {
1240: if (!supportsTrait(name)) {
1241: if (name == null) {
1242: throw unsupportedTrait(name);
1243: }
1244:
1245: String unknownTraitValue = ownerDocument
1246: .getUnknownTraitsNS(this , NULL_NS, name);
1247: if (unknownTraitValue != null) {
1248: return unknownTraitValue;
1249: } else {
1250: return "";
1251: }
1252: } else {
1253: throw unsupportedTraitType(name, TRAIT_TYPE_STRING);
1254: }
1255: }
1256: }
1257:
1258: /**
1259: * Implementation method.
1260: *
1261: * Creates a TraitAnim for the requested trait. This method does not
1262: * check whether or not there is an existing TraitAnim for the trait.
1263: * Instead, it creates a new TraitAnim and associates it with the
1264: * given trait. After this call, any call to getSafeTraitAnimNS or
1265: * getTraitAnimNS will return this new object.
1266: *
1267: * @param traitName the trait name.
1268: * @param traitNamespace the trait's namespace. Should not be null.
1269: */
1270: TraitAnim createTraitAnimNS(String traitNamespace,
1271: final String traitName) {
1272: if (traitNamespace == null || traitNamespace.length() == 0) {
1273: traitNamespace = NULL_NS;
1274: }
1275:
1276: TraitAnim traitAnim = null;
1277: if (NULL_NS == traitNamespace) {
1278: traitAnim = createTraitAnimImpl(traitName);
1279: } else {
1280: traitAnim = createTraitAnimNSImpl(traitNamespace, traitName);
1281: }
1282:
1283: if (traitAnimsNS == null) {
1284: traitAnimsNS = new Hashtable();
1285: }
1286:
1287: Hashtable nsTraitAnims = (Hashtable) traitAnimsNS
1288: .get(traitNamespace);
1289: if (nsTraitAnims == null) {
1290: nsTraitAnims = new Hashtable();
1291: traitAnimsNS.put(traitNamespace, nsTraitAnims);
1292: }
1293:
1294: nsTraitAnims.put(traitName, traitAnim);
1295: return traitAnim;
1296: }
1297:
1298: /**
1299: * To be overridden by derived classes. Should create the proper
1300: * TraitAnim type for the given trait in the anonymous namespace.
1301: *
1302: * @param traitName the trait name.
1303: */
1304: TraitAnim createTraitAnimImpl(final String traitName) {
1305: //
1306: // If the trait is supported but the element did not create
1307: // a TraitAnim in its implementation of createTraitAnimImpl,
1308: // it means the trait is not animatable.
1309: //
1310: if (supportsTrait(traitName)) {
1311: throw notAnimatable(null, traitName);
1312: }
1313:
1314: return new StringTraitAnim(this , NULL_NS, traitName);
1315: }
1316:
1317: /**
1318: * To be overridden by derived classes. Should create the proper
1319: * TraitAnim type for the given trait in the desired namespace.
1320: *
1321: * @param traitName the trait name.
1322: */
1323: TraitAnim createTraitAnimNSImpl(final String traitNamespace,
1324: final String traitName) {
1325: //
1326: // If the trait is supported but the element did not create
1327: // a TraitAnim in its implementation of createTraitAnimImpl,
1328: // it means the trait is not animatable.
1329: //
1330: if (supportsTraitNS(traitNamespace, traitName)) {
1331: throw notAnimatable(traitNamespace, traitName);
1332: }
1333:
1334: return new StringTraitAnim(this , traitNamespace, traitName);
1335: }
1336:
1337: /**
1338: * Same as {@link org.w3c.dom.svg.SVGElement#getTrait getTrait}, but for
1339: * namespaced traits. Parameter name must be a non-qualified trait name,
1340: * i.e. without prefix.
1341: *
1342: * @param namespaceURI the requested trait's namespace.
1343: * @param name the requested trait's local name (un-prefixed, e.g, 'href')
1344: *
1345: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1346: * trait is not supported on this element or null.
1347: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1348: * trait's computed value cannot be converted to a String (SVG Tiny only).
1349: * @throws SecurityException if the application does not have the necessary
1350: * privilege rights to access this (SVG) content.
1351: */
1352: public final String getTraitNS(String namespaceURI, String name)
1353: throws DOMException {
1354: if (namespaceURI == null) {
1355: return getTrait(name);
1356: }
1357:
1358: name = intern(name);
1359: namespaceURI = intern(namespaceURI);
1360:
1361: if (!supportsTraitNS(namespaceURI, name)) {
1362: throw unsupportedTraitNS(name, namespaceURI);
1363: }
1364:
1365: StringTraitAnim anim = (StringTraitAnim) getTraitAnimNS(
1366: namespaceURI, name);
1367: if (anim == null || !anim.active) {
1368: return getTraitNSImpl(namespaceURI, name);
1369: }
1370:
1371: return anim.getTrait(TRAIT_TYPE_STRING);
1372: }
1373:
1374: /**
1375: * Same as {@link org.w3c.dom.svg.SVGElement#getTrait getTrait}, but for
1376: * namespaced traits. Parameter name must be a non-qualified trait name,
1377: * i.e. without prefix.
1378: *
1379: * @param namespaceURI the requested trait's namespace.
1380: * @param name the requested trait's local name (un-prefixed, e.g, 'href')
1381: *
1382: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1383: * trait is not supported on this element or null.
1384: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1385: * trait's computed value cannot be converted to a String (SVG Tiny only).
1386: * @throws SecurityException if the application does not have the necessary
1387: * privilege rights to access this (SVG) content.
1388: */
1389: String getTraitNSImpl(String namespaceURI, String name) {
1390: if (SVGConstants.PERSEUS_NAMESPACE_URI == namespaceURI) {
1391: if (SVGConstants.PERSEUS_CHILDREN_REQUIRED_ATTRIBUTE == name) {
1392: if (paintNeedsLoad) {
1393: return SVGConstants.SVG_TRUE_VALUE;
1394: } else {
1395: return SVGConstants.SVG_FALSE_VALUE;
1396: }
1397: }
1398: } else if (SVGConstants.XML_NAMESPACE_URI == namespaceURI) {
1399: if (SVGConstants.XML_BASE_ATTRIBUTE_LOCAL_NAME == name) {
1400: return getURIBase();
1401: } else if (SVGConstants.XML_SPACE_ATTRIBUTE_LOCAL_NAME == name) {
1402: switch (getXMLSpace()) {
1403: case XML_SPACE_DEFAULT:
1404: return SVGConstants.XML_DEFAULT_VALUE;
1405: case XML_SPACE_PRESERVE:
1406: default:
1407: return SVGConstants.XML_PRESERVE_VALUE;
1408: }
1409: }
1410: }
1411:
1412: if (!supportsTraitNS(namespaceURI, name)) {
1413: String unknownTraitValue = ownerDocument
1414: .getUnknownTraitsNS(this , namespaceURI, name);
1415:
1416: if (unknownTraitValue != null) {
1417: return unknownTraitValue;
1418: }
1419:
1420: return "";
1421: } else {
1422: throw unsupportedTraitTypeNS(name, namespaceURI,
1423: TRAIT_TYPE_STRING);
1424: }
1425: }
1426:
1427: /**
1428: * @param name the requested trait's name.
1429: * @return the trait value as float.
1430: *
1431: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1432: * trait is not supported on this element or null.
1433: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1434: * trait's computed value cannot be converted to a float
1435: */
1436: public final float getFloatTrait(String name) throws DOMException {
1437: name = intern(name);
1438:
1439: if (!supportsTrait(name)) {
1440: throw unsupportedTrait(name);
1441: }
1442:
1443: TraitAnim anim = getTraitAnimNS(NULL_NS, name);
1444: if (anim == null || !anim.active) {
1445: return getFloatTraitImpl(name);
1446: }
1447:
1448: // Get the computed value from the trait animation.
1449: return parseFloatTrait(name, anim.getTrait(TRAIT_TYPE_FLOAT));
1450: }
1451:
1452: /**
1453: * @param name the requested trait's name.
1454: * @return the trait value as float.
1455: *
1456: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1457: * trait is not supported on this element or null.
1458: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1459: * trait's computed value cannot be converted to a float
1460: */
1461: float getFloatTraitImpl(final String name) {
1462: throw unsupportedTraitType(name, TRAIT_TYPE_FLOAT);
1463: }
1464:
1465: /**
1466: * Returns the trait value as {@link org.w3c.dom.svg.SVGMatrix SVGMatrix}.
1467: * The returned object is a copy of the actual trait value and will not
1468: * change ifthe corresponding trait changes.
1469: *
1470: * @param name matrix trait name.
1471: * @return the trait value corresponding to name as SVGMatrix.
1472: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1473: * trait is not supported on this element or null.
1474: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1475: * trait's computed value cannot be converted to {@link
1476: * org.w3c.dom.svg.SVGMatrix SVGMatrix}
1477: */
1478: public final SVGMatrix getMatrixTrait(String name)
1479: throws DOMException {
1480: name = intern(name);
1481:
1482: if (!supportsTrait(name)) {
1483: throw unsupportedTrait(name);
1484: }
1485:
1486: TraitAnim anim = getTraitAnimNS(NULL_NS, name);
1487: if (anim == null || !anim.active) {
1488: return getMatrixTraitImpl(name);
1489: }
1490:
1491: // Get the computed value from the trait animation
1492: SVGMatrix m = parseTransformTrait(name, anim
1493: .getTrait(TRAIT_TYPE_SVG_MATRIX));
1494:
1495: if (m == null) {
1496: m = new Transform(1, 0, 0, 1, 0, 0);
1497: }
1498:
1499: return m;
1500: }
1501:
1502: /**
1503: * Returns the trait value as {@link org.w3c.dom.svg.SVGMatrix SVGMatrix}.
1504: * The returned object is a copy of the actual trait value and will not
1505: * change ifthe corresponding trait changes.
1506: *
1507: * @param name matrix trait name.
1508: * @return the trait value corresponding to name as SVGMatrix.
1509: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1510: * trait is not supported on this element or null.
1511: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1512: * trait's computed value cannot be converted to {@link
1513: * org.w3c.dom.svg.SVGMatrix SVGMatrix}
1514: */
1515: SVGMatrix getMatrixTraitImpl(final String name) throws DOMException {
1516: throw unsupportedTraitType(name, TRAIT_TYPE_SVG_MATRIX);
1517: }
1518:
1519: /**
1520: * @param name the trait's name.
1521: * @return the trait value as {@link org.w3c.dom.svg.SVGRect SVGRect}. The
1522: * returned object is a copy of the actual trait value and will not change
1523: * if the corresponding trait changes.
1524: *
1525: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1526: * trait is not supported on this element or null.
1527: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1528: * trait's computed value cannot be converted to {@link
1529: * org.w3c.dom.svg.SVGRect SVGRect}
1530: */
1531: public final SVGRect getRectTrait(String name) throws DOMException {
1532: name = intern(name);
1533:
1534: if (!supportsTrait(name)) {
1535: throw unsupportedTrait(name);
1536: }
1537:
1538: TraitAnim anim = getTraitAnimNS(NULL_NS, name);
1539: if (anim == null || !anim.active) {
1540: return getRectTraitImpl(name);
1541: }
1542:
1543: // Get the computed value from the trait animation.
1544: return toSVGRect(toViewBox(name, anim
1545: .getTrait(TRAIT_TYPE_SVG_RECT)));
1546: }
1547:
1548: /**
1549: * @param name the trait's name.
1550: * @return the trait value as {@link org.w3c.dom.svg.SVGRect SVGRect}. The
1551: * returned object is a copy of the actual trait value and will not change
1552: * if the corresponding trait changes.
1553: *
1554: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1555: * trait is not supported on this element or null.
1556: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1557: * trait's computed value cannot be converted to {@link
1558: * org.w3c.dom.svg.SVGRect SVGRect}
1559: */
1560: SVGRect getRectTraitImpl(final String name) throws DOMException {
1561: throw unsupportedTraitType(name, TRAIT_TYPE_SVG_RECT);
1562: }
1563:
1564: /**
1565: * Returns the trait value as {@link org.w3c.dom.svg.SVGPath SVGPath}. The
1566: * returned object is a copy of the actual trait value and will not change
1567: * if the corresponding trait changes.
1568: *
1569: * @param name the trait's name.
1570: * @return the trait's value, as an <code>SVGPath</code> object.
1571: *
1572: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1573: * trait is not supported on this element or null.
1574: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1575: * trait's computed value cannot be converted to {@link
1576: * org.w3c.dom.svg.SVGPath SVGPath}
1577: */
1578: public final SVGPath getPathTrait(String name) throws DOMException {
1579: name = intern(name);
1580:
1581: if (!supportsTrait(name)) {
1582: throw unsupportedTrait(name);
1583: }
1584:
1585: TraitAnim anim = getTraitAnimNS(NULL_NS, name);
1586: if (anim == null || !anim.active) {
1587: return getPathTraitImpl(name);
1588: }
1589:
1590: // Get the computed value from the trait animation.
1591: return parsePathTrait(name, anim.getTrait(TRAIT_TYPE_SVG_PATH));
1592: }
1593:
1594: /**
1595: * Returns the trait value as {@link org.w3c.dom.svg.SVGPath SVGPath}. The
1596: * returned object is a copy of the actual trait value and will not change
1597: * if the corresponding trait changes.
1598: *
1599: * @param name the trait's name.
1600: * @return the trait's value, as an <code>SVGPath</code> object.
1601: *
1602: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1603: * trait is not supported on this element or null.
1604: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1605: * trait's computed value cannot be converted to {@link
1606: * org.w3c.dom.svg.SVGPath SVGPath}
1607: */
1608: SVGPath getPathTraitImpl(final String name) throws DOMException {
1609: throw unsupportedTraitType(name, TRAIT_TYPE_SVG_PATH);
1610: }
1611:
1612: /**
1613: * Returns the trait value as {@link org.w3c.dom.svg.SVGRGBColor
1614: * SVGRGBColor}. The returned object is a copy of the trait value and will
1615: * not change if the corresponding trait changes. If the actual trait value
1616: * is not an RGBColor (i.e. "none"), this method will return null.
1617: *
1618: * @param name the requested trait name.
1619: * @return the trait value, as an <code>SVGRGBColor</code> object.
1620: *
1621: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1622: * trait is not supported on this element or null.
1623: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1624: * trait's computed value cannot be converted to {@link
1625: * org.w3c.dom.svg.SVGRGBColor SVGRGBColor}
1626: */
1627: public final SVGRGBColor getRGBColorTrait(String name)
1628: throws DOMException {
1629: name = intern(name);
1630:
1631: if (!supportsTrait(name)) {
1632: throw unsupportedTrait(name);
1633: }
1634:
1635: TraitAnim anim = getTraitAnimNS(NULL_NS, name);
1636: if (anim == null || !anim.active) {
1637: return getRGBColorTraitImpl(name);
1638: }
1639:
1640: // Get the computed value from the trait animation
1641: return toSVGRGBColor(name, parseColorTrait(name, anim
1642: .getTrait(TRAIT_TYPE_SVG_RGB_COLOR)));
1643: }
1644:
1645: /**
1646: * Returns the trait value as {@link org.w3c.dom.svg.SVGRGBColor
1647: * SVGRGBColor}. The returned object is a copy of the trait value and will
1648: * not change if the corresponding trait changes. If the actual trait value
1649: * is not an RGBColor (i.e. "none"), this method will return null.
1650: *
1651: * @param name the requested trait name.
1652: * @return the trait value, as an <code>SVGRGBColor</code> object.
1653: *
1654: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1655: * trait is not supported on this element or null.
1656: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1657: * trait's computed value cannot be converted to {@link
1658: * org.w3c.dom.svg.SVGRGBColor SVGRGBColor}
1659: */
1660: SVGRGBColor getRGBColorTraitImpl(final String name)
1661: throws DOMException {
1662: throw unsupportedTraitType(name, TRAIT_TYPE_SVG_RGB_COLOR);
1663: }
1664:
1665: /**
1666: * Adds a new attribute.
1667: *
1668: * @param name - the name of the attribute to add.
1669: * @param value - the value to set.
1670: * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified name
1671: * contains an illegal character. NO_MODIFICATION_ALLOWED_ERR: Raised if
1672: * this node is readonly.
1673: */
1674: public final void setAttribute(String name, String value)
1675: throws DOMException {
1676: checkNCName(name);
1677:
1678: if (value == null) {
1679: throw illegalTraitValue(name, value);
1680: }
1681:
1682: name = name.intern();
1683: setTraitImpl(name, value);
1684: }
1685:
1686: /**
1687: * Returns the requested attribute.
1688: *
1689: * @param name - the name of the attribute to add.
1690: * @return the attribute value or empty string if the attribute is not
1691: * specified.
1692: * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified name
1693: * contains an illegal character.
1694: */
1695: public final String getAttribute(String name) throws DOMException {
1696: checkNCName(name);
1697:
1698: name = name.intern();
1699: return getTraitImpl(name);
1700: }
1701:
1702: /**
1703: * The traits supported by default are: externalResourcesRequired,
1704: * xml:base, xml:space, requiredFeatures, requiredExtensions and
1705: * systemLanguage.
1706: *
1707: * @param name the trait's name.
1708: * @param value the trait's value.
1709: *
1710: * @throws DOMException with error code NOT_SUPPORTED_ERR if the requested
1711: * trait is not supported on this element or null.
1712: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
1713: * trait's value cannot be specified as a String
1714: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
1715: * value is an invalid value for the given trait or null.
1716: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
1717: * attempt is made to change readonly trait.
1718: */
1719: public final void setTrait(String name, String value)
1720: throws DOMException {
1721: name = intern(name);
1722:
1723: if (!supportsTrait(name)) {
1724: throw unsupportedTrait(name);
1725: }
1726:
1727: if (value == null) {
1728: throw illegalTraitValue(name, value);
1729: }
1730:
1731: TraitAnim anim = (TraitAnim) getTraitAnimNS(NULL_NS, name);
1732:
1733: if (anim == null || !anim.active) {
1734: setTraitImpl(name, value);
1735: } else {
1736: anim.setTrait(value, TRAIT_TYPE_STRING);
1737: }
1738: }
1739:
1740: /**
1741: * The traits supported by default are: externalResourcesRequired,
1742: * xml:base, xml:space, requiredFeatures, requiredExtensions and
1743: * systemLanguage.
1744: *
1745: * @param name the trait's name.
1746: * @param value the trait's value.
1747: *
1748: * @throws DOMException with error code NOT_SUPPORTED_ERR if the requested
1749: * trait is not supported on this element or null.
1750: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
1751: * trait's value cannot be specified as a String
1752: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
1753: * value is an invalid value for the given trait or null.
1754: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
1755: * attempt is made to change readonly trait.
1756: */
1757: public void setTraitImpl(final String name, final String value)
1758: throws DOMException {
1759: if (SVGConstants.SVG_ID_ATTRIBUTE == name) {
1760: try {
1761: setId(value);
1762: } catch (IllegalArgumentException iae) {
1763: iae.printStackTrace();
1764: throw illegalTraitValue(name, value);
1765: }
1766: } else if (SVGConstants.SVG_REQUIRED_FEATURES_ATTRIBUTE == name) {
1767: if (value == null) {
1768: throw illegalTraitValue(name, value);
1769: }
1770: setRequiredFeatures(parseStringArrayTrait(name, value, " "));
1771: } else if (SVGConstants.SVG_REQUIRED_EXTENSIONS_ATTRIBUTE == name) {
1772: if (value == null) {
1773: throw illegalTraitValue(name, value);
1774: }
1775: setRequiredExtensions(parseStringArrayTrait(name, value,
1776: " "));
1777: } else if (SVGConstants.SVG_SYSTEM_LANGUAGE_ATTRIBUTE == name) {
1778: if (value == null) {
1779: throw illegalTraitValue(name, value);
1780: }
1781: setSystemLanguage(parseStringArrayTrait(name, value, ","));
1782: } else {
1783: // The trait is not handled by this element as a string.
1784: // There are two situations. If this trait is supported
1785: // by the element, then it means that the String type is
1786: // not supported for the trait, and the following throws an
1787: // exception. Otherwise, this means the trait is just unknown,
1788: // and it goes into the generic trait map.
1789: if (supportsTrait(name)) {
1790: throw unsupportedTraitType(name, TRAIT_TYPE_STRING);
1791: } else {
1792: if (name == null) {
1793: throw unsupportedTrait(name);
1794: }
1795:
1796: if (value == null) {
1797: throw illegalTraitValue(name, value);
1798: }
1799:
1800: ownerDocument.setUnknownTraitsNS(this , NULL_NS, name,
1801: value);
1802: }
1803: }
1804: }
1805:
1806: /**
1807: * Adds a new attribute.
1808: *
1809: * @param namespaceURI - the namespace URI of the attribute to create or
1810: * alter.
1811: * @param name - the local name of the attribute to create or alter.
1812: * @param value - the value to set in string form.
1813: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
1814: * value is an invalid value for the given trait or null.
1815: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
1816: * attempt is made to change readonly trait.
1817: */
1818: public final void setAttributeNS(String namespaceURI, String name,
1819: String value) throws DOMException {
1820: if (namespaceURI == null || namespaceURI.length() == 0) {
1821: setAttribute(name, value);
1822: return;
1823: }
1824:
1825: checkNCName(name);
1826:
1827: if (value == null) {
1828: throw illegalTraitValue(name, namespaceURI, value);
1829: }
1830:
1831: namespaceURI = namespaceURI.intern();
1832: name = name.intern();
1833:
1834: setTraitNSImpl(namespaceURI, name, value);
1835: }
1836:
1837: /**
1838: * Returns the requested attribute in the specified namespace.
1839: *
1840: * @param namespaceURI - the namespace URI of the attribute to create or
1841: * alter.
1842: * @param name - the local name of the attribute to create or alter.
1843: * @return the attribute value as a string, or the empty string if the
1844: * attribute was not specified.
1845: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
1846: * value is an invalid value for the given trait or null.
1847: */
1848: public final String getAttributeNS(String namespaceURI, String name)
1849: throws DOMException {
1850: if (namespaceURI == null || namespaceURI.length() == 0) {
1851: return getAttribute(name);
1852: }
1853:
1854: checkNCName(name);
1855:
1856: namespaceURI = namespaceURI.intern();
1857: name = name.intern();
1858:
1859: return getTraitNSImpl(namespaceURI, name);
1860: }
1861:
1862: /*
1863: * Same as {@link org.w3c.dom.svg.SVGElement#setTrait setTrait}, but for
1864: * namespaced traits. Parameter name must be a non-qualified trait name,
1865: * i.e. without prefix.
1866: *
1867: * @param namespaceURI the trait's namespace.
1868: * @param name the trait's local name (un-prefixed).
1869: * @param value the trait's value.
1870: *
1871: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1872: * trait is not supported on this element or null.
1873: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
1874: * trait's value cannot be specified as a String
1875: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
1876: * value is an invalid value for the given trait or null.
1877: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
1878: * attempt is made to change readonly trait.
1879: */
1880:
1881: public final void setTraitNS(String namespaceURI, String name,
1882: String value) throws DOMException {
1883: if (namespaceURI == null || namespaceURI.length() == 0) {
1884: setTrait(name, value);
1885: return;
1886: }
1887:
1888: namespaceURI = intern(namespaceURI);
1889: name = intern(name);
1890:
1891: if (!supportsTraitNS(namespaceURI, name)) {
1892: throw unsupportedTraitNS(name, namespaceURI);
1893: }
1894:
1895: StringTraitAnim anim = (StringTraitAnim) getTraitAnimNS(
1896: namespaceURI, name);
1897:
1898: if (anim == null || !anim.active) {
1899: setTraitNSImpl(namespaceURI, name, value);
1900: } else {
1901: anim.setTrait(value, TRAIT_TYPE_STRING);
1902: }
1903: }
1904:
1905: /**
1906: * Same as {@link org.w3c.dom.svg.SVGElement#setTrait setTrait}, but for
1907: * namespaced traits. Parameter name must be a non-qualified trait name,
1908: * i.e. without prefix.
1909: *
1910: * @param namespaceURI the trait's namespace.
1911: * @param name the trait's local name (un-prefixed).
1912: * @param value the trait's value.
1913: *
1914: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1915: * trait is not supported on this element or null.
1916: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
1917: * trait's value cannot be specified as a String
1918: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
1919: * value is an invalid value for the given trait or null.
1920: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
1921: * attempt is made to change readonly trait.
1922: */
1923: public void setTraitNSImpl(final String namespaceURI,
1924: final String name, final String value) throws DOMException {
1925: if (SVGConstants.PERSEUS_NAMESPACE_URI == namespaceURI) {
1926: if (SVGConstants.PERSEUS_CHILDREN_REQUIRED_ATTRIBUTE == name) {
1927: if (SVGConstants.SVG_TRUE_VALUE.equals(value)) {
1928: setPreferedPaintNeedsLoad(true);
1929: return;
1930: } else if (SVGConstants.SVG_FALSE_VALUE.equals(value)) {
1931: setPreferedPaintNeedsLoad(false);
1932: return;
1933: } else {
1934: throw illegalTraitValue(namespaceURI, name, value);
1935: }
1936: }
1937: } else if (SVGConstants.XML_NAMESPACE_URI == namespaceURI) {
1938: if (SVGConstants.XML_BASE_ATTRIBUTE_LOCAL_NAME == name) {
1939: if (value == null) {
1940: throw illegalTraitValue(name, value);
1941: }
1942: setURIBase(value);
1943: } else if (SVGConstants.XML_SPACE_ATTRIBUTE_LOCAL_NAME == name) {
1944: if (SVGConstants.XML_DEFAULT_VALUE.equals(value)
1945: || (value != null && value.length() == 0)) {
1946: setXMLSpace(XML_SPACE_DEFAULT);
1947: return;
1948: } else if (SVGConstants.XML_PRESERVE_VALUE
1949: .equals(value)) {
1950: setXMLSpace(XML_SPACE_PRESERVE);
1951: return;
1952: } else {
1953: throw illegalTraitValue(name, value);
1954: }
1955: }
1956: }
1957:
1958: // The trait is not handled by this element as a string.
1959: // There are two situations. If this trait is supported
1960: // by the element, then it means that the String type is
1961: // not supported for the trait which should never happen
1962: // because all traits have to be supported as a string.
1963: // So that causes an internal error.
1964: // Otherwise, this means the trait is just unknown,
1965: // and it goes into the generic trait map.
1966: if (supportsTraitNS(name, value)) {
1967: throw new Error();
1968: }
1969:
1970: // Trait is unknown, treat as a generic string trait.
1971: ownerDocument.setUnknownTraitsNS(this , namespaceURI, name,
1972: value);
1973: }
1974:
1975: /**
1976: * Set the trait value as float.
1977: *
1978: * @param name the trait's name.
1979: * @param value the trait's value.
1980: *
1981: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1982: * trait is not supported on this element.
1983: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
1984: * trait's value cannot be specified as a float
1985: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
1986: * value is an invalid value for the given trait.
1987: */
1988: public final void setFloatTrait(String name, float value)
1989: throws DOMException {
1990: name = intern(name);
1991:
1992: if (!supportsTrait(name)) {
1993: throw unsupportedTrait(name);
1994: }
1995:
1996: TraitAnim anim = (TraitAnim) getTraitAnimNS(NULL_NS, name);
1997: if (anim == null || !anim.active) {
1998: setFloatTraitImpl(name, value);
1999: } else {
2000: anim.setTrait(Float.toString(value), TRAIT_TYPE_FLOAT);
2001: }
2002: }
2003:
2004: /**
2005: * Converts the input float array value to a String value.
2006: *
2007: * @param traitName the name of the trait to convert.
2008: * @param value the float trait value to convert.
2009: */
2010: String toStringTrait(final String traitName, final float[][] value) {
2011: throw new Error(traitName);
2012: }
2013:
2014: /**
2015: * Conversts the input PaintServer value to a String trait value.
2016: *
2017: * @param value the PaintServer value to convert.
2018: */
2019: String toString(final PaintServer paintServer) {
2020: if (paintServer == null) {
2021: return SVGConstants.CSS_NONE_VALUE;
2022: }
2023:
2024: return paintServer.toString();
2025: }
2026:
2027: /**
2028: * Set the trait value as float.
2029: *
2030: * @param name the trait's name.
2031: * @param value the trait's value.
2032: *
2033: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
2034: * trait is not supported on this element.
2035: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
2036: * trait's value cannot be specified as a float
2037: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2038: * value is an invalid value for the given trait.
2039: */
2040: void setFloatArrayTrait(final String name, final float[][] value)
2041: throws DOMException {
2042: throw new Error(name);
2043: }
2044:
2045: /**
2046: * Set the trait value as a float.
2047: *
2048: * @param name the trait's name.
2049: * @param value the trait's value.
2050: *
2051: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
2052: * trait is not supported on this element.
2053: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
2054: * trait's value cannot be specified as a float
2055: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2056: * value is an invalid value for the given trait.
2057: */
2058: void setFloatTraitImpl(final String name, final float value) {
2059: throw unsupportedTraitType(name, TRAIT_TYPE_FLOAT);
2060: }
2061:
2062: /**
2063: * Set the trait value as {@link org.w3c.dom.svg.SVGMatrix SVGMatrix}.
2064: * Values in SVGMarix are copied in the trait so subsequent changes to the
2065: * givenSVGMatrix have no effect on the value of the trait.
2066: *
2067: * @param name name of trait to set
2068: * @param matrix SVGMatrix value of trait
2069: *
2070: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
2071: * trait is not supported on this element or null.
2072: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
2073: * trait's value cannot be specified as an {@link org.w3c.dom.svg.SVGMatrix
2074: * SVGMatrix}
2075: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2076: * value is an invalid value for the given trait or null.
2077: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
2078: * attempt is made to change readonly trait.
2079: */
2080: public final void setMatrixTrait(String name, final SVGMatrix matrix)
2081: throws DOMException {
2082: name = intern(name);
2083:
2084: if (!supportsTrait(name)) {
2085: throw unsupportedTrait(name);
2086: }
2087:
2088: if (matrix == null) {
2089: throw illegalTraitValue(name, null);
2090: }
2091:
2092: TraitAnim anim = (TraitAnim) getTraitAnimNS(NULL_NS, name);
2093: if (anim == null || !anim.active) {
2094: setMatrixTraitImpl(name, new Transform(matrix));
2095: } else {
2096: anim.setTrait(toStringTrait((Transform) matrix),
2097: TRAIT_TYPE_SVG_MATRIX);
2098: }
2099: }
2100:
2101: /**
2102: * Set the trait value as {@link org.w3c.dom.svg.SVGMatrix SVGMatrix}.
2103: * Values in SVGMarix are copied in the trait so subsequent changes to the
2104: * givenSVGMatrix have no effect on the value of the trait.
2105: *
2106: * @param name name of trait to set
2107: * @param matrix Transform value of trait
2108: *
2109: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
2110: * trait is not supported on this element or null.
2111: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
2112: * trait's value cannot be specified as an {@link org.w3c.dom.svg.SVGMatrix
2113: * SVGMatrix}
2114: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2115: * value is an invalid value for the given trait or null.
2116: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
2117: * attempt is made to change readonly trait.
2118: */
2119: void setMatrixTraitImpl(final String name, final Transform matrix)
2120: throws DOMException {
2121: throw unsupportedTraitType(name, TRAIT_TYPE_SVG_MATRIX);
2122: }
2123:
2124: /**
2125: * Set the trait value as {@link org.w3c.dom.svg.SVGRect SVGRect}. Values in
2126: * SVGRect are copied in the trait so subsequent changes to the given
2127: * SVGRect have no effect on the value of the trait.
2128: *
2129: * @param name the trait name.
2130: * @param rect the trait value, as an <code>SVGRect</code> object.
2131: *
2132: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
2133: * trait is not supported on this element or null.
2134: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
2135: * trait's value cannot be specified as an {@link org.w3c.dom.svg.SVGRect
2136: * SVGRect}
2137: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2138: * value is an invalid value for the given trait or null. SVGRect is
2139: * invalid if the width or height values are set to negative.
2140: */
2141: public final void setRectTrait(String name, final SVGRect rect)
2142: throws DOMException {
2143: name = intern(name);
2144:
2145: if (!supportsTrait(name)) {
2146: throw unsupportedTrait(name);
2147: }
2148:
2149: TraitAnim anim = (TraitAnim) getTraitAnimNS(NULL_NS, name);
2150: if (anim == null || !anim.active) {
2151: setRectTraitImpl(name, rect);
2152: } else {
2153: if (rect == null) {
2154: throw illegalTraitValue(name, null);
2155: }
2156:
2157: float[] vb = { rect.getX(), rect.getY(), rect.getWidth(),
2158: rect.getHeight() };
2159:
2160: anim.setTrait(toStringTrait(vb), TRAIT_TYPE_SVG_RECT);
2161: }
2162: }
2163:
2164: /**
2165: * Set the trait value as {@link org.w3c.dom.svg.SVGRect SVGRect}. Values in
2166: * SVGRect are copied in the trait so subsequent changes to the given
2167: * SVGRect have no effect on the value of the trait.
2168: *
2169: * @param name the trait name.
2170: * @param rect the trait value, as an <code>SVGRect</code> object.
2171: *
2172: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
2173: * trait is not supported on this element or null.
2174: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
2175: * trait's value cannot be specified as an {@link org.w3c.dom.svg.SVGRect
2176: * SVGRect}
2177: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2178: * value is an invalid value for the given trait or null. SVGRect is
2179: * invalid if the width or height values are set to negative.
2180: */
2181: public void setRectTraitImpl(final String name, final SVGRect rect)
2182: throws DOMException {
2183: throw unsupportedTraitType(name, TRAIT_TYPE_SVG_RECT);
2184: }
2185:
2186: /**
2187: * Set the trait value as {@link org.w3c.dom.svg.SVGPath SVGPath}. Values in
2188: * SVGPath are copied in the trait so subsequent changes to the given
2189: * SVGPath have no effect on the value of the trait.
2190: *
2191: * @param name the trait name.
2192: * @param path the trait value, as an <code>SVGPath</code> object.
2193: *
2194: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
2195: * trait is not supported on this element or null.
2196: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
2197: * trait's value cannot be specified as an {@link org.w3c.dom.svg.SVGPath
2198: * SVGPath}
2199: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2200: * value is an invalid value for the given trait or null. SVGPath is
2201: * invalid if it does not begin with a MOVE_TO segment.
2202: */
2203: public final void setPathTrait(String name, final SVGPath path)
2204: throws DOMException {
2205: name = intern(name);
2206:
2207: if (!supportsTrait(name)) {
2208: throw unsupportedTrait(name);
2209: }
2210:
2211: if (path == null) {
2212: throw illegalTraitValue(name, null);
2213: }
2214:
2215: TraitAnim anim = (TraitAnim) getTraitAnimNS(NULL_NS, name);
2216: if (anim == null || !anim.active) {
2217: setPathTraitImpl(name, path);
2218: } else {
2219: if (path == null) {
2220: throw illegalTraitValue(name, null);
2221: }
2222: anim
2223: .setTrait(((Path) path).toString(),
2224: TRAIT_TYPE_SVG_PATH);
2225: }
2226: }
2227:
2228: /**
2229: * Set the trait value as {@link org.w3c.dom.svg.SVGPath SVGPath}. Values in
2230: * SVGPath are copied in the trait so subsequent changes to the given
2231: * SVGPath have no effect on the value of the trait.
2232: *
2233: * @param name the trait name.
2234: * @param path the trait value, as an <code>SVGPath</code> object.
2235: *
2236: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
2237: * trait is not supported on this element or null.
2238: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
2239: * trait's value cannot be specified as an {@link org.w3c.dom.svg.SVGPath
2240: * SVGPath}
2241: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2242: * value is an invalid value for the given trait or null. SVGPath is
2243: * invalid if it does not begin with a MOVE_TO segment.
2244: */
2245: void setPathTraitImpl(final String name, final SVGPath path)
2246: throws DOMException {
2247: throw unsupportedTraitType(name, TRAIT_TYPE_SVG_PATH);
2248: }
2249:
2250: /**
2251: * Set the trait value as {@link org.w3c.dom.svg.SVGRGBColor SVGRGBColor}.
2252: *
2253: * @param name the trait name.
2254: * @param color the trait value, as a color.
2255: *
2256: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
2257: * trait is not supported on this element or null.
2258: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
2259: * trait's value cannot be specified as an {@link
2260: * org.w3c.dom.svg.SVGRGBColor SVGRGBColor}
2261: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2262: * value is null.
2263: */
2264: public final void setRGBColorTrait(String name,
2265: final SVGRGBColor color) throws DOMException {
2266: name = intern(name);
2267:
2268: if (!supportsTrait(name)) {
2269: throw unsupportedTrait(name);
2270: }
2271:
2272: if (color == null) {
2273: throw illegalTraitValue(name, null);
2274: }
2275:
2276: TraitAnim anim = (TraitAnim) getTraitAnimNS(NULL_NS, name);
2277: if (anim == null || !anim.active) {
2278: setRGBColorTraitImpl(name, color);
2279: } else {
2280: anim.setTrait(color.toString(), TRAIT_TYPE_SVG_RGB_COLOR);
2281: }
2282:
2283: }
2284:
2285: /**
2286: * Set the trait value as {@link org.w3c.dom.svg.SVGRGBColor SVGRGBColor}.
2287: *
2288: * @param name the trait name.
2289: * @param color the trait value, as a color.
2290: *
2291: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
2292: * trait is not supported on this element or null.
2293: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
2294: * trait's value cannot be specified as an {@link
2295: * org.w3c.dom.svg.SVGRGBColor SVGRGBColor}
2296: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2297: * value is null.
2298: */
2299: void setRGBColorTraitImpl(final String name, final SVGRGBColor color)
2300: throws DOMException {
2301: throw unsupportedTraitType(name, TRAIT_TYPE_SVG_RGB_COLOR);
2302: }
2303:
2304: /**
2305: * Parses the input value and converts it to a String array.
2306: *
2307: * @param value the value to convert to a String array
2308: * @param name the name of the trait being converted.
2309: * @param seperators the string of characters which are seperators
2310: * between array values.
2311: */
2312: protected final String[] parseStringArrayTrait(final String name,
2313: final String value, final String seperators)
2314: throws DOMException {
2315: // Don't accept null trait values.
2316: if (value == null) {
2317: throw illegalTraitValue(name, value);
2318: }
2319:
2320: SimpleTokenizer st = new SimpleTokenizer(value, seperators);
2321: int n = st.countTokens();
2322: String[] result = new String[n];
2323: for (int i = 0; i < n; i++) {
2324: result[i] = st.nextToken().trim().intern();
2325: }
2326:
2327: return result;
2328: }
2329:
2330: /**
2331: * Parses the input value and converts it to a float value.
2332: *
2333: * @param name the name of the trait to convert to a float.
2334: * @param value the value to convert to a float.
2335: * @return the value converted to a float value.
2336: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2337: * value is an invalid float value or null.
2338: */
2339: protected final float parseFloatTrait(final String name,
2340: final String value) throws DOMException {
2341: try {
2342: return ownerDocument.lengthParser.parseNumber(value);
2343: } catch (IllegalArgumentException iae) {
2344: throw illegalTraitValue(name, value);
2345: }
2346: }
2347:
2348: /**
2349: * Parses the input value and converts it to a float array value.
2350: *
2351: * @param name the name of the trait to convert to a float array.
2352: * @param value the value to convert to a float.
2353: * @return the value converted to a float array value.
2354: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2355: * value is an invalid float value or null.
2356: */
2357: protected final float[] parsePositiveFloatArrayTrait(
2358: final String name, final String value) throws DOMException {
2359: try {
2360: SimpleTokenizer st = new SimpleTokenizer(value, ", ");
2361: float[] da = null;
2362: int n = st.countTokens();
2363: float totalLength = 0;
2364:
2365: if ((n % 2) == 0) {
2366: da = new float[n];
2367: for (int i = 0; i < da.length; i++) {
2368: da[i] = ownerDocument.lengthParser.parseNumber(st
2369: .nextToken());
2370:
2371: if (Float.isNaN(da[i]) || da[i] < 0) {
2372: // The CSS number was invalid.
2373: // Do not set the value
2374: throw new IllegalArgumentException();
2375: }
2376:
2377: totalLength += da[i];
2378: }
2379: } else {
2380: da = new float[2 * n];
2381: for (int i = 0; i < n; i++) {
2382: da[i] = ownerDocument.lengthParser.parseNumber(st
2383: .nextToken());
2384: da[n + i] = da[i];
2385:
2386: if (Float.isNaN(da[i]) || da[i] < 0) {
2387: // The CSS number was invalid.
2388: // Do not set the value
2389: throw new IllegalArgumentException();
2390: }
2391:
2392: totalLength += da[i];
2393: }
2394: }
2395:
2396: if (totalLength > 0) {
2397: return da;
2398: } else {
2399: return null;
2400: }
2401: } catch (IllegalArgumentException iae) {
2402: throw illegalTraitValue(name, value);
2403: } catch (NullPointerException iae) {
2404: throw illegalTraitValue(name, value);
2405: }
2406: }
2407:
2408: /**
2409: * Parses the input value and converts it to a positive float value.
2410: *
2411: * @param name the trait name.
2412: * @param value the value to convert to a float.
2413: * @return the value converted to a float value.
2414: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2415: * value is an invalid positive float value or null.
2416: */
2417: protected final float parsePositiveFloatTrait(final String name,
2418: final String value) throws DOMException {
2419: try {
2420: float v = ownerDocument.lengthParser.parseNumber(value);
2421: if (v < 0) {
2422: throw new IllegalArgumentException();
2423: }
2424: return v;
2425: } catch (IllegalArgumentException iae) {
2426: throw illegalTraitValue(name, value);
2427: }
2428: }
2429:
2430: /**
2431: * Parses the input value and converts it to a float.
2432: *
2433: * @param name the trait name.
2434: * @param value the value to convert to a float.
2435: * @param isHorizontal controls whether this is a horizontal length or not.
2436: * @return the value converted to a float.
2437: * @throws DOMException if the trait value is invalid.
2438: */
2439: protected final float parseLengthTrait(final String name,
2440: final String value, boolean isHorizontal)
2441: throws DOMException {
2442: try {
2443: Length l = ownerDocument.lengthParser.parseLength(value);
2444: switch (l.unit) {
2445: case Length.SVG_LENGTHTYPE_NUMBER:
2446: return l.value;
2447: case Length.SVG_LENGTHTYPE_IN:
2448: return (l.value * 25.4f / ownerDocument
2449: .getPixelMMSize());
2450: case Length.SVG_LENGTHTYPE_CM:
2451: return (l.value * 10f / ownerDocument.getPixelMMSize());
2452: case Length.SVG_LENGTHTYPE_MM:
2453: return (l.value / ownerDocument.getPixelMMSize());
2454: case Length.SVG_LENGTHTYPE_PT:
2455: return (l.value * 25.4f / (72f * ownerDocument
2456: .getPixelMMSize()));
2457: case Length.SVG_LENGTHTYPE_PC:
2458: return (l.value * 25.4f / (6f * ownerDocument
2459: .getPixelMMSize()));
2460: case Length.SVG_LENGTHTYPE_PERCENTAGE:
2461: if (isHorizontal) {
2462: return ownerDocument.width * l.value / 100f;
2463: } else {
2464: return ownerDocument.height * l.value / 100f;
2465: }
2466: default:
2467: // This should never happen.
2468: throw new Error();
2469: }
2470: } catch (IllegalArgumentException iae) {
2471: throw illegalTraitValue(name, value);
2472: }
2473: }
2474:
2475: /**
2476: * Parses the input value and converts it to a float.
2477: * @param name the trait name.
2478: * @param value the value to convert to a float.
2479: * @param isHorizontal controls whether this is a horizontal length or not.
2480: * @return the value converted to a float.
2481: * @throws DOMException if the trait value is invalid.
2482: */
2483: protected final float parsePositiveLengthTrait(final String name,
2484: final String value, final boolean isHorizontal)
2485: throws DOMException {
2486: float v = parseLengthTrait(name, value, isHorizontal);
2487: if (v < 0) {
2488: throw illegalTraitValue(name, value);
2489: }
2490: return v;
2491: }
2492:
2493: /**
2494: * Parses the input value and converts it to a Path value.
2495: *
2496: * @param name the trait name.
2497: * @param value the value to convert.
2498: * @throws DOMException if the input value is invalid.
2499: */
2500: protected final Path parsePathTrait(final String name,
2501: final String value) throws DOMException {
2502: try {
2503: return ownerDocument.pathParser.parsePath(value);
2504: } catch (IllegalArgumentException iae) {
2505: DOMException de = illegalTraitValue(name, value);
2506: if (!loaded) {
2507: ownerDocument.setDelayedException(de);
2508: return ownerDocument.pathParser.getPath();
2509: } else {
2510: throw de;
2511: }
2512: }
2513: }
2514:
2515: /**
2516: * Parses the input points value and converts it to a Path value.
2517: *
2518: * @param name the trait name.
2519: * @param value the value to convert.
2520: * @throws DOMException if the input value is invalid.
2521: */
2522: protected final Path parsePointsTrait(final String name,
2523: final String value) throws DOMException {
2524: try {
2525: return ownerDocument.pathParser.parsePoints(value);
2526: } catch (IllegalArgumentException iae) {
2527: DOMException de = illegalTraitValue(name, value);
2528: if (!loaded) {
2529: ownerDocument.setDelayedException(de);
2530: return ownerDocument.pathParser.getPath();
2531: } else {
2532: throw de;
2533: }
2534: }
2535: }
2536:
2537: /**
2538: * Parses the input value and converts it to an Transform value.
2539: *
2540: * @param name the trait's name.
2541: * @param value the value to convert to a transform.
2542: * @return the value converted to an Transform object.
2543: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2544: * value is an invalid transform trait value.
2545: */
2546: protected final Transform parseTransformTrait(final String name,
2547: final String value) throws DOMException {
2548: try {
2549: return ownerDocument.transformListParser
2550: .parseTransformList(value);
2551: } catch (IllegalArgumentException iae) {
2552: throw illegalTraitValue(name, value);
2553: }
2554: }
2555:
2556: /**
2557: * Parses the input value and converts it to an RGB value
2558: *
2559: * @param traitName the name of the color trait being parsed.
2560: * @param value the value to convert to an RGB
2561: * @return the value converted to a RGB object
2562: *
2563: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2564: * value is an invalid color trait value.
2565: */
2566: protected final RGB parseColorTrait(final String traitName,
2567: final String value) throws DOMException {
2568: try {
2569: return ownerDocument.colorParser.parseColor(value);
2570: } catch (IllegalArgumentException e) {
2571: throw illegalTraitValue(traitName, value);
2572: }
2573: }
2574:
2575: /**
2576: * Parses the input value and converts it to a Paint value
2577: *
2578: * @param traitName the name of the color trait being parsed.
2579: * @param paintTarget the PaintTarget requesting the PaintServer.
2580: * @param value the value to convert to a Paint
2581: * @return the value converted to a Paint object
2582: *
2583: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
2584: * value is an invalid color trait value.
2585: */
2586: protected final PaintServer parsePaintTrait(final String traitName,
2587: final PaintTarget paintTarget, final String value)
2588: throws DOMException {
2589: if (value == null) {
2590: throw illegalTraitValue(traitName, value);
2591: }
2592:
2593: if (value.startsWith("url(#")) {
2594: if (value.length() < 7
2595: || value.charAt(value.length() - 1) != ')') {
2596: throw illegalTraitValue(traitName, value);
2597: }
2598:
2599: String idRef = value.substring(5, value.length() - 1);
2600:
2601: return PaintServerReference.resolve(ownerDocument,
2602: paintTarget, traitName, idRef);
2603: } else {
2604: try {
2605: return ownerDocument.colorParser.parseColor(value);
2606: } catch (IllegalArgumentException e) {
2607: throw illegalTraitValue(traitName, value);
2608: }
2609: }
2610: }
2611:
2612: /**
2613: * Parses the input value and converts it to a Time value.
2614: *
2615: * @param traitName the name of the clock trait being parsed.
2616: * @param value the value to convert to a Time instance.
2617: * @return the value converted to a Time object.
2618: * @throws DOMException if the input value is invalid.
2619: */
2620: protected final Time parseClockTrait(final String traitName,
2621: final String value) throws DOMException {
2622: if (SVGConstants.SVG_INDEFINITE_VALUE.equals(value)) {
2623: return Time.INDEFINITE;
2624: }
2625:
2626: try {
2627: return new Time(ownerDocument.clockParser.parseClock(value));
2628: } catch (IllegalArgumentException iae) {
2629: throw illegalTraitValue(traitName, value);
2630: }
2631: }
2632:
2633: /**
2634: * Parses the input value and converts it to a Time value. If there
2635: * is a syntax error or if the value is invalid for the given usage
2636: * (has to be [0, infinite[ for min, and ]0, infinite[ for max,
2637: * then the default is used. For min, the default is 0. For max, the
2638: * default is 'indefinite'
2639: *
2640: * @param traitName the name of the clock trait being parsed.
2641: * @param value the value to convert to a Time instance.
2642: * @param isMin should
2643: * @return the value converted to a Time object.
2644: * @throws DOMException if the input value is invalid.
2645: */
2646: protected final Time parseMinMaxClock(final String traitName,
2647: final String value, final boolean isMin)
2648: throws DOMException {
2649: if (SVGConstants.SVG_INDEFINITE_VALUE.equals(value)) {
2650: return Time.INDEFINITE;
2651: }
2652:
2653: if (value == null) {
2654: throw illegalTraitValue(traitName, value);
2655: }
2656:
2657: try {
2658: long v = ownerDocument.clockParser.parseClock(value);
2659: if (v < 0) {
2660: throw new IllegalArgumentException();
2661: }
2662:
2663: if (v == 0 && !isMin) {
2664: throw new IllegalArgumentException();
2665: }
2666:
2667: return new Time(v);
2668: } catch (IllegalArgumentException iae) {
2669: if (isMin) {
2670: return new Time(0);
2671: }
2672: return Time.INDEFINITE;
2673: }
2674: }
2675:
2676: /**
2677: * Utility method. This should be used for XML attribute values converted
2678: * to float arrays.
2679: *
2680: * @param traitName the name of the trait to parse
2681: * @param ctx the build context
2682: * @return the attribute value, converted to float
2683: * @throws DOMException if the value represents an invalid
2684: * floating point array value.
2685: */
2686: public final float[] parseFloatArrayTrait(final String traitName,
2687: final String value) throws DOMException {
2688: return parseFloatArrayTrait(traitName, value, ',');
2689: }
2690:
2691: /**
2692: * Utility method. This should be used for XML attribute values converted
2693: * to float arrays.
2694: *
2695: * @param traitName the name of the trait to parse
2696: * @param value the value to parse
2697: * @param sep the number separator in the input value list of numbers.
2698: * @return the attribute value, converted to float
2699: * @throws DOMException if the value represents an invalid
2700: * floating point array value.
2701: */
2702: public final float[] parseFloatArrayTrait(final String traitName,
2703: final String value, final char sep) throws DOMException {
2704: try {
2705: return ownerDocument.numberListParser.parseNumberList(
2706: value, sep);
2707: } catch (IllegalArgumentException e) {
2708: e.printStackTrace();
2709: throw illegalTraitValue(traitName, value);
2710: }
2711: }
2712:
2713: /**
2714: * CSS 2 Specification (section 15.3.2) and SVG 1.1 specification
2715: * (20.8.3):
2716: *
2717: * all | [ normal | italic | oblique ] [, [normal | italic | oblique] ]*
2718: *
2719: * @param name the name of the trait to parse
2720: * @param value the trait value
2721: * @return the font style in the FontFace.FONT_STYLE_XXX value set.
2722: * @throws DOMException if the value is not a legal one for this trait.
2723: */
2724: public final int parseFontStylesTrait(final String name,
2725: final String value) {
2726: if (value == null) {
2727: throw illegalTraitValue(name, value);
2728: }
2729:
2730: if (SVGConstants.CSS_ALL_VALUE.equals(value)) {
2731: return FontFace.FONT_STYLE_ALL;
2732: }
2733:
2734: SimpleTokenizer st = new SimpleTokenizer(value,
2735: SVGConstants.COMMA_STR);
2736:
2737: if (st.countTokens() < 1) {
2738: throw illegalTraitValue(name, value);
2739: }
2740:
2741: int styles = 0;
2742: while (st.hasMoreTokens()) {
2743: String t = st.nextToken().trim();
2744: if (SVGConstants.CSS_NORMAL_VALUE.equals(t)) {
2745: styles |= TextNode.FONT_STYLE_NORMAL;
2746: } else if (SVGConstants.CSS_ITALIC_VALUE.equals(t)) {
2747: styles |= TextNode.FONT_STYLE_ITALIC;
2748: } else if (SVGConstants.CSS_OBLIQUE_VALUE.equals(t)) {
2749: styles |= TextNode.FONT_STYLE_OBLIQUE;
2750: } else {
2751: throw illegalTraitValue(name, value);
2752: }
2753: }
2754:
2755: return styles;
2756: }
2757:
2758: /**
2759: * CSS 2 specification ((section 15.3.2) and SVG 1.1 specification
2760: * (20.8.3):
2761: *
2762: * all | [normal | bold |100 | 200 | 300 | 400 | 500 | 600 |
2763: * 700 | 800 | 900] [, [normal | bold |100 | 200 | 300 |
2764: * 400 | 500 | 600 | 700 | 800 | 900]]*
2765: *
2766: * @param name the name of the trait to parse
2767: * @param value the trait value.
2768: * @return the font weight as an int value in the
2769: * FontFace.FONT_WEIGHT_XXX set.
2770: * @throws DOMException if the value is not a legal one for this trait.
2771: */
2772: protected final int parseFontWeightsTrait(final String name,
2773: final String value) {
2774: if (value == null) {
2775: throw illegalTraitValue(name, value);
2776: }
2777:
2778: if (SVGConstants.CSS_ALL_VALUE.equals(value)) {
2779: return FontFace.FONT_WEIGHT_ALL;
2780: }
2781:
2782: SimpleTokenizer st = new SimpleTokenizer(value,
2783: SVGConstants.COMMA_STR);
2784:
2785: if (st.countTokens() < 1) {
2786: throw illegalTraitValue(name, value);
2787: }
2788:
2789: int weights = 0;
2790: while (st.hasMoreTokens()) {
2791: String t = st.nextToken().trim();
2792: if (SVGConstants.CSS_NORMAL_VALUE.equals(t)) {
2793: weights |= TextNode.FONT_WEIGHT_NORMAL;
2794: } else if (SVGConstants.CSS_BOLD_VALUE.equals(t)) {
2795: weights |= TextNode.FONT_WEIGHT_BOLD;
2796: } else if (SVGConstants.CSS_100_VALUE.equals(t)) {
2797: weights |= TextNode.FONT_WEIGHT_100;
2798: } else if (SVGConstants.CSS_200_VALUE.equals(t)) {
2799: weights |= TextNode.FONT_WEIGHT_200;
2800: } else if (SVGConstants.CSS_300_VALUE.equals(t)) {
2801: weights |= TextNode.FONT_WEIGHT_300;
2802: } else if (SVGConstants.CSS_400_VALUE.equals(t)) {
2803: weights |= TextNode.FONT_WEIGHT_400;
2804: } else if (SVGConstants.CSS_500_VALUE.equals(t)) {
2805: weights |= TextNode.FONT_WEIGHT_500;
2806: } else if (SVGConstants.CSS_600_VALUE.equals(t)) {
2807: weights |= TextNode.FONT_WEIGHT_600;
2808: } else if (SVGConstants.CSS_700_VALUE.equals(t)) {
2809: weights |= TextNode.FONT_WEIGHT_700;
2810: } else if (SVGConstants.CSS_800_VALUE.equals(t)) {
2811: weights |= TextNode.FONT_WEIGHT_800;
2812: } else if (SVGConstants.CSS_900_VALUE.equals(t)) {
2813: weights |= TextNode.FONT_WEIGHT_900;
2814: } else {
2815: throw illegalTraitValue(name, value);
2816: }
2817: }
2818:
2819: return weights;
2820: }
2821:
2822: /**
2823: * Parses the input value assuming it has the folloing syntax:
2824: * Value: [ <family-name> | <generic-family> ] [, [<family-name> |
2825: * <generic-family> ]]*
2826: * @param name the name of the trait being parsed.
2827: * @param value the font family value to be parsed. Should not be null.
2828: * @return an array of font-family strings
2829: */
2830: public String[] parseFontFamilyTrait(final String name,
2831: final String value) {
2832: if (value == null) {
2833: throw illegalTraitValue(name, value);
2834: }
2835:
2836: SimpleTokenizer st = new SimpleTokenizer(value,
2837: SVGConstants.COMMA_STR);
2838: String[] fontFamily = new String[st.countTokens()];
2839: int i = 0;
2840: while (st.hasMoreTokens()) {
2841: fontFamily[i] = st.nextToken();
2842:
2843: // Remove leading and trailing white spaces
2844: fontFamily[i] = fontFamily[i].trim();
2845:
2846: //
2847: // Now, take care of quotes
2848: //
2849:
2850: // <!> NOTE
2851: //
2852: // According to the CSS spec., if font family values are not
2853: // quoted, then the spaces should be consolidated. The following
2854: // code does not do that.
2855: //
2856: if (fontFamily[i].length() > 0) {
2857: if (fontFamily[i].charAt(0) == '\'') {
2858: // If there is a trailing quote, remove the quotes
2859: if (fontFamily[i]
2860: .charAt(fontFamily[i].length() - 1) == '\'') {
2861: fontFamily[i] = fontFamily[i].substring(1,
2862: fontFamily[i].length() - 1);
2863: }
2864: }
2865: }
2866: i++;
2867: }
2868:
2869: return fontFamily;
2870: }
2871:
2872: /**
2873: * Parses the input value, assuming a unicode range syntax, as for the
2874: * <code><hkern></code> element's u1 and u2 attributes.
2875: *
2876: * @param name the trait name.
2877: * @param value the trait value.
2878: * @return an array of unicode range pairs, as integer pairs.
2879: * @throws DOMException if the input trait value is invalid.
2880: */
2881: protected final int[][] parseUnicodeRangeTrait(final String name,
2882: final String value) throws DOMException {
2883: try {
2884: return ownerDocument.unicodeParser.parseUnicode(value);
2885: } catch (IllegalArgumentException iae) {
2886: throw illegalTraitValue(name, value);
2887: }
2888: }
2889:
2890: /**
2891: * Throws a DOMException if the element is not loading, i.e., if
2892: * its loaded field is set to true.
2893: *
2894: * @param name the name of the trait that is accessed.
2895: */
2896: protected void checkWriteLoading(final String name)
2897: throws DOMException {
2898: if (loaded && isInDocumentTree()) {
2899: throw readOnlyTraitError(name);
2900: }
2901: }
2902:
2903: /**
2904: * Throws a DOMException if the input float trait value is
2905: * strictly negative.
2906: *
2907: * @param name the trait name.
2908: * @param value the trait float value.
2909: */
2910: protected void checkPositive(final String name, final float value) {
2911: if (value < 0) {
2912: throw illegalTraitValue(name, Float.toString(value));
2913: }
2914: }
2915:
2916: /**
2917: * @param name the trait name.
2918: * @return a DOMException describing the type mismatch error.
2919: */
2920: protected DOMException unsupportedTraitType(final String name,
2921: final String type) {
2922: if (name == null) {
2923: return unsupportedTrait(name);
2924: }
2925:
2926: return new DOMException(DOMException.TYPE_MISMATCH_ERR,
2927: Messages.formatMessage(
2928: Messages.ERROR_TRAIT_TYPE_MISMATCH,
2929: new String[] { name, type, getLocalName(),
2930: getNamespaceURI() }));
2931: }
2932:
2933: /**
2934: * @param name the trait name.
2935: * @return a DOMException describing the type mismatch error.
2936: */
2937: protected DOMException unsupportedTraitTypeNS(final String name,
2938: final String namespaceURI, final String type) {
2939: return new DOMException(DOMException.TYPE_MISMATCH_ERR,
2940: Messages.formatMessage(
2941: Messages.ERROR_TRAIT_TYPE_NS_MISMATCH,
2942: new String[] { name, namespaceURI, type,
2943: getLocalName(), getNamespaceURI() }));
2944: }
2945:
2946: /**
2947: * @param name the trait name
2948: * @return a DOMException describing the unsupported trait error.
2949: */
2950: protected DOMException unsupportedTrait(final String name) {
2951: return new DOMException(DOMException.NOT_SUPPORTED_ERR,
2952: Messages.formatMessage(
2953: Messages.ERROR_UNSUPPORTED_TRAIT, new String[] {
2954: name, null, getLocalName(),
2955: getNamespaceURI() }));
2956: }
2957:
2958: /**
2959: * @param name the trait name
2960: * @param namespaceURI the trait's namespace URI.
2961: * @return a DOMException describing the unsupported trait error.
2962: */
2963: protected DOMException unsupportedTraitNS(final String name,
2964: final String namespaceURI) {
2965: return new DOMException(DOMException.NOT_SUPPORTED_ERR,
2966: Messages.formatMessage(
2967: Messages.ERROR_UNSUPPORTED_TRAIT, new String[] {
2968: name, namespaceURI, getLocalName(),
2969: getNamespaceURI() }));
2970: }
2971:
2972: /**
2973: * @param name the name of the trait
2974: * @param value the illegal value.
2975: * @return a DOMException describing an illegal trait value
2976: */
2977: DOMException illegalTraitValue(final String name, final String value) {
2978: return new DOMException(DOMException.INVALID_ACCESS_ERR,
2979: Messages.formatMessage(
2980: Messages.ERROR_INVALID_TRAIT_VALUE,
2981: new String[] { name, value,
2982: getLocalName() + "(" + getId() + ")",
2983: getNamespaceURI() }));
2984: }
2985:
2986: /**
2987: * @param name the name of the trait
2988: * @param value the illegal value.
2989: * @return a DOMException describing an illegal trait value
2990: */
2991: DOMException notAnimatable(final String traitNamespace,
2992: final String traitName) {
2993: return new DOMException(DOMException.NOT_SUPPORTED_ERR,
2994: Messages.formatMessage(
2995: Messages.ERROR_TRAIT_NOT_ANIMATABLE,
2996: new String[] { traitNamespace, traitName,
2997: getLocalName(), getNamespaceURI() }));
2998: }
2999:
3000: /**
3001: * @param targetId the target element's id (may be null)
3002: * @param traitNamespace the animated trait's namespace.
3003: * @param traitName the animated trait's name.
3004: * @param targetNamespace the target element's namespace.
3005: * @param targetName the target element's name
3006: * @param animationId the animation id (may be null)
3007: * @param animationNamespace the animation's namespace
3008: * @param animationLocalName the animation's local name.
3009: * @param errorDescription the animation error's description.
3010: */
3011: protected DOMException animationError(final String targetId,
3012: final String traitNamespace, final String traitName,
3013: final String targetNamespace, final String targetName,
3014: final String animationId, final String animationNamespace,
3015: final String animationLocalName,
3016: final String errorDescription) {
3017: return new DOMException(DOMException.INVALID_STATE_ERR,
3018: Messages.formatMessage(
3019: Messages.ERROR_INVALID_ANIMATION_CONFIGURATION,
3020: new String[] { targetId, traitNamespace,
3021: traitName, targetNamespace, targetName,
3022: animationId, animationNamespace,
3023: animationLocalName, animationLocalName,
3024: errorDescription }));
3025: }
3026:
3027: /**
3028: * @param name the name of the trait
3029: * @param namespaceURI the trait's namespace URI.
3030: * @param value the illegal value.
3031: * @return a DOMException describing an illegal trait value
3032: */
3033: protected DOMException illegalTraitValue(final String name,
3034: final String namespaceURI, final String value) {
3035: return illegalTraitValue(name + "(" + namespaceURI + ")", value);
3036: }
3037:
3038: /**
3039: * @param name the trait name.
3040: * @return DOMException describing the write error on a read-only attribute.
3041: */
3042: protected DOMException readOnlyTraitError(final String name) {
3043: return new DOMException(
3044: DOMException.NO_MODIFICATION_ALLOWED_ERR, Messages
3045: .formatMessage(Messages.ERROR_READ_ONLY_TRAIT,
3046: new String[] { name, getLocalName(),
3047: getNamespaceURI() }));
3048: }
3049:
3050: /**
3051: * Converts an animated float[][] value into an AWT color value.
3052: *
3053: * @param name the trait's name.
3054: * @param value the float[][] to convert.
3055: * @return the color converted to an AWT <code>Color</code> object.
3056: */
3057: protected RGB toRGB(final String name, final float[][] v)
3058: throws DOMException {
3059: if (v != null) {
3060: return new RGB((int) v[0][0], (int) v[0][1], (int) v[0][2]);
3061: } else {
3062: return null;
3063: }
3064: }
3065:
3066: /**
3067: * Converts an animated float[][] value into an String rgb value.
3068: *
3069: * @param name the trait's name.
3070: * @param value the float[][] to convert.
3071: * @return the color converted to a string.
3072: */
3073: protected String toRGBString(final String name, final float[][] v)
3074: throws DOMException {
3075: if (v != null) {
3076: return "rgb(" + ((int) v[0][0]) + "," + ((int) v[0][1])
3077: + "," + ((int) v[0][2]) + ")";
3078: } else {
3079: return "none";
3080: }
3081: }
3082:
3083: /**
3084: * Converts an J2D RGB to an SVG DOM RGBColor
3085: *
3086: * @param traitName the name of the trait whose value is convereted.
3087: * @param paint the PaintServer to convert. Should not be null.
3088: * @return the color, converted to an <code>SVGRGBColor</code> instance.
3089: *
3090: * @throws DOMException with error code TYPE_MISMATCH_ERR if the
3091: * paint is not an instance of Colorl
3092: */
3093: protected SVGRGBColor toSVGRGBColor(final String traitName,
3094: final PaintServer paint) {
3095: if (paint == null) {
3096: return null;
3097: }
3098:
3099: if (!(paint instanceof SVGRGBColor)) {
3100: throw unsupportedTraitType(traitName,
3101: TRAIT_TYPE_SVG_RGB_COLOR);
3102: }
3103:
3104: return (SVGRGBColor) paint;
3105: }
3106:
3107: /**
3108: * Converts a viewBox array to an SVGRect value.
3109: *
3110: * @param name the name of the trait.
3111: * @param viewBox the viewbox value to convet.
3112: */
3113: protected SVGRect toSVGRect(final float[][] viewBox) {
3114: if (viewBox == null) {
3115: return null;
3116: }
3117:
3118: SVGRect r = new Box(viewBox[0][0], viewBox[0][1],
3119: viewBox[1][0], viewBox[2][0]);
3120:
3121: return r;
3122: }
3123:
3124: /**
3125: * Converts an comma seperated list of floats to a viewBox array
3126: *
3127: * @param name the trait name
3128: * @param value the trait value to be converted to an SVGRect.
3129: * The expected syntax is
3130: * "float comma-wsp float comma-wsp float comma-wsp float comma-wsp"
3131: * @return an array of four floats.
3132: *
3133: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
3134: * value is an invalid value for the given trait or null.
3135: */
3136: protected float[][] toViewBox(final String name, final String value)
3137: throws DOMException {
3138: if (value == null) {
3139: throw illegalTraitValue(name, value);
3140: }
3141:
3142: try {
3143: return ownerDocument.viewBoxParser.parseViewBox(value);
3144: } catch (IllegalArgumentException iae) {
3145: throw illegalTraitValue(name, value);
3146: }
3147: }
3148:
3149: /**
3150: * Converts a Java String array to a trait string array with the format:
3151: * "str1, str2, .., strN"
3152: *
3153: * @param array the string array to be converted.
3154: * @return a string with the value "" if the array is null or
3155: * "float1,float2,..,floatN"
3156: */
3157: protected String toStringTrait(final String[] array) {
3158: return toStringTrait(array, ",");
3159: }
3160:
3161: /**
3162: * Converts a Java String array to a trait string array with the format:
3163: * "str1, str2, .., strN"
3164: *
3165: * @param array the string array to be converted.
3166: * @param sep seperator to use in the output string array.
3167: *
3168: * @return a string with the value "" if the array is null or
3169: * "float1,float2,..,floatN"
3170: */
3171: protected String toStringTrait(final String[] array,
3172: final String sep) {
3173: if (array == null || array.length < 1) {
3174: return "";
3175: }
3176:
3177: StringBuffer sb = new StringBuffer();
3178:
3179: for (int i = 0; i < array.length - 1; i++) {
3180: sb.append(array[i]);
3181: sb.append(sep);
3182: }
3183:
3184: sb.append(array[array.length - 1]);
3185: return sb.toString();
3186: }
3187:
3188: /**
3189: * Converts a Java String array to a trait string array with the format:
3190: * "str1, str2, .., strN". In addition, the string values are put inside
3191: * single quotes if there are spaces in the string values. This is needed
3192: * for values such as the CSS 2 font-family attribute.
3193: *
3194: * @param array the string array to be converted.
3195: *
3196: * @return a string with the value "" if the array is null or
3197: * "float1,float2,..,floatN"
3198: */
3199: protected String toStringTraitQuote(final String[] array) {
3200: if (array == null || array.length < 1) {
3201: return "";
3202: }
3203:
3204: StringBuffer sb = new StringBuffer();
3205:
3206: for (int i = 0; i < array.length - 1; i++) {
3207: if (array[i].indexOf(' ') != -1) {
3208: sb.append('\'');
3209: sb.append(array[i]);
3210: sb.append('\'');
3211: } else {
3212: sb.append(array[i]);
3213: }
3214: sb.append(',');
3215: }
3216:
3217: if (array[array.length - 1].indexOf(' ') != -1) {
3218: sb.append('\'');
3219: sb.append(array[array.length - 1]);
3220: sb.append('\'');
3221: } else {
3222: sb.append(array[array.length - 1]);
3223: }
3224:
3225: return sb.toString();
3226: }
3227:
3228: /**
3229: * Helper method. Converts the input array value to a string trait value.
3230: *
3231: * @param array the float array to be converted.
3232: * @return a string with the value "none" if the array is null or
3233: * "float1,float2,..,floatN"
3234: */
3235: protected String toStringTrait(final float[] array) {
3236: return toStringTrait(array, ',');
3237: }
3238:
3239: /**
3240: * Helper method. Converts the input array value to a string trait value.
3241: *
3242: * @param array the float array to be converted.
3243: * @return a string with the value "none" if the array is null or
3244: * "float1,float2,..,floatN"
3245: */
3246: protected String toStringTrait(final float[] array, final char sep) {
3247: if (array == null) {
3248: return SVGConstants.CSS_NONE_VALUE;
3249: }
3250:
3251: StringBuffer sb = new StringBuffer();
3252:
3253: for (int i = 0; i < array.length - 1; i++) {
3254: sb.append(array[i]);
3255: sb.append(sep);
3256: }
3257:
3258: sb.append(array[array.length - 1]);
3259: return sb.toString();
3260: }
3261:
3262: /**
3263: * Helper method. Convertst the input array of float arrays into a
3264: * string trait value.
3265: *
3266: * @param array the array of float arrays to convert.
3267: * @return a string the the value "" if the array is null or
3268: * "f01 f02 f03 f04; f11 f12 f13 f14; ...;fn1 fn2 fn3 fn4"
3269: * @throws NullPointerException if one of the array values is null
3270: * @throws ArrayIndexOutOfBoundsException if one of the array values is of
3271: * length 0.
3272: */
3273: protected String toStringTrait(final float[][] array) {
3274: if (array == null || array.length == 0) {
3275: return "";
3276: }
3277:
3278: StringBuffer sb = new StringBuffer();
3279:
3280: for (int i = 0; i < array.length; i++) {
3281: for (int j = 0; j < array[i].length - 1; j++) {
3282: sb.append(array[i][j]);
3283: sb.append(SVGConstants.COMMA);
3284: }
3285: sb.append(array[i][array[i].length - 1]);
3286: sb.append(SVGConstants.SEMI_COLON);
3287: }
3288:
3289: String value = sb.toString();
3290:
3291: // Trim trailing ';'
3292: return value.substring(0, value.length() - 1);
3293: }
3294:
3295: /**
3296: * Helper method. Converts the input <code>Transform</code>
3297: * to an SVGMatrix trait value.
3298: *
3299: * @param transform the transform to convert.
3300: * @return the SVGMatrix equivalent value.
3301: */
3302: protected SVGMatrix toSVGMatrixTrait(final Transform transform) {
3303: if (transform == null) {
3304: return new Transform(1, 0, 0, 1, 0, 0);
3305: } else {
3306: return new Transform(transform);
3307: }
3308: }
3309:
3310: /**
3311: * Converts an align value to a preserveAspectRatio string trait
3312: * value.
3313: *
3314: * @param align one of StructureNode.ALIGN_NONE,
3315: * StructureNode.ALIGN_XMIDYMID
3316: */
3317: protected static String alignToStringTrait(final int align) {
3318: switch (align) {
3319: case StructureNode.ALIGN_XMIDYMID:
3320: return SVGConstants.SVG_IMAGE_PRESERVE_ASPECT_RATIO_DEFAULT_VALUE;
3321: default:
3322: return SVGConstants.SVG_NONE_VALUE;
3323: }
3324: }
3325:
3326: /**
3327: * Converts a FontFace's font-styles to a String trait.
3328: *
3329: * @param styles the FontFace type styles value.
3330: */
3331: protected String fontStylesToStringTrait(final int styles) {
3332: if (styles == FontFace.FONT_STYLE_ALL) {
3333: return SVGConstants.CSS_ALL_VALUE;
3334: }
3335:
3336: StringBuffer sb = new StringBuffer();
3337:
3338: if ((styles & TextNode.FONT_STYLE_NORMAL) != 0) {
3339: sb.append(SVGConstants.CSS_NORMAL_VALUE);
3340: sb.append(SVGConstants.COMMA);
3341: }
3342:
3343: if ((styles & TextNode.FONT_STYLE_ITALIC) != 0) {
3344: sb.append(SVGConstants.CSS_ITALIC_VALUE);
3345: sb.append(SVGConstants.COMMA);
3346: }
3347:
3348: if ((styles & TextNode.FONT_STYLE_OBLIQUE) != 0) {
3349: sb.append(SVGConstants.CSS_OBLIQUE_VALUE);
3350: sb.append(SVGConstants.COMMA);
3351: }
3352:
3353: if (sb.length() > 0) {
3354: return sb.toString().substring(0, sb.length() - 1);
3355: }
3356:
3357: return sb.toString();
3358: }
3359:
3360: /**
3361: * Converts an FontFace's font-weights to a String trait.
3362: *
3363: * @param weight the FontFace type' weights value.
3364: */
3365: protected String fontWeightsToStringTrait(final int weight) {
3366: if (weight == FontFace.FONT_WEIGHT_ALL) {
3367: return SVGConstants.CSS_ALL_VALUE;
3368: }
3369:
3370: StringBuffer sb = new StringBuffer();
3371: if ((weight & TextNode.FONT_WEIGHT_100) != 0) {
3372: sb.append(SVGConstants.CSS_100_VALUE);
3373: sb.append(SVGConstants.COMMA);
3374: }
3375:
3376: if ((weight & TextNode.FONT_WEIGHT_200) != 0) {
3377: sb.append(SVGConstants.CSS_200_VALUE);
3378: sb.append(SVGConstants.COMMA);
3379: }
3380:
3381: if ((weight & TextNode.FONT_WEIGHT_300) != 0) {
3382: sb.append(SVGConstants.CSS_300_VALUE);
3383: sb.append(SVGConstants.COMMA);
3384: }
3385:
3386: if ((weight & TextNode.FONT_WEIGHT_400) != 0) {
3387: sb.append(SVGConstants.CSS_400_VALUE);
3388: sb.append(SVGConstants.COMMA);
3389: }
3390:
3391: if ((weight & TextNode.FONT_WEIGHT_500) != 0) {
3392: sb.append(SVGConstants.CSS_500_VALUE);
3393: sb.append(SVGConstants.COMMA);
3394: }
3395:
3396: if ((weight & TextNode.FONT_WEIGHT_600) != 0) {
3397: sb.append(SVGConstants.CSS_600_VALUE);
3398: sb.append(SVGConstants.COMMA);
3399: }
3400:
3401: if ((weight & TextNode.FONT_WEIGHT_700) != 0) {
3402: sb.append(SVGConstants.CSS_700_VALUE);
3403: sb.append(SVGConstants.COMMA);
3404: }
3405:
3406: if ((weight & TextNode.FONT_WEIGHT_800) != 0) {
3407: sb.append(SVGConstants.CSS_800_VALUE);
3408: sb.append(SVGConstants.COMMA);
3409: }
3410:
3411: if ((weight & TextNode.FONT_WEIGHT_900) != 0) {
3412: sb.append(SVGConstants.CSS_900_VALUE);
3413: sb.append(SVGConstants.COMMA);
3414: }
3415:
3416: if (sb.length() > 0) {
3417: return sb.toString().substring(0, sb.length() - 1);
3418: }
3419:
3420: return sb.toString();
3421: }
3422:
3423: /**
3424: * Helper method. Converts the input <code>Transform</code>
3425: * to a string trait value.
3426: *
3427: * @param transform the transform to convert.
3428: * @return the string trait value.
3429: */
3430: protected static String toStringTrait(final Transform transform) {
3431: if (transform == null) {
3432: return Transformable.IDENTITY_TRANSFORM_TRAIT;
3433: } else {
3434: StringBuffer sb = new StringBuffer();
3435: sb.append("matrix(");
3436: sb.append(transform.getComponent(0));
3437: sb.append(",");
3438: sb.append(transform.getComponent(1));
3439: sb.append(",");
3440: sb.append(transform.getComponent(2));
3441: sb.append(",");
3442: sb.append(transform.getComponent(3));
3443: sb.append(",");
3444: sb.append(transform.getComponent(4));
3445: sb.append(",");
3446: sb.append(transform.getComponent(5));
3447: sb.append(")");
3448: return sb.toString();
3449: }
3450: }
3451:
3452: /**
3453: * Helper method. Converts the input unicode range into a String
3454: * trait, with the following syntax:
3455: * "U+b1-e1,U+b2-e2,...,U+bn-en"
3456: *
3457: * @param u the unicode range to convert.
3458: * @return the string value with the unicode range syntax.
3459: */
3460: protected String unicodeRangeToStringTrait(final int[][] u) {
3461: if (u == null) {
3462: return null;
3463: }
3464:
3465: if (u.length == 0) {
3466: return SVGConstants.EMPTY;
3467: }
3468:
3469: StringBuffer sb = new StringBuffer();
3470: for (int i = 0; i < u.length - 1; i++) {
3471: if (u[i] == null || u[i].length != 2) {
3472: throw new IllegalArgumentException();
3473: }
3474: sb.append("U+");
3475: sb.append(Integer.toHexString(u[i][0]));
3476: sb.append('-');
3477: sb.append(Integer.toHexString(u[i][1]));
3478: sb.append(',');
3479: }
3480:
3481: if (u[u.length - 1] == null || u[u.length - 1].length != 2) {
3482: throw new IllegalArgumentException();
3483: }
3484: sb.append("U+");
3485: sb.append(Integer.toHexString(u[u.length - 1][0]));
3486: sb.append('-');
3487: sb.append(Integer.toHexString(u[u.length - 1][1]));
3488:
3489: return sb.toString();
3490: }
3491:
3492: /**
3493: * Converts the input float value to an animated float array trait.
3494: *
3495: * @param v the float value to wrap in a float[][] array.
3496: * @return the wrapped value.
3497: */
3498: float[][] toAnimatedFloatArray(final float v) {
3499: return new float[][] { { v } };
3500: }
3501:
3502: /**
3503: * Converts the input float[] array to an animated float array trait.
3504: *
3505: * @param a the float array to wrap in a float[][] array. Should not
3506: * be null.
3507: * @return the wrapped value.
3508: */
3509: float[][] toAnimatedFloatArray(final float[] a) {
3510: float[][] v = new float[a.length][];
3511: // This assumes that each value in the input array are separate
3512: // components.
3513: for (int i = 0; i < a.length; i++) {
3514: v[i] = new float[] { a[i] };
3515: }
3516: return v;
3517: }
3518:
3519: /**
3520: * Utility method to convert a Path to an animatable float array.
3521: *
3522: * @param p the path to convert
3523: * @return the converted value.
3524: */
3525: float[][] toAnimatedFloatArray(final Path path) {
3526: return new float[][] { path.getData() };
3527: }
3528:
3529: /**
3530: * Converts an animated float array to a trait float array value.
3531: * This is used for multi-component trait values, such as
3532: * stroke-dasharray, or the text's x, y or rotate values.
3533: *
3534: * @param value the animated value to convert.
3535: * @return an float array trait value.
3536: */
3537: float[] toTraitFloatArray(final float[][] value) {
3538: float[] v = new float[value.length];
3539: for (int i = 0; i < v.length; i++) {
3540: v[i] = value[i][0];
3541: }
3542:
3543: return v;
3544: }
3545:
3546: /**
3547: * @return a text description of this node including the node
3548: * ID if one was set.
3549: */
3550: public String toString() {
3551: if (getId() != null && getId().length() > 0) {
3552: return "ElementNode[" + getId() + "] [" + super .toString()
3553: + "]";
3554: } else {
3555: return super .toString();
3556: }
3557: }
3558:
3559: // =========================================================================
3560: // Type comparison utilities.
3561: //
3562:
3563: /**
3564: * @param objA first object to compare.
3565: * @param objB second object to compare.
3566: * @return true if the objects are both null or if they are Object.equals()
3567: */
3568: public static boolean equal(final Object objA, final Object objB) {
3569: if (objA == objB) {
3570: return true;
3571: }
3572:
3573: if (objA == null || objB == null) {
3574: return false;
3575: }
3576:
3577: return objA.equals(objB);
3578: }
3579:
3580: /**
3581: * @param faa first float array to compare
3582: * @param faab second float array to compare
3583: * @return true if the objects are both null or if they are equal
3584: */
3585: public static boolean equal(final float[] faa, final float[] fab) {
3586: if (faa == fab) {
3587: return true;
3588: }
3589:
3590: if (faa == null || fab == null || faa.length != fab.length) {
3591: return false;
3592: }
3593:
3594: int n = faa.length;
3595: for (int i = 0; i < n; i++) {
3596: if (faa[i] != fab[i]) {
3597: return false;
3598: }
3599: }
3600:
3601: return true;
3602: }
3603:
3604: /**
3605: * @param saa first string array to compare
3606: * @param sab second string array to compare
3607: * @return true if the objects are both null or if they are equal
3608: */
3609: public static boolean equal(final String[] saa, final String[] sab) {
3610: if (saa == sab) {
3611: return true;
3612: }
3613:
3614: if (saa == null || sab == null || saa.length != sab.length) {
3615: return false;
3616: }
3617:
3618: int n = saa.length;
3619: for (int i = 0; i < n; i++) {
3620: if (!equal(saa[i], sab[i])) {
3621: return false;
3622: }
3623: }
3624:
3625: return true;
3626: }
3627:
3628: /**
3629: * @param iaa first int array to compare
3630: * @param iab second int array to compare
3631: * @return true if the objects are both null or if they are equal
3632: */
3633: public static boolean equal(final int[][] iaa, final int[][] iab) {
3634: if (iaa == iab) {
3635: return true;
3636: }
3637:
3638: if (iaa == null || iab == null || iaa.length != iab.length) {
3639: return false;
3640: }
3641:
3642: int n = iaa.length;
3643: for (int i = 0; i < n; i++) {
3644: if (iaa[i] != iab[i]) {
3645: if (iaa[i] == null || iab[i] == null
3646: || iaa[i].length != iab[i].length) {
3647: return false;
3648: }
3649:
3650: int m = iaa[i].length;
3651: for (int j = 0; j < m; j++) {
3652: if (iaa[i][j] != iab[i][j]) {
3653: return false;
3654: }
3655: }
3656: }
3657: }
3658:
3659: return true;
3660: }
3661:
3662: /**
3663: * @param faa first float array to compare
3664: * @param fab second float array to compare
3665: * @return true if the objects are both null or if they are equal
3666: */
3667: public static boolean equal(final float[][] faa, final float[][] fab) {
3668: if (faa == fab) {
3669: return true;
3670: }
3671:
3672: if (faa == null || fab == null || faa.length != fab.length) {
3673: return false;
3674: }
3675:
3676: int n = faa.length;
3677: for (int i = 0; i < n; i++) {
3678: if (faa[i] != fab[i]) {
3679: if (faa[i] == null || fab[i] == null
3680: || faa[i].length != fab[i].length) {
3681: return false;
3682: }
3683:
3684: int m = faa[i].length;
3685: for (int j = 0; j < m; j++) {
3686: if (faa[i][j] != fab[i][j]) {
3687: return false;
3688: }
3689: }
3690: }
3691: }
3692:
3693: return true;
3694: }
3695:
3696: /**
3697: * Utility method.
3698: *
3699: * @param str the String object to intern.
3700: * @return null if the input string is null. The interned string otherwise.
3701: */
3702: public static String intern(final String str) {
3703: if (str == null) {
3704: return null;
3705: }
3706:
3707: return str.intern();
3708: }
3709:
3710: }
|