View Javadoc

1   // Copyright 2001-2005, FreeHEP.
2   package org.freehep.graphicsio.swf;
3   
4   import java.awt.Color;
5   import java.awt.geom.AffineTransform;
6   import java.awt.geom.Rectangle2D;
7   import java.io.IOException;
8   import java.util.Vector;
9   
10  import org.freehep.util.io.BitOutputStream;
11  
12  /**
13   * DefineText TAG.
14   * 
15   * @author Mark Donszelmann
16   * @author Charles Loomis
17   * @version $Id: DefineText.java 8584 2006-08-10 23:06:37Z duns $
18   */
19  public class DefineText extends DefinitionTag {
20  
21      protected int character;
22  
23      protected Rectangle2D bounds;
24  
25      protected AffineTransform matrix;
26  
27      protected Vector /* TextRecord */text;
28  
29      public DefineText(int id, Rectangle2D bounds, AffineTransform matrix,
30              Vector /* TextRecord */text) {
31          this();
32          character = id;
33          this.bounds = bounds;
34          this.matrix = matrix;
35          this.text = text;
36      }
37  
38      public DefineText() {
39          super(11, 1);
40      }
41  
42      protected DefineText(int tagID, int version) {
43          super(tagID, version);
44      }
45  
46      public SWFTag read(int tagID, SWFInputStream swf, int len)
47              throws IOException {
48          DefineText tag = new DefineText();
49          tag.read(tagID, swf, len, false);
50          return tag;
51      }
52  
53      protected void read(int tagID, SWFInputStream swf, int len, boolean hasAlpha)
54              throws IOException {
55  
56          character = swf.readUnsignedShort();
57          swf.getDictionary().put(character, this);
58  
59          bounds = swf.readRect();
60          matrix = swf.readMatrix();
61          int glyphBits = swf.readUnsignedByte();
62          int advanceBits = swf.readUnsignedByte();
63  
64          text = new Vector();
65          boolean type1 = swf.readBitFlag();
66          Record record = type1 ? (Record) new RecordType1(swf, glyphBits,
67                  advanceBits, hasAlpha) : (Record) new RecordType0(swf,
68                  glyphBits, advanceBits);
69          while (!record.isEndRecord()) {
70              text.add(record);
71              type1 = swf.readBitFlag();
72              record = type1 ? (Record) new RecordType1(swf, glyphBits,
73                      advanceBits, hasAlpha) : (Record) new RecordType0(swf,
74                      glyphBits, advanceBits);
75          }
76      }
77  
78      public void write(int tagID, SWFOutputStream swf) throws IOException {
79  
80          write(swf, false);
81      }
82  
83      protected void write(SWFOutputStream swf, boolean hasAlpha)
84              throws IOException {
85  
86          swf.writeUnsignedShort(character);
87          swf.writeRect(bounds);
88          swf.writeMatrix(matrix);
89          int glyphBits = 0;
90          int advanceBits = 0;
91          for (int i = 0; i < text.size(); i++) {
92              Record t = (Record) text.get(i);
93              if (t instanceof RecordType0) {
94                  RecordType0 t0 = (RecordType0) t;
95                  glyphBits = Math.max(glyphBits, t0.getGlyphBits());
96                  advanceBits = Math.max(advanceBits, t0.getAdvanceBits());
97              }
98          }
99  
100         swf.writeUnsignedByte(glyphBits);
101         swf.writeUnsignedByte(advanceBits);
102 
103         for (int i = 0; i < text.size(); i++) {
104             Record t = (Record) text.get(i);
105             t.write(swf, glyphBits, advanceBits, hasAlpha);
106         }
107         swf.writeUnsignedByte(0);
108     }
109 
110     public String toString() {
111         StringBuffer s = new StringBuffer();
112         s.append(super.toString() + "\n");
113         s.append("  character:  " + character + "\n");
114         s.append("  bounds:     " + bounds + "\n");
115         s.append("  matrix:     " + matrix + "\n");
116         s.append("  texts:      " + text.size() + "\n");
117         for (int i = 0; i < text.size(); i++) {
118             s.append(text.get(i) + "\n");
119         }
120         return s.toString();
121     }
122 
123     /**
124      * Abstract Superclass for Text Records.
125      */
126     public static abstract class Record {
127         public abstract void write(SWFOutputStream swf, int glyphBits,
128                 int advanceBits, boolean hasAlpha) throws IOException;
129 
130         public abstract boolean isEndRecord();
131     }
132 
133     /**
134      * Text0 Record, for the actual glyphs.
135      */
136     public static class RecordType0 extends Record {
137         private Vector /* GlyphEntry */glyphs = null;
138 
139         public RecordType0() {
140             this.glyphs = new Vector();
141         }
142 
143         public void add(GlyphEntry glyph) {
144             glyphs.add(glyph);
145         }
146 
147         RecordType0(SWFInputStream swf, int glyphBits, int advanceBits)
148                 throws IOException {
149 
150             int glyphCount = (int) swf.readUBits(7);
151             if (glyphCount == 0)
152                 return; // end record
153 
154             glyphs = new Vector();
155             for (int i = 0; i < glyphCount; i++) {
156                 GlyphEntry entry = new GlyphEntry(swf, glyphBits, advanceBits);
157                 glyphs.add(entry);
158             }
159             swf.byteAlign();
160         }
161 
162         public void write(SWFOutputStream swf, int glyphBits, int advanceBits,
163                 boolean hasAlpha) throws IOException {
164 
165             swf.writeUBits(0, 1); // type 0
166             swf.writeUBits(glyphs.size(), 7);
167             for (int i = 0; i < glyphs.size(); i++) {
168                 ((GlyphEntry) glyphs.get(i)).write(swf, glyphBits, advanceBits);
169             }
170             swf.byteAlign();
171         }
172 
173         public boolean isEndRecord() {
174             return glyphs == null;
175         }
176 
177         public int getGlyphBits() {
178             int glyphBits = 0;
179             for (int i = 0; i < glyphs.size(); i++) {
180                 glyphBits = Math.max(glyphBits, ((GlyphEntry) glyphs.get(i))
181                         .getGlyphBits());
182             }
183             return glyphBits;
184         }
185 
186         public int getAdvanceBits() {
187             int advanceBits = 0;
188             for (int i = 0; i < glyphs.size(); i++) {
189                 advanceBits = Math.max(advanceBits,
190                         ((GlyphEntry) glyphs.get(i)).getAdvanceBits());
191             }
192             return advanceBits;
193         }
194 
195         public String toString() {
196             StringBuffer s = new StringBuffer();
197             s.append("    glyphCount: " + glyphs.size() + "\n");
198             s.append("    ");
199             for (int i = 0; i < glyphs.size(); i++) {
200                 s.append(glyphs.get(i) + " ");
201             }
202             s.append("\n");
203             return s.toString();
204         }
205     }
206 
207     /**
208      * Text1 Record, for the attributes of the text.
209      */
210     public static class RecordType1 extends Record {
211         private int fontID = -1;
212 
213         private Color color;
214 
215         private int xOffset, yOffset;
216 
217         private int height; // in TWIPS
218 
219         // only for swf >= 7
220         private Vector /* GlyphEntry */glyphs = null;
221 
222         public RecordType1(int fontID, Color color, int xOffset, int yOffset,
223                 int height) {
224             this.fontID = fontID;
225             this.color = color;
226             this.xOffset = xOffset;
227             this.yOffset = yOffset;
228             this.height = height;
229 
230             glyphs = new Vector();
231         }
232 
233         // only for swf >= 7
234         public void add(GlyphEntry glyph) {
235             glyphs.add(glyph);
236         }
237 
238         RecordType1(SWFInputStream input, int glyphBits, int advanceBits,
239                 boolean hasAlpha) throws IOException {
240             /* int reserved = (int) */ input.readUBits(3);
241             boolean hasFont = input.readBitFlag();
242             boolean hasColor = input.readBitFlag();
243             boolean hasYOffset = input.readBitFlag();
244             boolean hasXOffset = input.readBitFlag();
245 
246             if (hasFont)
247                 fontID = input.readUnsignedShort();
248             if (hasColor)
249                 color = input.readColor(hasAlpha);
250             if (hasXOffset)
251                 xOffset = input.readShort();
252             if (hasYOffset)
253                 yOffset = input.readShort();
254             if (hasFont)
255                 height = input.readUnsignedShort();
256 
257             glyphs = new Vector();
258             if (input.getVersion() >= 7) {
259                 int glyphCount = (int) input.readUnsignedByte();
260                 for (int i = 0; i < glyphCount; i++) {
261                     glyphs.add(new GlyphEntry(input, glyphBits, advanceBits));
262                 }
263             }
264         }
265 
266         public void write(SWFOutputStream swf, int glyphBits, int advanceBits,
267                 boolean hasAlpha) throws IOException {
268 
269             swf.writeBitFlag(true);
270             swf.writeUBits(0, 3);
271             swf.writeBitFlag(fontID >= 0);
272             swf.writeBitFlag(color != null);
273             swf.writeBitFlag(yOffset != 0);
274             swf.writeBitFlag(xOffset != 0);
275 
276             if (fontID >= 0)
277                 swf.writeUnsignedShort(fontID);
278             if (color != null)
279                 swf.writeColor(color, hasAlpha);
280             if (xOffset != 0)
281                 swf.writeShort(xOffset);
282             if (yOffset != 0)
283                 swf.writeShort(yOffset);
284             if (fontID >= 0)
285                 swf.writeUnsignedShort(height);
286 
287             if (swf.getVersion() >= 7) {
288                 swf.writeUnsignedByte(glyphs.size());
289                 for (int i = 0; i < glyphs.size(); i++) {
290                     ((GlyphEntry) glyphs.get(i)).write(swf, glyphBits,
291                             advanceBits);
292                 }
293             }
294         }
295 
296         public int getGlyphBits() {
297             int glyphBits = 0;
298             for (int i = 0; i < glyphs.size(); i++) {
299                 glyphBits = Math.max(glyphBits, ((GlyphEntry) glyphs.get(i))
300                         .getGlyphBits());
301             }
302             return glyphBits;
303         }
304 
305         public int getAdvanceBits() {
306             int advanceBits = 0;
307             for (int i = 0; i < glyphs.size(); i++) {
308                 advanceBits = Math.max(advanceBits,
309                         ((GlyphEntry) glyphs.get(i)).getAdvanceBits());
310             }
311             return advanceBits;
312         }
313 
314         public boolean isEndRecord() {
315             return false;
316         }
317 
318         public String toString() {
319             StringBuffer s = new StringBuffer();
320             s.append("    FontID:  " + fontID + "\n");
321             s.append("    Color:   " + color + "\n");
322             s.append("    xOffset: " + xOffset + "\n");
323             s.append("    yOffset: " + yOffset + "\n");
324             s.append("    height:  " + height + "\n");
325             s.append("    glyphCount (swf >= 7): " + glyphs.size() + "\n");
326             s.append("    ");
327             for (int i = 0; i < glyphs.size(); i++) {
328                 s.append(glyphs.get(i) + " ");
329             }
330             s.append("\n");
331             return s.toString();
332         }
333     }
334 
335     public static class GlyphEntry {
336 
337         private int index;
338 
339         private int advance;
340 
341         public GlyphEntry(int index, int advance) {
342             this.index = index;
343             this.advance = advance;
344         }
345 
346         public GlyphEntry(SWFInputStream input, int glyphBits, int advanceBits)
347                 throws IOException {
348             index = (int) input.readUBits(glyphBits);
349             advance = (int) input.readSBits(advanceBits);
350         }
351 
352         public void write(SWFOutputStream swf, int glyphBits, int advanceBits)
353                 throws IOException {
354 
355             swf.writeUBits(index, glyphBits);
356             swf.writeSBits(advance, advanceBits);
357         }
358 
359         public int getGlyphBits() {
360             return BitOutputStream.minBits(index, false);
361         }
362 
363         public int getAdvanceBits() {
364             return BitOutputStream.minBits(advance, true);
365         }
366 
367         public String toString() {
368             return "GlyphEntry[" + index + "," + advance + "]";
369         }
370     }
371 }