FileDocCategorySizeDatePackage
Text.javaAPI DocphoneME MR2 API (J2ME)51476Wed May 02 18:00:34 BST 2007com.sun.perseus.model

Text

public class Text extends Group
Models text content. In Perseus, text nodes are described by their content (a character string), a number of font properties which guide which Font is selected to render the text and a text property (text-anchor) which defines how the text is positioned about its anchor point.
Text nodes lazily (i.e., on paint request) evaluate which font they use to render their content. At that time, the characters in the Text content is matched with the glyphs that available Fonts can display. This generates a set of children GlyphProxy nodes which are then laid-out using the text property and the font metrics.
version
$Id: Text.java,v 1.18 2006/06/29 10:47:35 ln156897 Exp $

Fields Summary
protected String
content
The text to be displayed
protected float[]
x
The origin of the text string on the x axis.
protected float[]
y
The origin of the text string on the y axis.
protected float[]
rotate
Per-glyph rotation
protected GlyphLayout
firstChunk
Points to the first text chunk.
protected GlyphLayout
lastChunk
Points to the last text chunk.
protected RenderingManager
renderingManager
Used to track the node's rendering area and the rendered areas.
protected float[]
helperDashArray
Used to scale dash array values.
Constructors Summary
public Text(DocumentNode ownerDocument)
Constructor.

param
ownerDocument this element's owner DocumentNode


                
        
        super(ownerDocument);

        if (DirtyAreaManager.ON) {
            renderingManager = new RenderingManager(this);
        }

    
Methods Summary
com.sun.perseus.j2d.BoxaddNodeBBox(com.sun.perseus.j2d.Box bbox, com.sun.perseus.j2d.Transform t)

param
bbox the bounding box to which this node's bounding box should be appended. That bounding box is in the target coordinate space. It may be null, in which case this node should create a new one.
param
t the transform from the node coordinate system to the coordinate system into which the bounds should be computed.
return
the bounding box of this node, in the target coordinate space,

        checkLayout();
        return addNodeBBox(bbox, t, firstChunk);
    
com.sun.perseus.j2d.BoxaddNodeBBox(com.sun.perseus.j2d.Box bbox, com.sun.perseus.j2d.Transform t, GlyphLayout fc)

param
bbox the bounding box to which this node's bounding box should be appended. That bounding box is in the target coordinate space. It may be null, in which case this node should create a new one.
param
t the transform from the node coordinate system to the coordinate system into which the bounds should be computed.
param
fc the GlyphLayout first chunk, so that the method can be used by TextProxy
return
the bounding box of this node, in the target coordinate space,

        GlyphLayout c = fc;
        while (c != null) {
            ownerDocument.bboxChunkTxf.setTransform(t);
            c.applyTransform(this, ownerDocument.bboxChunkTxf);
            bbox = c.addBBox(bbox, ownerDocument.bboxChunkTxf);
            c = c.nextSibling;
        }
        return bbox;
    
public voidappendTextChild(java.lang.String text)

param
text the text to append to this node's content. If text is null or empty, this does nothing.

        if (text == null || text.length() == 0) {
            return;
        }

        if (content == null) {
            setContent(text);
        } else {
            setContent(content + text);
        }
    
protected intapplyXMLSpace(char[] s)
Applies the xml:space policy

param
s the array of characters which should be processed
return
the index of the last (inclusive) relevant character after processing.

        switch (getXMLSpace()) {
        case XML_SPACE_DEFAULT:
        case XML_SPACE_INHERIT:
            return applyXMLSpaceDefault(s);
        default:
            return applyXMLSpacePreserve(s);
        }

    
protected intapplyXMLSpaceDefault(char[] s)
Applies the xml:space="default" policy ** SPECIFICATION TEXT, SECTION 10.15 ** When xml:space="default", the SVG user agent will do the following using a copy of the original character data content. First, it will remove all newline characters. Then it will convert all tab characters into space characters. Then, it will strip off all leading and trailing space characters. Then, all contiguous space characters will be consolidated

param
s the array of characters which should be processed
return
the index of the last (exclusive) relevant character after processing.

        int j = 0;

        // Remove newline characters and 
        // convert tabs to white spaces. 
        // Output to s.
        int i = 0;
        for (; i < s.length; i++) {
            if (s[i] != '\n") {
                if (s[i] == '\t") {
                    s[i] = ' ";
                }
                s[j++] = s[i];
            }
        }

        int length = j;

        // Now, consolidate white spaces

        // Trim leading spaces
        for (i = 0; i < length; i++) {
            if (s[i] != ' ") {
                break;
            }
        }

        // Consolidate spaces
        j = 0;
        s[j++] = s[i++];
        for (; i < length; i++) {
            // Keep all non-space characters
            if (s[i] != ' ") {
                s[j++] = s[i];
            } else {
                // Only keep space character if
                // previous character is not a ' '
                if (s[j - 1] != ' ") {
                    s[j++] = ' ";
                }
            }
        }

        // Trim trailing space
        length = j;
        if (s[j - 1] == ' ") {
            length = j - 1;
        }

        return length;
    
