/* * $RCSfile: CompositeGraphicsNode.java,v $ * * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package com.sun.perseus.model; import org.w3c.dom.DOMException; import org.w3c.dom.svg.SVGRect; import org.w3c.dom.svg.SVGRGBColor; import org.w3c.dom.svg.SVGLocatableElement; import com.sun.perseus.j2d.GraphicsProperties; import com.sun.perseus.j2d.Transform; import com.sun.perseus.util.SVGConstants; import com.sun.perseus.j2d.RGB; import com.sun.perseus.j2d.PaintDef; import com.sun.perseus.j2d.PaintTarget; import com.sun.perseus.j2d.PaintServer; /** * <code>CompositeGraphicsNode</code> is the base class for all nodes which are * both composites (i.e., they can have children) and have graphic properties * (such as <code>fill</code> or <code>stroke</code>). * * @version $Id: CompositeGraphicsNode.java,v 1.16 2006/06/29 10:47:29 ln156897 Exp $ */ public abstract class CompositeGraphicsNode extends ElementNode implements GraphicsNode, PaintTarget, SVGLocatableElement { // ======================================================================= // Constants used for packing and unpacking data in the pack member // ======================================================================= protected static final int FONT_STYLE_MASK = 0x60000000; /* 30-29 */ protected static final int FONT_WEIGHT_MASK = 0x1E000000; /* 28-27-26-25 */ protected static final int TEXT_ANCHOR_MASK = 0x01800000; /* 24-23 */ protected static final int STROKE_OPACITY_MASK = 0x007F8000; /* 22-21-20-19-18-17-16-15 */ protected static final int FILL_OPACITY_MASK = 0x00007F80; /* 14-13-12-11-10-09-08-07 */ protected static final int FILL_RULE_MASK = 0x00000040; /* 06 */ protected static final int STROKE_LINE_CAP_MASK = 0x00000030; /* 05-04 */ protected static final int STROKE_LINE_JOIN_MASK = 0x0000000C; /* 03-02 */ protected static final int VISIBILITY_MASK = 0x00000002; /* 01 */ protected static final int DISPLAY_MASK = 0x00000001; /* 00 */ // ======================================================================= // Constants used for packing and unpacking data in the pack2 member // ======================================================================= protected static final int OPACITY_MASK = 0x000000FF; /* 7-6-5-4-3-2-1-0 */ protected static final int FONT_STYLE_NORMAL_IMPL = 0x00000000; protected static final int FONT_STYLE_ITALIC_IMPL = 0x40000000; protected static final int FONT_STYLE_OBLIQUE_IMPL = 0x60000000; protected static final int FONT_WEIGHT_100_IMPL = 0x00000000; protected static final int FONT_WEIGHT_200_IMPL = 0x02000000; protected static final int FONT_WEIGHT_300_IMPL = 0x04000000; protected static final int FONT_WEIGHT_400_IMPL = 0x06000000; protected static final int FONT_WEIGHT_500_IMPL = 0x08000000; protected static final int FONT_WEIGHT_600_IMPL = 0x0A000000; protected static final int FONT_WEIGHT_700_IMPL = 0x0C000000; protected static final int FONT_WEIGHT_800_IMPL = 0x0E000000; protected static final int FONT_WEIGHT_900_IMPL = 0x10000000; protected static final int FONT_WEIGHT_LIGHTER_IMPL = 0x12000000; protected static final int FONT_WEIGHT_BOLDER_IMPL = 0x14000000; protected static final int TEXT_ANCHOR_MIDDLE_IMPL = 0x00000000; protected static final int TEXT_ANCHOR_START_IMPL = 0x00800000; protected static final int TEXT_ANCHOR_END_IMPL = 0x01000000; protected static final int CAP_BUTT_IMPL = 0x00000000; protected static final int CAP_ROUND_IMPL = 0x00000010; protected static final int CAP_SQUARE_IMPL = 0x00000020; protected static final int JOIN_MITER_IMPL = 0x00000000; protected static final int JOIN_ROUND_IMPL = 0x00000004; protected static final int JOIN_BEVEL_IMPL = 0x00000008; // ==================================================================== // Property values // ==================================================================== /** * The current color. The fill and stroke colors may be * relative to the current color */ protected RGB color = INITIAL_COLOR; /** * The fill paint used to fill this node */ protected PaintServer fill = INITIAL_FILL; /** * The stroke paint used to stroke the outline of * this ShapeNode */ protected PaintServer stroke = INITIAL_STROKE; /** * The stroke width */ protected float strokeWidth = INITIAL_STROKE_WIDTH; /** * The stroke miter limit */ protected float strokeMiterLimit = INITIAL_STROKE_MITER_LIMIT; /** * The stroke dash array */ protected float[] strokeDashArray = INITIAL_STROKE_DASH_ARRAY; /** * The stroke dash offset */ protected float strokeDashOffset = INITIAL_STROKE_DASH_OFFSET; // // Property pack // // fontStyle: 3 styles, 2 bits // fontWeight: 9 weights, 4 bits // textAnchor 3 values, 2 bits // strokeOpacity: 8 bits [0-255] // fillOpacity: 8 bits [0-255] // fillRule: 1 bits // strokeLineCap: 3 values, 2 bits // strokeLineJoin 3 values, 2 bits // visibility: 2 values, 1 bit // display: 2 values, 1 bit // Total: 31 bits // // Encoding: // // fontStyle: 30-29 // fontWeight: 28-27-26-25 // textAnchor: 24-23 // strokeOpacity: 22-21-20-19-18-17-16-15 // fillOpacity: 14-13-12-11-10-09-08-07 // fillRule: 06 // strokeLineCap: 05-04 // strokeLineJoin: 03-02 // visibility: 01 // display: 00 // protected int pack = INITIAL_PACK; protected static final int INITIAL_FONT_STYLE_IMPL = FONT_STYLE_NORMAL_IMPL; protected static final int INITIAL_FONT_WEIGHT_IMPL = FONT_WEIGHT_400_IMPL; protected static final int INITIAL_TEXT_ANCHOR_IMPL = TEXT_ANCHOR_START_IMPL; protected static final int INITIAL_STROKE_OPACITY_IMPL = 200 << 15; protected static final int INITIAL_FILL_OPACITY_IMPL = 200 << 7; protected static final int INITIAL_FILL_RULE_IMPL = FILL_RULE_MASK; protected static final int INITIAL_STROKE_LINE_CAP_IMPL = CAP_BUTT_IMPL; protected static final int INITIAL_STROKE_LINE_JOIN_IMPL = JOIN_MITER_IMPL; protected static final int INITIAL_VISIBILITY_IMPL = 0x2; protected static final int INITIAL_DISPLAY_IMPL = 0x1; protected static final int INITIAL_PACK = INITIAL_FONT_STYLE_IMPL | INITIAL_FONT_WEIGHT_IMPL | INITIAL_TEXT_ANCHOR_IMPL | INITIAL_STROKE_OPACITY_IMPL | INITIAL_FILL_OPACITY_IMPL | INITIAL_FILL_RULE_IMPL | INITIAL_STROKE_LINE_CAP_IMPL | INITIAL_STROKE_LINE_JOIN_IMPL | INITIAL_VISIBILITY_IMPL | INITIAL_DISPLAY_IMPL; // // Property pack2 // // opacity: 8 bits [0-255] // Total: 8 bits // // Encoding: // // opacity: 07-06-05-04-03-02-01-00 // protected int pack2 = INITIAL_PACK2; protected static final int INITIAL_OPACITY_IMPL = 200; protected static final int INITIAL_PACK2 = INITIAL_OPACITY_IMPL; // ==================================================================== // Property value types (inherited, relative, none, specific) // ==================================================================== // /** * Marker used to mark that the color relative property was set. */ public static final int COLOR_RELATIVE_MARKER = 23; /** * Markers are used to keep track of inherited properties, color relative * properties and bolder/lighter font weights. * * 0-22 : property inheritance * 23-24 : color relative * 24 : is bolder marker * 25 : is lighter marker */ protected int markers = DEFAULT_INHERITANCE | TextNode.DEFAULT_INHERITANCE | ViewportNode.DEFAULT_INHERITANCE | DEFAULT_COLOR_RELATIVE; // ==================================================================== // ModelNode Implementation // ==================================================================== /** * Cached Transform. May point to the parent transform. */ protected Transform txf = null; /** * Cached inverse transform. May point to the parent inverse transform. */ protected Transform inverseTxf = null; /** * Constructor. * * @param ownerDocument this element's owner <code>DocumentNode</code> */ public CompositeGraphicsNode(final DocumentNode ownerDocument) { super(ownerDocument); // By default, a CompositeGraphicsNode is renderable canRenderState &= CAN_RENDER_RENDERABLE_MASK; } /** * A <code>CompositeGraphicsNode</code> contributes to its parent bounding * box only if its display property is turned on. * * @return true if the node's bounding box should be accounted for. */ protected boolean contributeBBox() { return (pack & DISPLAY_MASK) != 0; } /** * @return the tight bounding box in the current user coordinate * space, that is, the least possible rectangle * including all contained graphical elements, but not including stroke. * The calculation is performed in the user coordinate space of the * element, that is, in the coordinate space used for drawing the element, * after applying the transform attribute, if any. In the process of * calculating the bounding box, any elements having the display * property (trait) set to none are ignored. * See <a * href="http://www.w3.org/TR/SVG/coords.html#ObjectBoundingBox">SVG * spec</a> for exact rules of bounding box calculation. */ public SVGRect getBBox() { return null; } /** * @return the tight bounding box in screen coordinate space. Tight bounding * box is the smallest possible rectangle that includes the geometry of all * contained graphics elements excluding stroke. The box coordinates are in * the screen coordinate space, which is connected to the current user * coordinate space by the matrix returned by {@link * org.w3c.dom.svg.SVGLocatableElement#getScreenCTM getScreenCTM} method. */ public SVGRect getScreenBBox() { return null; } /** * Returns the value of the given Object-valued property. * * @return the value of the given Object-valued property. */ protected Object getPropertyState(final int propertyIndex) { switch (propertyIndex) { case PROPERTY_FILL: return fill; case PROPERTY_STROKE: return stroke; case PROPERTY_COLOR: return color; case PROPERTY_STROKE_DASH_ARRAY: return strokeDashArray; default: return super.getPropertyState(propertyIndex); } } /** * Returns the value of the given float-valued property. * * @return the value of the given property. */ protected float getFloatPropertyState(final int propertyIndex) { switch (propertyIndex) { case PROPERTY_STROKE_WIDTH: return strokeWidth; case PROPERTY_STROKE_MITER_LIMIT: return strokeMiterLimit; case PROPERTY_STROKE_DASH_OFFSET: return strokeDashOffset; default: return super.getFloatPropertyState(propertyIndex); } } /** * Returns the value for the given packed property. * * @return the value for the given property. */ protected int getPackedPropertyState(final int propertyIndex) { switch (propertyIndex) { case GraphicsNode.PROPERTY_FILL_RULE: return pack & CompositeGraphicsNode.FILL_RULE_MASK; case GraphicsNode.PROPERTY_STROKE_LINE_JOIN: return pack & CompositeGraphicsNode.STROKE_LINE_JOIN_MASK; case GraphicsNode.PROPERTY_STROKE_LINE_CAP: return pack & CompositeGraphicsNode.STROKE_LINE_CAP_MASK; case GraphicsNode.PROPERTY_DISPLAY: return pack & CompositeGraphicsNode.DISPLAY_MASK; case GraphicsNode.PROPERTY_VISIBILITY: return pack & CompositeGraphicsNode.VISIBILITY_MASK; case GraphicsNode.PROPERTY_FILL_OPACITY: return pack & CompositeGraphicsNode.FILL_OPACITY_MASK; case GraphicsNode.PROPERTY_STROKE_OPACITY: return pack & CompositeGraphicsNode.STROKE_OPACITY_MASK; case GraphicsNode.PROPERTY_OPACITY: return pack2 & CompositeGraphicsNode.OPACITY_MASK; default: return super.getPackedPropertyState(propertyIndex); } } /** * Sets the computed value of the given Object-valued property. * * @param propertyIndex the property index * @param propertyValue the computed value of the property. */ protected void setPropertyState(final int propertyIndex, final Object propertyValue) { switch (propertyIndex) { case PROPERTY_FILL: setComputedFill((PaintServer) propertyValue); break; case PROPERTY_STROKE: setComputedStroke((PaintServer) propertyValue); break; case PROPERTY_COLOR: setComputedColor((RGB) propertyValue); break; case PROPERTY_STROKE_DASH_ARRAY: setComputedStrokeDashArray((float[]) propertyValue); break; default: super.setPropertyState(propertyIndex, propertyValue); break; } } /** * Sets the computed value of the given float-valued property. * * @param propertyIndex the property index * @param propertyValue the computed value of the property. */ protected void setFloatPropertyState(final int propertyIndex, final float propertyValue) { switch (propertyIndex) { case PROPERTY_STROKE_WIDTH: setComputedStrokeWidth(propertyValue); break; case PROPERTY_STROKE_MITER_LIMIT: setComputedStrokeMiterLimit(propertyValue); break; case PROPERTY_STROKE_DASH_OFFSET: setComputedStrokeDashOffset(propertyValue); break; default: super.setFloatPropertyState(propertyIndex, propertyValue); break; } } /** * Sets the computed value of the given packed property. * * @param propertyIndex the property index * @param propertyValue the computed value of the property. */ protected void setPackedPropertyState(final int propertyIndex, final int propertyValue) { switch (propertyIndex) { case GraphicsNode.PROPERTY_FILL_RULE: if (propertyValue == 0) { setComputedFillRule(WIND_EVEN_ODD); } else { setComputedFillRule(WIND_NON_ZERO); } break; case GraphicsNode.PROPERTY_STROKE_LINE_JOIN: switch (propertyValue) { case CompositeGraphicsNode.JOIN_MITER_IMPL: setComputedStrokeLineJoin(JOIN_MITER); break; case CompositeGraphicsNode.JOIN_ROUND_IMPL: setComputedStrokeLineJoin(JOIN_ROUND); break; case CompositeGraphicsNode.JOIN_BEVEL_IMPL: default: setComputedStrokeLineJoin(JOIN_BEVEL); break; } break; case GraphicsNode.PROPERTY_STROKE_LINE_CAP: switch (propertyValue) { case CompositeGraphicsNode.CAP_BUTT_IMPL: setComputedStrokeLineCap(CAP_BUTT); break; case CompositeGraphicsNode.CAP_ROUND_IMPL: setComputedStrokeLineCap(CAP_ROUND); break; case CompositeGraphicsNode.CAP_SQUARE_IMPL: default: setComputedStrokeLineCap(CAP_SQUARE); break; } break; case GraphicsNode.PROPERTY_DISPLAY: if (propertyValue != 0) { setComputedDisplay(true); } else { setComputedDisplay(false); } break; case GraphicsNode.PROPERTY_VISIBILITY: if (propertyValue != 0) { setComputedVisibility(true); } else { setComputedVisibility(false); } break; case GraphicsNode.PROPERTY_FILL_OPACITY: setComputedFillOpacity((propertyValue >> 7) / 200.0f); break; case GraphicsNode.PROPERTY_STROKE_OPACITY: setComputedStrokeOpacity((propertyValue >> 15) / 200.0f); break; case GraphicsNode.PROPERTY_OPACITY: setComputedOpacity(propertyValue / 200.0f); break; default: super.setPackedPropertyState(propertyIndex, propertyValue); break; } } /** * Checks the state of the Object-valued property. * * @param propertyIndex the property index * @param propertyValue the computed value of the property. */ protected boolean isPropertyState(final int propertyIndex, final Object propertyValue) { switch (propertyIndex) { case GraphicsNode.PROPERTY_FILL: return fill == propertyValue; case GraphicsNode.PROPERTY_STROKE: return stroke == propertyValue; case GraphicsNode.PROPERTY_COLOR: return color == propertyValue; case GraphicsNode.PROPERTY_STROKE_DASH_ARRAY: return strokeDashArray == propertyValue; default: return super.isPropertyState(propertyIndex, propertyValue); } } /** * Checks the state of the float property value. * * @param propertyIndex the property index * @param propertyValue the computed value of the property. */ protected boolean isFloatPropertyState(final int propertyIndex, final float propertyValue) { switch (propertyIndex) { case GraphicsNode.PROPERTY_STROKE_WIDTH: return strokeWidth == propertyValue; case GraphicsNode.PROPERTY_STROKE_MITER_LIMIT: return strokeMiterLimit == propertyValue; case GraphicsNode.PROPERTY_STROKE_DASH_OFFSET: return strokeDashOffset == propertyValue; default: return super.isFloatPropertyState(propertyIndex, propertyValue); } } /** * Checks the state of the packed property value. * * @param propertyIndex the property index * @param propertyValue the computed value of the property. */ protected boolean isPackedPropertyState(final int propertyIndex, final int propertyValue) { switch (propertyIndex) { case GraphicsNode.PROPERTY_FILL_RULE: return (propertyValue == (pack & CompositeGraphicsNode.FILL_RULE_MASK)); case GraphicsNode.PROPERTY_STROKE_LINE_JOIN: return (propertyValue == (pack & CompositeGraphicsNode.STROKE_LINE_JOIN_MASK)); case GraphicsNode.PROPERTY_STROKE_LINE_CAP: return (propertyValue == (pack & CompositeGraphicsNode.STROKE_LINE_CAP_MASK)); case GraphicsNode.PROPERTY_DISPLAY: return (propertyValue == (pack & CompositeGraphicsNode.DISPLAY_MASK)); case GraphicsNode.PROPERTY_VISIBILITY: return (propertyValue == (pack & CompositeGraphicsNode.VISIBILITY_MASK)); case GraphicsNode.PROPERTY_FILL_OPACITY: return (propertyValue == (pack & CompositeGraphicsNode.FILL_OPACITY_MASK)); case GraphicsNode.PROPERTY_STROKE_OPACITY: return (propertyValue == (pack & CompositeGraphicsNode.STROKE_OPACITY_MASK)); case GraphicsNode.PROPERTY_OPACITY: return (propertyValue == (pack2 & CompositeGraphicsNode.OPACITY_MASK)); default: return super.isPackedPropertyState(propertyIndex, propertyValue); } } /** * Recomputes all inherited properties. */ void recomputeInheritedProperties() { ModelNode p = ownerDocument; if (parent != null) { p = parent; } recomputePropertyState(PROPERTY_FILL, p.getPropertyState(PROPERTY_FILL)); recomputePropertyState(PROPERTY_STROKE, p.getPropertyState(PROPERTY_STROKE)); recomputePropertyState(PROPERTY_COLOR, p.getPropertyState(PROPERTY_COLOR)); recomputePackedPropertyState(PROPERTY_FILL_RULE, p.getPackedPropertyState(PROPERTY_FILL_RULE)); recomputeFloatPropertyState(PROPERTY_STROKE_WIDTH, p.getFloatPropertyState(PROPERTY_STROKE_WIDTH)); recomputePackedPropertyState(PROPERTY_STROKE_LINE_JOIN, p.getPackedPropertyState( PROPERTY_STROKE_LINE_JOIN)); recomputePackedPropertyState(PROPERTY_STROKE_LINE_CAP, p.getPackedPropertyState( PROPERTY_STROKE_LINE_CAP)); recomputeFloatPropertyState(PROPERTY_STROKE_MITER_LIMIT, p.getFloatPropertyState( PROPERTY_STROKE_MITER_LIMIT)); recomputePropertyState(PROPERTY_STROKE_DASH_ARRAY, p.getPropertyState(PROPERTY_STROKE_DASH_ARRAY)); recomputeFloatPropertyState(PROPERTY_STROKE_DASH_OFFSET, p.getFloatPropertyState( PROPERTY_STROKE_DASH_OFFSET)); recomputePackedPropertyState(PROPERTY_DISPLAY, p.getPackedPropertyState(PROPERTY_DISPLAY)); recomputePackedPropertyState(PROPERTY_VISIBILITY, p.getPackedPropertyState(PROPERTY_VISIBILITY)); recomputePackedPropertyState(PROPERTY_FILL_OPACITY, p.getPackedPropertyState(PROPERTY_FILL_OPACITY)); recomputePackedPropertyState(PROPERTY_STROKE_OPACITY, p.getPackedPropertyState( PROPERTY_STROKE_OPACITY)); recomputePackedPropertyState(PROPERTY_OPACITY, p.getPackedPropertyState( PROPERTY_OPACITY)); } /** * Recomputes the given Object-valued property's state given the * new parent property. * * @param propertyIndex index for the property whose value is changing. * @param parentPropertyValue the value that children of this node should * now inherit. * */ protected void recomputePropertyState(final int propertyIndex, final Object parentPropertyValue) { // We do not need to recompute the property value if: // - the property is _not_ inherited // or // - the property is inherited by the new parent property computed value // is the same as the current value. if (!isInherited(propertyIndex) || isPropertyState(propertyIndex, parentPropertyValue)) { // If the property is color relative, the propagation happens // through the color property changes. This means that with // currentColor, we inherit the computed value, not the specified // currentColor indirection. return; } setPropertyState(propertyIndex, parentPropertyValue); propagatePropertyState(propertyIndex, parentPropertyValue); } /** * Recomputes the given float-valued property's state given the new parent * property. * * @param propertyIndex index for the property whose value is changing. * @param parentPropertyValue the value that children of this node should * now inherit. * */ protected void recomputeFloatPropertyState(final int propertyIndex, final float parentPropertyValue) { // We do not need to recompute the property value if: // - the property is _not_ inherited // or // - the property is inherited by the new parent property computed value // is the same as the current value. if (!isInherited(propertyIndex) || isFloatPropertyState(propertyIndex, parentPropertyValue)) { // If the property is color relative, the propagation happens // through the color property changes. This means that with // currentColor, we inherit the computed value, not the specified // currentColor indirection. return; } setFloatPropertyState(propertyIndex, parentPropertyValue); propagateFloatPropertyState(propertyIndex, parentPropertyValue); } /** * Recomputes the given packed property's state given the new parent * property. * * @param propertyIndex index for the property whose value is changing. * @param parentPropertyValue the value that children of this node should * now inherit. * */ protected void recomputePackedPropertyState(final int propertyIndex, final int parentPropertyValue) { // We do not need to recompute the property value if: // - the property is _not_ inherited // or // - the property is inherited by the new parent property computed value // is the same as the current value. if (!isInherited(propertyIndex) || isPackedPropertyState(propertyIndex, parentPropertyValue)) { // If the property is color relative, the propagation happens // through the color property changes. This means that with // currentColor, we inherit the computed value, not the specified // currentColor indirection. return; } setPackedPropertyState(propertyIndex, parentPropertyValue); propagatePackedPropertyState(propertyIndex, parentPropertyValue); } /** * Called when the computed value of the given Object-valued property * has changed. * * @param propertyIndex index for the property whose value has changed. * @param parentPropertyValue the value that children of this node should * now inherit. * */ protected void propagatePropertyState(final int propertyIndex, final Object parentPropertyValue) { // Propagate to proxies. if (firstProxy != null) { ElementNodeProxy proxy = firstProxy; while (proxy != null) { ((CompositeGraphicsNodeProxy) proxy).proxiedPropertyStateChange( propertyIndex, parentPropertyValue); proxy = proxy.nextProxy; } } // Propagate to regular children. ModelNode node = getFirstChildNode(); while (node != null) { node.recomputePropertyState(propertyIndex, parentPropertyValue); node = node.nextSibling; } } /** * Called when the computed value of the given float-valued property has * changed. * * @param propertyIndex index for the property whose value has changed. * @param parentPropertyValue the value that children of this node should * now inherit. * */ protected void propagateFloatPropertyState( final int propertyIndex, final float parentPropertyValue) { // Propagate to proxies. if (firstProxy != null) { ElementNodeProxy proxy = firstProxy; while (proxy != null) { ((CompositeGraphicsNodeProxy) proxy).proxiedFloatPropertyStateChange( propertyIndex, parentPropertyValue); proxy = proxy.nextProxy; } } // Propagate to regular children. ModelNode node = getFirstChildNode(); while (node != null) { node.recomputeFloatPropertyState(propertyIndex, parentPropertyValue); node = node.nextSibling; } } /** * Called when the computed value of the given packed property has changed. * * @param propertyIndex index for the property whose value has changed. * @param parentPropertyValue the value that children of this node should * now inherit. * */ protected void propagatePackedPropertyState(final int propertyIndex, final int parentPropertyValue) { // Propagate to proxies. if (firstProxy != null) { ElementNodeProxy proxy = firstProxy; while (proxy != null) { ((CompositeGraphicsNodeProxy) proxy).proxiedPackedPropertyStateChange( propertyIndex, parentPropertyValue); proxy = proxy.nextProxy; } } // Propagate to regular children. ModelNode node = getFirstChildNode(); while (node != null) { node.recomputePackedPropertyState(propertyIndex, parentPropertyValue); node = node.nextSibling; } } /** * Recomputes the transform cache, if one exists. This should recursively * call recomputeTransformState on children node or expanded content, if * any. * * By default, because a ModelNode has no transform and no cached transform, * this only does a pass down. * * @param parentTransform the Transform applied to this node's parent. */ protected void recomputeTransformState(final Transform parentTransform) { txf = appendTransform(parentTransform, txf); computeCanRenderTransformBit(txf); inverseTxf = null; // inverseTxf = computeInverseTransform(txf, parentTransform, // inverseTxf); recomputeTransformState(txf, getFirstChildNode()); } /** * @return this node's cached transform. */ public Transform getTransformState() { return txf; } /** * @return this node's cached inverse transform. */ Transform getInverseTransformState() { if (((canRenderState & CAN_RENDER_NON_INVERTIBLE_TXF_BIT) == 0)) { if (inverseTxf == null) { // If there is a parent, check if this node's transform is the // same as the parent's in which cahse if (parent != null && txf == parent.getTransformState()) { inverseTxf = parent.getInverseTransformState(); } else { inverseTxf = new Transform(null); try { inverseTxf = (Transform) txf.inverse(inverseTxf); } catch (Exception e) { // If we get an exception, then we have a real error // condition, because we just checked that the // transform was invertible. throw new Error(); } } } } else { inverseTxf = null; } return inverseTxf; } /** * Check if the property is inherited. * * @param propertyIndex the index of the property for which the * inherited state should be returned. * @return true if the input property is inherited. False * otherwise */ public final boolean isInherited(final int propertyIndex) { return isMarkerSet(propertyIndex); } /** * Sets the given Object-valued property's inheritance status * @param propertyIndex the index for the property whose inherited state * is set * @param inherit the new property's state */ public void setInherited(final int propertyIndex, final boolean inherit) { if (isInherited(propertyIndex) == inherit) { return; } modifyingNode(); setInheritedQuiet(propertyIndex, inherit); if (inherit) { // The property is now inherited. We store the inherited // value on the node, which means we keep the computed value // on the node. Object inheritedValue = getInheritedPropertyState(propertyIndex); setPropertyState(propertyIndex, inheritedValue); // Notify children that the inherited value has changed. propagatePropertyState(propertyIndex, inheritedValue); } // If the value is not inherited, it means that we are in the middle of // specifying a value on the node. So we do not notify descendants, // because this is done in the corresponding methods, e.g., setFill. modifiedNode(); } /** * Sets the given float-valued property's inheritance status * @param propertyIndex the index for the property whose inherited state * is set * @param inherit the new property's state */ public void setFloatInherited(final int propertyIndex, final boolean inherit) { if (isInherited(propertyIndex) == inherit) { return; } modifyingNode(); setInheritedQuiet(propertyIndex, inherit); if (inherit) { // The property is now inherited. We store the inherited // value on the node, which means we keep the computed value // on the node. float inheritedValue = getInheritedFloatPropertyState(propertyIndex); setFloatPropertyState(propertyIndex, inheritedValue); // Notify children that the inherited value has changed. propagateFloatPropertyState(propertyIndex, inheritedValue); } // If the value is not inherited, it means that we are in the middle of // specifying a value on the node. So we do not notify descendants, // because this is done in the corresponding methods, e.g., setFill. modifiedNode(); } /** * Sets the input packed property's inheritance status * @param propertyIndex the index for the property whose inherited state * is set * @param inherit the new property's state */ public void setPackedInherited(final int propertyIndex, final boolean inherit) { if (isInherited(propertyIndex) == inherit) { return; } modifyingNode(); setInheritedQuiet(propertyIndex, inherit); if (inherit) { // The property is now inherited. We store the inherited // value on the node, which means we keep the computed value // on the node. int inheritedValue = getInheritedPackedPropertyState(propertyIndex); setPackedPropertyState(propertyIndex, inheritedValue); // Notify children that the inherited value has changed. propagatePackedPropertyState(propertyIndex, inheritedValue); } // If the value is not inherited, it means that we are in the middle of // specifying a value on the node. So we do not notify descendants, // because this is done in the corresponding methods, e.g., setFill. modifiedNode(); } /** * Implementation. Sets the input property's inheritance status, * but does not send modification events. * * @param propertyIndex the index for the property whose inherited state * is set * @param inherit the new property's state */ protected void setInheritedQuiet(final int propertyIndex, final boolean inherit) { if (inherit) { setMarker(propertyIndex); } else { clearMarker(propertyIndex); } } /** * Returns true if the input property is color relative. False * otherwise * @param propertyIndex index for the property whose color relative * state should be returned. * @return true if the property at index propertyIndex is relative to * the color property. */ public boolean isColorRelative(final int propertyIndex) { return isMarkerSet(propertyIndex << COLOR_RELATIVE_MARKER); } /** * Returns true if the input property can be color-relative. * * @param propertyIndex the index of the property which may be * color-relative. * @return true if the input property can be color relative. False * otherwise. */ public boolean isColorRelativeProperty(final int propertyIndex) { switch (propertyIndex) { case PROPERTY_FILL: return true; case PROPERTY_STROKE: return true; default: return false; } } /** * Sets the input property as a color-relative property * * @param propertyIndex index of the property for which the color relative * state is set. * @param isColorRelative the new color relative state for the property * at propertyIndex. */ public void setColorRelative(final int propertyIndex, final boolean isColorRelative) { if (isColorRelative && !isColorRelativeProperty(propertyIndex)) { throw new IllegalArgumentException(); } if (isColorRelative(propertyIndex) == isColorRelative) { return; } modifyingNode(); setColorRelativeQuiet(propertyIndex, isColorRelative); if (isColorRelative) { // The property is now color relative. We store the relative // value in the on the node, i.e., the computed value. setPropertyState(propertyIndex, color); // Notify children that the inherited value has changed. propagatePropertyState(propertyIndex, color); } modifiedNode(); } /** * Sets the input marker. * * @param marker the marker to set. */ void setMarker(final int marker) { markers |= marker; } /** * Clears the input marker. * * @param marker the marker to clear. */ void clearMarker(final int marker) { markers &= ~marker; } /** * @return true if the input marker is set. */ final boolean isMarkerSet(final int marker) { return (markers & marker) != 0; } /** * Implementation. Sets the input property as a color-relative property * but does not generate modification events. * * @param propertyIndex index of the property for which the color relative * state is set. * @param isColorRelative the new color relative state for the property * at propertyIndex. */ protected void setColorRelativeQuiet(final int propertyIndex, final boolean isColorRelative) { if (isColorRelative) { setMarker(propertyIndex << COLOR_RELATIVE_MARKER); } else { clearMarker(propertyIndex << COLOR_RELATIVE_MARKER); } } // ==================================================================== // GraphicsNode implementation // ==================================================================== /** * Setting the fill property clears the inherited and color relative * states (they are set to false). * * @param newFill the new fill property */ public void setFill(final PaintServer newFill) { if (!isInherited(PROPERTY_FILL) && equal(newFill, fill)) { return; } modifyingNode(); if (fill != null) { fill.dispose(); } setComputedFill(newFill); setInheritedQuiet(PROPERTY_FILL, false); setColorRelativeQuiet(PROPERTY_FILL, false); propagatePropertyState(PROPERTY_FILL, fill); modifiedNode(); } /** * @param newFill the new computed fill property. */ void setComputedFill(final PaintServer newFill) { this.fill = newFill; } /** * @return the current fill property. This is not the computed values, * i.e., it does not account for the inherited or color * relative states. */ public PaintServer getFill() { return fill; } /** * Setting the fillOpacity property clears the inherited and color relative * states (they are set to false). * * @param newFillOpacity the new fill property */ public void setFillOpacity(float newFillOpacity) { if (!isInherited(PROPERTY_FILL_OPACITY) && newFillOpacity == getFillOpacity()) { return; } modifyingNode(); if (newFillOpacity > 1) { newFillOpacity = 1; } else if (newFillOpacity < 0) { newFillOpacity = 0; } setInheritedQuiet(PROPERTY_FILL_OPACITY, false); setComputedFillOpacity(newFillOpacity); propagatePackedPropertyState(PROPERTY_FILL_OPACITY, pack & FILL_OPACITY_MASK); modifiedNode(); } /** * @param newFillOpacity the new computed value of the fill opacity * property. */ void setComputedFillOpacity(final float newFillOpacity) { pack &= ~FILL_OPACITY_MASK; pack |= ((((int) (newFillOpacity * 200)) << 7) & FILL_OPACITY_MASK); } /** * @return the current fillOpacity property. */ public float getFillOpacity() { return ((pack & FILL_OPACITY_MASK) >> 7) / 200.0f; } /** * Setting the stroke clears the inherited and color relative states * (i.e., they are set to false). * * @param newStroke new stroke property. */ public void setStroke(final PaintServer newStroke) { if (!isInherited(PROPERTY_STROKE) && equal(newStroke, stroke)) { return; } modifyingNode(); if (newStroke != stroke) { if (stroke != null) { stroke.dispose(); } } setInheritedQuiet(PROPERTY_STROKE, false); setColorRelativeQuiet(PROPERTY_STROKE, false); setComputedStroke(newStroke); propagatePropertyState(PROPERTY_STROKE, stroke); modifiedNode(); } /** * @param newStroke the new computed stroke property. */ void setComputedStroke(final PaintServer newStroke) { this.stroke = newStroke; } /** * @return the stroke property. This is not the computed value as * it does not account for the inherited and color relative * states. */ public PaintServer getStroke() { return stroke; } /** * Setting the strokeOpacity property clears the inherited and color * relative states (they are set to false). * * @param newStrokeOpacity the new stroke property */ public void setStrokeOpacity(float newStrokeOpacity) { if (!isInherited(PROPERTY_STROKE_OPACITY) && newStrokeOpacity == getStrokeOpacity()) { return; } modifyingNode(); if (newStrokeOpacity > 1) { newStrokeOpacity = 1; } else if (newStrokeOpacity < 0) { newStrokeOpacity = 0; } setInheritedQuiet(PROPERTY_STROKE_OPACITY, false); setComputedStrokeOpacity(newStrokeOpacity); propagatePackedPropertyState(PROPERTY_STROKE_OPACITY, pack & STROKE_OPACITY_MASK); modifiedNode(); } /** * @param newStrokeOpacity the new computed stroke-opacity property. */ void setComputedStrokeOpacity(final float newStrokeOpacity) { pack &= ~STROKE_OPACITY_MASK; pack |= ((((int) (newStrokeOpacity * 200)) << 15) & STROKE_OPACITY_MASK); } /** * @return the current strokeOpacity property. */ public float getStrokeOpacity() { return ((pack & STROKE_OPACITY_MASK) >> 15) / 200.0f; } /** * Setting the color property clears this property's inherited flag. * @param newColor new color property. */ public void setColor(final RGB newColor) { if (!isInherited(PROPERTY_COLOR) && equal(newColor, color)) { return; } modifyingNode(); setComputedColor(newColor); setInheritedQuiet(PROPERTY_COLOR, false); propagatePropertyState(PROPERTY_COLOR, color); modifiedNode(); } /** * @param newColor the new computed color property. */ void setComputedColor(final RGB newColor) { color = newColor; // We need to recompute the fill and stroke colors if they are // color-relative. if (isColorRelative(PROPERTY_FILL)) { setComputedFill(newColor); propagatePropertyState(PROPERTY_FILL, fill); } if (isColorRelative(PROPERTY_STROKE)) { setComputedStroke(newColor); propagatePropertyState(PROPERTY_STROKE, stroke); } } /** * @return the current color property. This is not the computed * value and does not account for the inherited state. */ public RGB getColor() { return color; } /** * Setting the fillRule property clears its inherited flag * @param newFillRule new fillRule property */ public void setFillRule(final int newFillRule) { if (!isInherited(PROPERTY_FILL_RULE) && newFillRule == getFillRule()) { return; } modifyingNode(); setInheritedQuiet(PROPERTY_FILL_RULE, false); setComputedFillRule(newFillRule); propagatePackedPropertyState(PROPERTY_FILL_RULE, pack & FILL_RULE_MASK); modifiedNode(); } /** * @param newFillRule the new computed fillRule property value. */ final void setComputedFillRule(final int newFillRule) { if (newFillRule == WIND_NON_ZERO) { pack |= FILL_RULE_MASK; } else { pack &= ~FILL_RULE_MASK; } } /** * @return the current fillRule property, exclusive of * the inherited flag. */ public int getFillRule() { if ((pack & FILL_RULE_MASK) == FILL_RULE_MASK) { return WIND_NON_ZERO; } return WIND_EVEN_ODD; } /** * Setting the strokeDashArray property clears its inherited flag. * * @param newStrokeDashArray new strokeDashArray property. */ public void setStrokeDashArray(final float[] newStrokeDashArray) { if (!isInherited(PROPERTY_STROKE_DASH_ARRAY) && equal(newStrokeDashArray, strokeDashArray)) { return; } modifyingNode(); setComputedStrokeDashArray(newStrokeDashArray); setInheritedQuiet(PROPERTY_STROKE_DASH_ARRAY, false); propagatePropertyState(PROPERTY_STROKE_DASH_ARRAY, newStrokeDashArray); modifiedNode(); } /** * @param newStrokeDashArray the new computed stroke-dasharray property * value. */ void setComputedStrokeDashArray(final float[] newStrokeDashArray) { strokeDashArray = newStrokeDashArray; } /** * @return current strokeDashArray, exclusive of the inherited * state. */ public float[] getStrokeDashArray() { return strokeDashArray; } /** * Setting the strokeLineCap property clears the inherited flag * * @param newStrokeLineCap new strokeLineCap property */ public void setStrokeLineCap(final int newStrokeLineCap) { if (!isInherited(PROPERTY_STROKE_LINE_CAP) && newStrokeLineCap == getStrokeLineCap()) { return; } modifyingNode(); setInheritedQuiet(PROPERTY_STROKE_LINE_CAP, false); setComputedStrokeLineCap(newStrokeLineCap); propagatePackedPropertyState(PROPERTY_STROKE_LINE_CAP, pack & STROKE_LINE_CAP_MASK); modifiedNode(); } /** * @param newStrokeLineCap the new value for the stroke-linecap property. */ void setComputedStrokeLineCap(final int newStrokeLineCap) { // Clear stroke-linecap pack &= ~STROKE_LINE_CAP_MASK; switch (newStrokeLineCap) { case CAP_BUTT: pack |= CAP_BUTT_IMPL; break; case CAP_ROUND: pack |= CAP_ROUND_IMPL; break; default: pack |= CAP_SQUARE_IMPL; break; } } /** * @return the strokeLineCap property exclusive of its inherited state */ public int getStrokeLineCap() { switch (pack & STROKE_LINE_CAP_MASK) { case CAP_BUTT_IMPL: return CAP_BUTT; case CAP_ROUND_IMPL: return CAP_ROUND; default: return CAP_SQUARE; } } /** * Setting the strokeLineJoin property clears the inherited flag * * @param newStrokeLineJoin new strokeLineJoin property */ public void setStrokeLineJoin(final int newStrokeLineJoin) { if (!isInherited(PROPERTY_STROKE_LINE_JOIN) && newStrokeLineJoin == getStrokeLineJoin()) { return; } modifyingNode(); setInheritedQuiet(PROPERTY_STROKE_LINE_JOIN, false); setComputedStrokeLineJoin(newStrokeLineJoin); propagatePackedPropertyState(PROPERTY_STROKE_LINE_JOIN, pack & STROKE_LINE_JOIN_MASK); modifiedNode(); } /** * @param newStrokeLineJoin the new computed value of stroke-line-join */ void setComputedStrokeLineJoin(final int newStrokeLineJoin) { // Clear stroke-linejoin pack &= ~STROKE_LINE_JOIN_MASK; switch (newStrokeLineJoin) { case JOIN_MITER: pack |= JOIN_MITER_IMPL; break; case JOIN_ROUND: pack |= JOIN_ROUND_IMPL; break; default: pack |= JOIN_BEVEL_IMPL; break; } } /** * @return current strokeLineJoin exclusive of the inherited state */ public int getStrokeLineJoin() { switch (pack & STROKE_LINE_JOIN_MASK) { case JOIN_MITER_IMPL: return JOIN_MITER; case JOIN_ROUND_IMPL: return JOIN_ROUND; default: return JOIN_BEVEL; } } /** * Setting the strokeWidth property clears its inherited flag. * * @param newStrokeWidth new strokeWidth property. Should be * positive or zero. */ public void setStrokeWidth(final float newStrokeWidth) { if (newStrokeWidth < 0) { throw new IllegalArgumentException(); } if (!isInherited(PROPERTY_STROKE_WIDTH) && newStrokeWidth == strokeWidth) { return; } modifyingNode(); setInheritedQuiet(PROPERTY_STROKE_WIDTH, false); setComputedStrokeWidth(newStrokeWidth); propagateFloatPropertyState(PROPERTY_STROKE_WIDTH, newStrokeWidth); modifiedNode(); } /** * @param newStrokeWidth the new computed stroke-width property value. */ void setComputedStrokeWidth(final float newStrokeWidth) { strokeWidth = newStrokeWidth; } /** * @return current strokeWidth, exclusive of inheritance */ public float getStrokeWidth() { return strokeWidth; } /** * Setting the strokeMiterLimit clears its inherited flag. * * @param newStrokeMiterLimit new strokeMiterLimit property */ public void setStrokeMiterLimit(final float newStrokeMiterLimit) { if (newStrokeMiterLimit < 1) { throw new IllegalArgumentException(); } if (!isInherited(PROPERTY_STROKE_MITER_LIMIT) && newStrokeMiterLimit == strokeMiterLimit) { return; } modifyingNode(); setComputedStrokeMiterLimit(newStrokeMiterLimit); setInheritedQuiet(PROPERTY_STROKE_MITER_LIMIT, false); propagateFloatPropertyState(PROPERTY_STROKE_MITER_LIMIT, strokeMiterLimit); modifiedNode(); } /** * @param newStrokeMiterLimit the new computed stroke-miterlimit property. */ void setComputedStrokeMiterLimit(final float newStrokeMiterLimit) { strokeMiterLimit = newStrokeMiterLimit; } /** * @return current strokeMiterLimit, exclusive of the inherited state */ public float getStrokeMiterLimit() { return strokeMiterLimit; } /** * Setting the strokeDashOffset property clears its inherited flag. * * @param newStrokeDashOffset new strokeDashOffset value */ public void setStrokeDashOffset(final float newStrokeDashOffset) { if (!isInherited(PROPERTY_STROKE_DASH_OFFSET) && newStrokeDashOffset == strokeDashOffset) { return; } modifyingNode(); setComputedStrokeDashOffset(newStrokeDashOffset); setInheritedQuiet(PROPERTY_STROKE_DASH_OFFSET, false); propagateFloatPropertyState(PROPERTY_STROKE_DASH_OFFSET, strokeDashOffset); modifiedNode(); } /** * @param newStrokeDashOffset the new stroke-dashoffset computed property * value. */ void setComputedStrokeDashOffset(final float newStrokeDashOffset) { strokeDashOffset = newStrokeDashOffset; } /** * @return current strokeDashOffset property value, exclusive of its * inherited state. */ public float getStrokeDashOffset() { return strokeDashOffset; } /** * Setting the visibility clears its inherited flag. * * @param newVisibility the new visibility value */ public void setVisibility(final boolean newVisibility) { if (!isInherited(PROPERTY_VISIBILITY) && newVisibility == getVisibility()) { return; } modifyingNode(); setComputedVisibility(newVisibility); setInheritedQuiet(PROPERTY_VISIBILITY, false); propagatePackedPropertyState(PROPERTY_VISIBILITY, pack & VISIBILITY_MASK); modifiedNode(); } /** * @param newVisibility the new computed visibility property. */ void setComputedVisibility(final boolean newVisibility) { if (newVisibility) { pack |= VISIBILITY_MASK; } else { pack &= ~VISIBILITY_MASK; } } /** * @return current visibility property, exclusive of inheritance. */ public boolean getVisibility() { return ((pack & VISIBILITY_MASK) == VISIBILITY_MASK); } /** * Setting the display property clears its inherited flag. * * @param newDisplay new display property value */ public void setDisplay(final boolean newDisplay) { if (!isInherited(PROPERTY_DISPLAY) && newDisplay == getDisplay()) { return; } modifyingNode(); setInheritedQuiet(PROPERTY_DISPLAY, false); setComputedDisplay(newDisplay); propagatePackedPropertyState(PROPERTY_DISPLAY, pack & DISPLAY_MASK); modifiedNode(); } /** * @param newDisplay the new computed display value */ void setComputedDisplay(final boolean newDisplay) { if (newDisplay) { pack |= DISPLAY_MASK; } else { pack &= ~DISPLAY_MASK; } computeCanRenderDisplayBit(newDisplay); } /** * @return current display property value, exclusive of inheritance */ public boolean getDisplay() { return ((pack & DISPLAY_MASK) == DISPLAY_MASK); } /** * Setting the opacity property clears the inherited and color * relative states (they are set to false). * * @param newOpacity the new opacity property */ public void setOpacity(float newOpacity) { if (!isInherited(PROPERTY_OPACITY) && newOpacity == getOpacity()) { return; } modifyingNode(); if (newOpacity > 1) { newOpacity = 1; } else if (newOpacity < 0) { newOpacity = 0; } setInheritedQuiet(PROPERTY_OPACITY, false); setComputedOpacity(newOpacity); propagatePackedPropertyState(PROPERTY_OPACITY, pack2 & OPACITY_MASK); modifiedNode(); } /** * @param newOpacity the new computed opacity property. */ void setComputedOpacity(final float newOpacity) { pack2 &= ~OPACITY_MASK; pack2 |= (((int) (newOpacity * 200)) & OPACITY_MASK); } /** * @return the current opacity property value. */ public float getOpacity() { return (pack2 & OPACITY_MASK) / 200.0f; } /** * Supported traits: stroke-width, stroke-miterlimit, stroke-dashoffset, * fill-rule, stroke-linejoin, stroke-linecap, display, visibility, * color, fill, stroke, fill-opacity, stroke-opacity, stroke-dasharray, * opacity * * @param traitName the name of the trait which the element may support. * @return true if this element supports the given trait in one of the * trait accessor methods. */ boolean supportsTrait(final String traitName) { if (SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_MITERLIMIT_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_DASHOFFSET_ATTRIBUTE == traitName || SVGConstants.SVG_FILL_RULE_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_LINEJOIN_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_LINECAP_ATTRIBUTE == traitName || SVGConstants.SVG_DISPLAY_ATTRIBUTE == traitName || SVGConstants.SVG_VISIBILITY_ATTRIBUTE == traitName || SVGConstants.SVG_COLOR_ATTRIBUTE == traitName || SVGConstants.SVG_FILL_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_ATTRIBUTE == traitName || SVGConstants.SVG_FILL_OPACITY_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_OPACITY_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE == traitName || SVGConstants.SVG_OPACITY_ATTRIBUTE == traitName) { return true; } else { return super.supportsTrait(traitName); } } /** * Returns the specified trait value as String. In SVG Tiny only certain * traits can be obtained as a String value. Syntax of the returned String * matches the syntax of the corresponding attribute. This element is * exactly equivalent to {@link org.w3c.dom.svg.SVGElement#getTraitNS * getTraitNS} with namespaceURI set to null. * * The method is meant to be overridden by derived classes. The * implementation pattern is that derived classes will override the method * and call their super class' implementation. If the ElementNode * implementation is called, it means that the trait is either not supported * or that it cannot be seen as a String. * * @param name the requested trait name. * @return the trait value. * * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested * trait is not supported on this element or null. * @throws DOMException with error code TYPE_MISMATCH_ERR if requested * trait's computed value cannot be converted to a String (SVG Tiny only). */ String getSpecifiedTraitImpl(final String name) throws DOMException { if ((SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE == name && isInherited(PROPERTY_STROKE_WIDTH)) || (SVGConstants.SVG_STROKE_MITERLIMIT_ATTRIBUTE == name && isInherited(PROPERTY_STROKE_MITER_LIMIT)) || (SVGConstants.SVG_STROKE_DASHOFFSET_ATTRIBUTE == name && isInherited(PROPERTY_STROKE_DASH_OFFSET)) || (SVGConstants.SVG_FILL_RULE_ATTRIBUTE == name && isInherited(PROPERTY_FILL_RULE)) || (SVGConstants.SVG_STROKE_LINEJOIN_ATTRIBUTE == name && isInherited(PROPERTY_STROKE_LINE_JOIN)) || (SVGConstants.SVG_STROKE_LINECAP_ATTRIBUTE == name && isInherited(PROPERTY_STROKE_LINE_CAP)) || (SVGConstants.SVG_DISPLAY_ATTRIBUTE == name && isInherited(PROPERTY_DISPLAY)) || (SVGConstants.SVG_VISIBILITY_ATTRIBUTE == name && isInherited(PROPERTY_VISIBILITY)) || (SVGConstants.SVG_COLOR_ATTRIBUTE == name && isInherited(PROPERTY_COLOR)) || (SVGConstants.SVG_FILL_ATTRIBUTE == name && isInherited(PROPERTY_FILL)) || (SVGConstants.SVG_STROKE_ATTRIBUTE == name && isInherited(PROPERTY_STROKE)) || (SVGConstants.SVG_FILL_OPACITY_ATTRIBUTE == name && isInherited(PROPERTY_FILL_OPACITY)) || (SVGConstants.SVG_STROKE_OPACITY_ATTRIBUTE == name && isInherited(PROPERTY_STROKE_OPACITY)) || (SVGConstants.SVG_OPACITY_ATTRIBUTE == name && isInherited(PROPERTY_OPACITY)) || (SVGConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE == name && isInherited(PROPERTY_STROKE_DASH_ARRAY))) { return SVGConstants.CSS_INHERIT_VALUE; } else if ((SVGConstants.SVG_FILL_ATTRIBUTE == name && isColorRelative(PROPERTY_FILL)) || (SVGConstants.SVG_STROKE_ATTRIBUTE == name && isColorRelative(PROPERTY_STROKE))) { return SVGConstants.CSS_CURRENTCOLOR_VALUE; } else if (SVGConstants.SVG_DISPLAY_ATTRIBUTE == name) { if (getDisplay()) { return SVGConstants.CSS_INLINE_VALUE; } else { return SVGConstants.CSS_NONE_VALUE; } } else { return super.getSpecifiedTraitImpl(name); } } /** * Converts the input fill-rule value to a string trait value. * * @param fillRule the fill-rule value to convert. In packed form, but * with mask applied. * @return the converted value. */ String fillRuleToStringTrait(final int fillRule) { if (fillRule == CompositeGraphicsNode.FILL_RULE_MASK) { return SVGConstants.CSS_NONZERO_VALUE; } return SVGConstants.CSS_EVENODD_VALUE; } /** * @param strokeLineJoin the value to convert. In packed form, but with * mask applied. * @return the converted value. */ String strokeLineJoinToStringTrait(final int strokeLineJoin) { switch (strokeLineJoin) { case CompositeGraphicsNode.JOIN_MITER_IMPL: return SVGConstants.CSS_MITER_VALUE; case CompositeGraphicsNode.JOIN_ROUND_IMPL: return SVGConstants.CSS_ROUND_VALUE; default: return SVGConstants.CSS_BEVEL_VALUE; } } /** * @param strokeLineCap the value to convert. * @return the converted value. */ String strokeLineCapToStringTrait(final int strokeLineCap) { switch (strokeLineCap) { case CompositeGraphicsNode.CAP_BUTT_IMPL: return SVGConstants.CSS_BUTT_VALUE; case CompositeGraphicsNode.CAP_ROUND_IMPL: return SVGConstants.CSS_ROUND_VALUE; case CompositeGraphicsNode.CAP_SQUARE_IMPL: default: return SVGConstants.CSS_SQUARE_VALUE; } } /** * Supported traits: stroke-width, stroke-miterlimit, stroke-dashoffset, * fill-rule, stroke-linejoin, stroke-linecap, display, visibility, * color, fill, stroke, fill-opacity, stroke-opacity, stroke-dasharray, * opacity * * @param name the requested trait's name * @return the requested trait value, as a string. * * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested * trait is not supported on this element or null. * @throws DOMException with error code TYPE_MISMATCH_ERR if requested * trait's computed value cannot be converted to a String (SVG Tiny only). */ public String getTraitImpl(final String name) throws DOMException { if (SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE == name) { return Float.toString(getStrokeWidth()); } else if (SVGConstants.SVG_STROKE_MITERLIMIT_ATTRIBUTE == name) { return Float.toString (getStrokeMiterLimit()); } else if (SVGConstants.SVG_STROKE_DASHOFFSET_ATTRIBUTE == name) { return Float.toString (getStrokeDashOffset()); } else if (SVGConstants.SVG_FILL_RULE_ATTRIBUTE == name) { return fillRuleToStringTrait(pack & FILL_RULE_MASK); } else if (SVGConstants.SVG_STROKE_LINEJOIN_ATTRIBUTE == name) { return strokeLineJoinToStringTrait (pack & STROKE_LINE_JOIN_MASK); } else if (SVGConstants.SVG_STROKE_LINECAP_ATTRIBUTE == name) { return strokeLineCapToStringTrait (pack & STROKE_LINE_CAP_MASK); } else if (SVGConstants.SVG_DISPLAY_ATTRIBUTE == name) { if (getDisplay()) { return SVGConstants.CSS_INLINE_VALUE; } else { return SVGConstants.CSS_NONE_VALUE; } } else if (SVGConstants.SVG_VISIBILITY_ATTRIBUTE == name) { if (getVisibility()) { return SVGConstants.CSS_VISIBLE_VALUE; } else { return SVGConstants.CSS_HIDDEN_VALUE; } } else if (SVGConstants.SVG_COLOR_ATTRIBUTE == name) { return getColor().toString(); } else if (SVGConstants.SVG_FILL_ATTRIBUTE == name) { return toString(getFill()); } else if (SVGConstants.SVG_STROKE_ATTRIBUTE == name) { return toString(getStroke()); } else if (SVGConstants.SVG_FILL_OPACITY_ATTRIBUTE == name) { return Float.toString(getFillOpacity()); } else if (SVGConstants.SVG_STROKE_OPACITY_ATTRIBUTE == name) { return Float.toString(getStrokeOpacity()); } else if (SVGConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE == name) { return toStringTrait(getStrokeDashArray()); } else if (SVGConstants.SVG_OPACITY_ATTRIBUTE == name) { return Float.toString(getOpacity()); } else { return super.getTraitImpl(name); } } /** * Supported float traits: stroke-width, stroke-miterlimit, * stroke-dashoffset, fill-opacity, stroke-opacity, opacity. * * @param name the requested trait's name * @return the requested trait's value, as a floating point. * * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested * trait is not supported on this element or null. * @throws DOMException with error code TYPE_MISMATCH_ERR if requested * trait's computed value cannot be converted to a float * @throws SecurityException if the application does not have the necessary * privilege rights to access this (SVG) content. */ float getFloatTraitImpl(final String name) throws DOMException { if (SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE == name) { return getStrokeWidth(); } else if (SVGConstants.SVG_STROKE_MITERLIMIT_ATTRIBUTE == name) { return getStrokeMiterLimit(); } else if (SVGConstants.SVG_STROKE_DASHOFFSET_ATTRIBUTE == name) { return getStrokeDashOffset(); } else if (SVGConstants.SVG_FILL_OPACITY_ATTRIBUTE == name) { return getFillOpacity(); } else if (SVGConstants.SVG_STROKE_OPACITY_ATTRIBUTE == name) { return getStrokeOpacity(); } else if (SVGConstants.SVG_OPACITY_ATTRIBUTE == name) { return getOpacity(); } else { return super.getFloatTraitImpl(name); } } /** * Supported color traits: color, fill, stroke * * @param name the requested trait's name. * @return the requested trait's value, as an <code>SVGRGBColor</code>. * * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested * trait is not supported on this element or null. * @throws DOMException with error code TYPE_MISMATCH_ERR if requested * trait's computed value cannot be converted to {@link * org.w3c.dom.svg.SVGRGBColor SVGRGBColor} * @throws SecurityException if the application does not have the necessary * privilege rights to access this (SVG) content. */ SVGRGBColor getRGBColorTraitImpl(String name) throws DOMException { if (SVGConstants.SVG_FILL_ATTRIBUTE.equals(name)) { return toSVGRGBColor(SVGConstants.SVG_FILL_ATTRIBUTE, getFill()); } else if (SVGConstants.SVG_STROKE_ATTRIBUTE.equals(name)) { return toSVGRGBColor(SVGConstants.SVG_STROKE_ATTRIBUTE, getStroke()); } else if (SVGConstants.SVG_COLOR_ATTRIBUTE.equals(name)) { return toSVGRGBColor(SVGConstants.SVG_COLOR_ATTRIBUTE, getColor()); } else { return super.getRGBColorTraitImpl(name); } } /** * @param traitName the trait name. */ TraitAnim createTraitAnimImpl(final String traitName) { if (SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_MITERLIMIT_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_DASHOFFSET_ATTRIBUTE == traitName || SVGConstants.SVG_FILL_OPACITY_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_OPACITY_ATTRIBUTE == traitName || SVGConstants.SVG_OPACITY_ATTRIBUTE == traitName) { return new FloatTraitAnim(this, traitName, TRAIT_TYPE_FLOAT); } else if (SVGConstants.SVG_COLOR_ATTRIBUTE == traitName || SVGConstants.SVG_FILL_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_ATTRIBUTE == traitName) { return new FloatTraitAnim(this, traitName, TRAIT_TYPE_SVG_RGB_COLOR); } else if (SVGConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE == traitName) { return new FloatTraitAnim(this, traitName, TRAIT_TYPE_STRING); } else if (SVGConstants.SVG_DISPLAY_ATTRIBUTE == traitName || SVGConstants.SVG_FILL_RULE_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_LINECAP_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_LINEJOIN_ATTRIBUTE == traitName || SVGConstants.SVG_VISIBILITY_ATTRIBUTE == traitName) { return new StringTraitAnim(this, NULL_NS, traitName); } else { return super.createTraitAnimImpl(traitName); } } /** * Set the trait value as float array. * * @param name the trait's name. * @param value the trait's value. * * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested * trait is not supported on this element. * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested * trait's value cannot be specified as a float * @throws DOMException with error code INVALID_ACCESS_ERR if the input * value is an invalid value for the given trait. */ void setFloatArrayTrait(final String name, final float[][] value) throws DOMException { if (SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE == name) { checkPositive(name, value[0][0]); setStrokeWidth(value[0][0]); } else if (SVGConstants.SVG_STROKE_MITERLIMIT_ATTRIBUTE .equals(name)) { if (value[0][0] < 1) { throw illegalTraitValue(name, Float.toString(value[0][0])); } setStrokeMiterLimit(value[0][0]); } else if (SVGConstants.SVG_STROKE_DASHOFFSET_ATTRIBUTE .equals(name)) { setStrokeDashOffset(value[0][0]); } else if (SVGConstants.SVG_COLOR_ATTRIBUTE == name) { setColor(toRGB(name, value)); } else if (SVGConstants.SVG_FILL_ATTRIBUTE == name) { setFill(toRGB(name, value)); } else if (SVGConstants.SVG_STROKE_ATTRIBUTE == name) { setStroke(toRGB(name, value)); } else if (SVGConstants.SVG_FILL_OPACITY_ATTRIBUTE == name) { setFillOpacity(value[0][0]); } else if (SVGConstants.SVG_STROKE_OPACITY_ATTRIBUTE == name) { setStrokeOpacity(value[0][0]); } else if (SVGConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE .equals(name)) { setStrokeDashArray(value[0]); } else if (SVGConstants.SVG_OPACITY_ATTRIBUTE == name) { setOpacity(value[0][0]); } else { super.setFloatArrayTrait(name, value); } } /** * Validates the input trait value. * * @param namespaceURI the trait's namespace URI. * @param traitName the name of the trait to be validated. * @param value the value to be validated * @param reqNamespaceURI the namespace of the element requesting * validation. * @param reqLocalName the local name of the element requesting validation. * @param reqTraitNamespace the namespace of the trait which has the values * value on the requesting element. * @param reqTraitName the name of the trait which has the values value on * the requesting element. * @throws DOMException with error code INVALID_ACCESS_ERR if the input * value is incompatible with the given trait. */ String validateTraitNS(final String namespaceURI, final String traitName, final String value, final String reqNamespaceURI, final String reqLocalName, final String reqTraitNamespace, final String reqTraitName) throws DOMException { if (namespaceURI != null && namespaceURI != NULL_NS) { return super.validateTraitNS(namespaceURI, traitName, value, reqNamespaceURI, reqLocalName, reqTraitNamespace, reqTraitName); } if (SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_MITERLIMIT_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_DASHOFFSET_ATTRIBUTE == traitName || SVGConstants.SVG_COLOR_ATTRIBUTE == traitName || SVGConstants.SVG_FILL_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_ATTRIBUTE == traitName || SVGConstants.SVG_FILL_OPACITY_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_OPACITY_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE .equals(traitName) || SVGConstants.SVG_OPACITY_ATTRIBUTE == traitName) { throw unsupportedTraitType(traitName, TRAIT_TYPE_FLOAT); } else if (SVGConstants.SVG_FILL_RULE_ATTRIBUTE == traitName) { if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { return fillRuleToStringTrait (getInheritedPackedPropertyState(PROPERTY_FILL_RULE)); } if (!SVGConstants.CSS_NONZERO_VALUE.equals(value) && !SVGConstants.CSS_EVENODD_VALUE.equals(value)) { throw illegalTraitValue(traitName, value); } return value; } else if (SVGConstants.SVG_STROKE_LINEJOIN_ATTRIBUTE == traitName) { if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { return strokeLineJoinToStringTrait( getInheritedPackedPropertyState( PROPERTY_STROKE_LINE_JOIN)); } if (!SVGConstants.CSS_MITER_VALUE.equals(value) && !SVGConstants.CSS_ROUND_VALUE.equals(value) && !SVGConstants.CSS_BEVEL_VALUE.equals(value)) { throw illegalTraitValue(traitName, value); } return value; } else if (SVGConstants.SVG_STROKE_LINECAP_ATTRIBUTE == traitName) { if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { return strokeLineCapToStringTrait( getInheritedPackedPropertyState( PROPERTY_STROKE_LINE_CAP)); } if (!SVGConstants.CSS_BUTT_VALUE.equals(value) && !SVGConstants.CSS_ROUND_VALUE.equals(value) && !SVGConstants.CSS_SQUARE_VALUE.equals(value)) { throw illegalTraitValue(traitName, value); } return value; } else if (SVGConstants.SVG_DISPLAY_ATTRIBUTE == traitName) { if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { if (getInheritedPackedPropertyState(PROPERTY_DISPLAY) != 0) { return SVGConstants.CSS_INLINE_VALUE; } return SVGConstants.CSS_NONE_VALUE; } if (!SVGConstants.CSS_INLINE_VALUE.equals(value) && !SVGConstants.CSS_NONE_VALUE.equals(value)) { throw illegalTraitValue(traitName, value); } return value; } else if (SVGConstants.SVG_VISIBILITY_ATTRIBUTE == traitName) { if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { if (getInheritedPackedPropertyState(PROPERTY_VISIBILITY) != 0) { return SVGConstants.CSS_VISIBLE_VALUE; } else { return SVGConstants.CSS_HIDDEN_VALUE; } } if (!SVGConstants.CSS_VISIBLE_VALUE.equals(value) && !SVGConstants.CSS_HIDDEN_VALUE.equals(value)) { throw illegalTraitValue(traitName, value); } return value; } return super.validateTraitNS(namespaceURI, traitName, value, reqNamespaceURI, reqLocalName, reqTraitNamespace, reqTraitName); } /** * Validates the float input trait value. * * @param traitName the name of the trait to be validated. * @param value the value to be validated * @param reqNamespaceURI the namespace of the element requesting * validation. * @param reqLocalName the local name of the element requesting validation. * @param reqTraitNamespace the namespace of the trait which has the values * value on the requesting element. * @param reqTraitName the name of the trait which has the values value on * the requesting element. * @throws DOMException with error code INVALID_ACCESS_ERR if the input * value is incompatible with the given trait. */ public float[][] validateFloatArrayTrait( final String traitName, final String value, final String reqNamespaceURI, final String reqLocalName, final String reqTraitNamespace, final String reqTraitName) throws DOMException { if (SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE == traitName) { return new float[][] { {parsePositiveFloatTrait(traitName, value)} }; } else if (SVGConstants.SVG_STROKE_MITERLIMIT_ATTRIBUTE .equals(traitName)) { float miter = parseFloatTrait(traitName, value); if (miter < 1) { throw illegalTraitValue(traitName, value); } return new float[][] { {miter} }; } else if (SVGConstants.SVG_STROKE_DASHOFFSET_ATTRIBUTE .equals(traitName)) { return new float[][] { {parseFloatTrait(traitName, value)} }; } else if (SVGConstants.SVG_FILL_RULE_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_LINEJOIN_ATTRIBUTE == traitName || SVGConstants.SVG_STROKE_LINECAP_ATTRIBUTE == traitName || SVGConstants.SVG_DISPLAY_ATTRIBUTE == traitName || SVGConstants.SVG_VISIBILITY_ATTRIBUTE == traitName) { throw unsupportedTraitType(traitName, TRAIT_TYPE_FLOAT); } else if (SVGConstants.SVG_COLOR_ATTRIBUTE == traitName) { RGB color = GraphicsProperties.INITIAL_COLOR; if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { color = (RGB) getInheritedPropertyState(PROPERTY_COLOR); } else { color = parseColorTrait (SVGConstants.SVG_COLOR_ATTRIBUTE, value); } if (color == null) { throw illegalTraitValue(traitName, value); } return new float[][] { {color.getRed(), color.getGreen(), color.getBlue()} }; } else if (SVGConstants.SVG_FILL_ATTRIBUTE == traitName) { RGB color = GraphicsProperties.INITIAL_FILL; if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { color = (RGB) getInheritedPropertyState(PROPERTY_FILL); } else if (SVGConstants.CSS_CURRENTCOLOR_VALUE.equals(value)) { color = this.color; } else { color = parseColorTrait (SVGConstants.SVG_FILL_ATTRIBUTE, value); } if (color == null) { throw illegalTraitValue(traitName, value); } return new float[][] { {color.getRed(), color.getGreen(), color.getBlue()} }; } else if (SVGConstants.SVG_STROKE_ATTRIBUTE == traitName) { RGB color = GraphicsProperties.INITIAL_STROKE; if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { color = (RGB) getInheritedPropertyState(PROPERTY_STROKE); } else if (SVGConstants.CSS_CURRENTCOLOR_VALUE.equals(value)) { color = getColor(); } else { color = parseColorTrait (SVGConstants.SVG_STROKE_ATTRIBUTE, value); } if (color == null) { throw illegalTraitValue(traitName, value); } return new float[][] { {color.getRed(), color.getGreen(), color.getBlue()} }; } else if (SVGConstants.SVG_FILL_OPACITY_ATTRIBUTE == traitName) { float v = GraphicsNode.INITIAL_FILL_OPACITY; if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { if (parent != null) { v = (getInheritedPackedPropertyState(PROPERTY_FILL_OPACITY) >> 7) / 200.0f; } } else { v = parseFloatTrait(traitName, value); if (v < 0) { v = 0; } else if (v > 1) { v = 1; } } return new float[][] {{v}}; } else if (SVGConstants.SVG_STROKE_OPACITY_ATTRIBUTE == traitName) { float v = GraphicsProperties.INITIAL_STROKE_OPACITY; if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { v = (getInheritedPackedPropertyState(PROPERTY_STROKE_OPACITY) >> 15) / 200.0f; } else { v = parseFloatTrait(traitName, value); if (v < 0) { v = 0; } else if (v > 1) { v = 1; } } return new float[][] {{v}}; } else if (SVGConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE .equals(traitName)) { float[] da = parsePositiveFloatArrayTrait(traitName, value); if (da == null) { throw illegalTraitValue(traitName, value); } else { return new float[][] {da}; } } else if (SVGConstants.SVG_OPACITY_ATTRIBUTE == traitName) { float v = GraphicsProperties.INITIAL_OPACITY; if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { v = getInheritedPackedPropertyState(PROPERTY_OPACITY) / 200.0f; } else { v = parseFloatTrait(traitName, value); if (v < 0) { v = 0; } else if (v > 1) { v = 1; } } return new float[][] {{v}}; } else { return super.validateFloatArrayTrait(traitName, value, reqNamespaceURI, reqLocalName, reqTraitNamespace, reqTraitName); } } /** * CompositeGraphicsNode handles the graphics node traits. * Other attributes are handled by the super class. * * Supported traits: stroke-width, stroke-miterlimit, stroke-dashoffset, * fill-rule, stroke-linejoin, stroke-linecap, display, visibility, * color, fill, stroke, fill-opacity, stroke-opacity, stroke-dasharray, * opacity * * @param name the name of the trait to set. * @param value the value of the trait to set. * * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested * trait is not supported on this element or null. * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested * trait's value cannot be specified as a String * @throws DOMException with error code INVALID_ACCESS_ERR if the input * value is an invalid value for the given trait or null. * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if * attempt is made to change readonly trait. */ public void setTraitImpl(final String name, final String value) throws DOMException { if (SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE == name) { // ======================= stroke-width ===================== // if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { setFloatInherited(PROPERTY_STROKE_WIDTH, true); } else { setStrokeWidth(parsePositiveFloatTrait(name, value)); } } else if (SVGConstants.SVG_STROKE_MITERLIMIT_ATTRIBUTE .equals(name)) { // ===================== stroke-miterlimit ================== // if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { setFloatInherited(PROPERTY_STROKE_MITER_LIMIT, true); } else { float miter = parseFloatTrait(name, value); if (miter < 1) { throw illegalTraitValue(name, value); } setStrokeMiterLimit(miter); } } else if (SVGConstants.SVG_STROKE_DASHOFFSET_ATTRIBUTE .equals(name)) { // ===================== stroke-dashoffset ================== // if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { setFloatInherited(PROPERTY_STROKE_DASH_OFFSET, true); } else { setStrokeDashOffset(parseFloatTrait(name, value)); } } else if (SVGConstants.SVG_FILL_RULE_ATTRIBUTE == name) { // ========================= fill-rule ====================== // if (SVGConstants.CSS_NONZERO_VALUE.equals(value)) { setFillRule(GraphicsProperties.WIND_NON_ZERO); } else if (SVGConstants.CSS_EVENODD_VALUE.equals(value)) { setFillRule(GraphicsProperties.WIND_EVEN_ODD); } else if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { setPackedInherited(PROPERTY_FILL_RULE, true); } else { throw illegalTraitValue(name, value); } } else if (SVGConstants.SVG_STROKE_LINEJOIN_ATTRIBUTE == name) { // ==================== stroke-linejoin ===================== // if (SVGConstants.CSS_MITER_VALUE.equals(value)) { setStrokeLineJoin(GraphicsProperties.JOIN_MITER); } else if (SVGConstants.CSS_ROUND_VALUE.equals(value)) { setStrokeLineJoin(GraphicsProperties.JOIN_ROUND); } else if (SVGConstants.CSS_BEVEL_VALUE.equals(value)) { setStrokeLineJoin(GraphicsProperties.JOIN_BEVEL); } else if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { setPackedInherited(PROPERTY_STROKE_LINE_JOIN, true); } else { throw illegalTraitValue(name, value); } } else if (SVGConstants.SVG_STROKE_LINECAP_ATTRIBUTE == name) { // ====================== stroke-linecap ==================== // if (SVGConstants.CSS_BUTT_VALUE.equals(value)) { setStrokeLineCap(GraphicsProperties.CAP_BUTT); } else if (SVGConstants.CSS_ROUND_VALUE.equals(value)) { setStrokeLineCap(GraphicsProperties.CAP_ROUND); } else if (SVGConstants.CSS_SQUARE_VALUE.equals(value)) { setStrokeLineCap(GraphicsProperties.CAP_SQUARE); } else if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { setPackedInherited(PROPERTY_STROKE_LINE_CAP, true); } else { throw illegalTraitValue(name, value); } } else if (SVGConstants.SVG_DISPLAY_ATTRIBUTE == name) { // ======================== display ========================= // if (SVGConstants.CSS_NONE_VALUE.equals(value)) { setDisplay(false); } else if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { if (!isInherited(PROPERTY_DISPLAY)) { setPackedInherited(PROPERTY_DISPLAY, true); } } else if (SVGConstants.CSS_BLOCK_VALUE.equals(value) || SVGConstants.CSS_COMPACT_VALUE.equals(value) || SVGConstants.CSS_INLINE_TABLE_VALUE.equals(value) || SVGConstants.CSS_INLINE_VALUE.equals(value) || SVGConstants.CSS_LIST_ITEM_VALUE.equals(value) || SVGConstants.CSS_MARKER_VALUE.equals(value) || SVGConstants.CSS_RUN_IN_VALUE.equals(value) || SVGConstants.CSS_TABLE_VALUE.equals(value) || SVGConstants.CSS_TABLE_ROW_GROUP_VALUE.equals(value) || SVGConstants.CSS_TABLE_HEADER_GROUP_VALUE.equals(value) || SVGConstants.CSS_TABLE_FOOTER_GROUP_VALUE.equals(value) || SVGConstants.CSS_TABLE_ROW_VALUE.equals(value) || SVGConstants.CSS_TABLE_COLUMN_GROUP_VALUE.equals(value) || SVGConstants.CSS_TABLE_COLUMN_VALUE.equals(value) || SVGConstants.CSS_TABLE_CELL_VALUE.equals(value) || SVGConstants.CSS_TABLE_CAPTION_VALUE.equals(value)) { setDisplay(true); } else { throw illegalTraitValue(name, value); } } else if (SVGConstants.SVG_VISIBILITY_ATTRIBUTE == name) { // ======================= visibility ======================= // if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { setPackedInherited(PROPERTY_VISIBILITY, true); } else if (SVGConstants.CSS_HIDDEN_VALUE.equals(value) || SVGConstants.CSS_COLLAPSE_VALUE.equals(value)) { setVisibility(false); } else if (SVGConstants.CSS_VISIBLE_VALUE.equals(value)) { setVisibility(true); } else { throw illegalTraitValue(name, value); } } else if (SVGConstants.SVG_COLOR_ATTRIBUTE == name) { // ========================= color ========================== // if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { setInherited(PROPERTY_COLOR, true); } else if (SVGConstants.CSS_NONE_VALUE.equals(value)) { // 'none' is not a legal value for 'color' throw illegalTraitValue(name, value); } else { RGB color = parseColorTrait (SVGConstants.SVG_COLOR_ATTRIBUTE, value); setColor(color); } } else if (SVGConstants.SVG_FILL_ATTRIBUTE == name) { // ========================= fill =========================== // if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { setInherited(PROPERTY_FILL, true); setColorRelative(PROPERTY_FILL, false); } else if (SVGConstants.CSS_NONE_VALUE.equals(value)) { setFill(null); } else if (SVGConstants.CSS_CURRENTCOLOR_VALUE.equals(value)) { setColorRelative(PROPERTY_FILL, true); setInherited(PROPERTY_FILL, false); } else { PaintServer fill = parsePaintTrait (SVGConstants.SVG_FILL_ATTRIBUTE, this, value); if (fill != null) { setFill(fill); } } } else if (SVGConstants.SVG_STROKE_ATTRIBUTE == name) { // ========================= stroke ========================= // if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { setInherited(PROPERTY_STROKE, true); setColorRelative(PROPERTY_STROKE, false); } else if (SVGConstants.CSS_NONE_VALUE.equals(value)) { setStroke(null); } else if (SVGConstants.CSS_CURRENTCOLOR_VALUE.equals(value)) { setColorRelative(PROPERTY_STROKE, true); setInherited(PROPERTY_STROKE, false); } else { PaintServer stroke = parsePaintTrait (SVGConstants.SVG_STROKE_ATTRIBUTE, this, value); if (stroke != null) { setStroke(stroke); } } } else if (SVGConstants.SVG_FILL_OPACITY_ATTRIBUTE == name) { // ====================== fill-opacity ======================= // if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { setPackedInherited(PROPERTY_FILL_OPACITY, true); } else { setFillOpacity(parseFloatTrait(name, value)); } } else if (SVGConstants.SVG_STROKE_OPACITY_ATTRIBUTE .equals(name)) { // ================= stroke-opacity ========================= // if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { setPackedInherited(PROPERTY_STROKE_OPACITY, true); } else { setStrokeOpacity(parseFloatTrait(name, value)); } } else if (SVGConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE .equals(name)) { // ==================== stroke-dasharray ==================== // if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { setInherited(PROPERTY_STROKE_DASH_ARRAY, true); } else if (SVGConstants.CSS_NONE_VALUE.equals(value)) { setStrokeDashArray(null); } else { setStrokeDashArray(parsePositiveFloatArrayTrait(name, value)); } } else if (SVGConstants.SVG_OPACITY_ATTRIBUTE .equals(name)) { // ================= opacity ========================= // if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) { setPackedInherited(PROPERTY_OPACITY, true); } else { setOpacity(parseFloatTrait(name, value)); } } else { super.setTraitImpl(name, value); } } /** * @param name the name of the trait to convert. * @param value the float trait value to convert. */ String toStringTrait(final String name, final float[][] value) { if (SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE == name || SVGConstants.SVG_STROKE_MITERLIMIT_ATTRIBUTE == name || SVGConstants.SVG_STROKE_DASHOFFSET_ATTRIBUTE == name || SVGConstants.SVG_FILL_OPACITY_ATTRIBUTE == name || SVGConstants.SVG_STROKE_OPACITY_ATTRIBUTE == name || SVGConstants.SVG_OPACITY_ATTRIBUTE == name) { return Float.toString(value[0][0]); } else if (SVGConstants.SVG_COLOR_ATTRIBUTE == name || SVGConstants.SVG_FILL_ATTRIBUTE == name || SVGConstants.SVG_STROKE_ATTRIBUTE == name) { return toRGBString(name, value); } else if (SVGConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE == name) { return toStringTrait(value[0]); } else { return super.toStringTrait(name, value); } } /** * Set the trait value as float. * * Supported float traits: stroke-width, stroke-miterlimit, * stroke-dashoffset, fill-opacity, stroke-opacity, opacity. * * @param name the name of the trait to set. * @param value the value of the trait to set. * * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested * trait is not supported on this element. * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested * trait's value cannot be specified as a float * @throws DOMException with error code INVALID_ACCESS_ERR if the input * value is an invalid value for the given trait. * @throws SecurityException if the application does not have the necessary * privilege rights to access this (SVG) content. */ public void setFloatTraitImpl(final String name, final float value) throws DOMException { if (SVGConstants.SVG_STROKE_WIDTH_ATTRIBUTE == name) { checkPositive(name, value); setStrokeWidth(value); } else if (SVGConstants.SVG_STROKE_MITERLIMIT_ATTRIBUTE == name) { if (value < 1) { throw illegalTraitValue(name, Float.toString(value)); } setStrokeMiterLimit(value); } else if (SVGConstants.SVG_STROKE_DASHOFFSET_ATTRIBUTE == name) { setStrokeDashOffset(value); } else if (SVGConstants.SVG_FILL_OPACITY_ATTRIBUTE == name) { setFillOpacity(value); } else if (SVGConstants.SVG_STROKE_OPACITY_ATTRIBUTE == name) { setStrokeOpacity(value); } else if (SVGConstants.SVG_OPACITY_ATTRIBUTE == name) { setOpacity(value); } else { super.setFloatTraitImpl(name, value); } } /** * Set the trait value as {@link org.w3c.dom.svg.SVGRGBColor SVGRGBColor}. * * Supported color traits: color, fill, stroke * * @param name the name of the trait to set. * @param value the value of the trait to set. * * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested * trait is not supported on this element or null. * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested * trait's value cannot be specified as an {@link * org.w3c.dom.svg.SVGRGBColor SVGRGBColor} * @throws DOMException with error code INVALID_ACCESS_ERR if the input * value is null. * @throws SecurityException if the application does not have the necessary * privilege rights to access this (SVG) content. */ void setRGBColorTraitImpl(final String name, final SVGRGBColor color) throws DOMException { try { // We use .equals here because the name string may not have been // interned. if (SVGConstants.SVG_FILL_ATTRIBUTE.equals(name)) { setFill((RGB) color); } else if (SVGConstants.SVG_STROKE_ATTRIBUTE .equals(name)) { setStroke((RGB) color); } else if (SVGConstants.SVG_COLOR_ATTRIBUTE .equals(name)) { setColor((RGB) color); } else { super.setRGBColorTraitImpl(name, color); } } catch (IllegalArgumentException iae) { throw new DOMException(DOMException.INVALID_ACCESS_ERR, iae.getMessage()); } } /** * @param paintType the key provided by the PaintTarget when it subscribed * to associated PaintServer. * @param paintServer the PaintServer generating the update. */ public void onPaintServerUpdate(final String paintType, final PaintServer paintServer) { if (paintType == SVGConstants.SVG_FILL_ATTRIBUTE) { setFill(paintServer); } else if (paintType == SVGConstants.SVG_STROKE_ATTRIBUTE) { setStroke(paintServer); } else { throw new Error(); } } }