View Javadoc

1   // Copyright 2001-2006, FreeHEP.
2   package org.freehep.graphicsio.swf;
3   
4   import java.io.IOException;
5   import java.util.Vector;
6   
7   import org.freehep.util.io.BitOutputStream;
8   
9   /**
10   * Shape TAG.
11   * 
12   * @author Mark Donszelmann
13   * @author Charles Loomis
14   * @version $Id: SWFShape.java 9979 2006-11-27 22:51:07Z duns $
15   */
16  public class SWFShape {
17  
18      private int numFillBits;
19  
20      private int numLineBits;
21  
22      protected FillStyleArray fillStyles;
23  
24      protected LineStyleArray lineStyles;
25  
26      private Vector records;
27  
28      public SWFShape(Vector records) {
29          this.records = records;
30      }
31  
32      // for font shapes
33      public SWFShape(SWFInputStream input) throws IOException {
34          this(input, null, null, false, false, false);
35      }
36  
37      public SWFShape(SWFInputStream input, FillStyleArray fillStyles,
38              LineStyleArray lineStyles, boolean isMorphStyle, boolean hasAlpha, boolean hasStyles)
39              throws IOException {
40  
41          this.fillStyles = fillStyles;
42          this.lineStyles = lineStyles;
43  
44          input.byteAlign();
45          numFillBits = (int) input.readUBits(4);
46          numLineBits = (int) input.readUBits(4);
47  
48          records = new Vector();
49  
50          boolean endOfShape = false;
51          do {
52              boolean edge = input.readBitFlag();
53              if (edge) {
54                  // Edge Record
55                  records.add(new EdgeRecord(input));
56              } else {
57                  // Shape Record
58                  int state = (int) input.readUBits(5);
59                  if (state == 0) {
60                      endOfShape = true;
61                  } else {
62                      records.add(new ShapeRecord(this, input, numFillBits,
63                              numLineBits, isMorphStyle, hasAlpha, hasStyles, state));
64                  }
65              }
66          } while (!endOfShape);
67      }
68  
69      // for font shapes
70      public void write(SWFOutputStream swf) throws IOException {
71          write(swf, false, false, false);	// FIXME, false for hasStyles is a guess.
72      }
73  
74      public void write(SWFOutputStream swf, boolean isMorphStyle, boolean hasAlpha, boolean hasStyles) throws IOException {
75          swf.byteAlign();
76          int numFillBits = 0;
77          int numLineBits = 0;
78  
79          for (int i = 0; i < records.size(); i++) {
80              Record r = (Record) records.get(i);
81              if (r instanceof ShapeRecord) {
82                  ShapeRecord s = (ShapeRecord) r;
83                  numFillBits = Math.max(numFillBits, s.getNumFillBits());
84                  numLineBits = Math.max(numLineBits, s.getNumLineBits());
85              }
86          }
87          swf.writeUBits(numFillBits, 4);
88          swf.writeUBits(numLineBits, 4);
89  
90          for (int i = 0; i < records.size(); i++) {
91              Record r = (Record) records.get(i);
92              r.write(swf, numFillBits, numLineBits, isMorphStyle, hasAlpha, hasStyles);
93          }
94          swf.writeUBits(0, 6); // End of Shape
95          swf.byteAlign(); // make sure any offset calculations will be correct
96      }
97  
98      void setNumFillBits(int numFillBits) {
99          this.numFillBits = numFillBits;
100     }
101 
102     void setNumLineBits(int numLineBits) {
103         this.numLineBits = numLineBits;
104     }
105 
106     void setFillStyles(FillStyleArray fillStyles) {
107         this.fillStyles = fillStyles;
108     }
109 
110     void setLineStyles(LineStyleArray lineStyles) {
111         this.lineStyles = lineStyles;
112     }
113 
114     public String toString() {
115         StringBuffer s = new StringBuffer();
116         for (int i = 0; i < records.size(); i++) {
117             s.append("    ");
118             s.append(i);
119             s.append(":");
120             s.append(records.get(i));
121             s.append("\n");
122         }
123         s.append("    End of shape\n");
124         return s.toString();
125     }
126 
127     /**
128      * Abstract superclass for Records.
129      */
130     public static abstract class Record {
131         public abstract void write(SWFOutputStream swf, int numFillBits,
132                 int numLineBits, boolean isMorphStyle, boolean hasAlpha, boolean hasStyles) throws IOException;
133     }
134 
135     /**
136      * Shape Record, specifying style, move, ...
137      */
138     public static class ShapeRecord extends Record {
139 
140         private static final int MOVE = 0x01;
141 
142         private static final int FILLSTYLE0 = 0x02;
143 
144         private static final int FILLSTYLE1 = 0x04;
145 
146         private static final int LINESTYLE = 0x08;
147 
148         private static final int NEWSTYLES = 0x10;
149 
150         private boolean move;
151 
152         private int moveX = 0;
153 
154         private int moveY = 0;
155 
156         private int fillStyle0 = -1;
157 
158         private int fillStyle1 = -1;
159 
160         private int lineStyle = -1;
161 
162         private FillStyleArray newFillStyles;
163 
164         private LineStyleArray newLineStyles;
165 
166         public ShapeRecord(boolean move, int moveX, int moveY, int fillStyle0,
167                 int fillStyle1, int lineStyle) {
168             this.move = move;
169             this.moveX = moveX;
170             this.moveY = moveY;
171             this.fillStyle0 = fillStyle0;
172             this.fillStyle1 = fillStyle1;
173             this.lineStyle = lineStyle;
174         }
175 
176         ShapeRecord(SWFShape shape, SWFInputStream input, int numFillBits,
177                 int numLineBits, boolean isMorphStyle, boolean hasAlpha, boolean hasStyles,
178                 int state) throws IOException {
179 
180             if ((state & MOVE) > 0) {
181                 move = true;
182                 int numMoveBits = (int) input.readUBits(5);
183                 moveX = (int) input.readSBits(numMoveBits);
184                 moveY = (int) input.readSBits(numMoveBits);
185             }
186 
187             if ((state & FILLSTYLE0) > 0)
188                 fillStyle0 = (int) input.readUBits(numFillBits);
189             if ((state & FILLSTYLE1) > 0)
190                 fillStyle1 = (int) input.readUBits(numFillBits);
191             if ((state & LINESTYLE) > 0)
192                 lineStyle = (int) input.readUBits(numLineBits);
193 
194             if ((state & NEWSTYLES) > 0) {
195                 newFillStyles = new FillStyleArray(input, isMorphStyle,
196                         hasAlpha);
197                 shape.setFillStyles(newFillStyles);
198                 newLineStyles = new LineStyleArray(input, isMorphStyle,
199                         hasAlpha, hasStyles);
200                 shape.setLineStyles(newLineStyles);
201 
202                 numFillBits = (int) input.readUBits(4);
203                 shape.setNumFillBits(numFillBits);
204                 numLineBits = (int) input.readUBits(4);
205                 shape.setNumLineBits(numLineBits);
206             }
207         }
208 
209         public void write(SWFOutputStream swf, int numFillBits,
210                 int numLineBits, boolean isMorphStyle, boolean hasAlpha, boolean hasStyles) throws IOException {
211 
212             int state = 0x00;
213             if (newFillStyles != null)
214                 state |= NEWSTYLES;
215             if (lineStyle != -1)
216                 state |= LINESTYLE;
217             if (fillStyle1 != -1)
218                 state |= FILLSTYLE1;
219             if (fillStyle0 != -1)
220                 state |= FILLSTYLE0;
221             if (move)
222                 state |= MOVE;
223             swf.writeUBits(state, 6);
224 
225             if (move) {
226                 int numMoveBits = Math.max(BitOutputStream.minBits(moveX, true), BitOutputStream
227                         .minBits(moveY, true));
228                 swf.writeUBits(numMoveBits, 5);
229                 swf.writeSBits(moveX, numMoveBits);
230                 swf.writeSBits(moveY, numMoveBits);
231             }
232 
233             if (fillStyle0 != -1)
234                 swf.writeUBits(fillStyle0, numFillBits);
235             if (fillStyle1 != -1)
236                 swf.writeUBits(fillStyle1, numFillBits);
237             if (lineStyle != -1)
238                 swf.writeUBits(lineStyle, numLineBits);
239 
240             if (newFillStyles != null) {
241                 newFillStyles.write(swf, isMorphStyle, hasAlpha);
242                 newLineStyles.write(swf, isMorphStyle, hasAlpha, hasStyles);
243                 swf.writeUBits(numFillBits, 4);
244                 swf.writeUBits(numLineBits, 4);
245             }
246         }
247 
248         public int getNumFillBits() {
249             int numFillBits = 0;
250             if (fillStyle0 != -1)
251                 numFillBits = Math.max(numFillBits, BitOutputStream
252                         .minBits(fillStyle0));
253             if (fillStyle1 != -1)
254                 numFillBits = Math.max(numFillBits, BitOutputStream
255                         .minBits(fillStyle1));
256             return numFillBits;
257         }
258 
259         public int getNumLineBits() {
260             return (lineStyle != -1) ? BitOutputStream.minBits(lineStyle) : 0;
261         }
262 
263         public String toString() {
264             StringBuffer s = new StringBuffer();
265             if (move)
266                 s.append("moveto(" + moveX + ", " + moveY + "); ");
267             if (fillStyle0 != -1)
268                 s.append("fillStyle0=" + fillStyle0 + "; ");
269             if (fillStyle1 != -1)
270                 s.append("fillStyle1=" + fillStyle1 + "; ");
271             if (lineStyle != -1)
272                 s.append("lineStyle=" + lineStyle + "; ");
273             if ((newFillStyles != null) || (newLineStyles != null))
274                 s.append("More Styles;\n");
275             if (newFillStyles != null)
276                 s.append(newFillStyles.toString());
277             if (newLineStyles != null)
278                 s.append(newLineStyles.toString());
279             return s.toString();
280         }
281     }
282 
283     /**
284      * Edge Record, specifying lines, curves, ...
285      */
286     public static class EdgeRecord extends Record {
287 
288         boolean curve;
289 
290         int controlDeltaX, controlDeltaY, anchorDeltaX, anchorDeltaY;
291 
292         int deltaX, deltaY;
293 
294         public EdgeRecord(int controlDeltaX, int controlDeltaY,
295                 int anchorDeltaX, int anchorDeltaY) {
296             curve = true;
297             this.controlDeltaX = controlDeltaX;
298             this.controlDeltaY = controlDeltaY;
299             this.anchorDeltaX = anchorDeltaX;
300             this.anchorDeltaY = anchorDeltaY;
301         }
302 
303         public EdgeRecord(int deltaX, int deltaY) {
304             curve = false;
305             this.deltaX = deltaX;
306             this.deltaY = deltaY;
307         }
308 
309         EdgeRecord(SWFInputStream input) throws IOException {
310             curve = !input.readBitFlag();
311             int numBits = (int) input.readUBits(4) + 2;
312             if (curve) {
313                 controlDeltaX = (int) input.readSBits(numBits);
314                 controlDeltaY = (int) input.readSBits(numBits);
315                 anchorDeltaX = (int) input.readSBits(numBits);
316                 anchorDeltaY = (int) input.readSBits(numBits);
317             } else {
318                 if (input.readBitFlag()) {
319                     // general line
320                     deltaX = (int) input.readSBits(numBits);
321                     deltaY = (int) input.readSBits(numBits);
322                 } else {
323                     if (input.readBitFlag()) {
324                         // vertical
325                         deltaX = 0;
326                         deltaY = (int) input.readSBits(numBits);
327                     } else {
328                         // horizontal
329                         deltaX = (int) input.readSBits(numBits);
330                         deltaY = 0;
331                     }
332                 }
333             }
334         }
335 
336         public void write(SWFOutputStream swf, int numFillBits,
337                 int numLineBits, boolean isMorphStyle, boolean hasAlpha, boolean hasStyles) throws IOException {
338 
339             swf.writeBitFlag(true);
340             swf.writeBitFlag(!curve);
341 
342             int numBits = 0;
343             if (curve) {
344                 numBits = Math.max(numBits, BitOutputStream.minBits(controlDeltaX, true));
345                 numBits = Math.max(numBits, BitOutputStream.minBits(controlDeltaY, true));
346                 numBits = Math.max(numBits, BitOutputStream.minBits(anchorDeltaX, true));
347                 numBits = Math.max(numBits, BitOutputStream.minBits(anchorDeltaY, true));
348             } else {
349                 if ((deltaX != 0) && (deltaY != 0)) {
350                     numBits = Math.max(numBits, BitOutputStream.minBits(deltaX, true));
351                     numBits = Math.max(numBits, BitOutputStream.minBits(deltaY, true));
352                 } else {
353                     if (deltaX == 0) {
354                         // vertical
355                         numBits = Math.max(numBits, BitOutputStream.minBits(deltaY, true));
356                     } else {
357                         // horizontal
358                         numBits = Math.max(numBits, BitOutputStream.minBits(deltaX, true));
359                     }
360                 }
361             }
362             swf.writeUBits(numBits - 2, 4);
363 
364             if (curve) {
365                 swf.writeSBits(controlDeltaX, numBits);
366                 swf.writeSBits(controlDeltaY, numBits);
367                 swf.writeSBits(anchorDeltaX, numBits);
368                 swf.writeSBits(anchorDeltaY, numBits);
369             } else {
370                 if ((deltaX != 0) && (deltaY != 0)) {
371                     // general line
372                     swf.writeBitFlag(true);
373                     swf.writeSBits(deltaX, numBits);
374                     swf.writeSBits(deltaY, numBits);
375                 } else {
376                     swf.writeBitFlag(false);
377                     if (deltaX == 0) {
378                         // vertical
379                         swf.writeBitFlag(true);
380                         swf.writeSBits(deltaY, numBits);
381                     } else {
382                         // horizontal
383                         swf.writeBitFlag(false);
384                         swf.writeSBits(deltaX, numBits);
385                     }
386                 }
387             }
388         }
389 
390         public String toString() {
391             if (curve) {
392                 return "rcurveto(" + controlDeltaX + ", " + controlDeltaY
393                         + ", " + anchorDeltaX + ", " + anchorDeltaY + ")";
394             } else {
395                 return "rlineto(" + deltaX + ", " + deltaY + ")";
396             }
397         }
398     }
399 }