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

TextProxy.java

/*
 *
 *
 * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt).
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */
package com.sun.perseus.model;

import com.sun.perseus.j2d.Box;
import com.sun.perseus.j2d.PaintServer;
import com.sun.perseus.j2d.PaintTarget;
import com.sun.perseus.j2d.RenderGraphics;
import com.sun.perseus.j2d.Tile;
import com.sun.perseus.j2d.Transform;

import org.w3c.dom.svg.SVGRect;

/**
 * A <code>TextProxy</code> proxies a <code>Text</code> node and 
 * computes its expanded content from the proxied text's data
 * content.
 *
 * @version $Id: TextProxy.java,v 1.10 2006/06/29 10:47:35 ln156897 Exp $
 */
public class TextProxy extends StructureNodeProxy {
    /**
     * Used to track the node's rendering area and the rendered areas.
     */
    protected RenderingManager renderingManager;

    /**
     * Points to the first text chunk.
     */
    protected GlyphLayout firstChunk;

    /**
     * Points to the last text chunk.
     */
    protected GlyphLayout lastChunk;

    /**
     * @param proxiedText <code>Text</code> node to proxy.
     */
    public TextProxy(final Text proxiedText) {
        super(proxiedText);
        if (DirtyAreaManager.ON) {
            renderingManager = new RenderingManager(this);
        }
    }

    /**
     * @return the tight bounding box in current user coordinate
     * space. 
     */
    public SVGRect getBBox() {
        return addNodeBBox(null, null);
    }

    /**
     * @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, 
     */
    Box addNodeBBox(final Box bbox, 
                    final Transform t) {
        checkLayout();
        return ((Text) proxied).addNodeBBox(bbox, t, firstChunk);
    }

    /**
     * Should be called whenever this node's rendering becomes dirty.
     */
    final void renderingDirty() {
        if (DirtyAreaManager.ON) {
            renderingManager.dirty();
        }
    }

    /**
     * An <code>TextProxy</code> has something to render 
     *
     * @return true
     */
    public boolean hasNodeRendering() {
        return true;
    }