protected intapplyXMLSpacePreserve(char[] s)
Applies the xml:space="preserve" policy ** SPECIFICATION TEXT, SECTION 10.15 ** When xml:space="preserve", the SVG user agent will do the following using a copy of the original character data content. It will convert all newline and tab characters into space characters. Then, it will draw all space characters, including leading, trailing and multiple contiguous space characters. Thus, when drawn with xml:space="preserve", the string "a b" (three spaces between "a" and "b") will produce a larger separation between "a" and "b" than "a b" (one space between "a" and "b").

param
s the array of characters which should be processed
return
the index of the last (exclusive) relevant character after processing.

        for (int i = 0; i < s.length; i++) {
            if (s[i] == '\n" || s[i] == '\t") {
                s[i] = ' ";
            }
        }

        return s.length;
    
ElementNodeProxybuildProxy()

return
an adequate ElementNodeProxy for this node.

        return new TextProxy(this);
    
voidcheckLayout()
Checks that the text's layout has been computed and computes it in case it was not.

        if (firstChunk == null) {
            firstChunk = layoutText(this);
            GlyphLayout cur = firstChunk;
            while (cur.nextSibling != null) {
                cur = cur.nextSibling;
            }
            lastChunk = (GlyphLayout) cur;
        }
    
protected voidclearLastRenderedTile()
After calling this method, getLastRenderedTile should always return null.

        renderingManager.clearLastRenderedTile();
    
public voidclearLayouts()
Clears all cached layout information. Because the computed transform property on text depends on the layout, clearLayouts on Text also clears the transform and property cache.

        clearLayouts(true);
    
protected voidclearLayouts(boolean notif)
Implementations. Clears layouts but does not generate a modification notification.

param
notif if true, then notifications are issued (i.e., calls to modifyingNode and modifiedNode).

        if (notif) {
            modifyingNode();
        }

        clearLayoutsQuiet();

        if (notif) {
            modifiedNode();
        }
    
protected voidclearLayoutsQuiet()
Clears all cached layout information but does not generate modification events for this node.

        firstChunk = null;
        lastChunk = null;

        //
        // Now, clear the proxies layouts
        //
        ElementNodeProxy p = firstProxy;
        while (p != null) {
            ((TextProxy) p).clearLayoutsQuiet();
            p = p.nextProxy;
        }

    
protected voidcomputeRenderingTile(com.sun.perseus.j2d.Tile tile)
This method is overridden for elements which has special renderings, such as the ShapeNodes.

param
tile the Tile instance whose bounds should be set.

        checkLayout();
        computeRenderingTile(tile, txf, this, firstChunk);
    
protected final voidcomputeRenderingTile(com.sun.perseus.j2d.Tile tile, com.sun.perseus.j2d.Transform t, com.sun.perseus.j2d.TextRenderingProperties trp, GlyphLayout fc)
The rendering tile of a Text node is the union of the rendering tile of its layouts.

param
tile the Tile instance whose bounds should be set.
param
t the Transform to the requested tile space, from this node's user
param
trp the TextRenderinProperties describing the nodes rendering characteristics. space.
param
fc the first GlyphLayout chunk.

        GlyphLayout gl = fc;
        Tile glt = null;
        while (gl != null) {
            ownerDocument.bboxChunkTxf.setTransform(t);
            gl.applyTransform(trp, ownerDocument.bboxChunkTxf);
            glt = gl.addRenderingTile(glt, trp, ownerDocument.bboxChunkTxf);
            gl = (GlyphLayout) gl.nextSibling;
        }

        if (glt != null) {
            tile.setTile(glt);
        } else {
            tile.setEmptyTile();
        }
    
TraitAnimcreateTraitAnimImpl(java.lang.String traitName)

param
traitName the trait name.

        if (SVGConstants.SVG_X_ATTRIBUTE == traitName
            ||
            SVGConstants.SVG_Y_ATTRIBUTE == traitName
            ||
            SVGConstants.SVG_ROTATE_ATTRIBUTE == traitName) {
            return new FloatTraitAnim(this, traitName, TRAIT_TYPE_FLOAT);
        } else if (SVGConstants.SVG_TEXT_PSEUDO_ATTRIBUTE == traitName) {
            return new StringTraitAnim(this, NULL_NS, traitName);
        } else {
            return super.createTraitAnimImpl(traitName);
        }
    
voiddrawText(com.sun.perseus.j2d.RenderGraphics rg, com.sun.perseus.j2d.Transform tx, GlyphLayout fc)
Draws text.

