KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * $Id: Font.java,v 1.3 2002/07/12 07:46:51 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 org.openlaszlo.iv.flash.parser.Parser;
54 import org.openlaszlo.iv.flash.util.*;
55 import org.openlaszlo.iv.flash.cache.*;
56 import org.openlaszlo.iv.flash.api.*;
57 import org.openlaszlo.iv.flash.api.shape.*;
58 import java.io.*;
59 import java.awt.geom.Rectangle2D JavaDoc;
60
61 /**
62  * This class defines flash font.
63  * <P>
64  * Flash text has been designed to be completely device independent.
65  * Text is guaranteed to look exactly the same on every device, regardless
66  * of which fonts are installed on the client machine.
67  * The SWF format achieves this by including the exact shape of every letter,
68  * number (or other text character) used in the movie. These character shape
69  * definitions are called glyphs.
70  * <P>
71  * Defining each and every glyph increases the size of a SWF file,
72  * particularly if the font is complex. However, it is a necessary tradeoff.
73  * At design time, Flash knows nothing about the capabilities of the client device,
74  * therefore glyphs must always be included in the SWF file, even if the desired font
75  * is already on the client machine.
76  * <P>
77  * To guarantee text is reproduced correctly, SWF also includes the exact position
78  * of every character in a text block. Again, this adds to the file size, but allows
79  * sophisticated text layout effects (like kerning and text wrapping) without requiring
80  * a complex layout engine built into the Flash player.
81  * <P>
82  *
83  * <h4>Glyph Definitions</h4>
84  * <P>
85  * Glyphs are defined once in a standard coordinate
86  * space called the EM square. The same set of glyphs are
87  * used for every point size of a given font. To render a glyph
88  * at different point sizes, the Flash player scales the glyph
89  * from EM coordinates to point-size coordinates.
90  * <P>
91  * Flash fonts do not include any hinting information for improving
92  * the quality of small font sizes. However, antialiasing dramatically
93  * improves the legibility of down-scaled text. Flash text remains
94  * legible down to about 12-points (viewed at 100%). Below that, text
95  * may appear fuzzy and blurred. In any case, it is rare for Flash movies
96  * to be used for large bodies of text with small point sizes.
97  * <P>
98  * TrueType fonts can be readily converted to SWF glyphs. A simple
99  * algorithm can replace the Quadratic B-splines (used by TrueType) with
100  * Quadratic Bezier curves (used by SWF).
101  * <P>
102  *
103  * <H4>The EM Square</H4>
104  * <P>
105  * The EM square is an imaginary square that
106  * is used to size and align glyphs. The EM square is
107  * generally large enough to completely contain all glyphs,
108  * including accented glyphs. It includes the font's ascent,
109  * descent, and some extra spacing to prevent lines of text from
110  * colliding.
111  * <P>
112  * SWF glyphs are always defined on an EM square of 1024 by 1024
113  * units. Glyphs from other sources (such as TrueType fonts) may
114  * be defined on a different EM square. To use these glyphs in SWF,
115  * they should be scaled to fit an EM square of 1024.
116  * <P>
117  *
118  * <H4>Kerning and Advance Values</H4>
119  * <P>
120  * Kerning defines the horizontal distance between two glyphs.
121  * This distance may be smaller or larger than the width of the
122  * left-hand glyph. Some kerning pairs are more aesthetically
123  * pleasing if they are moved closer together.
124  * <P>
125  * SWF stores kerning information as an advance value.
126  * That is, the horizontal advance from one glyph to another.
127  * SWF stores an advance value for every character in a text block.
128  * <P>
129  *
130  * <H4>The DefineFont Tag</H4>
131  * <P>
132  * The <CODE>DefineFont</CODE> tag defines the shape outlines of
133  * each glyph used in a particular font. Only the glyphs that are
134  * used by subsequent <CODE>DefineText</CODE> tags are actually defined.
135  * <P>
136  * The FontId uniquely identifies the font. It can be used by subsequent
137  * <CODE>DefineText</CODE> tags to select the font.
138  * <P>
139  * The offset table and shape table are used together. These tables
140  * have the same number of entries, and there is a one-to-one ordering match
141  * between the order of the offsets, and the order of the shapes.
142  * The offset table points to locations in the shape table. Each offset entry
143  * stores the difference (in bytes) between the start of the offset table and
144  * the location of the corresponding shape:
145  * <CODE><pre>
146  * Location of ShapeRecord[n] = StartOfOffsetTable + OffsetTable[n]
147  * </PRE></CODE>
148  * Because the <CODE>ShapeTable</CODE> immediately follows the <CODE>OffsetTable</CODE>,
149  * the number of entries in both tables can be inferred by dividing
150  * the first offset by two:
151  * <CODE><PRE>
152  * Shape count = OffsetTable[0] / 2
153  * </PRE></CODE>
154  * <P>
155  *
156  * <H4>Mapping to Native Fonts</H4>
157  * <P>
158  * SWF also supports the use of native fonts. Rather than using the
159  * glyph outlines in the DefineFont tag, fonts can be rendered using
160  * the client machine's font engine. Since most native font engines
161  * include hinting techniques, they may produce better results at very
162  * small point sizes.
163  * <P>
164  * The DefineFontInfo tag defines the mapping of a Flash font to a native font.
165  * It includes the font name, font style - bold, italic, or plain, and the
166  * encoding scheme used - ANSI, Unicode or ShiftJIS. It also defines a mapping
167  * of glyph indices to character codes. Thus if 'a' were the first character in
168  * your DefineFont tag, the DefineFontInfo tag would map index zero to the character
169  * code for 'a'.
170  * <P>
171  *
172  * <H4>DefineFont2</H4>
173  * <P>
174  * The DefineFont2 tag extends the functionality of DefineFont.
175  * Enhancements include:
176  * <UL>
177  * <LI>32-bit entries in the OffsetTable, for fonts with more than 64K glyphs.
178  * <li>Mapping to native fonts, by incorporating all the functionality of DefineFontInfo.
179  * <LI>Ascent, descent and leading information.
180  * <LI>An advance table that defines the advance for each glyph (in EM square coordinates).
181  * <LI>A bounds table that defines the bounding-box of each glyph (in EM square coordinates).
182  * <LI>A table of kerning pairs that defines the distance between pairs of glyphs
183  * </UL>
184  * <P>
185  *
186  * <H4>Kerning Record</H4>
187  * <P>
188  * A Kerning Record defines the distance between two glyphs in EM
189  * square coordinates. Certain pairs of glyphs appear more aesthetically
190  * pleasing if they are moved closer together, or farther apart.
191  * The FontKerningCode1 and FontKerningCode2 fields are the character codes
192  * for the left and right characters. The FontKerningAdjustment field is a
193  * signed integer that defines the offset from the advance value of the
194  * left-hand character. The distance between two characters can be calculated
195  * like this:
196  * <CODE><PRE>
197  * Distance = FontAdvanceTable[ord(FontKerningCode1)] + FontKerningAdjustment
198  * </PRE></CODE>
199  *
200  * @author Dmitry Skavish
201  */