    /**
     * Paints this node into the input <code>RenderGraphics</code>.
     *
     * @param rg the <tt>RenderGraphics</tt> where the node should paint itself
     */
    public void paint(final RenderGraphics rg) {
        checkLayout();

        if (canRenderState != 0) {
            return;
        }

        if (DirtyAreaManager.ON) {
            Tile primitiveTile = getRenderingTile();
            if (primitiveTile == null 
                || 
                rg.getRenderingTile().isHit(primitiveTile)) {
                // rg.setPrimitiveTile(primitiveTile);
                ((Text) proxied).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 {
            ((Text) proxied).paintRendered(rg, this, txf, firstChunk);
        }
    }

    /**
     * Checks that the text's layout has been computed and computes it in 
     * case it was not.    
     */
    void checkLayout() {
        if (firstChunk == null) {
            firstChunk = ((Text) proxied).layoutText(this);
            GlyphLayout cur = firstChunk;
            while (cur.nextSibling != null) {
                cur = cur.nextSibling;
            }
            lastChunk = (GlyphLayout) cur;
        }
    }

    /**
     * This method is overridden for elements which has special renderings, 
     * such as the ShapeNodes.
     *
     * @param tile the Tile instance whose bounds should be set.
     */
    protected void computeRenderingTile(final Tile tile) {
        checkLayout();
        ((Text) proxied).computeRenderingTile(tile, txf, this, firstChunk);
    }

    /**
     * Disallow proxing of anything else than <code>Text</code> nodes.
     *
     * @param newProxied this node's new proxied node
     * @throws IllegalArgumentException if the input new proxy is not
     *         a <code>Text</code> node.
     * @see ElementNodeProxy#setProxied
     */
    protected void setProxied(final ElementNode newProxied) {
        if (newProxied != null && !(newProxied instanceof Text)) {
            throw new IllegalArgumentException();
        }

        super.setProxied(newProxied);
        clearLayoutsQuiet();
    }

    /**
     * Clears the node's layout cache. For ElementNodeProxy,
     * we just reset the node so that expanded content be
     * computed again and we request the proxied node to 
     * also clear its layout cache. This is to ensure that
     * Font Data Base changes are covered.
     */
    public void clearLayouts() {
        modifyingNode();
        clearLayoutsQuiet();
        super.clearLayouts();
        modifiedNode();
    }

    /**
     * Clears all cached layout information
     * but does not generate modification
     * events for this node.
     */
    public void clearLayoutsQuiet() {
        firstChunk = null;
        lastChunk = null;
    }

    /**
     * @return a string description of this ElementNodeProxy
     */
    /*
    public String toString() {
        return "TextProxy[proxied=" + proxied + "]" + " text-anchor : " 
            + rcs.getTextAnchor();
    }
    */

    /**
     * @param newDisplay the new computed display value
     */
    public void setDisplay(final boolean newDisplay) {
        super.setDisplay(newDisplay);

        renderingDirty();
    }

    /**
     * @param newVisibility the new computed visibility property.
     */
    public void setVisibility(final boolean newVisibility) {
        super.setVisibility(newVisibility);

        renderingDirty();
    }

    /**
     * @param newFill the new computed fill property.
     */
    public void setFill(final PaintServer newFill) {
        this.fill = newFill;
        renderingDirty();
    }

    /**
     * @param newStroke the new computed stroke property.
     */
    public void setStroke(final PaintServer newStroke) {
        this.stroke = newStroke;
        renderingDirty();
    }

    /**
     * @param newStrokeWidth the new computed stroke-width property value.
     */
    public void setStrokeWidth(final float newStrokeWidth) {
        strokeWidth = newStrokeWidth;

        // Only dirty rendering if the object is actually stroked.
        if (stroke != null) {
            renderingDirty();
        }
    }

    /**
     * @param newStrokeLineJoin the new computed value for stroke-line-join
     */
    public void setStrokeLineJoin(final int newStrokeLineJoin) {
        super.setStrokeLineJoin(newStrokeLineJoin);

        if (stroke != null) {
            renderingDirty();
        }
    }

    /**
     * @param newStrokeLineCap the new value for the stroke-linecap property.
     */
    public void setStrokeLineCap(final int newStrokeLineCap) {
        super.setStrokeLineCap(newStrokeLineCap);

        if (stroke != null) {
            renderingDirty();
        }
    }

    /**
     * @param newStrokeMiterLimit the new computed stroke-miterlimit property.
     */
    public void setStrokeMiterLimit(final float newStrokeMiterLimit) {
        strokeMiterLimit = newStrokeMiterLimit; 

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

    /**
     * @param newStrokeDashArray the new computed stroke-dasharray property 
     *        value.
     */
    public void setStrokeDashArray(final float[] newStrokeDashArray) {
        strokeDashArray = newStrokeDashArray;

        if (stroke != null) {
            renderingDirty();
        }
    }

    /**
     * @param newStrokeDashOffset the new stroke-dashoffset computed property 
     *        value.
     */
    public void setStrokeDashOffset(final float newStrokeDashOffset) {
        strokeDashOffset = newStrokeDashOffset;

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

    /**
     * @param newFillOpacity the new computed value for the fill opacity 
     *        property.
     */
    public void setFillOpacity(final float newFillOpacity) {                
        super.setFillOpacity(newFillOpacity);
        
        if (fill != null) {
            renderingDirty();
        }
    }

    /**
     * @param newStrokeOpacity the new computed stroke-opacity property.
     */
    public void setStrokeOpacity(final float newStrokeOpacity) {
        super.setStrokeOpacity(newStrokeOpacity);
        
        if (stroke != null) {
            renderingDirty();
        }
    }

    /**
     * @param newFontSize the new computed font-size property value.
     */
    public void setFontSize(final float newFontSize) {
        this.fontSize = newFontSize;
        
        if (stroke != null || fill != null) {
            renderingDirty();
        }

        computeCanRenderFontSizeBit(newFontSize);
    }

    /**
     * @param newFontFamily the new computed font-family property value.
     */
    public void setFontFamily(final String[] newFontFamily) {
        this.fontFamily = newFontFamily;

        clearLayoutsQuiet();

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

    /**
     * Sets the value of the computed text anchor property.
     *
     * @param newTextAnchor the new value for the computed text anchor property.
     */
    public void setTextAnchor(final int newTextAnchor) {
        super.setTextAnchor(newTextAnchor);

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

    /**
     * @param newFontWeight new computed value for the font-weight property.
     */
    public void setFontWeight(final int newFontWeight) {
        super.setFontWeight(newFontWeight);

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

        clearLayoutsQuiet();
    }

    /**
     * @param newFontStyle the new computed font-style property.
     */
    public void setFontStyle(final int newFontStyle) {
        super.setFontStyle(newFontStyle);
        if (stroke != null || fill != null) {
            renderingDirty();
        }

        clearLayoutsQuiet();
    }

}