param
rg the RenderGraphics where the node should paint itself.
param
tx the rendering transform.
param
fc the first chunk to render.

        GlyphLayout c = fc;
        while (c != null) {
            ownerDocument.paintChunkTxf.setTransform(tx);
            c.applyTransform(rg, ownerDocument.paintChunkTxf);
            c.drawText(rg, ownerDocument.paintChunkTxf);
            c = c.nextSibling;
        }
    
voidfillText(com.sun.perseus.j2d.RenderGraphics rg, com.sun.perseus.j2d.Transform tx, GlyphLayout fc)
Fills text.

param
rg the RenderGraphics where the node should paint itself.
param
tx the rendering transform.
param
fc the first chunk to render.

        GlyphLayout c = fc;
        while (c != null) {
            ownerDocument.paintChunkTxf.setTransform(tx);
            c.applyTransform(rg, ownerDocument.paintChunkTxf);
            c.fillText(rg, ownerDocument.paintChunkTxf);
            c = c.nextSibling;
        }
    
public org.w3c.dom.svg.SVGRectgetBBox()

return
the tight bounding box in current user coordinate space.

        return addNodeBBox(null, null);
    
public java.lang.StringgetContent()

return
this node's text content as a string

        return content;
    
floatgetFloatTraitImpl(java.lang.String name)
Text handles x, y float traits.

param
name the trait name (e.g., "y")
return
the trait's float value (e.g., 10f)
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.

        if (SVGConstants.SVG_X_ATTRIBUTE == name) {
            return getX()[0];
        } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
            return getY()[0];
        } else {
            return super.getFloatTraitImpl(name);
        }
    
protected com.sun.perseus.j2d.TilegetLastRenderedTile()

return
the tile which encompasses the node's last actual rendering. If this node's hasRendering method returns false, then this method should return null. By default, this method returns null because hasNodeRendering returns false by default.

        return renderingManager.getLastRenderedTile();
    
public java.lang.StringgetLocalName()

return
the SVGConstants.SVG_TEXT_TAG value

        return SVGConstants.SVG_TEXT_TAG;
    
public booleangetPaintNeedsLoad()

return
true always, as a text node needs its textual content which is not fully loaded until the element has been loaded.

        return true;
    
protected com.sun.perseus.j2d.TilegetRenderingTile()

return
the bounding box, in screen coordinate, which encompasses the node's rendering.

        return renderingManager.getRenderingTile();
    
public float[]getRotate()

return
this text's set of rotation values for its glyphs.

        return rotate;
    
public org.w3c.dom.svg.SVGRectgetScreenBBox()

return
the tight bounding box in screen coordinate space.

        // There is no screen bounding box if the element is not hooked
        // into the main tree.
        if (!inDocumentTree()) {
            return null;
        }
        
        return addNodeBBox(null, txf);
    
public java.lang.StringgetTraitImpl(java.lang.String name)
Text handles x, y, and #text traits.

param
name the requested trait's name (e.g., "#text")
return
the requested trait's string value (e.g., "Hello SVG Text")
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).

        if (SVGConstants.SVG_X_ATTRIBUTE == name) {
            return toStringTrait(getX());
        } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
            return toStringTrait(getY());
        } else if (SVGConstants.SVG_ROTATE_ATTRIBUTE == name) {
            if (rotate == null) {
                return "";
            }

            /*
            float[] rt = new float[rotate.length];
            for (int i = 0; i < rt.length; i++) {
                rt[i] = MathSupport.toDegrees(rotate[i]);
            }
            */

            System.err.println(">>>>>>>>>>>>>>>>>> getTraitImpl(" 
                               + name + ") : '"
                               + toStringTrait(rotate) + "'");
            return toStringTrait(rotate);
        } else if (SVGConstants.SVG_TEXT_PSEUDO_ATTRIBUTE == name) {
            if (content == null) {
                return "";
            }
            return getContent();
        } else {
            return super.getTraitImpl(name);
        }
    
public float[]getX()

return
this text's x-axis author position

        return x;
    
public float[]getY()

return
this text's y-axis anchor position

        return y;
    
public booleanhasDescendants()

return
true if the content string is not null and not empty or if this node has children. false otherwise.

        return super.hasDescendants() 
            || 
            content != null && !("".equals(content));
    
public booleanhasNodeRendering()
An Text has something to render

return
true

        return true;
    
protected booleanisHitVP(float[] pt, com.sun.perseus.j2d.TextRenderingProperties trp, com.sun.perseus.j2d.Transform itx, GlyphLayout lc)
Returns true if this node is hit by the input point. The input point is in viewport space. By default, a node is not hit, not matter what the input coordinate is.

