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.j2d.Box;
029: import com.sun.perseus.j2d.GraphicsProperties;
030: import com.sun.perseus.j2d.PaintTarget;
031: import com.sun.perseus.j2d.RasterImage;
032: import com.sun.perseus.j2d.RenderGraphics;
033: import com.sun.perseus.j2d.Tile;
034: import com.sun.perseus.j2d.Transform;
035:
036: import com.sun.perseus.util.SVGConstants;
037: import com.sun.perseus.util.RunnableQueue;
038: import com.sun.perseus.util.RunnableQueue.RunnableHandler;
039:
040: import org.w3c.dom.DOMException;
041:
042: /**
043: * This class models the SVG Tiny <code><image></code>.
044: *
045: * A value of 0 on the width and height attributes disables the
046: * rendering of the Image object. Negative width or height values
047: * on the <code>ImageNode</code> are illegal.
048: *
049: * If the referenced <code>Image</code> is null, this node will draw
050: * a gray box using the current fill value
051: *
052: * @version $Id: ImageNode.java,v 1.17 2006/06/29 10:47:32 ln156897 Exp $
053: */
054: public class ImageNode extends AbstractRenderingNode implements
055: RasterImageConsumer {
056: /**
057: * width and height are required on <image>
058: */
059: static final String[] REQUIRED_TRAITS = {
060: SVGConstants.SVG_WIDTH_ATTRIBUTE,
061: SVGConstants.SVG_HEIGHT_ATTRIBUTE };
062:
063: /**
064: * xlink:href is required on <image>
065: */
066: static final String[][] REQUIRED_TRAITS_NS = { {
067: SVGConstants.XLINK_NAMESPACE_URI,
068: SVGConstants.SVG_HREF_ATTRIBUTE } };
069:
070: /**
071: * The viewport defined by the image element
072: */
073: protected float x, y, width, height;
074:
075: /**
076: * The painted Image. The image is built from the
077: * href attribute.
078: */
079: protected RasterImage image;
080:
081: /**
082: * Controls whether the image has been loaded or
083: * not.
084: */
085: protected boolean imageLoaded;
086:
087: /**
088: * The reference to the image data. This can be using
089: * base64 PNG or JPEG encoding or an absolute or relative
090: * URI.
091: */
092: protected String href;
093:
094: /**
095: * The absolute URI is computed from the href and the
096: * node's base URI.
097: */
098: protected String absoluteURI;
099:
100: /**
101: * Controls whether the image is aligned in the viewport
102: * or if it is just scaled to the viewport.
103: */
104: protected int align = StructureNode.ALIGN_XMIDYMID;
105:
106: /**
107: * Constant used to identify broken URI values
108: */
109: protected static final String BROKEN_URI = "broken uri";
110:
111: // =========================================================================
112: // Image specific
113: // =========================================================================
114:
115: /**
116: * Constructor.
117: *
118: * @param ownerDocument this element's owner <code>DocumentNode</code>
119: */
120: public ImageNode(final DocumentNode ownerDocument) {
121: super (ownerDocument);
122: image = ownerDocument.getImageLoader().getLoadingImage();
123:
124: // Initially, the image's width and height are zero, so we
125: // set the corresponding bits accordingly.
126: canRenderState |= CAN_RENDER_ZERO_WIDTH_BIT;
127: canRenderState |= CAN_RENDER_ZERO_HEIGHT_BIT;
128: }
129:
130: /**
131: * @return the SVGConstants.SVG_IMAGE_TAG value
132: */
133: public String getLocalName() {
134: return SVGConstants.SVG_IMAGE_TAG;
135: }
136:
137: /**
138: * Used by <code>DocumentNode</code> to create a new instance from
139: * a prototype <code>ImageNode</code>.
140: *
141: * @param doc the <code>DocumentNode</code> for which a new node is
142: * should be created.
143: * @return a new <code>ImageNode</code> for the requested document.
144: */
145: public ElementNode newInstance(final DocumentNode doc) {
146: return new ImageNode(doc);
147: }
148:
149: /**
150: * Computes the rendering tile for the given set of GraphicsProperties.
151: *
152: * @param tile the Tile instance whose bounds should be set.
153: * @param t the Transform to the requested tile space, from this node's user
154: * space.
155: * @param gp the <code>GraphicsProperties</code> for which the tile
156: * should be computed.
157: * @return the screen bounding box when this node is rendered with the
158: * given render context.
159: */
160: protected void computeRenderingTile(final Tile tile,
161: final Transform t, final GraphicsProperties gp) {
162: tile.snapBox(addNodeBBox(null, t));
163: }
164:
165: /**
166: * @param newX the new position of this image's upper left
167: * corner on the x-axis
168: */
169: public void setX(final float newX) {
170: if (newX == x) {
171: return;
172: }
173: modifyingNode();
174: renderingDirty();
175: this .x = newX;
176: modifiedNode();
177: }
178:
179: /**
180: * @param newY the new postion of this image's upper left
181: * corner on the y-axis
182: */
183: public void setY(final float newY) {
184: if (newY == y) {
185: return;
186: }
187: modifyingNode();
188: renderingDirty();
189: this .y = newY;
190: modifiedNode();
191: }
192:
193: /**
194: * @return this image's upper left corner position on the x-axis
195: */
196: public float getX() {
197: return x;
198: }
199:
200: /**
201: * @return this image's upper left corner position on the y-axis
202: */
203: public float getY() {
204: return y;
205: }
206:
207: /**
208: * @param newWidth this node's new width. Should be strictly positive
209: */
210: public void setWidth(final float newWidth) {
211: if (newWidth < 0) {
212: throw new IllegalArgumentException();
213: }
214:
215: if (newWidth == width) {
216: return;
217: }
218:
219: modifyingNode();
220: renderingDirty();
221: this .width = newWidth;
222: computeCanRenderWidthBit(width);
223: modifiedNode();
224: }
225:
226: /**
227: * @return this node's width
228: */
229: public float getWidth() {
230: return width;
231: }
232:
233: /**
234: * @param newHeight the new height for this image's node
235: * Should be strictly positive.
236: */
237: public void setHeight(final float newHeight) {
238: if (newHeight < 0) {
239: throw new IllegalArgumentException();
240: }
241:
242: if (newHeight == height) {
243: return;
244: }
245:
246: modifyingNode();
247: renderingDirty();
248: this .height = newHeight;
249: computeCanRenderHeightBit(height);
250: modifiedNode();
251: }
252:
253: /**
254: * @return this image's height
255: */
256: public float getHeight() {
257: return height;
258: }
259:
260: /**
261: * Sets this node's parent but does not generate change
262: * events.
263: *
264: * @param newParent the node's new parent node.
265: */
266: protected void setParentQuiet(final ModelNode newParent) {
267: super .setParentQuiet(newParent);
268:
269: // Reset the image if this node has a different parent that
270: // impacts the computation of the absoluteURI
271: if (href != null && !href.equals(absoluteURI)) {
272: willNeedImage();
273: }
274: }
275:
276: /**
277: * @param newHref the new reference for this node's image.
278: * @throws IllegalArgumentException if the href cannot be resolved
279: * into an absoluteURI and paintNeedsLoad is set to true.
280: */
281: public void setHref(final String newHref) {
282: if (newHref == null) {
283: throw new IllegalArgumentException();
284: }
285:
286: if (equal(newHref, href)) {
287: return;
288: }
289:
290: modifyingNode();
291: renderingDirty();
292: this .href = newHref;
293: this .image = ownerDocument.getImageLoader().getLoadingImage();
294: ownerDocument.getImageLoader().removeRasterImageConsumer(
295: absoluteURI, this );
296: this .absoluteURI = null;
297: this .imageLoaded = false;
298:
299: // Only declare the new URI to load if this node is
300: // part of the document tree and if its href is set
301: // to a non-null value.
302: if (isInDocumentTree() && href != null) {
303: willNeedImage();
304: }
305: modifiedNode();
306: }
307:
308: /**
309: * Implementation. Declares to the ImageLoader that an image will be
310: * needed.
311: */
312: void willNeedImage() {
313: imageLoaded = false;
314: image = ownerDocument.getImageLoader().getLoadingImage();
315:
316: absoluteURI = ownerDocument.getImageLoader().resolveURI(href,
317: getURIBase());
318:
319: if (absoluteURI == null) {
320: if (paintNeedsLoad) {
321: throw new IllegalArgumentException();
322: } else {
323: absoluteURI = BROKEN_URI;
324: imageLoaded = true;
325: image = ownerDocument.getImageLoader().getBrokenImage();
326: return;
327: }
328: } else {
329: ownerDocument.getImageLoader().addRasterImageConsumer(
330: absoluteURI, this );
331: ownerDocument.getImageLoader().needsURI(absoluteURI);
332: }
333: }
334:
335: /**
336: * @return this node's image reference. This should be a URI
337: */
338: public String getHref() {
339: return href;
340: }
341:
342: /**
343: * @return this node's <tt>Image</tt> resource. May be null
344: * in case no uri has been set or if loading the
345: * image data failed.
346: */
347: public RasterImage getImage() {
348: return image;
349: }
350:
351: /**
352: * Sets the node's image if the computed absolute URI
353: * is equal to the input uri.
354: *
355: * @param image the new node image. Should not be null.
356: * @param uri the uri <code>image</code> corresponds to. This is
357: * passed in case the node's uri changed between a call
358: * to the <code>ImageLoader</code>'s <code>needsURI</code>
359: * and a call to <code>setImage</code>.
360: */
361: public void setImage(final RasterImage image, final String uri) {
362: // This is done to handle situations where the href/parent
363: // or other change occur while the image is loading.
364: if (absoluteURI != null && absoluteURI.equals(uri)) {
365: if (this .image != image) {
366: modifyingNode();
367: this .image = image;
368: modifiedNode();
369: }
370: }
371: }
372:
373: /**
374: * @return the associated RunnableQueue. If not null, setImage should
375: * be called from within the runnable queue.
376: */
377: public RunnableQueue getUpdateQueue() {
378: return ownerDocument.getUpdateQueue();
379: }
380:
381: /**
382: * @return the associated RunnableHandler, in case the associated
383: * RunnableQueue is not null.
384: */
385: public RunnableHandler getRunnableHandler() {
386: return ownerDocument.getRunnableHandler();
387: }
388:
389: /**
390: * @param newAlign one of StructureNode.ALIGN_NONE or
391: * StructureNode.ALIGN_XMIDYMID
392: */
393: public void setAlign(final int newAlign) {
394: if (newAlign == align) {
395: return;
396: }
397: modifyingNode();
398: this .align = newAlign;
399: modifiedNode();
400: }
401:
402: /**
403: * @return the image's align property
404: * @see StructureNode#ALIGN_NONE
405: * @see StructureNode#ALIGN_XMIDYMID
406: */
407: public int getAlign() {
408: return align;
409: }
410:
411: /**
412: * Paints this node into the input RenderGraphics.
413: *
414: * @param rg this node is painted into this <tt>RenderGraphics</tt>
415: * @param gp the <code>GraphicsProperties</code> controlling the operation's
416: * rendering
417: * @param pt the <code>PaintTarget</code> for the paint operation.
418: * @param txf the <code>Transform</code> from user space to device space for
419: * the paint operation.
420: */
421: void paintRendered(final RenderGraphics rg,
422: final GraphicsProperties gp, final PaintTarget pt,
423: final Transform tx) {
424: if (!gp.getVisibility()) {
425: return;
426: }
427:
428: rg.setTransform(tx);
429: rg.setOpacity(getOpacity());
430:
431: if (!imageLoaded) {
432: loadImage();
433: }
434:
435: //
436: // Scale the image so that it fits into width/height
437: // and is centered
438: //
439: int iw = image.getWidth();
440: int ih = image.getHeight();
441:
442: if (align == StructureNode.ALIGN_NONE) {
443: rg.drawImage(image, x, y, width, height);
444: } else {
445: float ws = width / iw;
446: float hs = height / ih;
447: float is = ws;
448: if (hs < ws) {
449: is = hs;
450: }
451:
452: float oh = ih * is;
453: float ow = iw * is;
454: float dx = (width - ow) / 2;
455: float dy = (height - oh) / 2;
456:
457: rg.drawImage(image, (x + dx), (y + dy), ow, oh);
458: }
459: }
460:
461: /**
462: * Implementation. Loads the image through the ownerDocument's
463: * ImageLoader. If this image's paintNeedsLoad is true, this
464: * will block until the image data has been retrieved. Otherwise,
465: * a request to asynchronously load the image is placed.
466: */
467: public void loadImage() {
468: // Note that if absoluteURI is null, it is because either href is null
469: // or this node is not hooked into the tree. In these cases, we stick
470: // to the loadingImage
471: if (absoluteURI != null) {
472: if (paintNeedsLoad) {
473: image = ownerDocument.getImageLoader().getImageAndWait(
474: absoluteURI);
475: if (image == ownerDocument.getImageLoader()
476: .getBrokenImage()) {
477: throw new IllegalStateException();
478: }
479: } else {
480: ownerDocument.getImageLoader().getImageLater(
481: absoluteURI, this );
482: }
483: }
484: imageLoaded = true;
485: }
486:
487: /**
488: * An <code>ImageNode</code> has something to render
489: *
490: * @return true
491: */
492: public boolean hasNodeRendering() {
493: return true;
494: }
495:
496: /**
497: * Returns true if this node is hit by the input point. The input point
498: * is in viewport space.
499: *
500: * @param pt the x/y coordinate. Should never be null and be
501: * of size two. If not, the behavior is unspecified.
502: * The x/y coordinate is in viewport space.
503: *
504: * @return true if the node is hit by the input point.
505: * @see #nodeHitAt
506: */
507: protected boolean isHitVP(float[] pt) {
508: if (!getVisibility()) {
509: return false;
510: }
511: getInverseTransformState()
512: .transformPoint(pt, ownerDocument.upt);
513: pt = ownerDocument.upt;
514: return (pt[0] > x && pt[0] < (x + width) && pt[1] > y && pt[1] < (y + height));
515: }
516:
517: /**
518: * Returns true if the proxy node is hit by the input point. The input point
519: * is in viewport space.
520: *
521: * @param pt the x/y coordinate. Should never be null and be
522: * of size two. If not, the behavior is unspecified.
523: * The x/y coordinate is in viewport space.
524: * @param proxy the tested <code>ElementNodeProxy</code>.
525: * @return true if the node is hit by the input point.
526: * @see #nodeHitAt
527: */
528: protected boolean isProxyHitVP(float[] pt,
529: AbstractRenderingNodeProxy proxy) {
530: proxy.getInverseTransformState().transformPoint(pt,
531: ownerDocument.upt);
532: pt = ownerDocument.upt;
533: return (pt[0] > x && pt[0] < (x + width) && pt[1] > y && pt[1] < (y + height));
534: }
535:
536: /**
537: * Supported traits: x, y, width, height
538: *
539: * @param traitName the name of the trait which the element may support.
540: * @return true if this element supports the given trait in one of the
541: * trait accessor methods.
542: */
543: boolean supportsTrait(final String traitName) {
544: if (SVGConstants.SVG_X_ATTRIBUTE == traitName
545: || SVGConstants.SVG_Y_ATTRIBUTE == traitName
546: || SVGConstants.SVG_WIDTH_ATTRIBUTE == traitName
547: || SVGConstants.SVG_HEIGHT_ATTRIBUTE == traitName
548: || SVGConstants.SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE == traitName) {
549: return true;
550: } else {
551: return super .supportsTrait(traitName);
552: }
553: }
554:
555: /**
556: * @return an array of traits that are required by this element.
557: */
558: public String[] getRequiredTraits() {
559: return REQUIRED_TRAITS;
560: }
561:
562: /**
563: * @return an array of namespaceURI, localName trait pairs required by
564: * this element.
565: */
566: public String[][] getRequiredTraitsNS() {
567: return REQUIRED_TRAITS_NS;
568: }
569:
570: /**
571: * Supported traits: xlink:href
572: *
573: * @param namespaceURI the trait's namespace.
574: * @param traitName the name of the trait which the element may support.
575: * @return true if this element supports the given trait in one of the
576: * trait accessor methods.
577: */
578: boolean supportsTraitNS(final String namespaceURI,
579: final String traitName) {
580: if (SVGConstants.XLINK_NAMESPACE_URI == namespaceURI
581: && SVGConstants.SVG_HREF_ATTRIBUTE == traitName) {
582: return true;
583: } else {
584: return super .supportsTraitNS(namespaceURI, traitName);
585: }
586: }
587:
588: /**
589: * ImageNode handles x, y, width and height traits.
590: * Other traits are handled by the super class.
591: *
592: * @param name the requested trait's name.
593: * @return the requested trait's value.
594: *
595: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
596: * trait is not supported on this element or null.
597: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
598: * trait's computed value cannot be converted to a String (SVG Tiny only).
599: */
600: public String getTraitImpl(final String name) throws DOMException {
601: if (SVGConstants.SVG_X_ATTRIBUTE == name) {
602: return Float.toString(getX());
603: } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
604: return Float.toString(getY());
605: } else if (SVGConstants.SVG_WIDTH_ATTRIBUTE == name) {
606: return Float.toString(getWidth());
607: } else if (SVGConstants.SVG_HEIGHT_ATTRIBUTE == name) {
608: return Float.toString(getHeight());
609: } else if (SVGConstants.SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE == name) {
610: return alignToStringTrait(align);
611: } else {
612: return super .getTraitImpl(name);
613: }
614: }
615:
616: /**
617: * ImageNode handles the xlink href attribute
618: *
619: * @param namespaceURI the requested trait's namespace URI.
620: * @param name the requested trait's local name (i.e., un-prefixed, as
621: * "href")
622: * @return the requested trait's string value.
623: *
624: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
625: * trait is not supported on this element or null.
626: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
627: * trait's computed value cannot be converted to a String (SVG Tiny
628: * only).
629: * @throws SecurityException if the application does not have the necessary
630: * privilege rights to access this (SVG) content.
631: */
632: String getTraitNSImpl(String namespaceURI, String name)
633: throws DOMException {
634: if (SVGConstants.XLINK_NAMESPACE_URI == namespaceURI
635: && SVGConstants.SVG_HREF_ATTRIBUTE == name) {
636: if (href == null) {
637: return "";
638: }
639: return href;
640: } else {
641: return super .getTraitNSImpl(namespaceURI, name);
642: }
643: }
644:
645: /**
646: * ImageNode handles x, y, width and height traits.
647: * Other attributes are handled by the super class.
648: *
649: * @param name the requested trait name.
650: * @param the requested trait's floating point value.
651: *
652: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
653: * trait is not supported on this element or null.
654: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
655: * trait's computed value cannot be converted to a float
656: * @throws SecurityException if the application does not have the necessary
657: * privilege rights to access this (SVG) content.
658: */
659: float getFloatTraitImpl(final String name) throws DOMException {
660: if (SVGConstants.SVG_X_ATTRIBUTE == name) {
661: return getX();
662: } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
663: return getY();
664: } else if (SVGConstants.SVG_WIDTH_ATTRIBUTE == name) {
665: return getWidth();
666: } else if (SVGConstants.SVG_HEIGHT_ATTRIBUTE == name) {
667: return getHeight();
668: } else {
669: return super .getFloatTraitImpl(name);
670: }
671: }
672:
673: /**
674: * @param traitName the trait name.
675: */
676: TraitAnim createTraitAnimImpl(final String traitName) {
677: if (SVGConstants.SVG_X_ATTRIBUTE == traitName
678: || SVGConstants.SVG_Y_ATTRIBUTE == traitName
679: || SVGConstants.SVG_WIDTH_ATTRIBUTE == traitName
680: || SVGConstants.SVG_HEIGHT_ATTRIBUTE == traitName) {
681: return new FloatTraitAnim(this , traitName, TRAIT_TYPE_FLOAT);
682: } else if (SVGConstants.SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE == traitName) {
683: return new StringTraitAnim(this , NULL_NS, traitName);
684: } else {
685: return super .createTraitAnimImpl(traitName);
686: }
687: }
688:
689: /**
690: * @param traitName the trait name.
691: * @param traitNamespace the trait's namespace. Should not be null.
692: */
693: TraitAnim createTraitAnimNSImpl(final String traitNamespace,
694: final String traitName) {
695: if (traitNamespace == SVGConstants.XLINK_NAMESPACE_URI
696: && traitName == SVGConstants.SVG_HREF_ATTRIBUTE) {
697: return new StringTraitAnim(this , traitNamespace, traitName);
698: }
699:
700: return super .createTraitAnimNSImpl(traitNamespace, traitName);
701: }
702:
703: /**
704: * Set the trait value as float.
705: *
706: * @param name the trait's name.
707: * @param value the trait's value.
708: *
709: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
710: * trait is not supported on this element.
711: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
712: * trait's value cannot be specified as a float
713: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
714: * value is an invalid value for the given trait.
715: */
716: void setFloatArrayTrait(final String name, final float[][] value)
717: throws DOMException {
718: if (SVGConstants.SVG_X_ATTRIBUTE == name) {
719: setX(value[0][0]);
720: } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
721: setY(value[0][0]);
722: } else if (SVGConstants.SVG_WIDTH_ATTRIBUTE == name) {
723: checkPositive(name, value[0][0]);
724: setWidth(value[0][0]);
725: } else if (SVGConstants.SVG_HEIGHT_ATTRIBUTE == name) {
726: checkPositive(name, value[0][0]);
727: setHeight(value[0][0]);
728: } else {
729: super .setFloatArrayTrait(name, value);
730: }
731: }
732:
733: /**
734: * Validates the input trait value.
735: *
736: * @param traitName the name of the trait to be validated.
737: * @param value the value to be validated
738: * @param reqNamespaceURI the namespace of the element requesting
739: * validation.
740: * @param reqLocalName the local name of the element requesting validation.
741: * @param reqTraitNamespace the namespace of the trait which has the values
742: * value on the requesting element.
743: * @param reqTraitName the name of the trait which has the values value on
744: * the requesting element.
745: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
746: * value is incompatible with the given trait.
747: */
748: public float[][] validateFloatArrayTrait(final String traitName,
749: final String value, final String reqNamespaceURI,
750: final String reqLocalName, final String reqTraitNamespace,
751: final String reqTraitName) throws DOMException {
752: if (SVGConstants.SVG_X_ATTRIBUTE == traitName
753: || SVGConstants.SVG_Y_ATTRIBUTE == traitName) {
754: return new float[][] { { parseFloatTrait(traitName, value) } };
755: } else if (SVGConstants.SVG_WIDTH_ATTRIBUTE == traitName
756: || SVGConstants.SVG_HEIGHT_ATTRIBUTE == traitName) {
757: return new float[][] { { parsePositiveFloatTrait(traitName,
758: value) } };
759: } else {
760: return super .validateFloatArrayTrait(traitName, value,
761: reqNamespaceURI, reqLocalName, reqTraitNamespace,
762: reqTraitName);
763: }
764: }
765:
766: /**
767: * Validates the input trait value.
768: *
769: * @param namespaceURI the trait's namespace URI.
770: * @param traitName the name of the trait to be validated.
771: * @param value the value to be validated
772: * @param reqNamespaceURI the namespace of the element requesting
773: * validation.
774: * @param reqLocalName the local name of the element requesting validation.
775: * @param reqTraitNamespace the namespace of the trait which has the values
776: * value on the requesting element.
777: * @param reqTraitName the name of the trait which has the values value on
778: * the requesting element.
779: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
780: * value is incompatible with the given trait.
781: */
782: String validateTraitNS(final String namespaceURI,
783: final String traitName, final String value,
784: final String reqNamespaceURI, final String reqLocalName,
785: final String reqTraitNamespace, final String reqTraitName)
786: throws DOMException {
787: if (namespaceURI != null) {
788: return super .validateTraitNS(namespaceURI, traitName,
789: value, reqNamespaceURI, reqLocalName,
790: reqTraitNamespace, reqTraitName);
791: }
792:
793: if (SVGConstants.SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE
794: .equals(traitName)) {
795: if (!SVGConstants.SVG_SVG_PRESERVE_ASPECT_RATIO_DEFAULT_VALUE
796: .equals(value)
797: && !SVGConstants.SVG_NONE_VALUE.equals(value)) {
798: throw illegalTraitValue(traitName, value);
799: }
800: return value;
801: } else {
802: return super .validateTraitNS(namespaceURI, traitName,
803: value, reqNamespaceURI, reqLocalName,
804: reqTraitNamespace, reqTraitName);
805: }
806: }
807:
808: /**
809: * ImageNode handles x, y, rx, ry, width and height traits.
810: * Other traits are handled by the super class.
811: *
812: * @param name the trait's name.
813: * @param value the new trait string value.
814: *
815: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
816: * trait is not supported on this element or null.
817: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
818: * trait's value cannot be specified as a String
819: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
820: * value is an invalid value for the given trait or null.
821: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
822: * attempt is made to change readonly trait.
823: */
824: public void setTraitImpl(final String name, final String value)
825: throws DOMException {
826: if (SVGConstants.SVG_X_ATTRIBUTE == name) {
827: setX(parseFloatTrait(name, value));
828: } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
829: setY(parseFloatTrait(name, value));
830: } else if (SVGConstants.SVG_WIDTH_ATTRIBUTE == name) {
831: setWidth(parsePositiveFloatTrait(name, value));
832: } else if (SVGConstants.SVG_HEIGHT_ATTRIBUTE == name) {
833: setHeight(parsePositiveFloatTrait(name, value));
834: } else if (SVGConstants.SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE
835: .equals(name)) {
836: if (SVGConstants.SVG_SVG_PRESERVE_ASPECT_RATIO_DEFAULT_VALUE
837: .equals(value)) {
838: setAlign(StructureNode.ALIGN_XMIDYMID);
839: } else if (SVGConstants.SVG_NONE_VALUE.equals(value)) {
840: setAlign(StructureNode.ALIGN_NONE);
841: } else {
842: throw illegalTraitValue(name, value);
843: }
844: } else {
845: super .setTraitImpl(name, value);
846: }
847: }
848:
849: /**
850: * ImageNode supports the xlink:href trait.
851: *
852: * @param namespaceURI the trait's namespace.
853: * @param name the trait's local name (un-prefixed, e.g., "href");
854: * @param value the new trait value (e.g., "http://www.sun.com/mypng.png")
855: *
856: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
857: * trait is not supported on this element or null.
858: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
859: * trait's value cannot be specified as a String
860: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
861: * value is an invalid value for the given trait or null.
862: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
863: * attempt is made to change readonly trait.
864: * @throws SecurityException if the application does not have the necessary
865: * privilege rights to access this (SVG) content.
866: */
867: public void setTraitNSImpl(final String namespaceURI,
868: final String name, final String value) throws DOMException {
869: try {
870: if (SVGConstants.XLINK_NAMESPACE_URI == namespaceURI
871: && SVGConstants.SVG_HREF_ATTRIBUTE == name) {
872: setHref(value);
873: } else {
874: super .setTraitNSImpl(namespaceURI, name, value);
875: }
876: } catch (IllegalArgumentException iae) {
877: throw illegalTraitValue(name, value);
878: }
879: }
880:
881: /**
882: * ImageNode handles x, y, rx, ry, width and height traits.
883: * Other traits are handled by the super class.
884: *
885: * @param name the trait's name.
886: * @param value the new trait's floating point value.
887: *
888: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
889: * trait is not supported on this element.
890: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
891: * trait's value cannot be specified as a float
892: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
893: * value is an invalid value for the given trait.
894: * @throws SecurityException if the application does not have the necessary
895: * privilege rights to access this (SVG) content.
896: */
897: public void setFloatTraitImpl(final String name, final float value)
898: throws DOMException {
899: try {
900: if (SVGConstants.SVG_X_ATTRIBUTE == name) {
901: setX(value);
902: } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
903: setY(value);
904: } else if (SVGConstants.SVG_WIDTH_ATTRIBUTE == name) {
905: setWidth(value);
906: } else if (SVGConstants.SVG_HEIGHT_ATTRIBUTE == name) {
907: setHeight(value);
908: } else {
909: super .setFloatTraitImpl(name, value);
910: }
911: } catch (IllegalArgumentException iae) {
912: throw illegalTraitValue(name, Float.toString(value));
913: }
914: }
915:
916: /**
917: * @param name the name of the trait to convert.
918: * @param value the float trait value to convert.
919: */
920: String toStringTrait(final String name, final float[][] value) {
921: if (SVGConstants.SVG_X_ATTRIBUTE == name
922: || SVGConstants.SVG_Y_ATTRIBUTE == name
923: || SVGConstants.SVG_WIDTH_ATTRIBUTE == name
924: || SVGConstants.SVG_HEIGHT_ATTRIBUTE == name) {
925: return Float.toString(value[0][0]);
926: } else {
927: return super .toStringTrait(name, value);
928: }
929: }
930:
931: /**
932: * @param bbox the bounding box to which this node's bounding box should be
933: * appended. That bounding box is in the target coordinate space. It
934: * may be null, in which case this node should create a new one.
935: * @param t the transform from the node coordinate system to the coordinate
936: * system into which the bounds should be computed.
937: * @return the bounding box of this node, in the target coordinate space,
938: */
939: Box addNodeBBox(Box bbox, final Transform t) {
940: return addTransformedBBox(bbox, x, y, width, height, t);
941: }
942: }
|