001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026: package com.sun.perseus.model;
027:
028: import com.sun.perseus.util.SVGConstants;
029:
030: import org.w3c.dom.DOMException;
031:
032: import org.w3c.dom.svg.SVGMatrix;
033: import org.w3c.dom.svg.SVGRect;
034:
035: import com.sun.perseus.j2d.Box;
036: import com.sun.perseus.j2d.RenderGraphics;
037: import com.sun.perseus.j2d.Transform;
038:
039: /**
040: * Represents an SVG Tiny <code><use></code> element.
041: *
042: * @version $Id: Use.java,v 1.13 2006/06/29 10:47:36 ln156897 Exp $
043: */
044: public class Use extends Group implements IDRef {
045: /**
046: * xlink:href is required on <use>
047: */
048: static final String[][] REQUIRED_TRAITS_NS = { {
049: SVGConstants.XLINK_NAMESPACE_URI,
050: SVGConstants.SVG_HREF_ATTRIBUTE } };
051:
052: /**
053: * The x and y coordinates of the use element
054: */
055: protected float x, y;
056:
057: /**
058: * Expanded content tree: the root <code>ElementNodeProxy</code>
059: */
060: protected ElementNodeProxy proxy;
061:
062: /**
063: * The identifier of the referenced node
064: */
065: protected String idRef;
066:
067: /**
068: * The referenced element.
069: */
070: protected ElementNode ref;
071:
072: /**
073: * Constructor.
074: *
075: * @param ownerDocument this element's owner <code>DocumentNode</code>
076: */
077: public Use(final DocumentNode ownerDocument) {
078: super (ownerDocument);
079: }
080:
081: /**
082: * Clears the text layouts, if any exist. This is typically
083: * called when the font selection has changed and nodes such
084: * as <code>Text</code> should recompute their layouts.
085: * This should recursively call clearLayouts on children
086: * node or expanded content, if any.
087: */
088: protected void clearLayouts() {
089: clearLayouts(proxy);
090: }
091:
092: /**
093: * Returns the <code>ModelNode</code>, if any, hit by the
094: * point at coordinate x/y.
095: *
096: * @param pt the x/y coordinate. Should never be null and be
097: * of size two. If not, the behavior is unspecified.
098: * The coordinates are in viewport space.
099: * @return the <tt>ModelNode</tt> hit at the given point or null
100: * if none was hit.
101: */
102: public ModelNode nodeHitAt(final float[] pt) {
103: // If a node does not render, it is never hit
104: if (canRenderState != 0) {
105: return null;
106: }
107:
108: // Check for a hit on expanded content
109: return nodeHitAt(getLastExpandedChild(), pt);
110: }
111:
112: /**
113: * Returns the <code>ModelNode</code>, if any, hit by the
114: * point at coordinate x/y in the proxy tree starting at
115: * proxy.
116: *
117: * @param pt the x/y coordinate. Should never be null and be
118: * of size two. If not, the behavior is unspecified.
119: * The coordinates are in viewport space.
120: * @param proxy the root of the proxy tree to test.
121: * @return the <tt>ModelNode</tt> hit at the given point or null
122: * if none was hit.
123: */
124: ModelNode proxyNodeHitAt(final float[] pt,
125: final ElementNodeProxy proxy) {
126: // If a node does not render, it is never hit
127: if (canRenderState != 0) {
128: return null;
129: }
130:
131: // Check for a hit on expanded content
132: return nodeHitAt(proxy.getLastExpandedChild(), pt);
133: }
134:
135: /**
136: * Called when the computed value of the given property has changed.
137: * On a use element, this propagates only to expanded content.
138: *
139: * @param propertyIndex index for the property whose value has changed.
140: * @param parentPropertyValue the value that children of this node should
141: * now inherit.
142: */
143: protected void propagatePropertyState(final int propertyIndex,
144: final Object parentPropertyValue) {
145:
146: // Propagate to proxies.
147: if (firstProxy != null) {
148: ElementNodeProxy proxy = firstProxy;
149: while (proxy != null) {
150: ((CompositeGraphicsNodeProxy) proxy)
151: .proxiedPropertyStateChange(propertyIndex,
152: parentPropertyValue);
153: proxy = proxy.nextProxy;
154: }
155: }
156:
157: // Propagate to expanded children.
158: ModelNode node = getFirstExpandedChild();
159: while (node != null) {
160: node.recomputePropertyState(propertyIndex,
161: parentPropertyValue);
162: node = node.nextSibling;
163: }
164: }
165:
166: /**
167: * Called when the computed value of the given float property has changed.
168: * On a use element, this propagates only to expanded content.
169: *
170: * @param propertyIndex index for the property whose value has changed.
171: * @param parentPropertyValue the value that children of this node should
172: * now inherit.
173: */
174: protected void propagateFloatPropertyState(final int propertyIndex,
175: final float parentPropertyValue) {
176: // Propagate to proxies.
177: if (firstProxy != null) {
178: ElementNodeProxy proxy = firstProxy;
179: while (proxy != null) {
180: ((CompositeGraphicsNodeProxy) proxy)
181: .proxiedFloatPropertyStateChange(propertyIndex,
182: parentPropertyValue);
183: proxy = proxy.nextProxy;
184: }
185: }
186:
187: // Propagate to expanded children.
188: ModelNode node = getFirstExpandedChild();
189: while (node != null) {
190: node.recomputeFloatPropertyState(propertyIndex,
191: parentPropertyValue);
192: node = node.nextSibling;
193: }
194: }
195:
196: /**
197: * Called when the computed value of the given packed property has changed.
198: * On a use element, this propagates only to expanded content.
199: *
200: * @param propertyIndex index for the property whose value has changed.
201: * @param parentPropertyValue the value that children of this node should
202: * now inherit.
203: */
204: protected void propagatePackedPropertyState(
205: final int propertyIndex, final int parentPropertyValue) {
206: // Propagate to proxies.
207: if (firstProxy != null) {
208: ElementNodeProxy proxy = firstProxy;
209: while (proxy != null) {
210: ((CompositeGraphicsNodeProxy) proxy)
211: .proxiedPackedPropertyStateChange(
212: propertyIndex, parentPropertyValue);
213: proxy = proxy.nextProxy;
214: }
215: }
216:
217: // Propagate to expanded children.
218: ModelNode node = getFirstExpandedChild();
219: while (node != null) {
220: node.recomputePackedPropertyState(propertyIndex,
221: parentPropertyValue);
222: node = node.nextSibling;
223: }
224: }
225:
226: /**
227: * Recomputes the transform cache, if one exists. This should recursively
228: * call recomputeTransformState on children node or expanded content, if
229: * any.
230: *
231: * By default, because a ModelNode has no transform and no cached transform,
232: * this only does a pass down.
233: *
234: * @param parentTransform the Transform applied to this node's parent.
235: */
236: protected void recomputeTransformState(
237: final Transform parentTransform) {
238: txf = appendTransform(parentTransform, txf);
239: inverseTxf = null;
240: computeCanRenderTransformBit(txf);
241: // inverseTxf = computeInverseTransform(txf, parentTransform,
242: // inverseTxf);
243: recomputeTransformState(txf, getFirstExpandedChild());
244: }
245:
246: /**
247: * Paints this node into the input <code>RenderGraphics</code>.
248: *
249: * @param rg the <tt>RenderGraphics</tt> where the node should paint itself
250: */
251: public void paint(final RenderGraphics rg) {
252: if (canRenderState != 0) {
253: return;
254: }
255:
256: paint(getFirstExpandedChild(), rg);
257: }
258:
259: /**
260: * This method is called before an element is hooked into the tree to
261: * validate it is in a state where it can be added. For a Use element, the
262: * reference must have been set and resolved or must still be null (i.e.,
263: * not set).
264: */
265: protected void preValidate() {
266: if (loaded && proxy == null) {
267: if (ref == null && (idRef != null) && !"".equals(idRef)) {
268: throw new DOMException(DOMException.INVALID_STATE_ERR,
269: Messages.formatMessage(
270: Messages.ERROR_MISSING_REFERENCE,
271: new String[] { getNamespaceURI(),
272: getLocalName(), getId() }));
273: }
274: }
275: }
276:
277: /**
278: * Sets this <code>Use</code> element's idRef
279: *
280: * @param idRef the identifier of the referenced node. Should not be null
281: */
282: public void setIdRef(final String idRef) {
283: if (idRef == this .idRef
284: || (idRef != null && idRef.equals(this .idRef))) {
285: // No change
286: return;
287: }
288:
289: this .idRef = idRef;
290: ownerDocument.resolveIDRef(this , idRef);
291:
292: // If the node is hooked into the document tree and the idRef has not
293: // been resolved as a result of ownerDocument.resolveIDRef, then
294: // we go into error.
295: if (isInDocumentTree()) {
296: if (proxy == null && (idRef != null) && !"".equals(idRef)) {
297: throw new DOMException(DOMException.INVALID_ACCESS_ERR,
298: Messages.formatMessage(
299: Messages.ERROR_MISSING_REFERENCE,
300: new String[] { getNamespaceURI(),
301: getLocalName(), getId() }));
302: }
303: }
304: }
305:
306: /**
307: * @return the SVGConstants.SVG_USE_TAG value
308: */
309: public String getLocalName() {
310: return SVGConstants.SVG_USE_TAG;
311: }
312:
313: /**
314: * Used by <code>DocumentNode</code> to create a new instance from
315: * a prototype <code>Use</code>.
316: *
317: * @param doc the <code>DocumentNode</code> for which a new node is
318: * should be created.
319: * @return a new <code>Use</code> for the requested document.
320: */
321: public ElementNode newInstance(final DocumentNode doc) {
322: return new Use(doc);
323: }
324:
325: /**
326: * @return the <code>Use</code> element's idRef.
327: */
328: public String getIdRef() {
329: return idRef;
330: }
331:
332: /**
333: * <code>IDRef</code> implementation.
334: *
335: * @param ref the resolved reference (mapped from the
336: * id passed to the setIdRef method).
337: */
338: public void resolveTo(final ElementNode ref) {
339: // Only set the proxy if the use is in the document tree.
340: if (isInDocumentTree()) {
341: setProxy(ref.buildProxy());
342: } else {
343: this .ref = ref;
344: }
345: }
346:
347: /**
348: * When a Use element is hooked into the document tree, it may
349: * expand immediately if its reference has already been set.
350: */
351: void nodeHookedInDocumentTree() {
352: super .nodeHookedInDocumentTree();
353:
354: if (ref != null) {
355: setProxy(ref.buildProxy());
356: }
357: }
358:
359: /**
360: * When a Use in unhooked from the document tree, it needs to set its
361: * proxy to null and cleanly remove references to itself.
362: */
363: final void nodeUnhookedFromDocumentTree() {
364: super .nodeUnhookedFromDocumentTree();
365:
366: if (proxy != null) {
367: unhookExpandedQuiet();
368: proxy = null;
369: }
370: }
371:
372: /**
373: * @return an adequate <code>ElementNodeProxy</code> for this node.
374: */
375: ElementNodeProxy buildProxy() {
376: return new UseProxy(this );
377: }
378:
379: /**
380: * Apply this node's x/y translation if it is not (0,0).
381: *
382: * @param tx the <code>Transform</code> to apply additional node
383: * transforms to. This may be null.
384: * @param workTx a <code>Transform</code> which can be re-used if a
385: * new <code>Transform</code> needs to be created and workTx
386: * is not the same instance as tx.
387: * @return a transform with this node's transform added.
388: */
389: protected Transform appendTransform(Transform tx,
390: final Transform workTx) {
391: if (transform == null && motion == null && x == 0 && y == 0) {
392: return tx;
393: }
394:
395: tx = recycleTransform(tx, workTx);
396:
397: if (motion != null) {
398: tx.mMultiply(motion);
399: }
400:
401: if (transform != null) {
402: tx.mMultiply(transform);
403: }
404:
405: tx.mTranslate(x, y);
406:
407: return tx;
408: }
409:
410: /**
411: * @param newX new x-axis origin
412: */
413: public void setX(final float newX) {
414: if (newX == x) {
415: return;
416: }
417:
418: modifyingNode();
419: this .x = newX;
420: recomputeTransformState();
421: recomputeProxyTransformState();
422: modifiedNode();
423: }
424:
425: /**
426: * @param newY new y-axis origin
427: */
428: public void setY(final float newY) {
429: if (newY == y) {
430: return;
431: }
432:
433: modifyingNode();
434: this .y = newY;
435: recomputeTransformState();
436: recomputeProxyTransformState();
437: modifiedNode();
438: }
439:
440: /**
441: * @return x-axis use origin
442: */
443: public float getX() {
444: return x;
445: }
446:
447: /**
448: * @return y-axis use origin
449: */
450: public float getY() {
451: return y;
452: }
453:
454: /**
455: * @return true if proxy is set
456: */
457: public boolean hasDescendants() {
458: return super .hasDescendants() || proxy != null;
459: }
460:
461: /**
462: * Sets the <code>ElementNodeProxy</code> as this use's expanded
463: * content.
464: *
465: * @param proxy the proxy that references the <code><use></code>'s
466: * expanded content.
467: * @throws NullPointerException if the input proxy node is null
468: */
469: void setProxy(final ElementNodeProxy proxy) {
470: if (proxy == null) {
471: throw new IllegalArgumentException();
472: }
473:
474: // If this node already had a proxy, make sure we remove that
475: // proxy from the node's expanded content.
476: if (this .proxy != null) {
477: modifyingNode();
478: unhookExpandedQuiet();
479: modifiedNode();
480: }
481:
482: this .proxy = proxy;
483: this .proxy.setParentQuiet(this );
484: nodeInserted(this .proxy);
485: this .proxy.nextSibling = null;
486:
487: // Now, notify potential proxies that the proxy has been set.
488: ElementNodeProxy useProxy = firstProxy;
489: while (useProxy != null) {
490: ((UseProxy) useProxy).useProxySet();
491: useProxy = useProxy.nextProxy;
492: }
493: }
494:
495: /**
496: * Some node types (such as <code>ElementNodeProxy</code>) have
497: * expanded children that they compute in some specific
498: * way depending on the implementation.
499: *
500: * @return a reference to the node's first expanded child, or null if there
501: * are no expanded children. This forces the computation of expanded
502: * content if needed.
503: */
504: protected ModelNode getFirstExpandedChild() {
505: return proxy;
506: }
507:
508: /**
509: * Some node types (such as <code>ElementNodeProxy</code>) have
510: * expanded children that they compute in some specific
511: * way depending on the implementation.
512: *
513: * @return a reference to the node's first expanded child, or null if there
514: * are no expanded children.
515: */
516: public ModelNode getFirstComputedExpandedChild() {
517: return proxy;
518: }
519:
520: /**
521: * Some node types (such as <code>ElementNodeProxy</code>) have
522: * expanded children that they compute in some specific
523: * way depending on the implementation.
524: *
525: * @return a reference to the node's last expanded child, or null if there
526: * are no expanded children. This forces the computation of expanded
527: * content if needed.
528: */
529: protected ModelNode getLastExpandedChild() {
530: return proxy;
531: }
532:
533: /**
534: * Utility method. Unhooks the expanded content.
535: */
536: protected void unhookExpandedQuiet() {
537: unhookQuiet(proxy);
538: proxy = null;
539:
540: ElementNodeProxy p = firstProxy;
541: while (p != null) {
542: p.unhookExpandedQuiet();
543: p = p.nextProxy;
544: }
545:
546: }
547:
548: // JAVADOC COMMENT ELIDED
549: public SVGRect getBBox() {
550: Transform t = null;
551:
552: if (x != 0 || y != 0) {
553: t = new Transform(1, 0, 0, 1, x, y);
554: }
555:
556: return addBBox(null, t);
557: }
558:
559: // JAVADOC COMMENT ELIDED
560: Box addBBox(Box bbox, Transform t) {
561: return proxy.addBBox(bbox, proxy.appendTransform(t, null));
562: }
563:
564: // JAVADOC COMMENT ELIDED
565: public SVGMatrix getScreenCTM() {
566: SVGMatrix m = super .getScreenCTM();
567: if (m != null) {
568: m = m.mTranslate(-x, -y);
569: }
570:
571: return m;
572: }
573:
574: /**
575: * Supported traits: x, y
576: *
577: * @param traitName the name of the trait which the element may support.
578: * @return true if this element supports the given trait in one of the
579: * trait accessor methods.
580: */
581: boolean supportsTrait(final String traitName) {
582: if (SVGConstants.SVG_X_ATTRIBUTE == traitName
583: || SVGConstants.SVG_Y_ATTRIBUTE == traitName) {
584: return true;
585: } else {
586: return super .supportsTrait(traitName);
587: }
588: }
589:
590: /**
591: * Supported traits: xlink:href
592: *
593: * @param namespaceURI the trait's namespace.
594: * @param traitName the name of the trait which the element may support.
595: * @return true if this element supports the given trait in one of the
596: * trait accessor methods.
597: */
598: boolean supportsTraitNS(final String namespaceURI,
599: final String traitName) {
600: if (SVGConstants.XLINK_NAMESPACE_URI == namespaceURI
601: && SVGConstants.SVG_HREF_ATTRIBUTE == traitName) {
602: return true;
603: } else {
604: return super .supportsTraitNS(namespaceURI, traitName);
605: }
606: }
607:
608: /**
609: * @return an array of namespaceURI, localName trait pairs required by
610: * this element.
611: */
612: public String[][] getRequiredTraitsNS() {
613: return REQUIRED_TRAITS_NS;
614: }
615:
616: /**
617: * Use handles x and y traits.
618: * Other traits are handled by the super class.
619: *
620: * @param name the requested trait's name.
621: * @return the requested trait's value.
622: *
623: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
624: * trait is not supported on this element or null.
625: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
626: * trait's computed value cannot be converted to a String (SVG Tiny only).
627: */
628: public String getTraitImpl(final String name) throws DOMException {
629: if (SVGConstants.SVG_X_ATTRIBUTE == name) {
630: return Float.toString(getX());
631: } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
632: return Float.toString(getY());
633: } else {
634: return super .getTraitImpl(name);
635: }
636: }
637:
638: /**
639: * Use handles the xlink href attribute
640: *
641: * @param namespaceURI the requested trait's namespace URI.
642: * @param name the requested trait's local name (i.e., un-prefixed, as
643: * "href")
644: * @return the requested trait's string value.
645: *
646: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
647: * trait is not supported on this element or null.
648: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
649: * trait's computed value cannot be converted to a String (SVG Tiny only).
650: * @throws SecurityException if the application does not have the necessary
651: * privilege rights to access this (SVG) content.
652: */
653: String getTraitNSImpl(String namespaceURI, String name)
654: throws DOMException {
655: if (SVGConstants.XLINK_NAMESPACE_URI == namespaceURI
656: && SVGConstants.SVG_HREF_ATTRIBUTE == name) {
657: if (idRef == null) {
658: return "";
659: }
660: return "#" + idRef;
661: } else {
662: return super .getTraitNSImpl(namespaceURI, name);
663: }
664: }
665:
666: /**
667: * Use handles x and y traits.
668: * Other attributes are handled by the super class.
669: *
670: * @param name the requested trait name.
671: * @param the requested trait's floating point value.
672: *
673: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
674: * trait is not supported on this element or null.
675: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
676: * trait's computed value cannot be converted to a float
677: * @throws SecurityException if the application does not have the necessary
678: * privilege rights to access this (SVG) content.
679: */
680: float getFloatTraitImpl(final String name) throws DOMException {
681: if (SVGConstants.SVG_X_ATTRIBUTE == name) {
682: return getX();
683: } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
684: return getY();
685: } else {
686: return super .getFloatTraitImpl(name);
687: }
688: }
689:
690: /**
691: * @param traitName the trait name.
692: */
693: TraitAnim createTraitAnimImpl(final String traitName) {
694: if (SVGConstants.SVG_X_ATTRIBUTE == traitName
695: || SVGConstants.SVG_Y_ATTRIBUTE == traitName) {
696: return new FloatTraitAnim(this , traitName, TRAIT_TYPE_FLOAT);
697: } else {
698: return super .createTraitAnimImpl(traitName);
699: }
700: }
701:
702: /**
703: * @param traitName the trait name.
704: * @param traitNamespace the trait's namespace. Should not be null.
705: */
706: TraitAnim createTraitAnimNSImpl(final String traitNamespace,
707: final String traitName) {
708: if (traitNamespace == SVGConstants.XLINK_NAMESPACE_URI
709: && traitName == SVGConstants.SVG_HREF_ATTRIBUTE) {
710: return new StringTraitAnim(this , traitNamespace, traitName);
711: }
712:
713: return super .createTraitAnimNSImpl(traitNamespace, traitName);
714: }
715:
716: /**
717: * Set the trait value as float.
718: *
719: * @param name the trait's name.
720: * @param value the trait's value.
721: *
722: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
723: * trait is not supported on this element.
724: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
725: * trait's value cannot be specified as a float
726: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
727: * value is an invalid value for the given trait.
728: */
729: void setFloatArrayTrait(final String name, final float[][] value)
730: throws DOMException {
731: if (SVGConstants.SVG_X_ATTRIBUTE == name) {
732: setX(value[0][0]);
733: } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
734: setY(value[0][0]);
735: } else {
736: super .setFloatArrayTrait(name, value);
737: }
738: }
739:
740: /**
741: * Validates the input trait value.
742: *
743: * @param traitName the name of the trait to be validated.
744: * @param value the value to be validated
745: * @param reqNamespaceURI the namespace of the element requesting
746: * validation.
747: * @param reqLocalName the local name of the element requesting validation.
748: * @param reqTraitNamespace the namespace of the trait which has the values
749: * value on the requesting element.
750: * @param reqTraitName the name of the trait which has the values value on
751: * the requesting element.
752: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
753: * value is incompatible with the given trait.
754: */
755: public float[][] validateFloatArrayTrait(final String traitName,
756: final String value, final String reqNamespaceURI,
757: final String reqLocalName, final String reqTraitNamespace,
758: final String reqTraitName) throws DOMException {
759: if (SVGConstants.SVG_X_ATTRIBUTE == traitName) {
760: return toAnimatedFloatArray(parseFloatTrait(traitName,
761: value));
762: } else if (SVGConstants.SVG_Y_ATTRIBUTE == traitName) {
763: return toAnimatedFloatArray(parseFloatTrait(traitName,
764: value));
765: } else {
766: return super .validateFloatArrayTrait(traitName, value,
767: reqNamespaceURI, reqLocalName, reqTraitNamespace,
768: reqTraitName);
769: }
770: }
771:
772: /**
773: * Validates the input trait value.
774: *
775: * @param namespaceURI the trait's namespace URI.
776: * @param traitName the name of the trait to be validated.
777: * @param value the value to be validated
778: * @param reqNamespaceURI the namespace of the element requesting
779: * validation.
780: * @param reqLocalName the local name of the element requesting validation.
781: * @param reqTraitNamespace the namespace of the trait which has the values
782: * value on the requesting element.
783: * @param reqTraitName the name of the trait which has the values value on
784: * the requesting element.
785: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
786: * value is incompatible with the given trait.
787: */
788: String validateTraitNS(final String namespaceURI,
789: final String traitName, final String value,
790: final String reqNamespaceURI, final String reqLocalName,
791: final String reqTraitNamespace, final String reqTraitName)
792: throws DOMException {
793: if (SVGConstants.XLINK_NAMESPACE_URI == namespaceURI
794: && SVGConstants.SVG_HREF_ATTRIBUTE == traitName) {
795: if (value == null || !value.startsWith("#")) {
796: throw illegalTraitValue(traitName, value);
797: }
798: return value;
799: } else {
800: return super .validateTraitNS(namespaceURI, traitName,
801: value, reqNamespaceURI, reqLocalName,
802: reqTraitNamespace, reqTraitName);
803: }
804: }
805:
806: /**
807: * Use handles x and y traits.
808: * Other traits are handled by the super class.
809: *
810: * @param name the trait's name.
811: * @param value the new trait string value.
812: *
813: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
814: * trait is not supported on this element or null.
815: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
816: * trait's value cannot be specified as a String
817: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
818: * value is an invalid value for the given trait or null.
819: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
820: * attempt is made to change readonly trait.
821: */
822: public void setTraitImpl(final String name, final String value)
823: throws DOMException {
824: if (SVGConstants.SVG_X_ATTRIBUTE == name) {
825: setX(parseFloatTrait(name, value));
826: } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
827: setY(parseFloatTrait(name, value));
828: } else {
829: super .setTraitImpl(name, value);
830: }
831: }
832:
833: /**
834: * Use supports the xlink:href trait.
835: *
836: * @param namespaceURI the trait's namespace.
837: * @param name the trait's local name (un-prefixed, e.g., "href");
838: * @param value the new trait value (e.g., "http://www.sun.com/mypng.png")
839: *
840: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
841: * trait is not supported on this element or null.
842: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
843: * trait's value cannot be specified as a String
844: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
845: * value is an invalid value for the given trait or null.
846: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
847: * attempt is made to change readonly trait.
848: * @throws SecurityException if the application does not have the necessary
849: * privilege rights to access this (SVG) content.
850: */
851: public void setTraitNSImpl(final String namespaceURI,
852: final String name, final String value) throws DOMException {
853: if (SVGConstants.XLINK_NAMESPACE_URI == namespaceURI
854: && SVGConstants.SVG_HREF_ATTRIBUTE == name) {
855: if (value == null || !value.startsWith("#")) {
856: throw illegalTraitValue(name, value);
857: }
858: setIdRef(value.substring(1));
859: } else {
860: super .setTraitNSImpl(namespaceURI, name, value);
861: }
862: }
863:
864: /**
865: * Use handles x and y traits.
866: * Other traits are handled by the super class.
867: *
868: * @param name the trait's name.
869: * @param value the new trait's floating point value.
870: *
871: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
872: * trait is not supported on this element.
873: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
874: * trait's value cannot be specified as a float
875: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
876: * value is an invalid value for the given trait.
877: * @throws SecurityException if the application does not have the necessary
878: * privilege rights to access this (SVG) content.
879: */
880: public void setFloatTraitImpl(final String name, final float value)
881: throws DOMException {
882: if (SVGConstants.SVG_X_ATTRIBUTE == name) {
883: setX(value);
884: } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
885: setY(value);
886: } else {
887: super .setFloatTraitImpl(name, value);
888: }
889: }
890:
891: /**
892: * @param name the name of the trait to convert.
893: * @param value the float trait value to convert.
894: */
895: String toStringTrait(final String name, final float[][] value) {
896: if (SVGConstants.SVG_X_ATTRIBUTE == name
897: || SVGConstants.SVG_Y_ATTRIBUTE == name) {
898: return Float.toString(value[0][0]);
899: } else {
900: return super.toStringTrait(name, value);
901: }
902: }
903:
904: }
|