param
pt the x/y coordinate. Should never be null and be of size two. If not, the behavior is unspecified. The x/y coordinate is in the node's user space.
param
trp the text rendering properties that apply to the layout rendering.
param
itx the transform from viewport space to the text's user space.
param
lc the GlyphLayout 'lastChunk' so that the method can be used by Text and TextProxy.
return
true if the node is hit by the input point.
see
#nodeHitAt

        // Node has to be visible to be a hit target
        if (!trp.getVisibility()) {
            return false;
        }

        GlyphLayout c = lc;

        while (c != null) {
            // Initialize hitChunkTransform to be from viewport space to the
            // chunk's user space. This is why we apply the inverse transform
            // second and why we invoke applyInverseTransform on the GlyphLayout
            // instance.
            ownerDocument.hitChunkTxf.setTransform(1, 0, 0, 1, 0, 0);
            c.applyInverseTransform(trp, ownerDocument.hitChunkTxf);
            ownerDocument.hitChunkTxf.mMultiply(itx);
            if (c.isHitVP(pt, this, ownerDocument.hitChunkTxf)) {
                return true;
            }
            c = c.prevSibling;
        }

        return false;
    
public GlyphLayoutlayoutText(com.sun.perseus.j2d.TextProperties tp)
Invoked when text layout should be performed or checked.

param
tp text is laid out for the input TextProperties
return
an GlyphLayout instance containing the laid out text.

        // There is always at least one, possibly empty 
        // text chunk.
        GlyphLayout startChunk = new GlyphLayout(ownerDocument);
        GlyphLayout chunk = startChunk;
        chunk.x = x[0];
        chunk.y = y[0];

        // Stop now if there is not actual content
        if (content == null || "".equals(content)) {
            return startChunk;
        }

        // Take care of white space handling
        char[] s = content.toCharArray();
        int length = applyXMLSpace(s);

        // First, build the list of font faces which match the font properties
        // for this text node.  FontFace resolution is done through the root
        // node element which holds the FontFace data base.
        FontFace.Match defaultMatch = ownerDocument.resolveFontFaces(tp);
        FontFace.Match firstMatch = defaultMatch.next;
        FontFace.Match curMatch = null;

        Glyph missingGlyph = defaultMatch.fontFace.getMissingGlyph();

        // Now, for each character in the content string, find a matching
        // font. The fontFace that matches can match up to n characters.
        int cur    = 0;  // Current index in character array 's'
        Glyph glyph = null;
        GlyphProxy proxy = null, prevProxy = null;
        float curAdv = 0;
        float fontSize = tp.getFontSize();

        while (cur < length) {
            // =================================================================
            // Check if we need to create a new text chunk

            if (cur > 0 && (cur < x.length || cur < y.length)) {
                // Create a new chunk. The current chunk becomes the
                // previous chunk.
                GlyphLayout prevChunk = chunk;
                chunk = new GlyphLayout(ownerDocument);
                prevProxy = null;

                // We have finished computing the advance of
                // the now previous chunk
                prevChunk.advance = curAdv;
                curAdv = 0;

                if (cur < x.length) {
                    chunk.x = x[cur];
                } else {
                    chunk.x = prevChunk.x + fontSize * prevChunk.advance;
                }

                if (cur < y.length) {
                    chunk.y = y[cur];
                } else {
                    chunk.y = prevChunk.y;
                }

                // Chain the new chunk with the previous one
                prevChunk.nextSibling = chunk;
                chunk.prevSibling = prevChunk;

            }

            // =================================================================
            // Find a matching glyph or default to the missing glyph.

            glyph = null;
            curMatch = firstMatch;
            while (curMatch != null) {
                if ((glyph = curMatch.fontFace.canDisplay(s, cur)) 
                    != 
                    null) {
                    break;
                }
                curMatch = curMatch.next;
            }

            if (glyph == null) {
                if ((glyph = defaultMatch.fontFace.canDisplay(s, cur)) 
                    == 
                    null) {
                    glyph = missingGlyph;
                }
            }

            // Create a proxy for the glyph
            proxy = new GlyphProxy(glyph);

            // =================================================================
            // Add the proxy to the current text chunk
            chunk.add(proxy);

            // Account for kerning, only if the previous glyph is part of 
            // the same text chunk.
            if (prevProxy != null) {
                float adjust = 
                    ((Font) proxy.proxied.parent)
                    .getHKern(prevProxy.proxied,
                              proxy.proxied);
                curAdv -= adjust;
            }

            proxy.setX(curAdv);

            if (rotate != null && cur < rotate.length) {
                // The rotation is in the text coordinate system
                proxy.setRotate(rotate[cur]);
            }

            cur += glyph.getLength();

            // Increment the advance *in the text coordinate system*.
            //
            // IMPORTANT NOTE: it is very important to use the 
            // glyph's advance in the text coordinate space. It
            // is not possible to work in the em square coordinate
            // space for the advance because the em square may be 
            // different for each glyph in the text string (when 
            // different fonts are used).
            curAdv += glyph.getTextHorizontalAdvanceX();
            
            prevProxy = proxy;
        }

        chunk.advance = curAdv;

        return startChunk;
    
