KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > iv > flash > api > text > LazyText


1 /*
2  * $Id: LazyText.java,v 1.7 2002/07/17 05:13:37 skavish Exp $
3  *
4  * ==========================================================================
5  *
6  * The JGenerator Software License, Version 1.0
7  *
8  * Copyright (c) 2000 Dmitry Skavish (skavish@usa.net). All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if
22  * any, must include the following acknowlegement:
23  * "This product includes software developed by Dmitry Skavish
24  * (skavish@usa.net, http://www.flashgap.com/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The name "The JGenerator" must not be used to endorse or promote
29  * products derived from this software without prior written permission.
30  * For written permission, please contact skavish@usa.net.
31  *
32  * 5. Products derived from this software may not be called "The JGenerator"
33  * nor may "The JGenerator" appear in their names without prior written
34  * permission of Dmitry Skavish.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL DMITRY SKAVISH OR THE OTHER
40  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  *
49  */

50
51 package org.openlaszlo.iv.flash.api.text;
52
53 import java.io.*;
54 import java.util.*;
55 import java.awt.geom.*;
56
57 import org.openlaszlo.iv.flash.parser.*;
58 import org.openlaszlo.iv.flash.util.*;
59 import org.openlaszlo.iv.flash.api.*;
60 import org.openlaszlo.iv.flash.context.*;
61
62 /**
63  * This class represents DefineText tag.
64  * <P>
65  * Basically it is alredy laid out text.
66  *
67  * @author Dmitry Skavish
68  * @see Text
69  */

