View Javadoc

1   // Copyright 2001, FreeHEP.
2   package org.freehep.graphicsio.swf;
3   
4   import java.awt.geom.Rectangle2D;
5   import java.io.IOException;
6   
7   /**
8    * DefineFont2 TAG.
9    * 
10   * @author Mark Donszelmann
11   * @author Charles Loomis
12   * @author Steve Hannah
13   * @version $Id: DefineFont2.java 8584 2006-08-10 23:06:37Z duns $
14   */
15  public class DefineFont2 extends DefinitionTag implements SWFConstants {
16  
17      private int character;
18  
19      private boolean shiftJIS = false;
20  
21      private boolean ansi = false;
22  
23      private boolean wideOffsets = false;
24  
25      private boolean wideCodes = false;
26  
27      private boolean italic = false;
28  
29      private boolean bold = false;
30  
31      private int languageCode;
32  
33      private String name;
34  
35      private long[] offsets;
36  
37      private long codeOffset;
38  
39      private SWFShape[] shapes;
40  
41      private int[] codes;
42  
43      private int ascent, descent, leading;
44  
45      private short[] advances;
46  
47      private Rectangle2D[] bounds;
48  
49      private KerningRecord[] kerning = new KerningRecord[0];
50  
51      public DefineFont2() {
52          super(48, 3);
53      }
54  
55      public DefineFont2(int character, boolean italic, boolean bold,
56              String name, SWFShape[] shapes, int[] codes) {
57          this(character, false, false, italic, bold, true, true, LANGUAGE_LATIN,
58                  name, shapes, codes, 0, 0, 0, null, null, null);
59      }
60  
61      public DefineFont2(int character, boolean shiftJIS, boolean ansi,
62              boolean italic, boolean bold, boolean wideOffsets,
63              boolean wideCodes, int languageCode, String name,
64              SWFShape[] shapes, int[] codes, int ascent, int descent,
65              int leading, short[] advances, Rectangle2D[] bounds,
66              KerningRecord[] kerning) {
67          this();
68          this.character = character;
69          this.shiftJIS = shiftJIS;
70          this.ansi = ansi;
71          this.italic = italic;
72          this.bold = bold;
73          this.wideOffsets = wideOffsets;
74          this.wideCodes = wideCodes;
75          this.languageCode = languageCode;
76          this.name = name;
77          this.shapes = shapes;
78          this.codes = codes;
79          this.ascent = ascent;
80          this.descent = descent;
81          this.leading = leading;
82          this.advances = advances;
83          this.bounds = bounds;
84          this.kerning = kerning;
85      }
86  
87      public SWFTag read(int tagID, SWFInputStream swf, int len)
88              throws IOException {
89  
90          DefineFont2 tag = new DefineFont2();
91          tag.character = swf.readUnsignedShort();
92          swf.getDictionary().put(tag.character, tag);
93  
94          boolean hasLayout = swf.readBitFlag();
95          tag.shiftJIS = swf.readBitFlag();
96          /* boolean reserved = */ swf.readBitFlag();
97          tag.ansi = swf.readBitFlag();
98          tag.wideOffsets = swf.readBitFlag();
99          tag.wideCodes = swf.readBitFlag();
100         tag.italic = swf.readBitFlag();
101         tag.bold = swf.readBitFlag();
102         tag.languageCode = swf.readLanguageCode();
103 
104         int nameLength = swf.readUnsignedByte();
105         if (swf.getVersion() >= 6) {
106             tag.name = swf.readUTF();
107         } else {
108             tag.name = new String(swf.readByte(nameLength));
109         }
110 
111         int glyphCount = swf.readUnsignedShort();
112 
113         tag.offsets = new long[glyphCount];
114         for (int i = 0; i < glyphCount; i++) {
115             tag.offsets[i] = (tag.wideOffsets) ? swf.readUnsignedInt()
116                     : (long) swf.readUnsignedShort();
117         }
118 
119         tag.codeOffset = (tag.wideOffsets) ? swf.readUnsignedInt() : (long) swf
120                 .readUnsignedShort();
121 
122         tag.shapes = new SWFShape[glyphCount];
123         for (int i = 0; i < glyphCount; i++) {
124             tag.shapes[i] = new SWFShape(swf);
125         }
126 
127         tag.codes = (tag.wideCodes) ? swf.readUnsignedShort(glyphCount) : swf
128                 .readUnsignedByte(glyphCount);
129 
130         if (hasLayout) {
131             tag.ascent = swf.readShort();
132             tag.descent = swf.readShort();
133             tag.leading = swf.readShort();
134             tag.advances = swf.readShort(glyphCount);
135             tag.bounds = new Rectangle2D[glyphCount];
136             for (int i = 0; i < glyphCount; i++) {
137                 tag.bounds[i] = swf.readRect();
138             }
139 
140             int kerningCount = swf.readUnsignedShort();
141             tag.kerning = new KerningRecord[kerningCount];
142             for (int i = 0; i < kerningCount; i++) {
143                 tag.kerning[i] = new KerningRecord(swf, tag.wideCodes);
144             }
145         }
146         return tag;
147     }
148 
149     public void write(int tagID, SWFOutputStream swf) throws IOException {
150         boolean hasLayout = (ascent != 0) || (descent != 0) || (leading != 0)
151                 || (advances != null) || (bounds != null) || (kerning != null);
152 
153         swf.writeUnsignedShort(character);
154         swf.writeBitFlag(hasLayout);
155         swf.writeBitFlag(shiftJIS);
156         swf.writeUBits(0, 1); // reserved
157         swf.writeBitFlag(ansi);
158         swf.writeBitFlag(wideOffsets);
159         swf.writeBitFlag(wideCodes);
160         swf.writeBitFlag(italic);
161         swf.writeBitFlag(bold);
162         if (swf.getVersion() >= 6) {
163             swf.writeLanguageCode(languageCode);
164         } else {
165             swf.writeUnsignedByte(0);
166         }
167 
168         swf.writeUnsignedByte(name.length());
169         if (swf.getVersion() >= 6) {
170             swf.writeUTF(name);
171         } else {
172             swf.writeByte(name.getBytes());
173         }
174 
175         // Shapes
176         swf.pushBuffer();
177         int[] offsets = new int[shapes.length];
178         int inc = wideOffsets ? 4 : 2;
179         inc = (offsets.length + 1) * inc;
180         for (int i = 0; i < shapes.length; i++) {
181             offsets[i] = swf.getBufferLength() + inc;
182             shapes[i].write(swf);
183             swf.byteAlign();
184         }
185         codeOffset = swf.getBufferLength() + inc;
186         swf.popBuffer();
187         swf.writeUnsignedShort(offsets.length);
188 
189         // Offset Table
190         for (int i = 0; i < offsets.length; i++) {
191             if (wideOffsets) {
192                 swf.writeUnsignedInt(offsets[i]);
193             } else {
194                 swf.writeUnsignedShort((int) offsets[i]);
195             }
196         }
197         if (wideOffsets) {
198             swf.writeUnsignedInt(codeOffset);
199         } else {
200             swf.writeUnsignedShort((int) codeOffset);
201         }
202         swf.append();
203 
204         if (wideCodes) {
205             for (int i = 0; i < offsets.length; i++) {
206                 swf.writeUnsignedShort(codes[i]);
207             }
208         } else {
209             for (int i = 0; i < offsets.length; i++) {
210                 swf.writeUnsignedByte(codes[i]);
211             }
212         }
213         if (hasLayout) {
214             swf.writeShort(ascent);
215             swf.writeShort(descent);
216             swf.writeShort(leading);
217             for (int i = 0; i < offsets.length; i++) {
218                 swf.writeShort(advances[i]);
219             }
220             for (int i = 0; i < bounds.length; i++) {
221                 swf.writeRect(bounds[i]);
222             }
223             swf.writeUnsignedShort(kerning.length);
224             for (int i = 0; i < kerning.length; i++) {
225                 kerning[i].write(swf, wideCodes);
226             }
227         }
228     }
229 
230     public long getId() {
231         return character;
232     }
233 
234     public boolean getShiftJIS() {
235         return shiftJIS;
236     }
237 
238     public boolean isAnsi() {
239         return ansi;
240     }
241 
242     public boolean isItalic() {
243         return italic;
244     }
245 
246     public boolean isBold() {
247         return bold;
248     }
249 
250     public boolean hasWideOffsets() {
251         return wideOffsets;
252     }
253 
254     public boolean hasWideCodes() {
255         return wideCodes;
256     }
257 
258     public String getName() {
259         return name;
260     }
261 
262     public SWFShape[] getShapes() {
263         return shapes;
264     }
265 
266     public int[] getCodes() {
267         return codes;
268     }
269 
270     public int getAscent() {
271         return ascent;
272     }
273 
274     public int getDescent() {
275         return descent;
276     }
277 
278     public int getLeading() {
279         return leading;
280     }
281 
282     public short[] getAdvances() {
283         return advances;
284     }
285 
286     public Rectangle2D[] getBounds() {
287         return bounds;
288     }
289 
290     public KerningRecord[] getKerning() {
291         return kerning;
292     }
293 
294     public void setId(int id) {
295         this.character = id;
296     }
297 
298     public void setShiftJIS(boolean shiftJIS) {
299         this.shiftJIS = shiftJIS;
300     }
301 
302     public void setAnsi(boolean ansi) {
303         this.ansi = ansi;
304     }
305 
306     public void setItalic(boolean italic) {
307         this.italic = italic;
308     }
309 
310     public void setBold(boolean bold) {
311         this.bold = bold;
312     }
313 
314     public void setWideOffsets(boolean wideOffsets) {
315         this.wideOffsets = wideOffsets;
316     }
317 
318     public void setWideCodes(boolean wideCodes) {
319         this.wideCodes = wideCodes;
320     }
321 
322     public void setName(String name) {
323         this.name = name;
324     }
325 
326     public void setCodes(int[] codes) {
327         this.codes = codes;
328     }
329 
330     public void setShapes(SWFShape[] shapes) {
331         this.shapes = shapes;
332     }
333 
334     public void setAscent(int ascent) {
335         this.ascent = ascent;
336     }
337 
338     public void setDescent(int descent) {
339         this.descent = descent;
340     }
341 
342     public void setLeading(int leading) {
343         this.leading = leading;
344     }
345 
346     public void setAdvances(short[] advances) {
347         this.advances = advances;
348     }
349 
350     public void setAdvances(int[] advances) {
351         short[] s = new short[advances.length];
352         for (int i = 0; i < s.length; i++) {
353             s[i] = (short) advances[i];
354         }
355         setAdvances(s);
356     }
357 
358     public void setBounds(Rectangle2D[] bounds) {
359         this.bounds = bounds;
360     }
361 
362     public void setKerning(KerningRecord[] kerning) {
363         this.kerning = kerning;
364     }
365 
366     public String toString() {
367         // FIXME: add other stuff...
368         StringBuffer s = new StringBuffer();
369         s.append(super.toString() + "\n");
370         s.append("  character:  " + character + "\n");
371         s.append("  name: " + name + "\n");
372         if (shiftJIS)
373             s.append("  shiftJIS\n");
374         if (ansi)
375             s.append("  ansi\n");
376         if (italic)
377             s.append("  italic\n");
378         if (bold)
379             s.append("  bold\n");
380         if (wideOffsets)
381             s.append("  wideOffsets\n");
382         if (wideCodes)
383             s.append("  wideCodes\n");
384         if (languageCode > 0)
385             s.append("  languageCode: " + languageCode + "\n");
386         if (ascent != 0)
387             s.append("  ascent: " + ascent + "\n");
388         if (descent != 0)
389             s.append("  descent: " + descent + "\n");
390         if (leading != 0)
391             s.append("  leading: " + leading + "\n");
392         if (advances != null) {
393             for (int i = 0; i < advances.length; i++) {
394                 s.append("  advances[" + i + "]: " + advances[i] + "\n");
395             }
396         }
397         if (bounds != null) {
398             for (int i = 0; i < bounds.length; i++) {
399                 s.append("  bounds[" + i + "]: " + bounds[i] + "\n");
400             }
401         }
402         s.append("  glyphCount: " + shapes.length + "\n");
403         for (int i = 0; i < shapes.length; i++) {
404             s.append("  >>> Shape " + i + "\n");
405             s.append(shapes[i] + "\n");
406         }
407 
408         return s.toString();
409     }
410 
411     public static class KerningRecord {
412 
413         private int code1, code2;
414 
415         private int adjustment;
416 
417         public KerningRecord(int code1, int code2, int adjustment) {
418             this.code1 = code1;
419             this.code2 = code2;
420             this.adjustment = adjustment;
421         }
422 
423         public KerningRecord(SWFInputStream input, boolean wideCodes)
424                 throws IOException {
425 
426             code1 = (wideCodes) ? input.readUnsignedShort() : input
427                     .readUnsignedByte();
428             code2 = (wideCodes) ? input.readUnsignedShort() : input
429                     .readUnsignedByte();
430             adjustment = input.readShort();
431         }
432 
433         public void write(SWFOutputStream swf, boolean wideCodes)
434                 throws IOException {
435 
436             if (wideCodes)
437                 swf.writeUnsignedShort(code1);
438             else
439                 swf.writeUnsignedByte(code1);
440             if (wideCodes)
441                 swf.writeUnsignedShort(code2);
442             else
443                 swf.writeUnsignedByte(code2);
444             swf.writeShort(adjustment);
445         }
446 
447         public String toString() {
448             return "Kerning[" + code1 + ", " + code2 + ", " + adjustment + "]";
449         }
450     }
451 
452 }