public ElementNodenewInstance(DocumentNode doc)
Used by DocumentNode to create a new instance from a prototype Text.

param
doc the DocumentNode for which a new node is should be created.
return
a new Text for the requested document.

        return new Text(doc);
    
public ModelNodenodeHitAt(float[] pt)
Returns the ModelNode, if any, hit by the point at coordinate x/y.

param
pt the x/y coordinate. Should never be null and be of size two. If not, the behavior is unspecified. The coordinates are in viewport space.
return
the ModelNode hit at the given point or null if none was hit.

        // If a node does not render, it is never hit
        if (canRenderState != 0) {
            return null;
        }
        
        checkLayout();

        if (isHitVP(pt, this, getInverseTransformState(), lastChunk)) {
            return this;
        }

        return null;
    
voidnodeHookedInDocumentTree()
To be overriddent by derived classes, such as TimedElementNode, if they need to perform special operations when hooked into the document tree.

        super.nodeHookedInDocumentTree();
        renderingDirty();
    
protected voidnodeRendered()
Simply notifies the RenderingManager.

        if (DirtyAreaManager.ON) {
            renderingManager.rendered();
        }
    
voidnodeUnhookedFromDocumentTree()
To be overriddent by derived classes, such as TimedElementNode, if they need to perform special operations when unhooked from the document tree.

        super.nodeUnhookedFromDocumentTree();
        renderingDirty();
    
public voidpaint(com.sun.perseus.j2d.RenderGraphics rg)
Paints this node into the input RenderGraphics. A Text node renders its associated GlyphLayout children.

param
rg the RenderGraphics where the node should paint itself

        if (canRenderState != 0) {
            return;
        }

        checkLayout();

        if (DirtyAreaManager.ON) {
            Tile primitiveTile = getRenderingTile();
            if (primitiveTile == null 
                || 
                rg.getRenderingTile().isHit(primitiveTile)) {
                // rg.setPrimitiveTile(primitiveTile);
                paintRendered(rg, this, txf, firstChunk);

                // nodeRendered is called seperately from paintRendered
                // because paintRendered is used in different contexts,
                // for example by proxy nodes to render, using their
                // proxied node's paintRendered method.
                nodeRendered();
            }
        } else {
            paintRendered(rg, this, txf, firstChunk);
        }
    
public voidpaintRendered(com.sun.perseus.j2d.RenderGraphics rg, com.sun.perseus.j2d.TextRenderingProperties trc, com.sun.perseus.j2d.Transform tx, GlyphLayout fc)
Paints this node into the input RenderGraphics, assuming the node is rendered.

param
rg the RenderGraphics where the node should paint itself.
param
tc the TextRenderingProperties holding the properties tha should be used for rendering into the input RenderGraphics
param
tx the transform to use when rendering this node
param
fc the first chunk to render.
see
ElementNode#paint
see
ElementNode#paintRendered
see
ModelNode#canRender

        if (!trc.getVisibility()) {
            return;
        }
        rg.setPaintTarget(this);
        rg.setPaintTransform(tx);
        
        rg.setFontSize(trc.getFontSize());
        rg.setTextAnchor(trc.getTextAnchor());
        
        // Fill text. Only apply the fill properties
        if (trc.getFill() != null) {
            rg.setFillRule(trc.getFillRule());
            rg.setFill(trc.getFill());
            rg.setFillOpacity(trc.getFillOpacity());
            fillText(rg, tx, fc);
        }

        // Stroke text. Only apply the stroke properties
        if (trc.getStroke() != null) {
            // We divide the strokeWidth by the fontSize to account
            // for the additional scale factor (by fontSize). The
            // additional scale factor is applied when rendering
            // GlyphLayouts.
            // See #GlyphLayout.applyTransform
            rg.setStrokeWidth(trc.getStrokeWidth() / trc.getFontSize());

            // do the same for dashArray and dashOffset if necessary
            float[] dashArray = trc.getStrokeDashArray();
            float[] trDashArray = null;
            float trDashOffset = 0;
            if (dashArray != null) {
                float fontSize = trc.getFontSize();

                if ((helperDashArray == null) || 
                        (helperDashArray.length != dashArray.length)) {
                    helperDashArray = new float[dashArray.length];
                }
                trDashArray = helperDashArray;
                
                for (int i = 0; i < dashArray.length; ++i) {
                    trDashArray[i] = dashArray[i] / fontSize;
                }

                trDashOffset = trc.getStrokeDashOffset() / fontSize;
            }

            rg.setStrokeDashArray(trDashArray);
            rg.setStrokeDashOffset(trDashOffset);

            rg.setStroke(trc.getStroke());
            rg.setStrokeOpacity(trc.getStrokeOpacity());
            rg.setStrokeLineCap(trc.getStrokeLineCap());
            rg.setStrokeLineJoin(trc.getStrokeLineJoin());
            rg.setStrokeMiterLimit(trc.getStrokeMiterLimit());
            drawText(rg, tx, fc);
        }
    
