/*
*
*
* 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.RenderGraphics;
import com.sun.perseus.j2d.TextRenderingProperties;
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: StructureNodeProxy.java,v 1.4 2006/06/29 10:47:35 ln156897 Exp $
*/
public class StructureNodeProxy extends CompositeGraphicsNodeProxy
implements TextRenderingProperties {
// ====================================================================
// Properties
// ====================================================================
/**
* Controls this node's fontFamily
*/
protected String[] fontFamily = INITIAL_FONT_FAMILY;
/**
* Controls this node's fontSize
*/
protected float fontSize = INITIAL_FONT_SIZE;
/**
* @param proxiedNode <code>StructureNode</code> to proxy
*/
protected StructureNodeProxy(final StructureNode proxiedNode) {
super(proxiedNode);
// We copy the computed value for all properties upon initialization.
// When the node is hooked in the tree, inherited properties will be
// recomputed. Note that the fontStyle, fontWeight and textAnchor
// properties are in the pack value that is already copied in the
// parent constructor.
fontFamily = proxiedNode.fontFamily;
fontSize = proxiedNode.fontSize;
}
/**
* Returns the value for the given property.
*
* @return the value for the given property.
*/
protected Object getPropertyState(final int propertyIndex) {
switch (propertyIndex) {
case TextNode.PROPERTY_FONT_FAMILY:
return fontFamily;
default:
return super.getPropertyState(propertyIndex);
}
}
/**
* Returns the value for the given float property.
*
* @return the value for the given property.
*/
protected float getFloatPropertyState(final int propertyIndex) {
switch (propertyIndex) {
case TextNode.PROPERTY_FONT_SIZE:
return fontSize;
default:
return super.getFloatPropertyState(propertyIndex);
}
}
/**
* Returns the value for the given packed property.
*
* @return the value for the given property.
*/
protected int getPackedPropertyState(final int propertyIndex) {
switch (propertyIndex) {
case TextNode.PROPERTY_FONT_STYLE:
return pack & StructureNode.FONT_STYLE_MASK;
case TextNode.PROPERTY_FONT_WEIGHT:
return pack & StructureNode.FONT_WEIGHT_MASK;
case TextNode.PROPERTY_TEXT_ANCHOR:
return pack & StructureNode.TEXT_ANCHOR_MASK;
default:
return super.getPackedPropertyState(propertyIndex);
}
}
/**
* Checks the state of the property value.
*
* @param propertyIndex the property index
* @param propertyValue the computed value for the property.
*/
protected boolean isPropertyState(final int propertyIndex,
final Object propertyValue) {
switch (propertyIndex) {
case TextNode.PROPERTY_FONT_FAMILY:
return fontFamily == propertyValue;
default:
return super.isPropertyState(propertyIndex, propertyValue);
}
}
/**
* Checks the state of the float property value.
*
* @param propertyIndex the property index
* @param propertyValue the computed value for the property.
*/
protected boolean isFloatPropertyState(final int propertyIndex,
final float propertyValue) {
switch (propertyIndex) {
case TextNode.PROPERTY_FONT_SIZE:
return fontSize == propertyValue;
default:
return super.isFloatPropertyState(propertyIndex, propertyValue);
}
}
/**
* Checks the state of the property value.
*
* @param propertyIndex the property index
* @param propertyValue the computed value for the property.
*/
protected boolean isPackedPropertyState(final int propertyIndex,
final int propertyValue) {
switch (propertyIndex) {
case TextNode.PROPERTY_FONT_STYLE:
return (propertyValue
==
(pack & StructureNode.FONT_STYLE_MASK));
case TextNode.PROPERTY_FONT_WEIGHT:
return (propertyValue
==
(pack & StructureNode.FONT_WEIGHT_MASK));
case TextNode.PROPERTY_TEXT_ANCHOR:
return (propertyValue
==
(pack & StructureNode.TEXT_ANCHOR_MASK));
default:
return super.isPackedPropertyState(propertyIndex, propertyValue);
}
}
/**
* Recomputes the given packed property's state given the new parent
* property.
*
* @param propertyIndex index for the property whose value is changing.
* @param parentPropertyValue the value that children of this node should
* now inherit.
*
*/
protected void recomputePackedPropertyState(final int propertyIndex,
final int parentPropertyValue) {
if (propertyIndex != StructureNode.PROPERTY_FONT_WEIGHT) {
super.recomputePackedPropertyState(propertyIndex,
parentPropertyValue);
} else {
// We do not need to recompute the fontWeight value if:
// - the fontWeight is _not_ inherited & not relative (i.e. lighter
// or bolder)
// or
// - the property is inherited but the new parent property computed
// value is the same as the current value & the bolder and lighter
// markes are in the same state
if ((!((StructureNode) proxied).isInherited(propertyIndex)
&&
!((StructureNode) proxied).isMarkerSet(
StructureNode.FONT_WEIGHT_BOLDER_MARKER)
&&
!((StructureNode) proxied).isMarkerSet(
StructureNode.FONT_WEIGHT_LIGHTER_MARKER))
||
isPackedPropertyState(propertyIndex, parentPropertyValue)) {
return;
}
setPackedPropertyState(propertyIndex, parentPropertyValue);
propagatePackedPropertyState(propertyIndex, parentPropertyValue);
}
}
/**
* Recomputes all inherited properties.
*/
void recomputeInheritedProperties() {
super.recomputeInheritedProperties();
ModelNode p = ownerDocument;
if (parent != null) {
p = parent;
}
recomputePropertyState(
TextNode.PROPERTY_FONT_FAMILY,
p.getPropertyState(TextNode.PROPERTY_FONT_FAMILY));
recomputeFloatPropertyState(
TextNode.PROPERTY_FONT_SIZE,
p.getFloatPropertyState(TextNode.PROPERTY_FONT_SIZE));
recomputePackedPropertyState(
TextNode.PROPERTY_FONT_STYLE,
p.getPackedPropertyState(TextNode.PROPERTY_FONT_STYLE));
recomputePackedPropertyState(
TextNode.PROPERTY_FONT_WEIGHT,
p.getPackedPropertyState(TextNode.PROPERTY_FONT_WEIGHT));
recomputePackedPropertyState(
TextNode.PROPERTY_TEXT_ANCHOR,
p.getPackedPropertyState(TextNode.PROPERTY_TEXT_ANCHOR));
}
/**
* @return the tight bounding box in current user coordinate
* space.
*/
public SVGRect getBBox() {
return addBBox(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 to apply from the node's coordinate space to the
* target coordinate space. May be null for the identity
* transform.
* @return the node's bounding box in the target coordinate space.
*/
Box addBBox(Box bbox, final Transform t) {
ModelNode c = getFirstExpandedChild();
while (c != null) {
if (c.canRenderState == 0) {
bbox = c.addBBox(bbox, c.appendTransform(t, null));
}
c = c.nextSibling;
}
return bbox;
}
/**
* By default, an <code>ElementNodeProxy</code> does not paint anything.
*
* @param rg the <tt>RenderGraphics</tt> where the node should paint itself
*/
public void paint(final RenderGraphics rg) {
if (canRenderState != 0) {
return;
}
paint(getFirstExpandedChild(), rg);
}
/**
* Sets the computed value for the given property.
*
* @param propertyIndex the property index
* @param propertyValue the computed value for the property.
*/
protected void setPropertyState(final int propertyIndex,
final Object propertyValue) {
switch (propertyIndex) {
case TextNode.PROPERTY_FONT_FAMILY:
setFontFamily((String[]) propertyValue);
break;
default:
super.setPropertyState(propertyIndex, propertyValue);
}
}
/**
* Sets the computed value for the given float property.
*
* @param propertyIndex the property index
* @param propertyValue the computed value for the property.
*/
protected void setFloatPropertyState(final int propertyIndex,
final float propertyValue) {
switch (propertyIndex) {
case TextNode.PROPERTY_FONT_SIZE:
setFontSize(propertyValue);
break;
default:
super.setFloatPropertyState(propertyIndex, propertyValue);
}
}
/**
* Sets the computed value for the given packed property.
*
* @param propertyIndex the property index
* @param propertyValue the computed value for the property.
*/
protected void setPackedPropertyState(final int propertyIndex,
final int propertyValue) {
switch (propertyIndex) {
case StructureNode.PROPERTY_FONT_STYLE:
switch (propertyValue) {
case StructureNode.FONT_STYLE_NORMAL_IMPL:
setFontStyle(FONT_STYLE_NORMAL);
break;
case StructureNode.FONT_STYLE_ITALIC_IMPL:
setFontStyle(FONT_STYLE_ITALIC);
break;
case StructureNode.FONT_STYLE_OBLIQUE_IMPL:
default:
setFontStyle(FONT_STYLE_OBLIQUE);
break;
}
break;
case StructureNode.PROPERTY_FONT_WEIGHT:
switch (propertyValue) {
case StructureNode.FONT_WEIGHT_100_IMPL:
setFontWeight(FONT_WEIGHT_100);
break;
case StructureNode.FONT_WEIGHT_200_IMPL:
setFontWeight(FONT_WEIGHT_200);
break;
case StructureNode.FONT_WEIGHT_300_IMPL:
setFontWeight(FONT_WEIGHT_300);
break;
case StructureNode.FONT_WEIGHT_400_IMPL:
setFontWeight(FONT_WEIGHT_400);
break;
case StructureNode.FONT_WEIGHT_500_IMPL:
setFontWeight(FONT_WEIGHT_500);
break;
case StructureNode.FONT_WEIGHT_600_IMPL:
setFontWeight(FONT_WEIGHT_600);
break;
case StructureNode.FONT_WEIGHT_700_IMPL:
setFontWeight(FONT_WEIGHT_700);
break;
case StructureNode.FONT_WEIGHT_800_IMPL:
setFontWeight(FONT_WEIGHT_800);
break;
case StructureNode.FONT_WEIGHT_900_IMPL:
setFontWeight(FONT_WEIGHT_900);
break;
}
break;
case StructureNode.PROPERTY_TEXT_ANCHOR:
switch (propertyValue) {
case StructureNode.TEXT_ANCHOR_START_IMPL:
setTextAnchor(TEXT_ANCHOR_START);
break;
case StructureNode.TEXT_ANCHOR_MIDDLE_IMPL:
setTextAnchor(TEXT_ANCHOR_MIDDLE);
break;
case StructureNode.TEXT_ANCHOR_END_IMPL:
default:
setTextAnchor(TEXT_ANCHOR_END);
break;
}
break;
default:
super.setPackedPropertyState(propertyIndex, propertyValue);
}
}
/**
* @return this node's computed font-family
*/
public String[] getFontFamily() {
return fontFamily;
}
/**
* @param newFontFamily the new computed font-family property value.
*/
public void setFontFamily(final String[] newFontFamily) {
this.fontFamily = newFontFamily;
}
/**
* @return this node's computed fontSize
*/
public float getFontSize() {
return fontSize;
}
/**
* @param newFontSize the new computed font-size property value.
*/
public void setFontSize(final float newFontSize) {
this.fontSize = newFontSize;
}
/**
* @return this node's computed fontStyle
*/
public int getFontStyle() {
switch (pack & StructureNode.FONT_STYLE_MASK) {
case StructureNode.FONT_STYLE_NORMAL_IMPL:
return FONT_STYLE_NORMAL;
case StructureNode.FONT_STYLE_ITALIC_IMPL:
return FONT_STYLE_ITALIC;
default:
return FONT_STYLE_OBLIQUE;
}
}
/**
* @param newFontStyle the new computed font-style property.
*/
public void setFontStyle(final int newFontStyle) {
pack &= ~StructureNode.FONT_STYLE_MASK;
switch (newFontStyle) {
case FONT_STYLE_NORMAL:
pack |= StructureNode.FONT_STYLE_NORMAL_IMPL;
break;
case FONT_STYLE_ITALIC:
pack |= StructureNode.FONT_STYLE_ITALIC_IMPL;
break;
default:
pack |= StructureNode.FONT_STYLE_OBLIQUE_IMPL;
break;
}
}
/**
* @return this node's computed fontWeight
*/
public int getFontWeight() {
switch (pack & StructureNode.FONT_WEIGHT_MASK) {
case StructureNode.FONT_WEIGHT_100_IMPL:
return FONT_WEIGHT_100;
case StructureNode.FONT_WEIGHT_200_IMPL:
return FONT_WEIGHT_200;
case StructureNode.FONT_WEIGHT_300_IMPL:
return FONT_WEIGHT_300;
case StructureNode.FONT_WEIGHT_400_IMPL:
return FONT_WEIGHT_400;
case StructureNode.FONT_WEIGHT_500_IMPL:
return FONT_WEIGHT_500;
case StructureNode.FONT_WEIGHT_600_IMPL:
return FONT_WEIGHT_600;
case StructureNode.FONT_WEIGHT_700_IMPL:
return FONT_WEIGHT_700;
case StructureNode.FONT_WEIGHT_800_IMPL:
return FONT_WEIGHT_800;
case StructureNode.FONT_WEIGHT_900_IMPL:
return FONT_WEIGHT_900;
case StructureNode.FONT_WEIGHT_LIGHTER_IMPL:
return TextNode.FONT_WEIGHT_LIGHTER;
default:
return TextNode.FONT_WEIGHT_BOLDER;
}
}
/**
* @param newFontWeight new computed value for the font-weight property.
*/
public void setFontWeight(final int newFontWeight) {
pack &= ~StructureNode.FONT_WEIGHT_MASK;
switch (newFontWeight) {
case FONT_WEIGHT_100:
pack |= StructureNode.FONT_WEIGHT_100_IMPL;
break;
case FONT_WEIGHT_200:
pack |= StructureNode.FONT_WEIGHT_200_IMPL;
break;
case FONT_WEIGHT_300:
pack |= StructureNode.FONT_WEIGHT_300_IMPL;
break;
case FONT_WEIGHT_400:
pack |= StructureNode.FONT_WEIGHT_400_IMPL;
break;
case FONT_WEIGHT_500:
pack |= StructureNode.FONT_WEIGHT_500_IMPL;
break;
case FONT_WEIGHT_600:
pack |= StructureNode.FONT_WEIGHT_600_IMPL;
break;
case FONT_WEIGHT_700:
pack |= StructureNode.FONT_WEIGHT_700_IMPL;
break;
case FONT_WEIGHT_800:
pack |= StructureNode.FONT_WEIGHT_800_IMPL;
break;
case FONT_WEIGHT_900:
pack |= StructureNode.FONT_WEIGHT_900_IMPL;
break;
case StructureNode.FONT_WEIGHT_LIGHTER:
pack |= StructureNode.FONT_WEIGHT_LIGHTER_IMPL;
break;
default:
pack |= StructureNode.FONT_WEIGHT_BOLDER_IMPL;
break;
}
}
/**
* @return this node's computed textAnchor
*/
public int getTextAnchor() {
switch (pack & StructureNode.TEXT_ANCHOR_MASK) {
case StructureNode.TEXT_ANCHOR_START_IMPL:
return TEXT_ANCHOR_START;
case StructureNode.TEXT_ANCHOR_MIDDLE_IMPL:
return TEXT_ANCHOR_MIDDLE;
default:
return TEXT_ANCHOR_END;
}
}
/**
* 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) {
pack &= ~StructureNode.TEXT_ANCHOR_MASK;
switch (newTextAnchor) {
case TEXT_ANCHOR_START:
pack |= StructureNode.TEXT_ANCHOR_START_IMPL;
break;
case TEXT_ANCHOR_MIDDLE:
pack |= StructureNode.TEXT_ANCHOR_MIDDLE_IMPL;
break;
default:
pack |= StructureNode.TEXT_ANCHOR_END_IMPL;
break;
}
}
}
|