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.PaintServer;
030: import com.sun.perseus.j2d.PaintTarget;
031: import com.sun.perseus.j2d.RenderGraphics;
032: import com.sun.perseus.j2d.Tile;
033: import com.sun.perseus.j2d.Transform;
034:
035: import org.w3c.dom.svg.SVGRect;
036:
037: /**
038: * A <code>TextProxy</code> proxies a <code>Text</code> node and
039: * computes its expanded content from the proxied text's data
040: * content.
041: *
042: * @version $Id: TextProxy.java,v 1.10 2006/06/29 10:47:35 ln156897 Exp $
043: */
044: public class TextProxy extends StructureNodeProxy {
045: /**
046: * Used to track the node's rendering area and the rendered areas.
047: */
048: protected RenderingManager renderingManager;
049:
050: /**
051: * Points to the first text chunk.
052: */
053: protected GlyphLayout firstChunk;
054:
055: /**
056: * Points to the last text chunk.
057: */
058: protected GlyphLayout lastChunk;
059:
060: /**
061: * @param proxiedText <code>Text</code> node to proxy.
062: */
063: public TextProxy(final Text proxiedText) {
064: super (proxiedText);
065: if (DirtyAreaManager.ON) {
066: renderingManager = new RenderingManager(this );
067: }
068: }
069:
070: /**
071: * @return the tight bounding box in current user coordinate
072: * space.
073: */
074: public SVGRect getBBox() {
075: return addNodeBBox(null, null);
076: }
077:
078: /**
079: * @param bbox the bounding box to which this node's bounding box should be
080: * appended. That bounding box is in the target coordinate space. It
081: * may be null, in which case this node should create a new one.
082: * @param t the transform from the node coordinate system to the coordinate
083: * system into which the bounds should be computed.
084: * @return the bounding box of this node, in the target coordinate space,
085: */
086: Box addNodeBBox(final Box bbox, final Transform t) {
087: checkLayout();
088: return ((Text) proxied).addNodeBBox(bbox, t, firstChunk);
089: }
090:
091: /**
092: * Should be called whenever this node's rendering becomes dirty.
093: */
094: final void renderingDirty() {
095: if (DirtyAreaManager.ON) {
096: renderingManager.dirty();
097: }
098: }
099:
100: /**
101: * An <code>TextProxy</code> has something to render
102: *
103: * @return true
104: */
105: public boolean hasNodeRendering() {
106: return true;
107: }
108:
109: /**
110: * Paints this node into the input <code>RenderGraphics</code>.
111: *
112: * @param rg the <tt>RenderGraphics</tt> where the node should paint itself
113: */
114: public void paint(final RenderGraphics rg) {
115: checkLayout();
116:
117: if (canRenderState != 0) {
118: return;
119: }
120:
121: if (DirtyAreaManager.ON) {
122: Tile primitiveTile = getRenderingTile();
123: if (primitiveTile == null
124: || rg.getRenderingTile().isHit(primitiveTile)) {
125: // rg.setPrimitiveTile(primitiveTile);
126: ((Text) proxied).paintRendered(rg, this , txf,
127: firstChunk);
128:
129: // nodeRendered is called seperately from paintRendered
130: // because paintRendered is used in different contexts,
131: // for example by proxy nodes to render, using their
132: // proxied node's paintRendered method.
133: nodeRendered();
134: }
135: } else {
136: ((Text) proxied).paintRendered(rg, this , txf, firstChunk);
137: }
138: }
139:
140: /**
141: * Checks that the text's layout has been computed and computes it in
142: * case it was not.
143: */
144: void checkLayout() {
145: if (firstChunk == null) {
146: firstChunk = ((Text) proxied).layoutText(this );
147: GlyphLayout cur = firstChunk;
148: while (cur.nextSibling != null) {
149: cur = cur.nextSibling;
150: }
151: lastChunk = (GlyphLayout) cur;
152: }
153: }
154:
155: /**
156: * This method is overridden for elements which has special renderings,
157: * such as the ShapeNodes.
158: *
159: * @param tile the Tile instance whose bounds should be set.
160: */
161: protected void computeRenderingTile(final Tile tile) {
162: checkLayout();
163: ((Text) proxied).computeRenderingTile(tile, txf, this ,
164: firstChunk);
165: }
166:
167: /**
168: * Disallow proxing of anything else than <code>Text</code> nodes.
169: *
170: * @param newProxied this node's new proxied node
171: * @throws IllegalArgumentException if the input new proxy is not
172: * a <code>Text</code> node.
173: * @see ElementNodeProxy#setProxied
174: */
175: protected void setProxied(final ElementNode newProxied) {
176: if (newProxied != null && !(newProxied instanceof Text)) {
177: throw new IllegalArgumentException();
178: }
179:
180: super .setProxied(newProxied);
181: clearLayoutsQuiet();
182: }
183:
184: /**
185: * Clears the node's layout cache. For ElementNodeProxy,
186: * we just reset the node so that expanded content be
187: * computed again and we request the proxied node to
188: * also clear its layout cache. This is to ensure that
189: * Font Data Base changes are covered.
190: */
191: public void clearLayouts() {
192: modifyingNode();
193: clearLayoutsQuiet();
194: super .clearLayouts();
195: modifiedNode();
196: }
197:
198: /**
199: * Clears all cached layout information
200: * but does not generate modification
201: * events for this node.
202: */
203: public void clearLayoutsQuiet() {
204: firstChunk = null;
205: lastChunk = null;
206: }
207:
208: /**
209: * @return a string description of this ElementNodeProxy
210: */
211: /*
212: public String toString() {
213: return "TextProxy[proxied=" + proxied + "]" + " text-anchor : "
214: + rcs.getTextAnchor();
215: }
216: */
217:
218: /**
219: * @param newDisplay the new computed display value
220: */
221: public void setDisplay(final boolean newDisplay) {
222: super .setDisplay(newDisplay);
223:
224: renderingDirty();
225: }
226:
227: /**
228: * @param newVisibility the new computed visibility property.
229: */
230: public void setVisibility(final boolean newVisibility) {
231: super .setVisibility(newVisibility);
232:
233: renderingDirty();
234: }
235:
236: /**
237: * @param newFill the new computed fill property.
238: */
239: public void setFill(final PaintServer newFill) {
240: this .fill = newFill;
241: renderingDirty();
242: }
243:
244: /**
245: * @param newStroke the new computed stroke property.
246: */
247: public void setStroke(final PaintServer newStroke) {
248: this .stroke = newStroke;
249: renderingDirty();
250: }
251:
252: /**
253: * @param newStrokeWidth the new computed stroke-width property value.
254: */
255: public void setStrokeWidth(final float newStrokeWidth) {
256: strokeWidth = newStrokeWidth;
257:
258: // Only dirty rendering if the object is actually stroked.
259: if (stroke != null) {
260: renderingDirty();
261: }
262: }
263:
264: /**
265: * @param newStrokeLineJoin the new computed value for stroke-line-join
266: */
267: public void setStrokeLineJoin(final int newStrokeLineJoin) {
268: super .setStrokeLineJoin(newStrokeLineJoin);
269:
270: if (stroke != null) {
271: renderingDirty();
272: }
273: }
274:
275: /**
276: * @param newStrokeLineCap the new value for the stroke-linecap property.
277: */
278: public void setStrokeLineCap(final int newStrokeLineCap) {
279: super .setStrokeLineCap(newStrokeLineCap);
280:
281: if (stroke != null) {
282: renderingDirty();
283: }
284: }
285:
286: /**
287: * @param newStrokeMiterLimit the new computed stroke-miterlimit property.
288: */
289: public void setStrokeMiterLimit(final float newStrokeMiterLimit) {
290: strokeMiterLimit = newStrokeMiterLimit;
291:
292: if (stroke != null && getStrokeLineJoin() == JOIN_MITER) {
293: renderingDirty();
294: }
295: }
296:
297: /**
298: * @param newStrokeDashArray the new computed stroke-dasharray property
299: * value.
300: */
301: public void setStrokeDashArray(final float[] newStrokeDashArray) {
302: strokeDashArray = newStrokeDashArray;
303:
304: if (stroke != null) {
305: renderingDirty();
306: }
307: }
308:
309: /**
310: * @param newStrokeDashOffset the new stroke-dashoffset computed property
311: * value.
312: */
313: public void setStrokeDashOffset(final float newStrokeDashOffset) {
314: strokeDashOffset = newStrokeDashOffset;
315:
316: if (stroke != null && strokeDashArray != null) {
317: renderingDirty();
318: }
319: }
320:
321: /**
322: * @param newFillOpacity the new computed value for the fill opacity
323: * property.
324: */
325: public void setFillOpacity(final float newFillOpacity) {
326: super .setFillOpacity(newFillOpacity);
327:
328: if (fill != null) {
329: renderingDirty();
330: }
331: }
332:
333: /**
334: * @param newStrokeOpacity the new computed stroke-opacity property.
335: */
336: public void setStrokeOpacity(final float newStrokeOpacity) {
337: super .setStrokeOpacity(newStrokeOpacity);
338:
339: if (stroke != null) {
340: renderingDirty();
341: }
342: }
343:
344: /**
345: * @param newFontSize the new computed font-size property value.
346: */
347: public void setFontSize(final float newFontSize) {
348: this .fontSize = newFontSize;
349:
350: if (stroke != null || fill != null) {
351: renderingDirty();
352: }
353:
354: computeCanRenderFontSizeBit(newFontSize);
355: }
356:
357: /**
358: * @param newFontFamily the new computed font-family property value.
359: */
360: public void setFontFamily(final String[] newFontFamily) {
361: this .fontFamily = newFontFamily;
362:
363: clearLayoutsQuiet();
364:
365: if (stroke != null || fill != null) {
366: renderingDirty();
367: }
368: }
369:
370: /**
371: * Sets the value of the computed text anchor property.
372: *
373: * @param newTextAnchor the new value for the computed text anchor property.
374: */
375: public void setTextAnchor(final int newTextAnchor) {
376: super .setTextAnchor(newTextAnchor);
377:
378: if (stroke != null || fill != null) {
379: renderingDirty();
380: }
381: }
382:
383: /**
384: * @param newFontWeight new computed value for the font-weight property.
385: */
386: public void setFontWeight(final int newFontWeight) {
387: super .setFontWeight(newFontWeight);
388:
389: if (stroke != null || fill != null) {
390: renderingDirty();
391: }
392:
393: clearLayoutsQuiet();
394: }
395:
396: /**
397: * @param newFontStyle the new computed font-style property.
398: */
399: public void setFontStyle(final int newFontStyle) {
400: super.setFontStyle(newFontStyle);
401: if (stroke != null || fill != null) {
402: renderingDirty();
403: }
404:
405: clearLayoutsQuiet();
406: }
407:
408: }
|