protected voidpropagateFloatPropertyState(int propertyIndex, float parentPropertyValue)
Called when the computed value of the given float property has changed. As we do not render any text children, this does not propage changes any further.

param
propertyIndex index for the property whose value has changed.
param
parentPropertyValue the value that children of this node should now inherit.

        
        // Propagate to proxies.
        if (firstProxy != null) {
            ElementNodeProxy proxy = firstProxy;
            while (proxy != null) {
                ((CompositeGraphicsNodeProxy) proxy)
                        .proxiedFloatPropertyStateChange(propertyIndex, 
                                                         parentPropertyValue);
                proxy = proxy.nextProxy;
            }
        }
    
protected voidpropagatePackedPropertyState(int propertyIndex, int parentPropertyValue)
Called when the computed value of the given packed property has changed. As we do not render any text children, this does not propage changes any further.

param
propertyIndex index for the property whose value has changed.
param
parentPropertyValue the value that children of this node should now inherit.

        // Propagate to proxies.
        if (firstProxy != null) {
            ElementNodeProxy proxy = firstProxy;
            while (proxy != null) {
                ((CompositeGraphicsNodeProxy) proxy)
                        .proxiedPackedPropertyStateChange(propertyIndex, 
                                                          parentPropertyValue);
                proxy = proxy.nextProxy;
            }
        }
    
protected voidpropagatePropertyState(int propertyIndex, java.lang.Object parentPropertyValue)
Called when the computed value of the given property has changed. As we do not render any text children, this does not propage changes any further.

param
propertyIndex index for the property whose value has changed.
param
parentPropertyValue the value that children of this node should now inherit.

   
        // Propagate to proxies.
        if (firstProxy != null) {
            ElementNodeProxy proxy = firstProxy;
            while (proxy != null) {
                ((CompositeGraphicsNodeProxy) proxy).proxiedPropertyStateChange(
                        propertyIndex, parentPropertyValue);
                proxy = proxy.nextProxy;
            }
        }
    
ModelNodeproxyNodeHitAt(float[] pt, ElementNodeProxy proxy)
Returns the ModelNode, if any, hit by the point at coordinate x/y in the proxy tree starting at proxy.

param
pt the x/y coordinate. Should never be null and be of size two. If not, the behavior is unspecified. The coordinates are in viewport space.
param
proxy the root of the proxy tree to test.
return
the ModelNode hit at the given point or null if none was hit.

        // If a node does not render, it is never hit
        if (canRenderState != 0) {
            return null;
        }
        
        TextProxy tp = (TextProxy) proxy;
        tp.checkLayout();

        if (isHitVP(pt, tp, tp.inverseTxf, tp.lastChunk)) {
            return proxy;
        }

        return null;
    
protected voidrecomputeTransformState(com.sun.perseus.j2d.Transform parentTransform)
Recomputes the transform cache, if one exists.

param
parentTransform the Transform applied to this node's parent.

        txf = appendTransform(parentTransform, txf);
        computeCanRenderTransformBit(txf);
        inverseTxf = null;
        // inverseTxf = computeInverseTransform(txf, parentTransform, 
        //                                      inverseTxf);
        renderingDirty();
    
final voidrenderingDirty()
Should be called whenever this node's rendering becomes dirty.

        if (DirtyAreaManager.ON) {
            renderingManager.dirty();
        }
    
voidsetComputedDisplay(boolean newDisplay)

param
newDisplay the new computed display value

        super.setComputedDisplay(newDisplay);

        renderingDirty();
    
voidsetComputedFill(com.sun.perseus.j2d.PaintServer newFill)

param
newFill the new computed fill property.

        this.fill = newFill;
        renderingDirty();
    
voidsetComputedFillOpacity(float newFillOpacity)

param
newFillOpacity the new computed value for the fill opacity property.

                
        super.setComputedFillOpacity(newFillOpacity);
        
        if (fill != null) {
            renderingDirty();
        }
    
voidsetComputedFontFamily(java.lang.String[] newFontFamily)

param
newFontFamily the new computed font-family property value.

        this.fontFamily = newFontFamily;

        clearLayoutsQuiet();

        if (stroke != null || fill != null) {
            renderingDirty();
        }
    
voidsetComputedFontSize(float newFontSize)

