0001: /*
0002: *
0003: *
0004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: */
0026: package com.sun.perseus.model;
0027:
0028: import com.sun.perseus.j2d.Box;
0029: import com.sun.perseus.j2d.RenderGraphics;
0030: import com.sun.perseus.j2d.TextProperties;
0031: import com.sun.perseus.j2d.TextRenderingProperties;
0032: import com.sun.perseus.util.SVGConstants;
0033:
0034: import org.w3c.dom.DOMException;
0035: import org.w3c.dom.svg.SVGRect;
0036:
0037: import com.sun.perseus.j2d.Transform;
0038:
0039: /**
0040: * <code>StructureNode</code> is the base class for all nodes that
0041: * represent structure content, such as images, defs or svg elements.
0042: *
0043: * @version $Id: StructureNode.java,v 1.8 2006/06/29 10:47:35 ln156897 Exp $
0044: */
0045: public abstract class StructureNode extends CompositeGraphicsNode
0046: implements TextNode, TextRenderingProperties {
0047: /**
0048: * Marker used to mark that the fontWeight property was set to bolder.
0049: */
0050: public static final int FONT_WEIGHT_BOLDER_MARKER = 1 << 23;
0051:
0052: /**
0053: * Marker used to mark that the fontWeight property was set to lighter.
0054: */
0055: public static final int FONT_WEIGHT_LIGHTER_MARKER = 1 << 24;
0056:
0057: /**
0058: * When align is set to ALIGN_NONE, the SVG content
0059: * is rescaled so that the widht and height of the
0060: * viewBox map to the viewport width and height and
0061: * the origin of the viewBox maps to the viewport
0062: * origin.
0063: */
0064: public static final int ALIGN_NONE = 0;
0065:
0066: /**
0067: * When align is set to ALIGN_XMIDYMID, the SVG
0068: * content is rescaled so that the aspect ratio
0069: * of the viewBox is preserved. With that constraint,
0070: * either the width or height of the viewBox is
0071: * mapped to the width or height of the viewPort.
0072: * The rescaled content is centered into the viewport.
0073: */
0074: public static final int ALIGN_XMIDYMID = 1;
0075:
0076: // ====================================================================
0077: // Properties
0078: // ====================================================================
0079: /**
0080: * Controls this node's fontFamily
0081: */
0082: protected String[] fontFamily = INITIAL_FONT_FAMILY;
0083:
0084: /**
0085: * Controls this node's fontSize
0086: */
0087: protected float fontSize = INITIAL_FONT_SIZE;
0088:
0089: /**
0090: * Constructor.
0091: *
0092: * @param ownerDocument this element's owner <code>DocumentNode</code>
0093: */
0094: public StructureNode(final DocumentNode ownerDocument) {
0095: super (ownerDocument);
0096: }
0097:
0098: /**
0099: * @param bbox the bounding box to which this node's bounding box should be
0100: * appended. That bounding box is in the target coordinate space. It
0101: * may be null, in which case this node should create a new one.
0102: * @param t the transform to apply from the node's coordinate space to the
0103: * target coordinate space. May be null for the identity
0104: * transform.
0105: * @return the node's bounding box in the target coordinate space.
0106: */
0107: Box addBBox(Box bbox, final Transform t) {
0108: ModelNode c = getFirstChildNode();
0109: while (c != null) {
0110: if (c.contributeBBox()) {
0111: bbox = c.addBBox(bbox, c.appendTransform(t, null));
0112: }
0113: c = c.nextSibling;
0114: }
0115:
0116: return bbox;
0117: }
0118:
0119: /**
0120: * @return the tight bounding box in current user coordinate
0121: * space.
0122: */
0123: public SVGRect getBBox() {
0124: return addBBox(null, null);
0125: }
0126:
0127: /**
0128: * @return the tight bounding box in screen coordinate space.
0129: */
0130: public SVGRect getScreenBBox() {
0131: // There is no screen bounding box if the element is not hooked
0132: // into the main tree.
0133: if (!inDocumentTree()) {
0134: return null;
0135: }
0136:
0137: return addBBox(null, txf);
0138: }
0139:
0140: /**
0141: * Returns the <code>ModelNode</code>, if any, hit by the
0142: * point at coordinate x/y.
0143: *
0144: * @param pt the x/y coordinate. Should never be null and be
0145: * of size two. If not, the behavior is unspecified.
0146: * The coordinates are in viewport space.
0147: * @return the <tt>ModelNode</tt> hit at the given point or null
0148: * if none was hit.
0149: */
0150: public ModelNode nodeHitAt(final float[] pt) {
0151: // If a node does not render, it is never hit
0152: if (canRenderState != 0) {
0153: return null;
0154: }
0155:
0156: // Check for a hit on children
0157: return nodeHitAt(getLastChildNode(), pt);
0158: }
0159:
0160: /**
0161: * Returns the <code>ModelNode</code>, if any, hit by the
0162: * point at coordinate x/y in the proxy tree starting at
0163: * proxy.
0164: *
0165: * @param pt the x/y coordinate. Should never be null and be
0166: * of size two. If not, the behavior is unspecified.
0167: * The coordinates are in viewport space.
0168: * @param proxy the root of the proxy tree to test.
0169: * @return the <tt>ModelNode</tt> hit at the given point or null
0170: * if none was hit.
0171: */
0172: ModelNode proxyNodeHitAt(final float[] pt,
0173: final ElementNodeProxy proxy) {
0174: // If a node does not render, it is never hit
0175: if (canRenderState != 0) {
0176: return null;
0177: }
0178:
0179: // Check for a hit on expanded children
0180: return nodeHitAt(proxy.getLastExpandedChild(), pt);
0181: }
0182:
0183: /**
0184: * @return the number of properties supported by this node
0185: */
0186: public int getNumberOfProperties() {
0187: return GraphicsNode.NUMBER_OF_PROPERTIES
0188: + TextNode.NUMBER_OF_PROPERTIES;
0189: }
0190:
0191: /**
0192: * Recomputes all inherited properties.
0193: */
0194: void recomputeInheritedProperties() {
0195: super .recomputeInheritedProperties();
0196: ModelNode p = ownerDocument;
0197: if (parent != null) {
0198: p = parent;
0199: }
0200: recomputePropertyState(PROPERTY_FONT_FAMILY, p
0201: .getPropertyState(PROPERTY_FONT_FAMILY));
0202: recomputeFloatPropertyState(PROPERTY_FONT_SIZE, p
0203: .getFloatPropertyState(PROPERTY_FONT_SIZE));
0204: recomputePackedPropertyState(PROPERTY_FONT_STYLE, p
0205: .getPackedPropertyState(PROPERTY_FONT_STYLE));
0206: recomputePackedPropertyState(PROPERTY_FONT_WEIGHT, p
0207: .getPackedPropertyState(PROPERTY_FONT_WEIGHT));
0208: recomputePackedPropertyState(PROPERTY_TEXT_ANCHOR, p
0209: .getPackedPropertyState(PROPERTY_TEXT_ANCHOR));
0210: }
0211:
0212: /**
0213: * Recomputes the given packed property's state given the new parent
0214: * property.
0215: *
0216: * @param propertyIndex index for the property whose value is changing.
0217: * @param parentPropertyValue the value that children of this node should
0218: * now inherit.
0219: *
0220: */
0221: protected void recomputePackedPropertyState(
0222: final int propertyIndex, final int parentPropertyValue) {
0223: if (propertyIndex != PROPERTY_FONT_WEIGHT) {
0224: super .recomputePackedPropertyState(propertyIndex,
0225: parentPropertyValue);
0226: } else {
0227: // We do not need to recompute the fontWeight value if:
0228: // - the fontWeight is _not_ inherited & not relative (i.e. lighter
0229: // or bolder)
0230: // or
0231: // - the property is inherited but the new parent property computed
0232: // value is the same as the current value & the bolder and lighter
0233: // markes are in the same state
0234: boolean isBolder = isMarkerSet(FONT_WEIGHT_BOLDER_MARKER);
0235: boolean isLighter = isMarkerSet(FONT_WEIGHT_LIGHTER_MARKER);
0236: if ((!isInherited(propertyIndex) && !isBolder && !isLighter)
0237: || isPackedPropertyState(propertyIndex,
0238: parentPropertyValue)) {
0239: return;
0240: }
0241:
0242: int packedFontWeight = parentPropertyValue;
0243: if (isBolder) {
0244: packedFontWeight = computeFontWeight(
0245: parentPropertyValue, FONT_WEIGHT_BOLDER);
0246: } else if (isLighter) {
0247: packedFontWeight = computeFontWeight(
0248: parentPropertyValue, FONT_WEIGHT_LIGHTER);
0249: }
0250:
0251: setPackedPropertyState(propertyIndex, packedFontWeight);
0252:
0253: propagatePackedPropertyState(propertyIndex,
0254: parentPropertyValue);
0255: }
0256: }
0257:
0258: /**
0259: * Returns the value for the given property.
0260: *
0261: * @return the value for the given property.
0262: */
0263: protected Object getPropertyState(final int propertyIndex) {
0264: switch (propertyIndex) {
0265: case PROPERTY_FONT_FAMILY:
0266: return fontFamily;
0267: default:
0268: return super .getPropertyState(propertyIndex);
0269: }
0270: }
0271:
0272: /**
0273: * Returns the value for the given float property.
0274: *
0275: * @return the value for the given property.
0276: */
0277: protected float getFloatPropertyState(final int propertyIndex) {
0278: switch (propertyIndex) {
0279: case PROPERTY_FONT_SIZE:
0280: return fontSize;
0281: default:
0282: return super .getFloatPropertyState(propertyIndex);
0283: }
0284: }
0285:
0286: /**
0287: * Returns the value for the given packed property.
0288: *
0289: * @return the value for the given packed property.
0290: */
0291: protected int getPackedPropertyState(final int propertyIndex) {
0292: switch (propertyIndex) {
0293: case TextNode.PROPERTY_FONT_STYLE:
0294: return pack & StructureNode.FONT_STYLE_MASK;
0295: case TextNode.PROPERTY_FONT_WEIGHT:
0296: return pack & StructureNode.FONT_WEIGHT_MASK;
0297: case TextNode.PROPERTY_TEXT_ANCHOR:
0298: return pack & StructureNode.TEXT_ANCHOR_MASK;
0299: default:
0300: return super .getPackedPropertyState(propertyIndex);
0301: }
0302: }
0303:
0304: /**
0305: * Sets the computed value for the given property.
0306: *
0307: * @param propertyIndex the property index
0308: * @param propertyValue the computed value for the property.
0309: */
0310: protected void setPropertyState(final int propertyIndex,
0311: final Object propertyValue) {
0312: switch (propertyIndex) {
0313: case PROPERTY_FONT_FAMILY:
0314: setComputedFontFamily((String[]) propertyValue);
0315: break;
0316: default:
0317: super .setPropertyState(propertyIndex, propertyValue);
0318: }
0319: }
0320:
0321: /**
0322: * Sets the computed value for the given float property.
0323: *
0324: * @param propertyIndex the property index
0325: * @param propertyValue the computed value for the property.
0326: */
0327: protected void setFloatPropertyState(final int propertyIndex,
0328: final float propertyValue) {
0329: switch (propertyIndex) {
0330: case PROPERTY_FONT_SIZE:
0331: setComputedFontSize(propertyValue);
0332: break;
0333: default:
0334: super .setFloatPropertyState(propertyIndex, propertyValue);
0335: }
0336: }
0337:
0338: /**
0339: * Sets the computed value for the given packed property.
0340: *
0341: * @param propertyIndex the property index
0342: * @param propertyValue the computed value for the property.
0343: */
0344: protected void setPackedPropertyState(final int propertyIndex,
0345: final int propertyValue) {
0346: switch (propertyIndex) {
0347: case PROPERTY_FONT_STYLE:
0348: switch (propertyValue) {
0349: case FONT_STYLE_NORMAL_IMPL:
0350: setComputedFontStyle(FONT_STYLE_NORMAL);
0351: break;
0352: case FONT_STYLE_ITALIC_IMPL:
0353: setComputedFontStyle(FONT_STYLE_ITALIC);
0354: break;
0355: case FONT_STYLE_OBLIQUE_IMPL:
0356: default:
0357: setComputedFontStyle(FONT_STYLE_OBLIQUE);
0358: break;
0359: }
0360: break;
0361: case PROPERTY_FONT_WEIGHT:
0362: setComputedFontWeight(propertyValue);
0363: break;
0364: case PROPERTY_TEXT_ANCHOR:
0365: switch (propertyValue) {
0366: case TEXT_ANCHOR_START_IMPL:
0367: setComputedTextAnchor(TEXT_ANCHOR_START);
0368: break;
0369: case TEXT_ANCHOR_MIDDLE_IMPL:
0370: setComputedTextAnchor(TEXT_ANCHOR_MIDDLE);
0371: break;
0372: case TEXT_ANCHOR_END_IMPL:
0373: default:
0374: setComputedTextAnchor(TEXT_ANCHOR_END);
0375: break;
0376: }
0377: break;
0378: default:
0379: super .setPackedPropertyState(propertyIndex, propertyValue);
0380: }
0381: }
0382:
0383: /**
0384: * Checks the state of the property value.
0385: *
0386: * @param propertyIndex the property index
0387: * @param propertyValue the computed value for the property.
0388: */
0389: protected boolean isPropertyState(final int propertyIndex,
0390: final Object propertyValue) {
0391: switch (propertyIndex) {
0392: case TextNode.PROPERTY_FONT_FAMILY:
0393: return fontFamily == propertyValue;
0394: default:
0395: return super .isPropertyState(propertyIndex, propertyValue);
0396: }
0397: }
0398:
0399: /**
0400: * Checks the state of the float property value.
0401: *
0402: * @param propertyIndex the property index
0403: * @param propertyValue the computed value for the property.
0404: */
0405: protected boolean isFloatPropertyState(final int propertyIndex,
0406: final float propertyValue) {
0407: switch (propertyIndex) {
0408: case TextNode.PROPERTY_FONT_SIZE:
0409: return fontSize == propertyValue;
0410: default:
0411: return super .isFloatPropertyState(propertyIndex,
0412: propertyValue);
0413: }
0414: }
0415:
0416: /**
0417: * Checks the state of the property value.
0418: *
0419: * @param propertyIndex the property index
0420: * @param propertyValue the computed value for the property.
0421: */
0422: protected boolean isPackedPropertyState(final int propertyIndex,
0423: final int propertyValue) {
0424: switch (propertyIndex) {
0425: case TextNode.PROPERTY_FONT_STYLE:
0426: return (propertyValue == (pack & StructureNode.FONT_STYLE_MASK));
0427: case TextNode.PROPERTY_FONT_WEIGHT:
0428: return (propertyValue == (pack & StructureNode.FONT_WEIGHT_MASK));
0429: case TextNode.PROPERTY_TEXT_ANCHOR:
0430: return (propertyValue == (pack & StructureNode.TEXT_ANCHOR_MASK));
0431: default:
0432: return super .isPackedPropertyState(propertyIndex,
0433: propertyValue);
0434: }
0435: }
0436:
0437: // ====================================================================
0438: // TextNodeProperties implementation
0439: // ====================================================================
0440:
0441: /**
0442: * @return this node's computed font-family
0443: */
0444: public String[] getFontFamily() {
0445: return fontFamily;
0446: }
0447:
0448: /**
0449: * @param newFontFamily The fontFamily is used when the property is
0450: * not inherited
0451: */
0452: public void setFontFamily(final String[] newFontFamily) {
0453: if (!isInherited(PROPERTY_FONT_FAMILY)
0454: && equal(newFontFamily, fontFamily)) {
0455: return;
0456: }
0457: modifyingNode();
0458: setInheritedQuiet(PROPERTY_FONT_FAMILY, false);
0459: setComputedFontFamily(newFontFamily);
0460: propagatePropertyState(PROPERTY_FONT_FAMILY, newFontFamily);
0461: modifiedNode();
0462: }
0463:
0464: /**
0465: * @param newFontFamily the new computed font-family property value.
0466: */
0467: void setComputedFontFamily(final String[] newFontFamily) {
0468: this .fontFamily = newFontFamily;
0469: }
0470:
0471: /**
0472: * @return this node's computed fontSize
0473: */
0474: public float getFontSize() {
0475: return fontSize;
0476: }
0477:
0478: /**
0479: * @param newFontSize the fontSize is used when the property is
0480: * not inherited. This should not be less than zero.
0481: */
0482: public void setFontSize(final float newFontSize) {
0483: if (newFontSize < 0) {
0484: throw new IllegalArgumentException();
0485: }
0486:
0487: if (!isInherited(PROPERTY_FONT_SIZE) && newFontSize == fontSize) {
0488: return;
0489: }
0490:
0491: modifyingNode();
0492: setInheritedQuiet(PROPERTY_FONT_SIZE, false);
0493: setComputedFontSize(newFontSize);
0494: propagateFloatPropertyState(PROPERTY_FONT_SIZE, newFontSize);
0495: modifiedNode();
0496: }
0497:
0498: /**
0499: * @param newFontSize the new computed font-size property value.
0500: */
0501: void setComputedFontSize(final float newFontSize) {
0502: this .fontSize = newFontSize;
0503: }
0504:
0505: /**
0506: * @return this node's computed fontStyle
0507: */
0508: public int getFontStyle() {
0509: switch (pack & FONT_STYLE_MASK) {
0510: case FONT_STYLE_NORMAL_IMPL:
0511: return FONT_STYLE_NORMAL;
0512: case FONT_STYLE_ITALIC_IMPL:
0513: return FONT_STYLE_ITALIC;
0514: default:
0515: return FONT_STYLE_OBLIQUE;
0516: }
0517: }
0518:
0519: /**
0520: * @param newFontStyle The fontStyle is used when the property is
0521: * not inherited
0522: */
0523: public void setFontStyle(final int newFontStyle) {
0524: if (!isInherited(PROPERTY_FONT_STYLE)
0525: && newFontStyle == getFontStyle()) {
0526: return;
0527: }
0528:
0529: modifyingNode();
0530: setInheritedQuiet(PROPERTY_FONT_STYLE, false);
0531: setComputedFontStyle(newFontStyle);
0532: propagatePackedPropertyState(PROPERTY_FONT_STYLE, pack
0533: & FONT_STYLE_MASK);
0534: modifiedNode();
0535: }
0536:
0537: /**
0538: * @param newFontStyle the new computed font-style property.
0539: */
0540: void setComputedFontStyle(final int newFontStyle) {
0541: pack &= ~FONT_STYLE_MASK;
0542: switch (newFontStyle) {
0543: case FONT_STYLE_NORMAL:
0544: pack |= FONT_STYLE_NORMAL_IMPL;
0545: break;
0546: case FONT_STYLE_ITALIC:
0547: pack |= FONT_STYLE_ITALIC_IMPL;
0548: break;
0549: default:
0550: pack |= FONT_STYLE_OBLIQUE_IMPL;
0551: break;
0552: }
0553: }
0554:
0555: /**
0556: * @return this node's computed fontWeight
0557: */
0558: public int getFontWeight() {
0559: switch (pack & FONT_WEIGHT_MASK) {
0560: case FONT_WEIGHT_100_IMPL:
0561: return FONT_WEIGHT_100;
0562: case FONT_WEIGHT_200_IMPL:
0563: return FONT_WEIGHT_200;
0564: case FONT_WEIGHT_300_IMPL:
0565: return FONT_WEIGHT_300;
0566: case FONT_WEIGHT_400_IMPL:
0567: return FONT_WEIGHT_400;
0568: case FONT_WEIGHT_500_IMPL:
0569: return FONT_WEIGHT_500;
0570: case FONT_WEIGHT_600_IMPL:
0571: return FONT_WEIGHT_600;
0572: case FONT_WEIGHT_700_IMPL:
0573: return FONT_WEIGHT_700;
0574: case FONT_WEIGHT_800_IMPL:
0575: return FONT_WEIGHT_800;
0576: case FONT_WEIGHT_900_IMPL:
0577: return FONT_WEIGHT_900;
0578: case FONT_WEIGHT_LIGHTER_IMPL:
0579: return FONT_WEIGHT_LIGHTER;
0580: default:
0581: return FONT_WEIGHT_BOLDER;
0582: }
0583: }
0584:
0585: /**
0586: * @param newFontWeight The fontWeight is used when the property is
0587: * not inherited
0588: */
0589: public void setFontWeight(final int newFontWeight) {
0590: if (!isInherited(PROPERTY_FONT_WEIGHT)
0591: && newFontWeight == getFontWeight()) {
0592: return;
0593: }
0594:
0595: modifyingNode();
0596: setInheritedQuiet(PROPERTY_FONT_WEIGHT, false);
0597:
0598: // Font weight is special: we need to account for relative values
0599: // bolder and lighter.
0600: int packedParentFontWeight = getInheritedPackedPropertyState(PROPERTY_FONT_WEIGHT);
0601: setComputedFontWeight(computeFontWeight(packedParentFontWeight,
0602: newFontWeight));
0603: propagatePackedPropertyState(PROPERTY_FONT_WEIGHT, pack
0604: & FONT_WEIGHT_MASK);
0605: modifiedNode();
0606: }
0607:
0608: /**
0609: * @param newFontWeight new computed value for the font-weight property.
0610: */
0611: void setComputedFontWeight(final int newFontWeight) {
0612: pack &= ~FONT_WEIGHT_MASK;
0613: pack |= newFontWeight;
0614: }
0615:
0616: /**
0617: * @return this node's computed textAnchor
0618: */
0619: public int getTextAnchor() {
0620: switch (pack & TEXT_ANCHOR_MASK) {
0621: case TEXT_ANCHOR_START_IMPL:
0622: return TEXT_ANCHOR_START;
0623: case TEXT_ANCHOR_MIDDLE_IMPL:
0624: return TEXT_ANCHOR_MIDDLE;
0625: default:
0626: return TEXT_ANCHOR_END;
0627: }
0628: }
0629:
0630: /**
0631: * @param newTextAnchor The textAnchor is used when the property is not
0632: * inherited
0633: */
0634: public void setTextAnchor(final int newTextAnchor) {
0635: if (!isInherited(PROPERTY_TEXT_ANCHOR)
0636: && newTextAnchor == getTextAnchor()) {
0637: return;
0638: }
0639:
0640: modifyingNode();
0641: setComputedTextAnchor(newTextAnchor);
0642: setInheritedQuiet(PROPERTY_TEXT_ANCHOR, false);
0643: propagatePackedPropertyState(PROPERTY_TEXT_ANCHOR, pack
0644: & TEXT_ANCHOR_MASK);
0645: modifiedNode();
0646: }
0647:
0648: /**
0649: * Sets the value of the computed text anchor property.
0650: *
0651: * @param newTextAnchor the new value for the computed text anchor property.
0652: */
0653: void setComputedTextAnchor(final int newTextAnchor) {
0654: pack &= ~TEXT_ANCHOR_MASK;
0655: switch (newTextAnchor) {
0656: case TEXT_ANCHOR_START:
0657: pack |= TEXT_ANCHOR_START_IMPL;
0658: break;
0659: case TEXT_ANCHOR_MIDDLE:
0660: pack |= TEXT_ANCHOR_MIDDLE_IMPL;
0661: break;
0662: default:
0663: pack |= TEXT_ANCHOR_END_IMPL;
0664: break;
0665: }
0666: }
0667:
0668: /**
0669: * Handles the 'bolder' and 'lighter' values as follows:
0670: *
0671: * - bolder computes to font-weight + 300. If the result
0672: * is more than 900, then the computed value is 900.
0673: * - lighter computes to font-weight - 300. If the result
0674: * is less than 100, then the comuted value is 100.
0675: *
0676: * *NOTE*
0677: *
0678: * This is not exactly implementing the CSS2 specification for bolder but
0679: * that part of the CSS 2 specification is known to be
0680: * underspecified. Handling of 'bolder' is being respecified for CSS
0681: * 2.1. Furthermore, the CSS 2 specification does not address the needs for
0682: * SVG Fonts well. For example, if you have the following fonts in the font
0683: * data base:
0684: *
0685: * font A: Arial, 100 to 500
0686: * font B: Arial, 600 to 900
0687: *
0688: * element 1: font-family="Arial" font-weight="normal"
0689: * |
0690: * + - element 2: font-family="Arial" font-weight="bolder"
0691: *
0692: * font-weight for element 1 is 400. The font weight for element B should be
0693: * that of the font for which there is a next bolder weight. In our
0694: * example, it is font A which has font weight 500. However, it is not the
0695: * desired behavior in most cases.
0696: *
0697: * Secondly, the SVG Font format allows non consecutive font-weight values
0698: * in the <font-face> element. For example:
0699: *
0700: * font C: Arial, 100,900
0701: * font D: Arial, 200,400
0702: *
0703: * While this does not make a lot of sense, it is possible to specify such
0704: * fonts and it is unclear what the behavior of bolder should be in that
0705: * case. It seems that taking the matching font which has the most distance
0706: * from the current font-weight could work, but that would be limiting
0707: * 'bolder' to a one step change....
0708: *
0709: * The approach taken in the Perseus implementation is such that bolder will
0710: * work for common cases with common Font specifications.
0711: *
0712: * @param refPackedFontWeight the reference font weight.
0713: * @param relFontWeight the possibly relative font weight.
0714: * @return the computed font weight.
0715: */
0716: int computeFontWeight(final int refPackedFontWeight,
0717: final int relFontWeight) {
0718: // Handle bolder and lighter
0719: if (relFontWeight == FONT_WEIGHT_BOLDER) {
0720: setMarker(FONT_WEIGHT_BOLDER_MARKER);
0721: clearMarker(FONT_WEIGHT_LIGHTER_MARKER);
0722: switch (refPackedFontWeight) {
0723: case FONT_WEIGHT_100_IMPL:
0724: return FONT_WEIGHT_400_IMPL;
0725: case FONT_WEIGHT_200_IMPL:
0726: return FONT_WEIGHT_500_IMPL;
0727: case FONT_WEIGHT_300_IMPL:
0728: return FONT_WEIGHT_600_IMPL;
0729: case FONT_WEIGHT_400_IMPL:
0730: return FONT_WEIGHT_700_IMPL;
0731: case FONT_WEIGHT_500_IMPL:
0732: return FONT_WEIGHT_800_IMPL;
0733: case FONT_WEIGHT_600_IMPL:
0734: case FONT_WEIGHT_700_IMPL:
0735: case FONT_WEIGHT_800_IMPL:
0736: case FONT_WEIGHT_900_IMPL:
0737: default:
0738: return FONT_WEIGHT_900_IMPL;
0739: }
0740: } else if (relFontWeight == FONT_WEIGHT_LIGHTER) {
0741: setMarker(FONT_WEIGHT_LIGHTER_MARKER);
0742: clearMarker(FONT_WEIGHT_BOLDER_MARKER);
0743: switch (refPackedFontWeight) {
0744: default:
0745: case FONT_WEIGHT_100_IMPL:
0746: case FONT_WEIGHT_200_IMPL:
0747: case FONT_WEIGHT_300_IMPL:
0748: case FONT_WEIGHT_400_IMPL:
0749: return FONT_WEIGHT_100_IMPL;
0750: case FONT_WEIGHT_500_IMPL:
0751: return FONT_WEIGHT_200_IMPL;
0752: case FONT_WEIGHT_600_IMPL:
0753: return FONT_WEIGHT_300_IMPL;
0754: case FONT_WEIGHT_700_IMPL:
0755: return FONT_WEIGHT_400_IMPL;
0756: case FONT_WEIGHT_800_IMPL:
0757: return FONT_WEIGHT_500_IMPL;
0758: case FONT_WEIGHT_900_IMPL:
0759: return FONT_WEIGHT_600_IMPL;
0760: }
0761: }
0762:
0763: clearMarker(FONT_WEIGHT_BOLDER_MARKER);
0764: clearMarker(FONT_WEIGHT_LIGHTER_MARKER);
0765: switch (relFontWeight) {
0766: default:
0767: case FONT_WEIGHT_100:
0768: return FONT_WEIGHT_100_IMPL;
0769: case FONT_WEIGHT_200:
0770: return FONT_WEIGHT_200_IMPL;
0771: case FONT_WEIGHT_300:
0772: return FONT_WEIGHT_300_IMPL;
0773: case FONT_WEIGHT_400:
0774: return FONT_WEIGHT_400_IMPL;
0775: case FONT_WEIGHT_500:
0776: return FONT_WEIGHT_500_IMPL;
0777: case FONT_WEIGHT_600:
0778: return FONT_WEIGHT_600_IMPL;
0779: case FONT_WEIGHT_700:
0780: return FONT_WEIGHT_700_IMPL;
0781: case FONT_WEIGHT_800:
0782: return FONT_WEIGHT_800_IMPL;
0783: case FONT_WEIGHT_900:
0784: return FONT_WEIGHT_900_IMPL;
0785: }
0786: }
0787:
0788: /**
0789: * Utility method: computes the transform needed to fit the input
0790: * box into the given output box for the given input alignment
0791: * property.
0792: *
0793: * @param ix the x origin of the input box
0794: * @param iy the y origin of the input box
0795: * @param iw the width of the input box
0796: * @param ih the height of the input box
0797: * @param ox the x origin of the output box
0798: * @param oy the y origin of the output box
0799: * @param ow the width of the output box
0800: * @param oh the height of the output box
0801: * @param align the desired alignment. One of ALIGN_NONE, or ALIGN_XMIDYMID
0802: * @param result the transform to which the fitting transform is
0803: * concatenated
0804: *
0805: */
0806: public static void getFittingTransform(final float ix,
0807: final float iy, final float iw, final float ih,
0808: final float ox, final float oy, final float ow,
0809: final float oh, final int align, final Transform result) {
0810: float inAR = iw / ih;
0811: float outAR = ow / oh;
0812:
0813: // Move to output box location (ox,oy)
0814: result.mTranslate(ox, oy);
0815:
0816: if (align == ALIGN_NONE) {
0817: // Scale without preserving aspect ratio
0818: result.mScale(ow / iw, oh / ih);
0819: // Move to (0,0)
0820: result.mTranslate(-ix, -iy);
0821: } else if (inAR < outAR) {
0822: float sf = oh / ih;
0823: result.mScale(sf);
0824: result.mTranslate(-ix - (iw - ow * ih / oh) / 2, -iy);
0825: } else {
0826: float sf = ow / iw;
0827: result.mScale(sf);
0828: result.mTranslate(-ix, -iy - (ih - oh * iw / ow) / 2);
0829: }
0830: }
0831:
0832: /**
0833: * @return an adequate <code>ElementNodeProxy</code> for this node.
0834: */
0835: ElementNodeProxy buildProxy() {
0836: return new StructureNodeProxy(this );
0837: }
0838:
0839: /**
0840: * Paints this node into the input <code>RenderGraphics</code>. By default,
0841: * a <code>StructureNode</code> only renders its regular (DOM) children and
0842: * it does not perform any rendering itself.
0843: *
0844: * @param rg the <tt>RenderGraphics</tt> where the node should paint itself
0845: */
0846: public void paint(final RenderGraphics rg) {
0847: if (canRenderState != 0) {
0848: return;
0849: }
0850:
0851: paint(getFirstChildNode(), rg);
0852: }
0853:
0854: /**
0855: * Supported traits: font-family, font-size, font-style, font-weight,
0856: * text-anchor.
0857: *
0858: * @param traitName the name of the trait which the element may support.
0859: * @return true if this element supports the given trait in one of the
0860: * trait accessor methods.
0861: */
0862: boolean supportsTrait(final String traitName) {
0863: if (SVGConstants.SVG_FONT_FAMILY_ATTRIBUTE == traitName
0864: || SVGConstants.SVG_FONT_SIZE_ATTRIBUTE == traitName
0865: || SVGConstants.SVG_FONT_STYLE_ATTRIBUTE == traitName
0866: || SVGConstants.SVG_FONT_WEIGHT_ATTRIBUTE == traitName
0867: || SVGConstants.SVG_TEXT_ANCHOR_ATTRIBUTE == traitName) {
0868: return true;
0869: } else {
0870: return super .supportsTrait(traitName);
0871: }
0872: }
0873:
0874: /**
0875: * Supported traits: font-family, font-size, font-style, font-weight,
0876: * text-anchor.
0877: *
0878: * @param name the requested trait name (e.g., "font-family").
0879: * @return the trait's value, as a string (e.g., "serif").
0880: *
0881: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
0882: * trait is not supported on this element or null.
0883: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
0884: * trait's computed value cannot be converted to a String (SVG Tiny only).
0885: */
0886: String getSpecifiedTraitImpl(final String name) throws DOMException {
0887: if ((SVGConstants.SVG_FONT_FAMILY_ATTRIBUTE == name && isInherited(PROPERTY_FONT_FAMILY))
0888: || (SVGConstants.SVG_FONT_SIZE_ATTRIBUTE == name && isInherited(PROPERTY_FONT_SIZE))
0889: || (SVGConstants.SVG_FONT_STYLE_ATTRIBUTE == name && isInherited(PROPERTY_FONT_STYLE))
0890: || (SVGConstants.SVG_FONT_WEIGHT_ATTRIBUTE == name && isInherited(PROPERTY_FONT_WEIGHT))
0891: || (SVGConstants.SVG_TEXT_ANCHOR_ATTRIBUTE == name && isInherited(PROPERTY_TEXT_ANCHOR))) {
0892: return SVGConstants.CSS_INHERIT_VALUE;
0893: } else {
0894: return super .getSpecifiedTraitImpl(name);
0895: }
0896: }
0897:
0898: /**
0899: * Converts the input font-style value to a string trait value.
0900: *
0901: * @param fontStyle the font-style value to convert.
0902: * @return the corresponding string trait value.
0903: */
0904: String fontWeightToStringTrait(final int fontWeight) {
0905: switch (fontWeight) {
0906: case StructureNode.FONT_WEIGHT_100_IMPL:
0907: return SVGConstants.CSS_100_VALUE;
0908: case StructureNode.FONT_WEIGHT_200_IMPL:
0909: return SVGConstants.CSS_200_VALUE;
0910: case StructureNode.FONT_WEIGHT_300_IMPL:
0911: return SVGConstants.CSS_300_VALUE;
0912: case StructureNode.FONT_WEIGHT_400_IMPL:
0913: return SVGConstants.CSS_400_VALUE;
0914: case StructureNode.FONT_WEIGHT_500_IMPL:
0915: return SVGConstants.CSS_500_VALUE;
0916: case StructureNode.FONT_WEIGHT_600_IMPL:
0917: return SVGConstants.CSS_600_VALUE;
0918: case StructureNode.FONT_WEIGHT_700_IMPL:
0919: return SVGConstants.CSS_700_VALUE;
0920: case StructureNode.FONT_WEIGHT_800_IMPL:
0921: return SVGConstants.CSS_800_VALUE;
0922: case StructureNode.FONT_WEIGHT_900_IMPL:
0923: default:
0924: return SVGConstants.CSS_900_VALUE;
0925: }
0926: }
0927:
0928: /**
0929: * Converts the input text-anchor value to a string trait value.
0930: *
0931: * @param textAnchor the text-anchor value to convert.
0932: * @return the corresponding string trait value.
0933: */
0934: String textAnchorToStringTrait(final int textAnchor) {
0935: switch (textAnchor) {
0936: case StructureNode.TEXT_ANCHOR_START_IMPL:
0937: return SVGConstants.CSS_START_VALUE;
0938: case StructureNode.TEXT_ANCHOR_MIDDLE_IMPL:
0939: return SVGConstants.CSS_MIDDLE_VALUE;
0940: case StructureNode.TEXT_ANCHOR_END_IMPL:
0941: return SVGConstants.CSS_END_VALUE;
0942: default:
0943: // Should _never_ happen.
0944: throw new Error();
0945: }
0946: }
0947:
0948: /**
0949: * Converts the input font-style value to a string trait value.
0950: *
0951: * @param fontStyle the font-style value to convert. In packed form, with
0952: * mask applied.
0953: * @return the corresponding string trait value.
0954: */
0955: String fontStyleToStringTrait(final int fontStyle) {
0956: switch (fontStyle) {
0957: case StructureNode.FONT_STYLE_NORMAL_IMPL:
0958: return SVGConstants.CSS_NORMAL_VALUE;
0959: case StructureNode.FONT_STYLE_OBLIQUE_IMPL:
0960: return SVGConstants.CSS_OBLIQUE_VALUE;
0961: case StructureNode.FONT_STYLE_ITALIC_IMPL:
0962: default:
0963: return SVGConstants.CSS_ITALIC_VALUE;
0964: }
0965: }
0966:
0967: /**
0968: * Supported traits: font-family, font-size, font-style, font-weight,
0969: * text-anchor.
0970: *
0971: * @param name the requested trait name (e.g., "font-family").
0972: * @return the trait's value, as a string (e.g., "serif").
0973: *
0974: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
0975: * trait is not supported on this element or null.
0976: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
0977: * trait's computed value cannot be converted to a String (SVG Tiny only).
0978: */
0979: public String getTraitImpl(final String name) throws DOMException {
0980: if (SVGConstants.SVG_FONT_FAMILY_ATTRIBUTE == name) {
0981: return toStringTraitQuote(getFontFamily());
0982: } else if (SVGConstants.SVG_FONT_SIZE_ATTRIBUTE == name) {
0983: return Float.toString(getFontSize());
0984: } else if (SVGConstants.SVG_FONT_STYLE_ATTRIBUTE == name) {
0985: return fontStyleToStringTrait(pack & FONT_STYLE_MASK);
0986: } else if (SVGConstants.SVG_FONT_WEIGHT_ATTRIBUTE == name) {
0987: return fontWeightToStringTrait(pack & FONT_WEIGHT_MASK);
0988: } else if (SVGConstants.SVG_TEXT_ANCHOR_ATTRIBUTE == name) {
0989: return textAnchorToStringTrait(pack & TEXT_ANCHOR_MASK);
0990: } else {
0991: return super .getTraitImpl(name);
0992: }
0993: }
0994:
0995: /**
0996: * Supported float traits: font-size
0997: *
0998: * @param name the requested trait name (e.g, "font-size")
0999: * @return the trait's value, as a float.
1000: *
1001: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1002: * trait is not supported on this element or null.
1003: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
1004: * trait's computed value cannot be converted to a float
1005: * @throws SecurityException if the application does not have the necessary
1006: * privilege rights to access this (SVG) content.
1007: */
1008: float getFloatTraitImpl(final String name) throws DOMException {
1009: if (SVGConstants.SVG_FONT_SIZE_ATTRIBUTE == name) {
1010: return getFontSize();
1011: } else {
1012: return super .getFloatTraitImpl(name);
1013: }
1014: }
1015:
1016: /**
1017: * @param traitName the trait name.
1018: */
1019: TraitAnim createTraitAnimImpl(final String traitName) {
1020: if (SVGConstants.SVG_FONT_SIZE_ATTRIBUTE == traitName) {
1021: return new FloatTraitAnim(this , traitName, TRAIT_TYPE_FLOAT);
1022: } else if (SVGConstants.SVG_FONT_FAMILY_ATTRIBUTE == traitName
1023: || SVGConstants.SVG_FONT_STYLE_ATTRIBUTE == traitName
1024: || SVGConstants.SVG_FONT_WEIGHT_ATTRIBUTE == traitName
1025: || SVGConstants.SVG_TEXT_ANCHOR_ATTRIBUTE == traitName) {
1026: return new StringTraitAnim(this , NULL_NS, traitName);
1027: } else {
1028: return super .createTraitAnimImpl(traitName);
1029: }
1030: }
1031:
1032: /**
1033: * Set the trait value as float.
1034: *
1035: * @param name the trait's name.
1036: * @param value the trait's value.
1037: *
1038: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1039: * trait is not supported on this element.
1040: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
1041: * trait's value cannot be specified as a float
1042: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
1043: * value is an invalid value for the given trait.
1044: */
1045: void setFloatArrayTrait(final String name, final float[][] value)
1046: throws DOMException {
1047: if (SVGConstants.SVG_FONT_SIZE_ATTRIBUTE == name) {
1048: checkPositive(name, value[0][0]);
1049: setFontSize(value[0][0]);
1050: } else {
1051: super .setFloatArrayTrait(name, value);
1052: }
1053: }
1054:
1055: /**
1056: * Validates the input trait value.
1057: *
1058: * @param traitName the name of the trait to be validated.
1059: * @param value the value to be validated
1060: * @param reqNamespaceURI the namespace of the element requesting
1061: * validation.
1062: * @param reqLocalName the local name of the element requesting validation.
1063: * @param reqTraitNamespace the namespace of the trait which has the values
1064: * value on the requesting element.
1065: * @param reqTraitName the name of the trait which has the values value on
1066: * the requesting element.
1067: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
1068: * value is incompatible with the given trait.
1069: */
1070: public float[][] validateFloatArrayTrait(final String traitName,
1071: final String value, final String reqNamespaceURI,
1072: final String reqLocalName, final String reqTraitNamespace,
1073: final String reqTraitName) throws DOMException {
1074: if (SVGConstants.SVG_FONT_SIZE_ATTRIBUTE == traitName) {
1075: return new float[][] { { parsePositiveFloatTrait(traitName,
1076: value) } };
1077: } else {
1078: return super .validateFloatArrayTrait(traitName, value,
1079: reqNamespaceURI, reqLocalName, reqTraitNamespace,
1080: reqTraitName);
1081: }
1082: }
1083:
1084: /**
1085: * Validates the input trait value.
1086: *
1087: * @param namespaceURI the trait's namespace URI.
1088: * @param traitName the name of the trait to be validated.
1089: * @param value the value to be validated
1090: * @param reqNamespaceURI the namespace of the element requesting
1091: * validation.
1092: * @param reqLocalName the local name of the element requesting validation.
1093: * @param reqTraitNamespace the namespace of the trait which has the values
1094: * value on the requesting element.
1095: * @param reqTraitName the name of the trait which has the values value on
1096: * the requesting element.
1097: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
1098: * value is incompatible with the given trait.
1099: */
1100: String validateTraitNS(final String namespaceURI,
1101: final String traitName, final String value,
1102: final String reqNamespaceURI, final String reqLocalName,
1103: final String reqTraitNamespace, final String reqTraitName)
1104: throws DOMException {
1105: if (namespaceURI != null && namespaceURI != NULL_NS) {
1106: return super .validateTraitNS(namespaceURI, traitName,
1107: value, reqNamespaceURI, reqLocalName,
1108: reqTraitNamespace, reqTraitName);
1109: }
1110:
1111: if (SVGConstants.SVG_FONT_SIZE_ATTRIBUTE == traitName) {
1112: throw unsupportedTraitType(traitName, TRAIT_TYPE_FLOAT);
1113: }
1114:
1115: if (SVGConstants.SVG_FONT_FAMILY_ATTRIBUTE == traitName) {
1116: if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) {
1117: return toStringTraitQuote((String[]) getInheritedPropertyState(PROPERTY_FONT_FAMILY));
1118: }
1119:
1120: return value;
1121: } else if (SVGConstants.SVG_FONT_STYLE_ATTRIBUTE == traitName) {
1122: if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) {
1123: return fontStyleToStringTrait(getInheritedPackedPropertyState(PROPERTY_FONT_STYLE));
1124: } else if (!SVGConstants.CSS_NORMAL_VALUE.equals(value)
1125: && !SVGConstants.CSS_ITALIC_VALUE.equals(value)
1126: && !SVGConstants.CSS_OBLIQUE_VALUE.equals(value)) {
1127: throw illegalTraitValue(traitName, value);
1128: }
1129:
1130: return value;
1131: } else if (SVGConstants.SVG_FONT_WEIGHT_ATTRIBUTE == traitName) {
1132: if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) {
1133: return fontWeightToStringTrait(getInheritedPackedPropertyState(PROPERTY_FONT_WEIGHT));
1134: } else if (SVGConstants.CSS_NORMAL_VALUE.equals(value)) {
1135: return SVGConstants.CSS_400_VALUE;
1136: } else if (SVGConstants.CSS_BOLD_VALUE.equals(value)) {
1137: return SVGConstants.CSS_700_VALUE;
1138: } else if (SVGConstants.CSS_BOLDER_VALUE.equals(value)) {
1139: // We need to base on the parent's animated value.
1140: int packedFontWeight = getInheritedPackedPropertyState(PROPERTY_FONT_WEIGHT);
1141: int fontWeight = computeFontWeight(packedFontWeight,
1142: FONT_WEIGHT_BOLDER);
1143: return fontWeightToStringTrait(fontWeight);
1144: } else if (SVGConstants.CSS_LIGHTER_VALUE.equals(value)) {
1145: // We need to base on the parent's animated value.
1146: int packedFontWeight = getInheritedPackedPropertyState(PROPERTY_FONT_WEIGHT);
1147: int fontWeight = computeFontWeight(packedFontWeight,
1148: FONT_WEIGHT_LIGHTER);
1149: return fontWeightToStringTrait(fontWeight);
1150: } else if (!SVGConstants.CSS_100_VALUE.equals(value)
1151: && !SVGConstants.CSS_200_VALUE.equals(value)
1152: && !SVGConstants.CSS_300_VALUE.equals(value)
1153: && !SVGConstants.CSS_400_VALUE.equals(value)
1154: && !SVGConstants.CSS_NORMAL_VALUE.equals(value)
1155: && !SVGConstants.CSS_500_VALUE.equals(value)
1156: && !SVGConstants.CSS_600_VALUE.equals(value)
1157: && !SVGConstants.CSS_700_VALUE.equals(value)
1158: && !SVGConstants.CSS_800_VALUE.equals(value)
1159: && !SVGConstants.CSS_900_VALUE.equals(value)) {
1160: throw illegalTraitValue(traitName, value);
1161: }
1162: return value;
1163: } else if (SVGConstants.SVG_TEXT_ANCHOR_ATTRIBUTE == traitName) {
1164: if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) {
1165: return textAnchorToStringTrait(getInheritedPackedPropertyState(PROPERTY_TEXT_ANCHOR));
1166: }
1167: if (!SVGConstants.CSS_START_VALUE.equals(value)
1168: && !SVGConstants.CSS_MIDDLE_VALUE.equals(value)
1169: && !SVGConstants.CSS_END_VALUE.equals(value)) {
1170: throw illegalTraitValue(traitName, value);
1171: }
1172: return value;
1173: }
1174:
1175: return super .validateTraitNS(namespaceURI, traitName, value,
1176: reqNamespaceURI, reqLocalName, reqTraitNamespace,
1177: reqTraitName);
1178: }
1179:
1180: /**
1181: * Supported traits: font-family, font-size, font-style, font-weight,
1182: * text-anchor.
1183: *
1184: * Supported traits: stroke-width, stroke-miterlimit, stroke-dashoffset,
1185: * fill-rule, stroke-linejoin, stroke-linecap, display, visibility,
1186: * color, fill, stroke, fill-opacity, stroke-opacity, stroke-dasharray
1187: *
1188: * @param name the trait name (e.g., "stroke-width")
1189: * @param value the trait's string value (e.g, "3")
1190: *
1191: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1192: * trait is not supported on this element or null.
1193: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
1194: * trait's value cannot be specified as a String
1195: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
1196: * value is an invalid value for the given trait or null.
1197: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
1198: * attempt is made to change readonly trait.
1199: */
1200: public void setTraitImpl(final String name, final String value)
1201: throws DOMException {
1202: if (SVGConstants.SVG_FONT_FAMILY_ATTRIBUTE == name) {
1203:
1204: // ======================= font-family ====================== //
1205:
1206: if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) {
1207: setInherited(PROPERTY_FONT_FAMILY, true);
1208: } else {
1209: setFontFamily(parseFontFamilyTrait(name, value));
1210: }
1211: } else if (SVGConstants.SVG_FONT_SIZE_ATTRIBUTE == name) {
1212:
1213: // ======================= font-size ======================== //
1214:
1215: if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) {
1216: setFloatInherited(PROPERTY_FONT_SIZE, true);
1217: } else {
1218: setFontSize(parsePositiveFloatTrait(name, value));
1219: }
1220: } else if (SVGConstants.SVG_FONT_STYLE_ATTRIBUTE == name) {
1221:
1222: // ======================= font-style ======================= //
1223:
1224: if (SVGConstants.CSS_NORMAL_VALUE.equals(value)) {
1225: setFontStyle(TextProperties.FONT_STYLE_NORMAL);
1226: } else if (SVGConstants.CSS_ITALIC_VALUE.equals(value)) {
1227: setFontStyle(TextProperties.FONT_STYLE_ITALIC);
1228: } else if (SVGConstants.CSS_OBLIQUE_VALUE.equals(value)) {
1229: setFontStyle(TextProperties.FONT_STYLE_OBLIQUE);
1230: } else if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) {
1231: setPackedInherited(PROPERTY_FONT_STYLE, true);
1232: } else {
1233: throw illegalTraitValue(name, value);
1234: }
1235:
1236: } else if (SVGConstants.SVG_FONT_WEIGHT_ATTRIBUTE == name) {
1237:
1238: // ======================= font-weight ======================= //
1239:
1240: if (SVGConstants.CSS_100_VALUE.equals(value)) {
1241: setFontWeight(TextNode.FONT_WEIGHT_100);
1242: } else if (SVGConstants.CSS_200_VALUE.equals(value)) {
1243: setFontWeight(TextNode.FONT_WEIGHT_200);
1244: } else if (SVGConstants.CSS_300_VALUE.equals(value)) {
1245: setFontWeight(TextNode.FONT_WEIGHT_300);
1246: } else if (SVGConstants.CSS_400_VALUE.equals(value)) {
1247: setFontWeight(TextNode.FONT_WEIGHT_400);
1248: } else if (SVGConstants.CSS_NORMAL_VALUE.equals(value)) {
1249: setFontWeight(TextNode.FONT_WEIGHT_NORMAL);
1250: } else if (SVGConstants.CSS_500_VALUE.equals(value)) {
1251: setFontWeight(TextNode.FONT_WEIGHT_500);
1252: } else if (SVGConstants.CSS_600_VALUE.equals(value)) {
1253: setFontWeight(TextNode.FONT_WEIGHT_600);
1254: } else if (SVGConstants.CSS_700_VALUE.equals(value)) {
1255: setFontWeight(TextNode.FONT_WEIGHT_700);
1256: } else if (SVGConstants.CSS_BOLD_VALUE.equals(value)) {
1257: setFontWeight(TextNode.FONT_WEIGHT_BOLD);
1258: } else if (SVGConstants.CSS_800_VALUE.equals(value)) {
1259: setFontWeight(TextNode.FONT_WEIGHT_800);
1260: } else if (SVGConstants.CSS_900_VALUE.equals(value)) {
1261: setFontWeight(TextNode.FONT_WEIGHT_900);
1262: } else if (SVGConstants.CSS_BOLDER_VALUE.equals(value)) {
1263: setFontWeight(TextNode.FONT_WEIGHT_BOLDER);
1264: } else if (SVGConstants.CSS_LIGHTER_VALUE.equals(value)) {
1265: setFontWeight(TextNode.FONT_WEIGHT_LIGHTER);
1266: } else if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) {
1267: setPackedInherited(PROPERTY_FONT_WEIGHT, true);
1268: clearMarker(FONT_WEIGHT_BOLDER_MARKER);
1269: clearMarker(FONT_WEIGHT_LIGHTER_MARKER);
1270: } else {
1271: throw illegalTraitValue(name, value);
1272: }
1273: } else if (SVGConstants.SVG_TEXT_ANCHOR_ATTRIBUTE == name) {
1274:
1275: // ======================= text-anchor ====================== //
1276:
1277: if (SVGConstants.CSS_START_VALUE.equals(value)) {
1278: setTextAnchor(TextProperties.TEXT_ANCHOR_START);
1279: } else if (SVGConstants.CSS_MIDDLE_VALUE.equals(value)) {
1280: setTextAnchor(TextProperties.TEXT_ANCHOR_MIDDLE);
1281: } else if (SVGConstants.CSS_END_VALUE.equals(value)) {
1282: setTextAnchor(TextProperties.TEXT_ANCHOR_END);
1283: } else if (SVGConstants.CSS_INHERIT_VALUE.equals(value)) {
1284: setPackedInherited(PROPERTY_TEXT_ANCHOR, true);
1285: } else {
1286: throw illegalTraitValue(name, value);
1287: }
1288: } else {
1289: super .setTraitImpl(name, value);
1290: }
1291: }
1292:
1293: /**
1294: * @param name the name of the trait to convert.
1295: * @param value the float trait value to convert.
1296: */
1297: String toStringTrait(final String name, final float[][] value) {
1298: if (SVGConstants.SVG_FONT_SIZE_ATTRIBUTE == name) {
1299: return Float.toString(value[0][0]);
1300: } else {
1301: return super .toStringTrait(name, value);
1302: }
1303: }
1304:
1305: /**
1306: * Set the trait value as float.
1307: * Supported float traits: font-size.
1308: *
1309: * @param name the trait name (e.g, "font-size")
1310: * @param value the trait value (e.g, 10f)
1311: *
1312: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
1313: * trait is not supported on this element.
1314: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
1315: * trait's value cannot be specified as a float
1316: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
1317: * value is an invalid value for the given trait.
1318: * @throws SecurityException if the application does not have the necessary
1319: * privilege rights to access this (SVG) content.
1320: */
1321: public void setFloatTraitImpl(final String name, final float value)
1322: throws DOMException {
1323: if (SVGConstants.SVG_FONT_SIZE_ATTRIBUTE == name) {
1324: checkPositive(name, value);
1325: setFontSize(value);
1326: } else {
1327: super.setFloatTraitImpl(name, value);
1328: }
1329: }
1330:
1331: }
|