001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026: package com.sun.perseus.model;
027:
028: import com.sun.perseus.j2d.Box;
029: import com.sun.perseus.j2d.RenderGraphics;
030: import com.sun.perseus.j2d.TextRenderingProperties;
031: import com.sun.perseus.j2d.Transform;
032: import org.w3c.dom.svg.SVGRect;
033:
034: /**
035: * A <code>TextProxy</code> proxies a <code>Text</code> node and
036: * computes its expanded content from the proxied text's data
037: * content.
038: *
039: * @version $Id: StructureNodeProxy.java,v 1.4 2006/06/29 10:47:35 ln156897 Exp $
040: */
041: public class StructureNodeProxy extends CompositeGraphicsNodeProxy
042: implements TextRenderingProperties {
043: // ====================================================================
044: // Properties
045: // ====================================================================
046: /**
047: * Controls this node's fontFamily
048: */
049: protected String[] fontFamily = INITIAL_FONT_FAMILY;
050:
051: /**
052: * Controls this node's fontSize
053: */
054: protected float fontSize = INITIAL_FONT_SIZE;
055:
056: /**
057: * @param proxiedNode <code>StructureNode</code> to proxy
058: */
059: protected StructureNodeProxy(final StructureNode proxiedNode) {
060: super (proxiedNode);
061:
062: // We copy the computed value for all properties upon initialization.
063: // When the node is hooked in the tree, inherited properties will be
064: // recomputed. Note that the fontStyle, fontWeight and textAnchor
065: // properties are in the pack value that is already copied in the
066: // parent constructor.
067: fontFamily = proxiedNode.fontFamily;
068: fontSize = proxiedNode.fontSize;
069: }
070:
071: /**
072: * Returns the value for the given property.
073: *
074: * @return the value for the given property.
075: */
076: protected Object getPropertyState(final int propertyIndex) {
077: switch (propertyIndex) {
078: case TextNode.PROPERTY_FONT_FAMILY:
079: return fontFamily;
080: default:
081: return super .getPropertyState(propertyIndex);
082: }
083: }
084:
085: /**
086: * Returns the value for the given float property.
087: *
088: * @return the value for the given property.
089: */
090: protected float getFloatPropertyState(final int propertyIndex) {
091: switch (propertyIndex) {
092: case TextNode.PROPERTY_FONT_SIZE:
093: return fontSize;
094: default:
095: return super .getFloatPropertyState(propertyIndex);
096: }
097: }
098:
099: /**
100: * Returns the value for the given packed property.
101: *
102: * @return the value for the given property.
103: */
104: protected int getPackedPropertyState(final int propertyIndex) {
105: switch (propertyIndex) {
106: case TextNode.PROPERTY_FONT_STYLE:
107: return pack & StructureNode.FONT_STYLE_MASK;
108: case TextNode.PROPERTY_FONT_WEIGHT:
109: return pack & StructureNode.FONT_WEIGHT_MASK;
110: case TextNode.PROPERTY_TEXT_ANCHOR:
111: return pack & StructureNode.TEXT_ANCHOR_MASK;
112: default:
113: return super .getPackedPropertyState(propertyIndex);
114: }
115: }
116:
117: /**
118: * Checks the state of the property value.
119: *
120: * @param propertyIndex the property index
121: * @param propertyValue the computed value for the property.
122: */
123: protected boolean isPropertyState(final int propertyIndex,
124: final Object propertyValue) {
125: switch (propertyIndex) {
126: case TextNode.PROPERTY_FONT_FAMILY:
127: return fontFamily == propertyValue;
128: default:
129: return super .isPropertyState(propertyIndex, propertyValue);
130: }
131: }
132:
133: /**
134: * Checks the state of the float property value.
135: *
136: * @param propertyIndex the property index
137: * @param propertyValue the computed value for the property.
138: */
139: protected boolean isFloatPropertyState(final int propertyIndex,
140: final float propertyValue) {
141: switch (propertyIndex) {
142: case TextNode.PROPERTY_FONT_SIZE:
143: return fontSize == propertyValue;
144: default:
145: return super .isFloatPropertyState(propertyIndex,
146: propertyValue);
147: }
148: }
149:
150: /**
151: * Checks the state of the property value.
152: *
153: * @param propertyIndex the property index
154: * @param propertyValue the computed value for the property.
155: */
156: protected boolean isPackedPropertyState(final int propertyIndex,
157: final int propertyValue) {
158: switch (propertyIndex) {
159: case TextNode.PROPERTY_FONT_STYLE:
160: return (propertyValue == (pack & StructureNode.FONT_STYLE_MASK));
161: case TextNode.PROPERTY_FONT_WEIGHT:
162: return (propertyValue == (pack & StructureNode.FONT_WEIGHT_MASK));
163: case TextNode.PROPERTY_TEXT_ANCHOR:
164: return (propertyValue == (pack & StructureNode.TEXT_ANCHOR_MASK));
165: default:
166: return super .isPackedPropertyState(propertyIndex,
167: propertyValue);
168: }
169: }
170:
171: /**
172: * Recomputes the given packed property's state given the new parent
173: * property.
174: *
175: * @param propertyIndex index for the property whose value is changing.
176: * @param parentPropertyValue the value that children of this node should
177: * now inherit.
178: *
179: */
180: protected void recomputePackedPropertyState(
181: final int propertyIndex, final int parentPropertyValue) {
182: if (propertyIndex != StructureNode.PROPERTY_FONT_WEIGHT) {
183: super .recomputePackedPropertyState(propertyIndex,
184: parentPropertyValue);
185: } else {
186: // We do not need to recompute the fontWeight value if:
187: // - the fontWeight is _not_ inherited & not relative (i.e. lighter
188: // or bolder)
189: // or
190: // - the property is inherited but the new parent property computed
191: // value is the same as the current value & the bolder and lighter
192: // markes are in the same state
193: if ((!((StructureNode) proxied).isInherited(propertyIndex)
194: && !((StructureNode) proxied)
195: .isMarkerSet(StructureNode.FONT_WEIGHT_BOLDER_MARKER) && !((StructureNode) proxied)
196: .isMarkerSet(StructureNode.FONT_WEIGHT_LIGHTER_MARKER))
197: || isPackedPropertyState(propertyIndex,
198: parentPropertyValue)) {
199: return;
200: }
201:
202: setPackedPropertyState(propertyIndex, parentPropertyValue);
203: propagatePackedPropertyState(propertyIndex,
204: parentPropertyValue);
205: }
206: }
207:
208: /**
209: * Recomputes all inherited properties.
210: */
211: void recomputeInheritedProperties() {
212: super .recomputeInheritedProperties();
213: ModelNode p = ownerDocument;
214: if (parent != null) {
215: p = parent;
216: }
217:
218: recomputePropertyState(TextNode.PROPERTY_FONT_FAMILY, p
219: .getPropertyState(TextNode.PROPERTY_FONT_FAMILY));
220: recomputeFloatPropertyState(TextNode.PROPERTY_FONT_SIZE, p
221: .getFloatPropertyState(TextNode.PROPERTY_FONT_SIZE));
222: recomputePackedPropertyState(TextNode.PROPERTY_FONT_STYLE, p
223: .getPackedPropertyState(TextNode.PROPERTY_FONT_STYLE));
224: recomputePackedPropertyState(TextNode.PROPERTY_FONT_WEIGHT, p
225: .getPackedPropertyState(TextNode.PROPERTY_FONT_WEIGHT));
226: recomputePackedPropertyState(TextNode.PROPERTY_TEXT_ANCHOR, p
227: .getPackedPropertyState(TextNode.PROPERTY_TEXT_ANCHOR));
228: }
229:
230: /**
231: * @return the tight bounding box in current user coordinate
232: * space.
233: */
234: public SVGRect getBBox() {
235: return addBBox(null, null);
236: }
237:
238: /**
239: * @param bbox the bounding box to which this node's bounding box should be
240: * appended. That bounding box is in the target coordinate space. It
241: * may be null, in which case this node should create a new one.
242: * @param t the transform to apply from the node's coordinate space to the
243: * target coordinate space. May be null for the identity
244: * transform.
245: * @return the node's bounding box in the target coordinate space.
246: */
247: Box addBBox(Box bbox, final Transform t) {
248: ModelNode c = getFirstExpandedChild();
249: while (c != null) {
250: if (c.canRenderState == 0) {
251: bbox = c.addBBox(bbox, c.appendTransform(t, null));
252: }
253: c = c.nextSibling;
254: }
255:
256: return bbox;
257: }
258:
259: /**
260: * By default, an <code>ElementNodeProxy</code> does not paint anything.
261: *
262: * @param rg the <tt>RenderGraphics</tt> where the node should paint itself
263: */
264: public void paint(final RenderGraphics rg) {
265: if (canRenderState != 0) {
266: return;
267: }
268:
269: paint(getFirstExpandedChild(), rg);
270: }
271:
272: /**
273: * Sets the computed value for the given property.
274: *
275: * @param propertyIndex the property index
276: * @param propertyValue the computed value for the property.
277: */
278: protected void setPropertyState(final int propertyIndex,
279: final Object propertyValue) {
280: switch (propertyIndex) {
281: case TextNode.PROPERTY_FONT_FAMILY:
282: setFontFamily((String[]) propertyValue);
283: break;
284: default:
285: super .setPropertyState(propertyIndex, propertyValue);
286: }
287: }
288:
289: /**
290: * Sets the computed value for the given float property.
291: *
292: * @param propertyIndex the property index
293: * @param propertyValue the computed value for the property.
294: */
295: protected void setFloatPropertyState(final int propertyIndex,
296: final float propertyValue) {
297: switch (propertyIndex) {
298: case TextNode.PROPERTY_FONT_SIZE:
299: setFontSize(propertyValue);
300: break;
301: default:
302: super .setFloatPropertyState(propertyIndex, propertyValue);
303: }
304: }
305:
306: /**
307: * Sets the computed value for the given packed property.
308: *
309: * @param propertyIndex the property index
310: * @param propertyValue the computed value for the property.
311: */
312: protected void setPackedPropertyState(final int propertyIndex,
313: final int propertyValue) {
314: switch (propertyIndex) {
315: case StructureNode.PROPERTY_FONT_STYLE:
316: switch (propertyValue) {
317: case StructureNode.FONT_STYLE_NORMAL_IMPL:
318: setFontStyle(FONT_STYLE_NORMAL);
319: break;
320: case StructureNode.FONT_STYLE_ITALIC_IMPL:
321: setFontStyle(FONT_STYLE_ITALIC);
322: break;
323: case StructureNode.FONT_STYLE_OBLIQUE_IMPL:
324: default:
325: setFontStyle(FONT_STYLE_OBLIQUE);
326: break;
327: }
328: break;
329: case StructureNode.PROPERTY_FONT_WEIGHT:
330: switch (propertyValue) {
331: case StructureNode.FONT_WEIGHT_100_IMPL:
332: setFontWeight(FONT_WEIGHT_100);
333: break;
334: case StructureNode.FONT_WEIGHT_200_IMPL:
335: setFontWeight(FONT_WEIGHT_200);
336: break;
337: case StructureNode.FONT_WEIGHT_300_IMPL:
338: setFontWeight(FONT_WEIGHT_300);
339: break;
340: case StructureNode.FONT_WEIGHT_400_IMPL:
341: setFontWeight(FONT_WEIGHT_400);
342: break;
343: case StructureNode.FONT_WEIGHT_500_IMPL:
344: setFontWeight(FONT_WEIGHT_500);
345: break;
346: case StructureNode.FONT_WEIGHT_600_IMPL:
347: setFontWeight(FONT_WEIGHT_600);
348: break;
349: case StructureNode.FONT_WEIGHT_700_IMPL:
350: setFontWeight(FONT_WEIGHT_700);
351: break;
352: case StructureNode.FONT_WEIGHT_800_IMPL:
353: setFontWeight(FONT_WEIGHT_800);
354: break;
355: case StructureNode.FONT_WEIGHT_900_IMPL:
356: setFontWeight(FONT_WEIGHT_900);
357: break;
358: }
359: break;
360: case StructureNode.PROPERTY_TEXT_ANCHOR:
361: switch (propertyValue) {
362: case StructureNode.TEXT_ANCHOR_START_IMPL:
363: setTextAnchor(TEXT_ANCHOR_START);
364: break;
365: case StructureNode.TEXT_ANCHOR_MIDDLE_IMPL:
366: setTextAnchor(TEXT_ANCHOR_MIDDLE);
367: break;
368: case StructureNode.TEXT_ANCHOR_END_IMPL:
369: default:
370: setTextAnchor(TEXT_ANCHOR_END);
371: break;
372: }
373: break;
374: default:
375: super .setPackedPropertyState(propertyIndex, propertyValue);
376: }
377: }
378:
379: /**
380: * @return this node's computed font-family
381: */
382: public String[] getFontFamily() {
383: return fontFamily;
384: }
385:
386: /**
387: * @param newFontFamily the new computed font-family property value.
388: */
389: public void setFontFamily(final String[] newFontFamily) {
390: this .fontFamily = newFontFamily;
391: }
392:
393: /**
394: * @return this node's computed fontSize
395: */
396: public float getFontSize() {
397: return fontSize;
398: }
399:
400: /**
401: * @param newFontSize the new computed font-size property value.
402: */
403: public void setFontSize(final float newFontSize) {
404: this .fontSize = newFontSize;
405: }
406:
407: /**
408: * @return this node's computed fontStyle
409: */
410: public int getFontStyle() {
411: switch (pack & StructureNode.FONT_STYLE_MASK) {
412: case StructureNode.FONT_STYLE_NORMAL_IMPL:
413: return FONT_STYLE_NORMAL;
414: case StructureNode.FONT_STYLE_ITALIC_IMPL:
415: return FONT_STYLE_ITALIC;
416: default:
417: return FONT_STYLE_OBLIQUE;
418: }
419: }
420:
421: /**
422: * @param newFontStyle the new computed font-style property.
423: */
424: public void setFontStyle(final int newFontStyle) {
425: pack &= ~StructureNode.FONT_STYLE_MASK;
426: switch (newFontStyle) {
427: case FONT_STYLE_NORMAL:
428: pack |= StructureNode.FONT_STYLE_NORMAL_IMPL;
429: break;
430: case FONT_STYLE_ITALIC:
431: pack |= StructureNode.FONT_STYLE_ITALIC_IMPL;
432: break;
433: default:
434: pack |= StructureNode.FONT_STYLE_OBLIQUE_IMPL;
435: break;
436: }
437: }
438:
439: /**
440: * @return this node's computed fontWeight
441: */
442: public int getFontWeight() {
443: switch (pack & StructureNode.FONT_WEIGHT_MASK) {
444: case StructureNode.FONT_WEIGHT_100_IMPL:
445: return FONT_WEIGHT_100;
446: case StructureNode.FONT_WEIGHT_200_IMPL:
447: return FONT_WEIGHT_200;
448: case StructureNode.FONT_WEIGHT_300_IMPL:
449: return FONT_WEIGHT_300;
450: case StructureNode.FONT_WEIGHT_400_IMPL:
451: return FONT_WEIGHT_400;
452: case StructureNode.FONT_WEIGHT_500_IMPL:
453: return FONT_WEIGHT_500;
454: case StructureNode.FONT_WEIGHT_600_IMPL:
455: return FONT_WEIGHT_600;
456: case StructureNode.FONT_WEIGHT_700_IMPL:
457: return FONT_WEIGHT_700;
458: case StructureNode.FONT_WEIGHT_800_IMPL:
459: return FONT_WEIGHT_800;
460: case StructureNode.FONT_WEIGHT_900_IMPL:
461: return FONT_WEIGHT_900;
462: case StructureNode.FONT_WEIGHT_LIGHTER_IMPL:
463: return TextNode.FONT_WEIGHT_LIGHTER;
464: default:
465: return TextNode.FONT_WEIGHT_BOLDER;
466: }
467: }
468:
469: /**
470: * @param newFontWeight new computed value for the font-weight property.
471: */
472: public void setFontWeight(final int newFontWeight) {
473: pack &= ~StructureNode.FONT_WEIGHT_MASK;
474:
475: switch (newFontWeight) {
476: case FONT_WEIGHT_100:
477: pack |= StructureNode.FONT_WEIGHT_100_IMPL;
478: break;
479: case FONT_WEIGHT_200:
480: pack |= StructureNode.FONT_WEIGHT_200_IMPL;
481: break;
482: case FONT_WEIGHT_300:
483: pack |= StructureNode.FONT_WEIGHT_300_IMPL;
484: break;
485: case FONT_WEIGHT_400:
486: pack |= StructureNode.FONT_WEIGHT_400_IMPL;
487: break;
488: case FONT_WEIGHT_500:
489: pack |= StructureNode.FONT_WEIGHT_500_IMPL;
490: break;
491: case FONT_WEIGHT_600:
492: pack |= StructureNode.FONT_WEIGHT_600_IMPL;
493: break;
494: case FONT_WEIGHT_700:
495: pack |= StructureNode.FONT_WEIGHT_700_IMPL;
496: break;
497: case FONT_WEIGHT_800:
498: pack |= StructureNode.FONT_WEIGHT_800_IMPL;
499: break;
500: case FONT_WEIGHT_900:
501: pack |= StructureNode.FONT_WEIGHT_900_IMPL;
502: break;
503: case StructureNode.FONT_WEIGHT_LIGHTER:
504: pack |= StructureNode.FONT_WEIGHT_LIGHTER_IMPL;
505: break;
506: default:
507: pack |= StructureNode.FONT_WEIGHT_BOLDER_IMPL;
508: break;
509: }
510: }
511:
512: /**
513: * @return this node's computed textAnchor
514: */
515: public int getTextAnchor() {
516: switch (pack & StructureNode.TEXT_ANCHOR_MASK) {
517: case StructureNode.TEXT_ANCHOR_START_IMPL:
518: return TEXT_ANCHOR_START;
519: case StructureNode.TEXT_ANCHOR_MIDDLE_IMPL:
520: return TEXT_ANCHOR_MIDDLE;
521: default:
522: return TEXT_ANCHOR_END;
523: }
524: }
525:
526: /**
527: * Sets the value of the computed text anchor property.
528: *
529: * @param newTextAnchor the new value for the computed text anchor property.
530: */
531: public void setTextAnchor(final int newTextAnchor) {
532: pack &= ~StructureNode.TEXT_ANCHOR_MASK;
533: switch (newTextAnchor) {
534: case TEXT_ANCHOR_START:
535: pack |= StructureNode.TEXT_ANCHOR_START_IMPL;
536: break;
537: case TEXT_ANCHOR_MIDDLE:
538: pack |= StructureNode.TEXT_ANCHOR_MIDDLE_IMPL;
539: break;
540: default:
541: pack |= StructureNode.TEXT_ANCHOR_END_IMPL;
542: break;
543: }
544: }
545:
546: }
|