param
newFontSize the new computed font-size property value.

        this.fontSize = newFontSize;
        
        if (stroke != null || fill != null) {
            renderingDirty();
        }

        computeCanRenderFontSizeBit(newFontSize);
    
voidsetComputedFontStyle(int newFontStyle)

param
newFontStyle the new computed font-style property.

        super.setComputedFontStyle(newFontStyle);

        clearLayoutsQuiet();

        if (stroke != null || fill != null) {
            renderingDirty();
        }
    
voidsetComputedFontWeight(int newFontWeight)

param
newFontWeight new computed value for the font-weight property.

        super.setComputedFontWeight(newFontWeight);

        clearLayoutsQuiet();

        if (stroke != null || fill != null) {
            renderingDirty();
        }
    
voidsetComputedStroke(com.sun.perseus.j2d.PaintServer newStroke)

param
newStroke the new computed stroke property.

        this.stroke = newStroke;
        renderingDirty();
    
voidsetComputedStrokeDashArray(float[] newStrokeDashArray)

param
newStrokeDashArray the new computed stroke-dasharray property value.

        strokeDashArray = newStrokeDashArray;

        if (stroke != null) {
            renderingDirty();
        }
    
voidsetComputedStrokeDashOffset(float newStrokeDashOffset)

param
newStrokeDashOffset the new stroke-dashoffset computed property value.

        strokeDashOffset = newStrokeDashOffset;

        if (stroke != null && strokeDashArray != null) {
            renderingDirty();
        }
    
voidsetComputedStrokeLineCap(int newStrokeLineCap)

param
newStrokeLineCap the new value for the stroke-linecap property.

        super.setComputedStrokeLineCap(newStrokeLineCap);

        if (stroke != null) {
            renderingDirty();
        }
    
voidsetComputedStrokeLineJoin(int newStrokeLineJoin)

param
newStrokeLineJoin the new computed value for stroke-line-join

        super.setComputedStrokeLineJoin(newStrokeLineJoin);

        if (stroke != null) {
            renderingDirty();
        }
    
voidsetComputedStrokeMiterLimit(float newStrokeMiterLimit)

param
newStrokeMiterLimit the new computed stroke-miterlimit property.

        strokeMiterLimit = newStrokeMiterLimit; 

        if (stroke != null && getStrokeLineJoin() == JOIN_MITER) {
            renderingDirty();
        }
    
voidsetComputedStrokeOpacity(float newStrokeOpacity)

param
newStrokeOpacity the new computed stroke-opacity property.

        super.setComputedStrokeOpacity(newStrokeOpacity);
        
        if (stroke != null) {
            renderingDirty();
        }
    
voidsetComputedStrokeWidth(float newStrokeWidth)

param
newStrokeWidth the new computed stroke-width property value.

        strokeWidth = newStrokeWidth;

        // Only dirty rendering if the object is actually stroked.
        if (stroke != null) {
            renderingDirty();
        }
    
voidsetComputedTextAnchor(int newTextAnchor)
Sets the value of the computed text anchor property.

param
newTextAnchor the new value for the computed text anchor property.

        super.setComputedTextAnchor(newTextAnchor);

        if (stroke != null || fill != null) {            
            renderingDirty();
        }
    
voidsetComputedVisibility(boolean newVisibility)

param
newVisibility the new computed visibility property.

        super.setComputedVisibility(newVisibility);

        renderingDirty();
    
public voidsetContent(java.lang.String newContent)

param
newContent this node's new content string

        if (equal(newContent, content)) {
            return;
        }
        modifyingNode();
        this.content = newContent;
        clearLayouts(false);
        modifiedNode();
    
voidsetFloatArrayTrait(java.lang.String name, float[][] value)
Set the trait value as float.

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.

        if (SVGConstants.SVG_X_ATTRIBUTE == name) {
            setX(toTraitFloatArray(value));
        } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
            setY(toTraitFloatArray(value));
        } else if (SVGConstants.SVG_ROTATE_ATTRIBUTE == name) {
            setRotate(toTraitFloatArray(value));
        } else {
            super.setFloatArrayTrait(name, value);
        }
    
public voidsetFloatTraitImpl(java.lang.String name, float value)
Text handles x, y float traits.

param
name the trait's name (e.g., "x")
param
value the trait's value (e.g, 10f)
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.

        if (SVGConstants.SVG_X_ATTRIBUTE == name) {
            setX(new float[] {value});
        } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
            setY(new float[] {value});
        } else {
            super.setFloatTraitImpl(name, value);
        }
    
public voidsetRotate(float[] newRotate)

param
newRotate this text's new per-glyph rotation

        if (equal(newRotate, rotate)) {
            return;
        }
        modifyingNode();
        this.rotate = newRotate;
        clearLayoutsQuiet();
        modifiedNode();
    
public voidsetTraitImpl(java.lang.String name, java.lang.String value)
Text handles x, y and #text traits.