202 public final class Font {
203
204     public static final int HAS_LAYOUT = 0x0080;
205     public static final int SHIFT_JIS = 0x0040;
206     public static final int UNICODE = 0x0020;
207     public static final int ANSI = 0x0010;
208     public static final int WIDE_OFFSETS = 0x0008;
209     public static final int WIDE_CODES = 0x0004;
210     public static final int ITALIC = 0x0002;
211     public static final int BOLD = 0x0001;
212
213     public int flags; // flags
214
public String JavaDoc fontName; // font name
215
public String JavaDoc fontKey; // font key in cache (constructed from name and italic and bold flags)
216
public boolean cached = false; // true if font is cached
217
public byte[] fileBuffer; // glyph buffer (usually .swt file buffer)
218
public int[] glyphOffsets; // offsets of glyphs in glyph buffer
219
private BareShape[] glyphs; // shapes of all glyphs (these shapes are parsed from glyph buffer on demand)
220
public int[] codeTable; // array of codes of all characters of the font, index in this array is index in every other array
221
public int blankPos = 0; // index of 'space' (optimization)
222
public int[] advanceTable; // advance values for coresponding characters
223
public int ascent; // ascent of the font
224
public int descent; // descent of the font
225
public int leading; // leading of the font
226
// kerning tables
227
public int[] kernLeftCodes; // left characters in kerning table
228
public int[] kernRightCodes; // right characters in kerning table
229
public int[] kernAdjustment; // adjustment for left-right characters pair in kerning table
230
// not used stuff
231
public byte[] boundsBuffer; // bounds buffer
232
public int boundsOffset; // offset of bounds table in bounds buffer
233
public int boundsLength; // length of bounds table in bounds buffer
234
private Rectangle2D JavaDoc[] bounds; // parsed bounds (parsed from bounds buffer on demand)
235

236     public Font() {
237         init( null );
238     }
239
240     /**
241      * Creates empty font of given name.
242      *
243      * @param fontName name of the created font
244      * @return created empty font
245      */

246     public static Font createDummyFont( String JavaDoc fontName ) {
247         Font f = new Font();
248         f.init( fontName );
249         return f;
250     }
251
252     private void init( String JavaDoc fontName ) {
253         flags = HAS_LAYOUT | ANSI;
254         fontName = fontName;
255         codeTable = new int[] { ' ' };
256         advanceTable = new int[] { 0 };
257         kernRightCodes = kernAdjustment = kernLeftCodes = new int[] { 0 };
258         fileBuffer = new byte[0];
259         glyphOffsets = new int[] { 0, 0 };
260     }
261
262     /**
263      * Returns size of glyphs table.
264      * <P>
265      * Since glyph table has one additional element to hold
266      * offset after the last element then number of glyphs of the font
267      * is one less than the size of the glyph table.
268      *
269      * @return number of glyphs + 1
270      */

271     public int getGlyphTableSize() {
272         return glyphOffsets.length;
273     }
274
275     /**
276      * Returns number of glyphs in the font
277      *
278      * @return number of glyphs
279      */

280     public int getNumGlyph() {
281         return glyphOffsets.length-1;
282     }
283
284     /**
285      * Returns index of specified character in codetable.
286      *
287      * @param ch specified character which index is to be returned
288      * @return index of specified character or -1 if there is no such character
289      */

290     public int getIndex( int ch ) {
291         try {
292             int idx = ch-' '+blankPos;
293             if( codeTable[idx] == ch ) return idx;
294         } catch( ArrayIndexOutOfBoundsException JavaDoc e ) {}
295
296         for( int i=0; i<codeTable.length; i++ ) {
297             if( ch == codeTable[i] ) return i;
298         }
299         return -1;
300     }
301
302     /**
303      * Returns font name
304      *
305      * @return font name
306      */

307     public String JavaDoc getFontName() {
308         return fontName;
309     }
310
311     /**
312      * Returns advance value for the character at specified index.
313      *
314      * @param idx index of character which advance value is to be returned
315      * @return advance value at specified index
316      */

317     public int getAdvanceValue( int idx ) {
318         try {
319             return advanceTable[idx];
320         } catch( Exception JavaDoc e ) {
321             return 0;
322         }
323     }
324
325
326     /**
327      * Return adjustment from kerning table for specified pair of characters
328      * <p>
329      * MAY BE IMPROVED BY USING BINARY SEARCH !!!!!!!!!!!!
330      *
331      * @param ch_left left character
332      * @param ch_right right character
333      * @return adjustment value for the pair of character
334      */

335     public int getKerning( int ch_left, int ch_right ) {
336         for( int i=0; i<kernLeftCodes.length; i++ ) {
337             if( ch_left == kernLeftCodes[i] && ch_right == kernRightCodes[i] ) {
338                 return kernAdjustment[i];
339             }
340         }
341         return 0;
342     }
343
344     /**
345      * Returns array of shapes of all glyphs of this font
346      * <P>
347      * Shapes parsing can be delayed until they are requested by this call
348      *
349      * @return array of font glyphs
350      */

351     public BareShape[] getGlyphs() {
352         if( glyphs == null ) {
353             Parser p = new Parser();
354             glyphs = new BareShape[ getNumGlyph() ];
355             for( int i=0; i<glyphs.length; i++ ) {
356                 p.init(fileBuffer, glyphOffsets[i], fileBuffer.length);
357                 glyphs[i] = BareShape.parseBareShape(p);
358             }
359         }
360         return glyphs;
361     }
362
363     /**
364      * Returns array of bounds of all glyphs of this font
365      *
366      * @return array of glyphs bounds
367      */

368     public Rectangle2D JavaDoc[] getGlyphBounds() {
369         if( bounds == null && boundsBuffer != null ) {
370             Parser p = new Parser();
371             bounds = new Rectangle2D JavaDoc[ getNumGlyph() ];
372             p.init(boundsBuffer, boundsOffset, boundsBuffer.length);
373             for( int i=0; i<bounds.length; i++ ) {
374                 bounds[i] = p.getRect();
375             }
376         }
377         return bounds;
378     }
379
380     /**
381      * Returns true if this font is large then the specified one
382      * <P>
383      * Font is considered large if it has more glyphs and layout
384      *
385      * @param f font to be compared with
386      * @return true if this font is large then the specified one
387      */

388     public boolean isLargeThan( Font f ) {
389         if( getNumGlyph() > f.getNumGlyph() ) return true;
390         if( getNumGlyph() < f.getNumGlyph() ) return false;
391
392         if( (f.flags&Font.HAS_LAYOUT) != 0 && (flags&Font.HAS_LAYOUT) == 0 ) return false;
393         if( (flags&Font.HAS_LAYOUT) != 0 && (f.flags&Font.HAS_LAYOUT) == 0 ) return true;
394
395         return getFontSize() > f.getFontSize();
396     }
397
398     /**
399      * Returns approximate size in bytes occupied by this font
400      * <p>
401      * Used mainly in caching algorithm.
402      *
403      * @return size of this font in bytes
404      */

405     public int getFontSize() {
406         int size = fileBuffer.length;
407         if( codeTable != null ) size += codeTable.length*4;
408         if( advanceTable != null ) size += advanceTable.length*4;
409         if( kernLeftCodes != null ) size += kernLeftCodes.length*4;
410         if( kernRightCodes != null ) size += kernRightCodes.length*4;
411         if( kernAdjustment != null ) size += kernAdjustment.length*4;
412         if( boundsBuffer != null && boundsBuffer != fileBuffer ) size += boundsBuffer.length;
413         return size;
414     }
415
416     public void printContent( PrintStream out, String JavaDoc indent, int id ) {
417         out.println( indent+"Font: id="+id+", fontName="+fontName+", flags="+Util.w2h(flags)+", nGlyph="+(glyphOffsets.length-1) );
418         /*
419         out.println( indent+" Glyphs:" );
420         BareShape[] shapes = getGlyphs();
421         for( int i=0; i<shapes.length; i++ ) {
422             out.println( indent+" i="+i+", code="+codeTable[i]);
423             shapes[i].printContent(out, indent+" ");
424         }
425         */

426         out.print( indent+" CodeTable:" );
427         for( int i=0; i<codeTable.length; i++ ) {
428             if( (i%10) == 0 ) {
429                 out.println(); out.print( indent+" " );
430             }
431             if( (flags&WIDE_CODES) != 0 ) {
432                 out.print( Util.b2h(i)+"["+Util.toPrint( (char)codeTable[i] )+"(0x"+Util.w2h(codeTable[i])+")] " );
433             } else {
434                 out.print( Util.b2h(i)+"["+Util.toPrint( (char)codeTable[i] )+"(0x"+Util.b2h(codeTable[i])+")] " );
435             }
436         }
437         out.println();
438         if( (flags&HAS_LAYOUT) != 0 ) {
439             out.println( indent+" hasLayout: ascent="+ascent+", descent="+descent+", leading="+leading );
440
441             out.println( indent+" bounds: " );
442             Rectangle2D JavaDoc[] bounds = getGlyphBounds();
443             for( int i=0; i<bounds.length; i++ ) {
444                 out.println( indent+" index="+i+", rect: "+bounds[i].toString() );
445             }
446             out.print( indent+" AdvanceTable:" );
447             for( int i=0; i<advanceTable.length; i++ ) {
448                 if( (i%10) == 0 ) {
449                     out.println(); out.print( indent+" " );
450                 }
451                 out.print( Util.b2h(i)+"["+advanceTable[i]+"] " );
452             }
453             out.println();
454             out.println( indent+" KerningTable:" );
455             for( int i=0; i<kernLeftCodes.length; i++ ) {
456                 int lc = kernLeftCodes[i];
457                 int rc = kernRightCodes[i];
458                 int ad = kernAdjustment[i];
459                 if( (flags&WIDE_CODES) != 0 ) {
460                     out.println( indent+" "+"["+Util.toPrint((char)lc)+"(0x"+Util.w2h(lc)+")] --> ["+Util.toPrint((char)rc)+"(0x"+Util.w2h(rc)+")] = "+ad );
461                 } else {
462                     out.println( indent+" "+"["+Util.toPrint((char)lc)+"(0x"+Util.b2h(lc)+")] --> ["+Util.toPrint((char)rc)+"(0x"+Util.b2h(rc)+")] = "+ad );
463                 }
464             }
465         }
466     }
467
468     /**
469      * Copy all data from this font to the specified one
470      *
471      * @param font specified font copy all the data to
472      */

473     public void copyTo( Font font ) {
474         font.flags = flags;
475         font.fontName = fontName;
476         font.fontKey = fontKey;
477         font.fileBuffer = fileBuffer;
478         font.glyphOffsets = glyphOffsets;
479         font.glyphs = glyphs;
480         font.codeTable = codeTable;
481         font.blankPos = blankPos;
482         font.advanceTable = advanceTable;
483         font.boundsBuffer = boundsBuffer;
484         font.boundsOffset = boundsOffset;
485         font.boundsLength = boundsLength;
486         font.bounds = bounds;
487         font.ascent = ascent;
488         font.descent = descent;
489         font.leading = leading;
490         font.kernLeftCodes = kernLeftCodes;
491         font.kernRightCodes = kernRightCodes;
492         font.kernAdjustment = kernAdjustment;
493         /*
494         font.glyphOffsets = new int[glyphOffsets.length];
495         System.arraycopy(glyphOffsets, 0, font.glyphOffsets, 0, glyphOffsets.length);
496         font.codeTable = new int[codeTable.length];
497         System.arraycopy(codeTable, 0, font.codeTable, 0, codeTable.length);
498         font.advanceTable = new int[advanceTable.length];
499         System.arraycopy(advanceTable, 0, font.advanceTable, 0, advanceTable.length);
500         font.kernLeftCodes = new int[kernLeftCodes.length];
501         System.arraycopy(kernLeftCodes, 0, font.kernLeftCodes, 0, kernLeftCodes.length);
502         font.kernRightCodes = new int[kernRightCodes.length];
503         System.arraycopy(kernRightCodes, 0, font.kernRightCodes, 0, kernRightCodes.length);
504         font.kernAdjustment = new int[kernAdjustment.length];
505         System.arraycopy(kernAdjustment, 0, font.kernAdjustment, 0, kernAdjustment.length);*/

506     }
507
508 }
509
Popular Tags