70 public final class LazyText extends FlashDef implements TextBlock {
71
72     public static final int HAS_FONT = 0x08;
73     public static final int HAS_COLOR = 0x04;
74     public static final int HAS_YOFFSET = 0x02;
75     public static final int HAS_XOFFSET = 0x01;
76
77     public boolean withAlpha; // true if color with alpha
78
public Rectangle2D bounds; // bounds of the text
79
public AffineTransform matrix; // matrix of the text
80
public IVVector records = new IVVector(); // vector of TextRecord's and TextStyleChangeRecord's
81
private Text text; // reconstructed text
82

83     public LazyText() {}
84
85     public LazyText( boolean withAlpha ) {
86         this.withAlpha = withAlpha;
87     }
88
89     public Rectangle2D getBounds() {
90         if( text != null ) return text.getBounds();
91         return bounds;
92     }
93
94     public void setBounds( Rectangle2D bounds ) {
95         this.bounds = bounds;
96     }
97
98     /**
99      * Returns vector of all text records of this text.
100      *
101      * @return vector of {@link TextRecord} or/and {@link TextStyleChangeRecord}
102      */

103     public IVVector getAllTextRecords1() {
104         if( text != null ) return text.getAllTextRecords();
105         return records;
106     }
107
108     /**
109      * Sets new vector of text records for this text.
110      *
111      * @param records new vector of {@link TextItem} or/and {@link TextStyleChangeRecord}
112      */

113     public void setAllTextRecords( IVVector records ) {
114         this.records = records;
115     }
116
117     /**
118      * Adds new text record to this text
119      *
120      * @param record new text record to be added
121      */

122     public void addTextRecord( TextRecord record ) {
123         records.addElement(record);
124     }
125
126     /**
127      * Adds new text style change record to this text
128      *
129      * @param record new text style change record to be added
130      */

131     public void addTextStyleChangeRecord( TextStyleChangeRecord record ) {
132         records.addElement(record);
133     }
134
135     public void setMatrix( AffineTransform matrix ) {
136         this.matrix = matrix;
137     }
138
139     public AffineTransform getMatrix() {
140         if( text != null ) return text.getMatrix();
141         return matrix;
142     }
143
144     public int getTag() {
145         if( withAlpha ) return Tag.DEFINETEXT2;
146         return Tag.DEFINETEXT;
147     }
148
149     public static LazyText parse( Parser p, boolean withAlpha ) {
150         LazyText text = new LazyText( withAlpha );
151         text._parse( p );
152         return text;
153     }
154
155     public void _parse( Parser p ) {
156         // get id
157
setID( p.getUWord() );
158         // get bounds and matrix
159
bounds = p.getRect();
160         matrix = p.getMatrix();
161
162         // get nBits
163
int nGlyphBits = p.getUByte();
164         int nAdvanceBits = p.getUByte();
165
166         boolean is_swt = p.getFile().isTemplate();
167         boolean is_const = true;
168         //System.out.println("LazyText.parse: nGlyphBits="+nGlyphBits+", nAdvanceBits="+nAdvanceBits);
169

170         // get textrecords
171
Font curFont = null;
172         boolean isData = false;
173         for(;;) {
174             int flags = p.getUByte();
175             if( flags == 0 ) {
176                 break;
177             }
178             //System.out.println("LazyText.parse: flags="+Util.b2h(flags));
179
//if( (flags&0x80) != 0 ) {
180
if( isData || (flags&0x80) == 0 ) {
181                 TextRecord tr = new TextRecord( flags ); // flags contains number of glyphs
182
records.addElement(tr);
183                 // glyph record
184
p.initBits();
185                 for( int i=0; i<flags; i++ ) {
186                     //System.out.println("LazyText.parse: i="+i);
187
int idx = p.getBits(nGlyphBits);
188                     int adv = p.getSBits(nAdvanceBits);
189                     char ch = (char) curFont.codeTable[idx]; // codetable has to be already setup
190
//System.out.println("LazyText.parse: idx="+idx+", adv="+adv+", ch="+ch);
191
tr.add(ch, idx, adv);
192                 }
193                 if( !is_swt && is_const ) {
194                     for( int i=0; i<flags; i++ ) {
195                         if( tr.getChar(i) == '{' && (i+1>=flags || tr.getChar(i+1)!='{') ) {
196                             is_const = false;
197                             break;
198                         }
199                     }
200                 }
201                 //tr.printContent(System.out, "trrecord: ");
202
} else {
203                 // control record
204
TextStyleChangeRecord ts = new TextStyleChangeRecord();
205                 records.addElement(ts);
206                 if( (flags&HAS_FONT) != 0 ) {
207                     // get font definition
208
curFont = ((FontDef)p.getDef(p.getUWord())).getFont();
209                     ts.setFont( curFont );
210                 }
211                 if( (flags&HAS_COLOR) != 0 ) {
212                     // get color
213
ts.setColor( Color.parse(p, withAlpha) );
214                 }
215                 if( (flags&HAS_XOFFSET) != 0 ) {
216                     ts.setX( p.getWord() );
217                 }
218                 if( (flags&HAS_YOFFSET) != 0 ) {
219                     ts.setY( p.getWord() );
220                 }
221                 if( (flags&HAS_FONT) != 0 ) {
222                     ts.setHeight( p.getUWord() );
223                 }
224                 //ts.printContent(System.out, "StyleChange: ");
225
}
226             isData = !isData;
227         }
228         setConstant(is_const);
229     }
230
231     public void write( FlashOutput fob ) {
232         if( text != null ) {
233             text.write(fob, this);
234         } else {
235             int start = fob.getPos(); // save for tag
236
fob.skip( 6 ); // 6 - long tag
237
fob.writeDefID( this );
238             fob.write(bounds);
239             fob.write(matrix);
240
241             // update indexes from font and calculate maximum index and advance value
242
int maxIdx = Integer.MIN_VALUE;
243             int maxAdv = Integer.MIN_VALUE;
244             Font lastFont = null;
245             for( int i=0; i<records.size(); i++ ) {
246                 Object JavaDoc o = records.elementAt(i);
247                 if( o instanceof TextStyleChangeRecord ) {
248                     Font f = ((TextStyleChangeRecord)o).getFont();
249                     if( f != null ) lastFont = f;
250                 } else {
251                     TextRecord tr = (TextRecord) o;
252                     int idx = tr.getMaxIndex();
253                     int adv = tr.getMaxAdvance();
254                     if( idx > maxIdx ) maxIdx = idx;
255                     if( adv > maxAdv ) maxAdv = adv;
256                 }
257
258             }
259             int nGlyphBits = Util.getMinBitsU(maxIdx);
260             int nAdvanceBits = Util.getMinBitsS(maxAdv);
261
262             fob.writeByte(nGlyphBits);
263             fob.writeByte(nAdvanceBits);
264
265             fob.setUserData( new int[] {nGlyphBits, nAdvanceBits} );
266             records.write( fob );
267
268             fob.writeByte(0);
269
270             int size = fob.getPos()-start-6; // 6 - long tag
271
fob.writeLongTagAt( getTag(), size, start );
272         }
273     }
274
275     public void printContent( PrintStream out, String JavaDoc indent ) {
276         out.println( indent+"LazyText: id="+getID() );
277         out.println( indent+" "+bounds );
278         out.println( indent+" "+matrix );
279         records.printContent( out, indent+" " );
280     }
281
282     // ------------------------------------------------------- //
283
// TextBlock implementation //
284
/**
285      * Layouts this text.
286      * <p>
287      * Does nothing, because the text is already laid out.
288      */

289     public void layout() {
290         if( text != null ) text.layout();
291     }
292
293     /**
294      * Returns vector of {@link TextRecord}s from this text
295      * of specified font.
296      *
297      * @param font font of text records to be returned
298      * @return text records of specified font
299      */

300     public IVVector getTextRecords( Font font ) {
301         if( text != null ) return text.getTextRecords(font);
302         IVVector trs = new IVVector();
303         Font lastFont = null;
304         for( int k=0; k<records.size(); k++ ) {
305             Object JavaDoc o = records.elementAt(k);
306             if( o instanceof TextStyleChangeRecord ) {
307                 Font f = ((TextStyleChangeRecord)o).getFont();
308                 if( f != null ) lastFont = f;
309             } else {
310                 if( lastFont == font ) trs.addElement(o);
311             }
312         }
313         return trs;
314     }
315
316     /**
317      * Updates records' font.
318      * <P>
319      * Changes one specified font into another in all records.
320      * In text records also updates indexes.
321      *
322      * @param old_font old font
323      * @param new_font new font
324      */

325     public void changeFont( Font old_font, Font new_font ) {
326         if( text != null ) {
327             text.changeFont(old_font, new_font);
328         } else {
329             FontDef.changeRecordsFont(records, old_font, new_font);
330         }
331     }
332
333     // ------------------------------------------------------- //
334

335     public void collectDeps( DepsCollector dc ) {
336         if( text != null ) {
337             text.collectDeps(dc);
338         } else {
339             for( int i=0; i<records.size(); i++ ) {
340                 FlashItem t = (FlashItem) records.elementAt(i);
341                 if( t instanceof TextStyleChangeRecord ) {
342                     TextStyleChangeRecord ts = (TextStyleChangeRecord) t;
343                     if( ts.getFont() != null ) dc.addDep(ts.getFont());
344                 }
345             }
346         }
347     }
348
349     public void collectFonts( FontsCollector fc ) {
350         if( text != null ) {
351             text.collectFonts(fc);
352         } else {
353             for( int i=0; i<records.size(); i++ ) {
354                 FlashItem t = (FlashItem) records.elementAt(i);
355                 if( t instanceof TextStyleChangeRecord ) {
356                     TextStyleChangeRecord ts = (TextStyleChangeRecord) t;
357                     if( ts.getFont() != null ) fc.addFont( ts.getFont(), this );
358                 }
359             }
360         }
361     }
362
363     /**
364      * if x == 0 && prevX was at the end then append
365      * if x == 0 && prevX was NOT at the end then new item
366      * if x != 0 then check if rest of x != 0 then if they are equal it's 'center'
367      * @return
368      */

369     public Text createText() {
370         Font font = null;
371         Color color = null;
372         int lastX = -1, lastY = 0;
373         int height = 0;
374         int last_rem = 0; // remainder in last line
375
char end_ch = '\0'; // last char in line
376

377         int max_ascent = 0;
378         int max_descent = 0;
379         int first_not_updated = 0;
380
381         boolean newItem = false;
382         IVVector items = new IVVector();
383         TextItem curItem = null;
384         for( int i=0; i<records.size(); ) {
385             Object JavaDoc o = records.elementAt(i++);
386             if( !(o instanceof TextStyleChangeRecord) ) return null;
387             TextStyleChangeRecord tsr = (TextStyleChangeRecord) o;
388             o = records.elementAt(i++);
389             if( !(o instanceof TextRecord) ) return null;
390             TextRecord tr = (TextRecord) o;
391             String JavaDoc str = new String JavaDoc(tr.getText(), 0, tr.getSize());
392
393             //System.out.println("New record: '"+str+"'");
394
// calculate first word size
395
int first_word_size = 0;
396             int k = 0;
397             int max_adv = 0;
398             for(; k<tr.getSize(); k++) if( tr.getChar(k) != ' ' ) break;
399             for(; k<tr.getSize(); k++) {
400                 if( tr.getChar(k) == ' ' ) break;
401                 int adv = tr.getAdvance(k);
402                 if( adv > max_adv ) max_adv = adv;
403                 first_word_size += adv;
404             }
405             first_word_size += max_adv-1;
406             //System.out.println(" first word size="+first_word_size);
407

408             newItem = false;
409             // get new font props
410
if( tsr.getFont() != null ) {
411                 font = tsr.getFont();
412                 height = tsr.getHeight();
413                 newItem = true;
414             }
415
416             if( tsr.getColor() != null ) {
417                 color = tsr.getColor();
418                 if( !(color instanceof AlphaColor) ) {
419                     color = new AlphaColor(color.getRGB());
420                     ((AlphaColor)color).setAlpha(255);
421                 }
422                 newItem = true;
423             }
424             //System.out.println(" newItem="+newItem);
425

426             if( newItem ) {
427                 if( curItem != null ) items.addElement(curItem);
428                 curItem = new TextItem("", font, height, color);
429             }
430
431             // check whether x and y have been changed
432
int newX = tsr.getX();
433             int newY = tsr.getY();
434             boolean x_changed = newX == Integer.MAX_VALUE? false: newX != lastX;
435             boolean y_changed = newY == Integer.MAX_VALUE? false: newY != lastY;
436             //System.out.println(" x_changed="+x_changed+", newX="+newX);
437
//System.out.println(" y_changed="+y_changed+", newY="+newY);
438

439             // calculate linesp
440
/*if( y_changed && i >= 2 ) {
441                 int delta = newY-lastY; // ascent+descent+linesp
442                 int linesp = delta-max_ascent-max_descent;
443                 for(; first_not_updated<items.size(); first_not_updated++ ) {
444                     TextItem item = (TextItem) items.elementAt(first_not_updated);
445                     item.linesp = linesp;
446                 }
447                 max_ascent = 0;
448                 max_descent = 0;
449             }
450
451             if( tsr.getFont() != null ) {
452                 int ascent = (font.ascent * height) / 1024;
453                 //int descent = (font.descent * height) / 1024 + curItem.linesp;
454                 int descent = (font.descent * height) / 1024;
455                 if( ascent > max_ascent ) max_ascent = ascent;
456                 if( descent > max_descent ) max_descent = descent;
457
458             } */

459
460             if( x_changed && y_changed ) {
461                 // next line
462
//if( newX == 0 ) {
463
// normal new line
464
if( end_ch == ' ' && last_rem < first_word_size ) {
465                         // add this text to current item
466
curItem.text += str;
467                     } else {
468                         // it's a newline
469
curItem.text += "\n"+str;
470                     }
471                 //} else {
472
// aligned new line: most likely to right
473
//}
474
} else if( y_changed ) {
475                 // x was not changed, usually it's a first record
476
// if it's a first record do not add newline
477
if( i == 2 ) curItem.text += str;
478                 else {
479                     curItem.text += "\n"+str;
480                 }
481             } else if( x_changed ) {
482                 // y was not change, very strange -> do not properly handle
483
curItem.text += str;
484             } else {
485                 // no x nor y were changed, just add text
486
curItem.text += str;
487             }
488
489             end_ch = str.length() == 0? '\0': str.charAt(str.length()-1);
490             // calculate the end of this record
491
if( x_changed ) lastX = newX;
492             for( int j=0; j<tr.getSize(); j++ ) {
493                 lastX += tr.getAdvance(j);
494             }
495             last_rem = (int) bounds.getMaxX()-lastX;
496             if( y_changed ) lastY = newY;
497         }
498
499         if( curItem != null ) items.addElement(curItem);
500
501         Text text = new Text(withAlpha);
502         text.setBounds(bounds);
503         text.setGenBounds(bounds);
504         text.setMatrix(matrix);
505         text.setTextItems(items);
506         //text.printContent(System.out, "");
507

508         return text;
509     }
510
511     public void apply( Context context ) {
512         if( isConstant() ) return;
513         text = createText();
514         if( text == null ) return;
515         text.apply(context);
516         //text.printContent(System.out, "apply: ");
517
}
518
519     protected boolean _isConstant() {
520         return true;
521     }
522
523     protected FlashItem copyInto( FlashItem item, ScriptCopier copier ) {
524         super.copyInto( item, copier );
525         ((LazyText)item).withAlpha = withAlpha;
526         ((LazyText)item).bounds = (Rectangle2D) bounds.clone();
527         ((LazyText)item).matrix = (AffineTransform) matrix.clone();
528         ((LazyText)item).records = records.getCopy(copier);
529         ((LazyText)item).text = text==null? null: (Text) text.getCopy(copier);
530         return item;
531     }
532
533     public FlashItem getCopy( ScriptCopier copier ) {
534         return copyInto( new LazyText(), copier );
535     }
536 }
537
Popular Tags