param
name the trait's name (e.g., "#text")
param
value the trait's value (e.g, "Hello SVG Text")
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.

        if (SVGConstants.SVG_X_ATTRIBUTE == name) {
            setX(parseFloatArrayTrait(name, value));
        } else if (SVGConstants.SVG_Y_ATTRIBUTE == name) {
            setY(parseFloatArrayTrait(name, value));
        } else if (SVGConstants.SVG_ROTATE_ATTRIBUTE == name) {
            float[] rt = parseFloatArrayTrait(name, value);
            /*
            if (rt != null) {
                for (int i = 0; i < rt.length; i++) {
                    rt[i] = MathSupport.toRadians(rt[i]); 
                }
            }
            */
            setRotate(rt);
        } else if (SVGConstants.SVG_TEXT_PSEUDO_ATTRIBUTE == name) {
            if (value == null) {
                throw illegalTraitValue(name, value);
            }
            setContent(value);
        } else {
            super.setTraitImpl(name, value);
        }
    
public voidsetX(float[] newX)

param
newX this text's new x-axis position

        if (equal(newX, x)) {
            return;
        }

        modifyingNode();
        if (newX == null || newX.length == 0) {
            this.x = new float[1];
            this.x[0] = 0;
        } else {
            this.x = newX;
        }
        clearLayoutsQuiet();
        renderingDirty();
        modifiedNode();
    
public voidsetY(float[] newY)

param
newY this text's new y-axis position

        if (equal(newY, y)) {
            return;
        }

        modifyingNode();
        if (newY == null || newY.length == 0) {
            this.y = new float[1];
            this.y[0] = 0;
        } else {
            this.y = newY;
        }
        clearLayoutsQuiet();
        renderingDirty();
        modifiedNode();
    
booleansupportsTrait(java.lang.String traitName)
Text handles x, y, and #text traits.

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.

        if (SVGConstants.SVG_X_ATTRIBUTE == traitName
            ||
            SVGConstants.SVG_Y_ATTRIBUTE == traitName
            ||
            SVGConstants.SVG_ROTATE_ATTRIBUTE == traitName
            ||
            SVGConstants.SVG_TEXT_PSEUDO_ATTRIBUTE == traitName) {
            return true;
        } else {
            return super.supportsTrait(traitName);
        }
    
public java.lang.StringtoString()
Debug helper.

return
a String containing the text content

        String xStr = "x[";
        for (int i = 0; i < x.length; i++) {
            xStr += x[i] + ", ";
        }
        xStr = xStr.substring(0, xStr.length() - 2);
        xStr += "]";

        String yStr = "y[";
        for (int i = 0; i < y.length; i++) {
            yStr += y[i] + ", ";
        }
        yStr = yStr.substring(0, yStr.length() - 2);
        yStr += "]";

        return super.toString() + "[\"" + content + "\"] " + xStr + " " + yStr;
    
java.lang.StringtoStringTrait(java.lang.String name, float[][] value)

param
name the name of the trait to convert.
param
value the float trait value to convert.

        if (SVGConstants.SVG_X_ATTRIBUTE == name
            ||
            SVGConstants.SVG_Y_ATTRIBUTE == name) {
            float[] v = new float[value.length];
            for (int i = 0; i < value.length; i++) {
                v[i] = value[i][0];
            }
            return toStringTrait(v);
        } else if (SVGConstants.SVG_ROTATE_ATTRIBUTE == name) {
            float[] v = new float[value.length];
            for (int i = 0; i < value.length; i++) {
                v[i] = value[i][0];
            }
            return toStringTrait(v);

        } else {
            return super.toStringTrait(name, value);
        }
    
public float[][]validateFloatArrayTrait(java.lang.String traitName, java.lang.String value, java.lang.String reqNamespaceURI, java.lang.String reqLocalName, java.lang.String reqTraitNamespace, java.lang.String reqTraitName)
Validates the 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.

        if (SVGConstants.SVG_X_ATTRIBUTE == traitName
            ||
            SVGConstants.SVG_Y_ATTRIBUTE == traitName) {
            return toAnimatedFloatArray(parseFloatArrayTrait(traitName, value));
        } else if (SVGConstants.SVG_ROTATE_ATTRIBUTE == traitName) {
            float[][] v = toAnimatedFloatArray(parseFloatArrayTrait(traitName, 
                                                                    value));
            // Convert from degrees to radians
            /* 
            for (int i = 0; i < v.length; i++) {
                v[i][0] = MathSupport.toRadians(v[i][0]);
            } 
            */
            return v;
        } else {
            return super.validateFloatArrayTrait(traitName,
                                                 value,
                                                 reqNamespaceURI,
                                                 reqLocalName,
                                                 reqTraitNamespace,
                                                 reqTraitName);
        }