KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * $Id: Text.java,v 1.5 2002/07/16 20:17:30 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
60 import org.openlaszlo.iv.flash.api.*;
61 import org.openlaszlo.iv.flash.api.text.*;
62 import org.openlaszlo.iv.flash.context.Context;
63
64 /**
65  * This class represent MM Generator undocumented text tag.
66  * <P>
67  * It contains vector of {@link TextItem}s.
68  *
69  * @author Dmitry Skavish
70  */

71 public final class Text extends FlashDef implements TextBlock {
72
73     public static final int PROPERTY_CONTROLLED = 0;
74     public static final int MM_STYLE = 1;
75     public static final int JG_STYLE = 2;
76
77     private boolean withAlpha; // true if color of change record has alpha
78
private Rectangle2D bounds; // original bounds of the text
79
private Rectangle2D genBounds; // bounds from MM Generator tag
80
private int boundsStyle = PROPERTY_CONTROLLED;// jgen or MM bounds style, by default controlled by property
81
private AffineTransform matrix; // matrix of the text
82
private IVVector items = new IVVector();// vector of TextItems
83
private TextLayout myLayout; // layout of this text
84

85     public Text() {}
86
87     public Text( boolean withAlpha ) {
88         this.withAlpha = withAlpha;
89     }
90
91     public static Text newText() {
92         Text t = new Text(true);
93         t.matrix = new AffineTransform();
94         return t;
95     }
96
97     public int getTag() {
98         if( withAlpha ) return Tag.DEFINETEXT2;
99         return Tag.DEFINETEXT;
100     }
101
102     // ------------------------------------------------------- //
103
// TextBlock implementation //
104

105     /**
106      * Layout this text
107      */

108     public void layout() {
109         if( myLayout != null ) return;
110         doLayout();
111     }
112
113     /**
114      * Returns vector of {@link TextRecord}s from this text
115      * of specified font.
116      *
117      * @param font font of text records to be returned
118      * @return text records of specified font
119      */

120     public IVVector getTextRecords( Font font ) {
121         layout();
122         return myLayout.getTextRecords( font );
123     }
124
125     /**
126      * Returns vector of all {@link TextRecord}s and {@link TextStyleChangeRecord}s from this text
127      *
128      * @return all text records
129      */

130     public IVVector getAllTextRecords() {
131         layout();
132         return myLayout.getAllTextRecords();
133     }
134
135     /**
136      * Updates records' font.
137      * <P>
138      * Changes one specified font into another in all records.
139      * In text records also updates indexes.
140      *
141      * @param old_font old font
142      * @param new_font new font
143      */

144     public void changeFont( Font old_font, Font new_font ) {
145         layout();
146         myLayout.changeFont(old_font, new_font);
147     }
148
149     // ------------------------------------------------------- //
150

151     public void setBoundsStyle( int boundsStyle ) {
152         this.boundsStyle = boundsStyle;
153     }
154
155     public int getBoundsStyle() {
156         return boundsStyle;
157     }
158
159     protected void doLayout() {
160         myLayout = new TextLayout(this,genBounds!=null?genBounds:bounds);
161         myLayout.layout();
162     }
163
164     public void collectDeps( DepsCollector dc ) {
165         for( int i=0; i<items.size(); i++ ) {
166             TextItem t = (TextItem) items.elementAt(i);
167             if( t.font != null ) dc.addDep( t.font );
168         }
169     }
170
171     public void collectFonts( FontsCollector fc ) {
172         for( int i=0; i<items.size(); i++ ) {
173             TextItem t = (TextItem) items.elementAt(i);
174             if( t.font != null ) fc.addFont( t.font, this );
175         }
176     }
177
178     public void apply( Context context ) {
179         if( myLayout != null ) return;
180         super.apply( context );
181         for( int i=0; i<items.size(); i++ ) {
182             TextItem t = (TextItem) items.elementAt(i);
183             t.apply( context );
184         }
185         // after applying context text bound could be changed, so we need to layout text
186
doLayout();
187     }
188
189     public boolean isConstant() {
190         for( int i=0; i<items.size(); i++ ) {
191             TextItem t = (TextItem) items.elementAt(i);
192             if( !t.isConstant() ) return false;
193         }
194         return true;
195     }
196
197     public Rectangle2D getBounds() {
198         // do I have to call layout here ? probably yes
199
layout();
200         return bounds;
201     }
202
203     public void setGenBounds( Rectangle2D bounds ) {
204         this.genBounds = bounds;
205     }
206
207     public void setBounds( Rectangle2D bounds ) {
208         this.bounds = bounds;
209     }
210
211     public void setBounds( int x, int y, int width, int height ) {
212         setBounds( GeomHelper.newRectangle(x,y,width,height) );
213     }
214
215     /**
216      * Returns vector of all text items ({@link TextItem}) of this text.
217      *
218      * @return vector of {@link TextItem}
219      */

220     public IVVector getTextItems() {
221         return items;
222     }
223
224     /**
225      * Sets new vector of text items ({@link TextItem}) for this text.
226      *
227      * @param items new vector of {@link TextItem}
228      */

229     public void setTextItems( IVVector items ) {
230         this.items = items;
231     }
232
233     /**
234      * Adds new text item to this text
235      *
236      * @param item new text item to be added
237      * @return added text item
238      */

239     public TextItem addTextItem( TextItem item ) {
240         items.addElement(item);
241         return item;
242     }
243
244     public void setMatrix( AffineTransform matrix ) {
245         this.matrix = matrix;
246     }
247
248     public AffineTransform getMatrix() {
249         return matrix;
250     }
251
252     /**
253      * Parses any DefineText tag.
254      * <P>
255      * If current parsed file is not generator template
256      * then parse text lazy ({@link LazyText}).
257      *
258      * @param p parser to parse with
259      * @param withAlpha with alpha or not
260      * @return LazyText or Text
261      */

262     public static FlashDef parse( Parser p, boolean withAlpha ) {
263         if( !p.getFile().isTemplate() ) {
264             return LazyText.parse( p, withAlpha );
265         } else {
266             Text text = new Text( withAlpha );
267             // get id
268
text.setID( p.getUWord() );
269             // get bounds and matrix
270
text.bounds = p.getRect();
271             text.matrix = p.getMatrix();
272
273             // do not parse futher, generator text tag will follow
274
p.skipLastTag();
275
276             return text;
277         }
278     }
279
280     /**
281      * Parses MM Generator define text tag: 0x2A.
282      * <P>
283      * Creates vector of TextItems
284      */

285     public void parseGenText( Parser p ) {
286         genBounds = p.getRect();
287
288         TextItem item = new TextItem();
289         boolean wasText = false;
290         for(;;) {
291             int code = p.getUByte();
292             if( code == 0 ) {
293                 items.addElement( item );
294                 break;
295             }
296             if( (code&0x80) != 0 ) {
297                 // control record
298
if( wasText ) {
299                     // save text item from previous record
300
items.addElement( item );
301                     item = (TextItem) item.getCopy(null);
302                     item.text = null;
303                     wasText = false;
304                 }
305                 code = code&0x7f;
306                 switch( code ) {
307                     case 0: // bold, italic
308
item.style = p.getUByte();
309                         break;
310                     case 1: // font id
311
item.font = ((FontDef)p.getDef(p.getUWord())).getFont();
312                         break;
313                     case 2: // font height
314
item.height = p.getUWord();
315                         break;
316                     case 3: // color with alpha
317
item.color = Color.parseRGBA(p);
318                         break;
319                     case 4: // 0 - normal, 1 - superscript, 2 - subscript
320
item.script = p.getUByte();
321                         break;
322                     case 5: // kerning
323
item.kerning = p.getWord();
324                         break;
325                     case 8: // left, center, right, justify
326
item.align = p.getUByte();
327                         break;
328                     case 9: // indent
329
item.indent = p.getWord();
330                         break;
331                     case 10: // left margin
332
item.marginleft = p.getWord();
333                         break;
334                     case 11: // right margin
335
item.marginright = p.getWord();
336                         break;
337                     case 12: // line space
338
item.linesp = p.getWord();
339                         break;
340                     default:
341                         // there is nothing we can do, so just eat one byte
342
Log.logRB( Resource.UNKNOWNGENTEXT, new Object JavaDoc[] {Util.b2h(code)} );
343                         p.getUByte();
344                         break;
345                 }
346             } else {
347
348                 String JavaDoc encoding = p.getFile().getEncoding();
349                 int length = code*2;
350                 String JavaDoc mystr;
351
352                 if( item.font != null && (item.font.flags&Font.UNICODE) != 0 ) {
353                     // font is Unicode, so try to convert to Unicode using specified or default
354
// encoding + we need to repair broken DBCS (if any)
355
byte[] buf = p.getTempByteBuf(length);
356                     int size = gen2DBCSbytes(p.getBuf(), p.getPos(), length, buf);
357                     if( encoding == null ) {
358                         mystr = new String JavaDoc(buf, 0, size);
359                     } else {
360                         try {
361                             mystr = new String JavaDoc(buf, 0, size, encoding);
362                         } catch( UnsupportedEncodingException e ) {
363                             Log.log(e);
364                             mystr = new String JavaDoc(buf, 0, size);
365                         }
366                     }
367                     //System.out.println("unicode: '"+mystr+"'\n");
368
} else {
369                     // font is not Unicode, so we must not convert to Unicode, just leave
370
// the characters as is + repair broken DBCS (if any)
371
char[] buf = p.getTempCharBuf(length/2);
372                     int size = gen2DBCSchars(p.getBuf(), p.getPos(), length, buf);
373                     mystr = new String JavaDoc(buf, 0, size);
374                     //System.out.println("normal: '"+mystr+"'\n");
375
}
376
377                 item.text = item.text == null? mystr: item.text+mystr;
378
379                 p.skip(length);
380
381                 wasText = true;
382             }
383         }
384     }
385
386     /**
387      * Converts array of bytes in Macromedia Generator character format
388      * into array of bytes suitable to be processed by encoding converters.
389      * <P>
390      * Chars are considered to be in broken DBCS, result is suitable to be
391      * converted to UNICODE.
392      *
393      * @param buf array of bytes in MM Generator char format
394      * @param pos position in this array
395      * @param length length of this array
396      * @param outbuf output buffer suitable to be converted to Unicode
397      * @return size of output buffer
398      */

399     public static int gen2DBCSbytes( byte[] buf, int pos, int length, byte[] outbuf ) {
400         int size = 0;
401         for( int i=0; i<length; i+=2 ) {
402             byte hi = buf[pos++];
403             byte lo = buf[pos++];
404             if( lo == 0 ) {
405                 outbuf[size++] = hi;
406             } else {
407                 outbuf[size+1] = hi;
408                 outbuf[size] = lo;
409                 size+=2;
410             }
411         }
412         return size;
413     }
414
415     /**
416      * Converts array of bytes in Macromedia Generator character format
417      * into array of DBCS bytes
418      * <P>
419      * Chars are considered to be in broken DBCS, result is DBCS
420      *
421      * @param buf array of bytes in MM Generator char format
422      * @param pos position in this array
423      * @param length length of this array
424      * @param outbuf output buffer, array od DBCS chars
425      * @return size of output buffer
426      */

427     public static int gen2DBCSchars( byte[] buf, int pos, int length, char[] outbuf ) {
428         int size = 0;
429         for( int i=0; i<length; i+=2 ) {
430             int hi = buf[pos++]&0xff;
431             int lo = buf[pos++]&0xff;
432             if( lo == 0 ) {
433                 outbuf[size++] = (char) hi;
434             } else {
435                 outbuf[size++] = (char) ((hi<<8) | lo);
436             }
437         }
438         return size;
439     }
440
441     public void write( FlashOutput fob ) {
442         write(fob, this);
443     }
444
445     public void write( FlashOutput fob, FlashDef def ) {
446         int start = fob.getPos(); // save for tag
447
fob.skip( 6 ); // 6 - long tag
448
fob.writeDefID(def);
449
450         layout();
451         fob.write(bounds);
452         fob.write(matrix);
453
454         myLayout.write(fob);
455
456         int size = fob.getPos()-start-6; // 6 - long tag
457
// we need to generate Tag.DEFINETEXT2 all the time tag because from generator text we get rgba colors
458
fob.writeLongTagAt(Tag.DEFINETEXT2, size, start );
459     }
460
461     public void printContent( PrintStream out, String JavaDoc indent ) {
462         out.println( indent+"Text: id="+getID() );
463         out.println( indent+" bounds: "+bounds );
464         out.println( indent+" genBounds: "+genBounds );
465         out.println( indent+" "+matrix );
466
467         TextItem last = new TextItem();
468         for( int i=0; i<items.size(); i++ ) {
469             TextItem t = (TextItem) items.elementAt(i);
470             out.println( indent+" TextItem: '"+t.text+"'" );
471             if( t.font != last.font ) out.println( indent+" font : '"+t.font.getFontName()+"'" );
472             if( t.height != last.height ) out.println( indent+" height: "+t.height );
473             if( t.style != last.style ) out.println( indent+" style : "+t.style );
474             if( t.align != last.align ) out.println( indent+" align : "+t.align );
475             if( t.indent != last.indent ) out.println( indent+" indent: "+t.indent );
476             if( t.linesp != last.linesp ) out.println( indent+" linesp: "+t.linesp );
477             if( t.kerning != last.kerning ) out.println( indent+" kerning: "+t.kerning );
478             if( t.script != last.script ) out.println( indent+" script: "+t.script );
479             if( t.marginleft != last.marginleft ) out.println( indent+" margin left: "+t.marginleft );
480             if( t.marginright != last.marginright ) out.println( indent+" margin right : "+t.marginright );
481             if( t.color != last.color ) t.color.printContent(out, indent+" ");
482             last = t;
483         }
484     }
485
486     protected FlashItem copyInto( FlashItem item, ScriptCopier copier ) {
487         super.copyInto( item, copier );
488         ((Text)item).withAlpha = withAlpha;
489         ((Text)item).bounds = (Rectangle2D) bounds.clone();
490         ((Text)item).genBounds = genBounds==null?null:(Rectangle2D)genBounds.clone();
491         ((Text)item).matrix = (AffineTransform) matrix.clone();
492         ((Text)item).items = items.getCopy(copier);
493         ((Text)item).myLayout = myLayout==null?null:myLayout.getCopy(copier);
494         return item;
495     }
496
497     public FlashItem getCopy( ScriptCopier copier ) {
498         return copyInto( new Text(), copier );
499     }
500 }
501
Popular Tags