Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/anotherbigidea/flash/readers/MovieBuilder.java


1   /****************************************************************
2    * Copyright (c) 2001, David N. Main, All rights reserved.
3    * 
4    * Redistribution and use in source and binary forms, with or
5    * without modification, are permitted provided that the 
6    * following conditions are met:
7    *
8    * 1. Redistributions of source code must retain the above 
9    * copyright notice, this list of conditions and the following 
10   * disclaimer. 
11   * 
12   * 2. Redistributions in binary form must reproduce the above 
13   * copyright notice, this list of conditions and the following 
14   * disclaimer in the documentation and/or other materials 
15   * provided with the distribution.
16   * 
17   * 3. The name of the author may not be used to endorse or 
18   * promote products derived from this software without specific 
19   * prior written permission. 
20   * 
21   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 
22   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
23   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
24   * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
25   * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
26   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
27   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
28   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
29   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
30   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
31   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
32   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33   ****************************************************************/
34  package com.anotherbigidea.flash.readers;
35  
36  import java.util.*;
37  import java.io.*;
38  import com.anotherbigidea.flash.*;
39  import com.anotherbigidea.flash.interfaces.*;
40  import com.anotherbigidea.flash.writers.*;
41  import com.anotherbigidea.flash.structs.*;
42  import com.anotherbigidea.flash.movie.*;
43  
44  /**
45   * An implementation of the SWFTagTypes interface that builds a Movie object
46   */
47  public class MovieBuilder implements SWFTagTypes 
48  {
49      protected Movie   movie;
50      protected MovieClip clip;
51      protected boolean newMovie = false;
52      protected Frame   frame;
53      protected Map     symbols = new HashMap();
54      protected TimeLine timeline;
55      protected Map     instances = new HashMap();
56      
57      /**
58       * Build a new Movie
59       */
60      public MovieBuilder()
61      {
62          movie = new Movie();
63          newMovie = true;
64          timeline = movie;
65      }
66      
67      /**
68       * Append to an existing movie (do not change size,rate,color,version etc)
69       */
70      public MovieBuilder( Movie movie )
71      {
72          this.movie = movie;
73          newMovie = false;
74          timeline = movie;
75      }
76      
77      /**
78       * Build the timeline of a MovieClip
79       */
80      protected MovieBuilder( MovieBuilder parent, MovieClip clip )
81      {
82          this.movie     = parent.movie;
83          this.symbols   = parent.symbols;
84          this.clip      = clip;
85          newMovie       = false;
86          timeline       = clip;
87      }    
88      
89      public Movie getMovie() { return movie; }
90      
91      /**
92       * Get the defined symbols - keyed by Integer( symbolId )
93       */
94      public Map getDefinedSymbols() { return symbols; }
95      
96      protected Symbol getSymbol( int id )
97      {
98          return (Symbol)symbols.get( new Integer( id ) );        
99      }
100     
101     protected void saveSymbol( int id, Symbol s )
102     {
103         symbols.put( new Integer(id), s );
104     }
105 
106     protected Instance getInstance( int depth )
107     {
108         return (Instance)instances.get( new Integer( depth ) );        
109     }
110     
111     protected void saveInstance( int depth, Instance inst )
112     {
113         if( inst == null )
114         {
115             try{ throw new Exception();  }
116             catch( Exception ex ) { ex.printStackTrace(); }
117         }
118         instances.put( new Integer(depth), inst );
119     }    
120     
121     /**
122      * SWFTags interface
123      */    
124     public void tag( int tagType, boolean longTag, byte[] contents ) 
125         throws IOException
126     {
127         //ignore unknown tags
128     }
129 
130     /**
131      * SWFHeader interface.
132      */
133     public void header( int version, long length,
134                         int twipsWidth, int twipsHeight,
135                         int frameRate, int frameCount ) throws IOException
136     {
137         if( newMovie )
138         {
139             movie.setVersion( version );
140             movie.setWidth( twipsWidth / SWFConstants.TWIPS );
141             movie.setHeight( twipsHeight / SWFConstants.TWIPS );
142             movie.setFrameRate( frameRate );
143         }
144     }
145     
146     /**
147      * SWFTagTypes interface
148      */
149     public void tagEnd() throws IOException
150     {
151         //nothing to do
152     }
153 
154     /**
155      * SWFTagTypes interface
156      */
157     public void tagShowFrame() throws IOException
158     {
159         //--complete the current frame
160         if( frame == null ) timeline.appendFrame();
161         else frame = null;
162     }
163     
164     protected Frame currentFrame()
165     {
166         if( frame == null ) frame = timeline.appendFrame();            
167         return frame;
168     }
169     
170     //--Tags yet to be implemented...
171     public void tagDefineSound( int id, int format, int frequency,
172                                 boolean bits16, boolean stereo,
173                                 int sampleCount, byte[] soundData ) 
174         throws IOException {}
175     public void tagDefineButtonSound( int buttonId,
176                     int rollOverSoundId, SoundInfo rollOverSoundInfo,
177                     int rollOutSoundId,  SoundInfo rollOutSoundInfo,
178                     int pressSoundId,    SoundInfo pressSoundInfo,
179                     int releaseSoundId,  SoundInfo releaseSoundInfo )
180         throws IOException {}
181     public void tagStartSound( int soundId, SoundInfo info ) throws IOException {}
182     public void tagSoundStreamHead( 
183         int playbackFrequency, boolean playback16bit, boolean playbackStereo,
184         int streamFormat, int streamFrequency, boolean stream16bit, boolean streamStereo,
185         int averageSampleCount ) throws IOException {}
186     public void tagSoundStreamHead2( 
187         int playbackFrequency, boolean playback16bit, boolean playbackStereo,
188         int streamFormat, int streamFrequency, boolean stream16bit, boolean streamStereo,
189         int averageSampleCount ) throws IOException {}
190     public void tagSoundStreamBlock( byte[] soundData ) throws IOException {}
191     public void tagSerialNumber( String serialNumber ) throws IOException {}
192     public void tagGenerator( byte[] data ) throws IOException {}
193     public void tagGeneratorText( byte[] data ) throws IOException {}
194     public void tagGeneratorCommand( byte[] data ) throws IOException {}
195     public void tagGeneratorFont( byte[] data ) throws IOException {}
196     public void tagNameCharacter( byte[] data ) throws IOException {}
197     public void tagDefineBits( int id, byte[] imageData ) throws IOException {}
198     public void tagJPEGTables( byte[] jpegEncodingData ) throws IOException {}
199     public void tagDefineBitsJPEG3( int id, byte[] imageData, byte[] alphaData ) throws IOException {}
200   public SWFActions tagDoInitAction( int spriteId ) throws IOException { return null; }
201     
202     
203     /**
204      * SWFTagTypes interface
205      */
206     public SWFActions tagDoAction() throws IOException
207     {
208         Actions acts = currentFrame().actions( movie.getVersion() );
209         
210         return acts;
211     }
212     
213     /**
214      * SWFTagTypes interface
215      */
216     public SWFShape tagDefineShape( int id, Rect outline ) throws IOException
217     {
218         Shape s = new Shape();
219         s.setBoundingRectangle( ((double)outline.getMinX()) / SWFConstants.TWIPS,
220                                 ((double)outline.getMinY()) / SWFConstants.TWIPS,
221                                 ((double)outline.getMaxX()) / SWFConstants.TWIPS,
222                                 ((double)outline.getMaxY()) / SWFConstants.TWIPS );
223         
224         saveSymbol( id, s );
225         
226         return new ShapeBuilder( s );
227     }
228     
229     /**
230      * SWFTagTypes interface
231      */
232     public SWFShape tagDefineShape2( int id, Rect outline ) throws IOException
233     {
234         Shape s = new Shape();
235         s.setBoundingRectangle( ((double)outline.getMinX()) / SWFConstants.TWIPS,
236                                 ((double)outline.getMinY()) / SWFConstants.TWIPS,
237                                 ((double)outline.getMaxX()) / SWFConstants.TWIPS,
238                                 ((double)outline.getMaxY()) / SWFConstants.TWIPS );
239         
240         saveSymbol( id, s );
241         
242         return new ShapeBuilder( s );
243     }
244     
245     /**
246      * SWFTagTypes interface
247      */
248     public SWFShape tagDefineShape3( int id, Rect outline ) throws IOException
249     {
250         Shape s = new Shape();
251         s.setBoundingRectangle( ((double)outline.getMinX()) / SWFConstants.TWIPS,
252                                 ((double)outline.getMinY()) / SWFConstants.TWIPS,
253                                 ((double)outline.getMaxX()) / SWFConstants.TWIPS,
254                                 ((double)outline.getMaxY()) / SWFConstants.TWIPS );
255         
256         saveSymbol( id, s );
257         
258         return new ShapeBuilder( s );
259     }    
260     
261     /**
262      * SWFTagTypes interface
263      */    
264     public void tagFreeCharacter( int charId ) throws IOException 
265     {
266         //nothing
267     }
268     
269     /**
270      * SWFTagTypes interface
271      */    
272     public void tagPlaceObject( int charId, int depth, 
273                                 Matrix matrix, AlphaTransform cxform ) 
274         throws IOException
275     {
276         Symbol s = getSymbol( charId );
277         if( s == null ) return;
278                 
279         timeline.setAvailableDepth( depth );
280         Instance inst = currentFrame().placeSymbol( s, ( matrix != null ) ? new Transform(matrix): null, cxform );
281         saveInstance( depth, inst );
282     }
283     
284     /**
285      * SWFTagTypes interface
286      */    
287     public SWFActions tagPlaceObject2( boolean isMove,
288                                        int clipDepth,
289                                        int depth,
290                                        int charId,
291                                        Matrix matrix,
292                                        AlphaTransform cxform,
293                                        int ratio,
294                                        String name,
295                                        int clipActionFlags )  
296         throws IOException    
297     {
298         Instance inst = null;
299             
300         if( depth == 59 )                 
301         {
302             //System.out.println( "Place2: " + charId + " isMove=" + isMove + " depth=" + depth + " frame=" + currentFrame().getFrameNumber() );
303         }
304         
305         if( isMove && charId <= 0 )
306         {
307             inst = getInstance( depth );
308             if( inst == null )
309             {                
310                 System.out.println( "Failed to find Instance at depth " + depth );
311                 return null;
312             }
313             
314             currentFrame().alter( inst, ( matrix != null ) ? new Transform(matrix): null, cxform, ratio );
315         }
316         else
317         {
318             Symbol s = getSymbol( charId );
319 
320             if( depth == 59 )                 
321             {
322                 //System.out.println( ">>> " + s );
323             }
324                        
325             if( s == null )
326             {
327                 System.out.println( "Failed to find Symbol with id " + charId );
328                 return null;
329             }
330                 
331             if( name != null )
332             {                
333                 Frame frame = currentFrame();
334                 
335                 if( isMove )
336                 {
337                     inst = frame.replaceMovieClip( s, depth, ( matrix != null ) ? new Transform(matrix): null, 
338                                                    cxform, name, null );
339                 }
340                 else
341                 {
342                     timeline.setAvailableDepth( depth );
343 
344                     inst = frame.placeMovieClip( s, ( matrix != null ) ? new Transform(matrix): null, 
345                                                    cxform, name, null );
346                 }
347                 
348                 saveInstance( depth, inst );                
349             }
350             else if( clipActionFlags != 0 )
351             {
352                 return new ClipActionBuilder( s, matrix, cxform, depth, name, 
353                                               movie.getVersion(), isMove );
354             }
355             else
356             {
357                 Frame frame = currentFrame();
358                 
359                 if( isMove )
360                 {
361                     inst = frame.replaceSymbol( s, depth, ( matrix != null ) ? new Transform(matrix): null, 
362                                                    cxform, ratio, clipDepth );
363                 }
364                 else
365                 {
366                     timeline.setAvailableDepth( depth );
367 
368                     inst = frame.placeSymbol( s, ( matrix != null ) ? new Transform(matrix): null, 
369                                                    cxform, ratio, clipDepth );
370                 }
371 
372                 saveInstance( depth, inst );
373             }
374         }        
375         
376         return null;
377     }
378         
379     /**
380      * SWFTagTypes interface
381      */ 
382     public void tagRemoveObject( int charId, int depth ) throws IOException
383     {     
384         Instance inst = getInstance( depth );
385         if( inst == null ) return;
386         
387         currentFrame().remove( inst );
388     }
389         
390     /**
391      * SWFTagTypes interface
392      */ 
393     public void tagRemoveObject2( int depth ) throws IOException
394     {        
395         Instance inst = getInstance( depth );
396         if( inst == null ) return;
397         
398         currentFrame().remove( inst );
399     }
400 
401     /**
402      * SWFTagTypes interface
403      */ 
404     public void tagSetBackgroundColor( Color color ) throws IOException
405     {
406         if( newMovie ) movie.setBackColor( color );      
407     }
408 
409     /**
410      * SWFTagTypes interface
411      */ 
412     public void tagFrameLabel( String label ) throws IOException
413     {
414     tagFrameLabel( label, false );
415     }
416 
417   /**
418    * SWFTagTypes interface
419    */ 
420   public void tagFrameLabel( String label, boolean isAnchor ) throws IOException
421   {
422     currentFrame().setLabel( label );
423     currentFrame().setAnchor( isAnchor );
424   }
425     
426     /**
427      * SWFTagTypes interface
428      */ 
429     public SWFTagTypes tagDefineSprite( int id ) throws IOException
430     {
431         MovieClip clip = new MovieClip();        
432         saveSymbol( id, clip );
433         
434         return new MovieBuilder( this, clip );
435     }
436     
437     /**
438      * SWFTagTypes interface
439      */ 
440     public void tagProtect( byte[] password ) throws IOException
441     {
442         if( newMovie ) movie.protect( true );
443     }
444     
445     /**
446      * SWFTagTypes interface
447      */ 
448     public void tagEnableDebug( byte[] password ) throws IOException
449     {
450         //not implemented
451     }
452     
453   /**
454    * SWFTagTypes interface
455    */ 
456   public void tagEnableDebug2( byte[] password ) throws IOException
457   {
458     //not implemented
459   }
460           
461     /**
462      * SWFTagTypes interface
463      */ 
464     public SWFVectors tagDefineFont( int id, int numGlyphs ) throws IOException
465     {
466         FontDefinition fontDef = new FontDefinition();
467         Font font = new Font( fontDef );
468         
469         saveSymbol( id, font );
470         
471         return new GlyphBuilder( fontDef, font, numGlyphs );
472     }
473 
474   /**
475    * SWFTagTypes interface
476    */ 
477   public void tagDefineFontInfo( int fontId, String fontName, int flags, int[] codes )
478   {
479     defineFontInfo( fontId, fontName, flags, codes, SWFConstants.LANGUAGE_CODE_NONE );
480   }
481 
482     /**
483      * SWFTagTypes interface
484      */ 
485     public void defineFontInfo( int fontId, String fontName, int flags, int[] codes, int langCode )
486     {
487         Symbol s = getSymbol(fontId);
488         if( s == null || !(s instanceof Font)) return;
489         
490         Font font = (Font)s;
491         FontDefinition def = font.getDefinition();
492         
493         def.setName( fontName );
494 
495         boolean isUnicode  = ( (flags & SWFConstants.FONT_UNICODE)  != 0 );
496         boolean isShiftJIS = ( (flags & SWFConstants.FONT_SHIFTJIS) != 0 );
497         boolean isAnsi     = ( (flags & SWFConstants.FONT_ANSI    ) != 0 );
498         boolean isItalic   = ( (flags & SWFConstants.FONT_ITALIC  ) != 0 );
499         boolean isBold     = ( (flags & SWFConstants.FONT_BOLD    ) != 0 );        
500         
501         def.setFontFlags( isUnicode, isShiftJIS, isAnsi, isItalic, isBold, false );
502         
503         //--set the glyph codes
504         List glyphs = font.getGlyphList();
505         int glyphCount = glyphs.size();
506         
507         for( int i = 0; i < codes.length && i < glyphCount; i++ )
508         {
509             int code = codes[i];
510             font.setCode( i, code );
511         }
512         
513         font.setLanguageCode( langCode );
514     }
515 
516   /**
517    * SWFTagTypes interface
518    */ 
519   public void tagDefineFontInfo2( int fontId, String fontName, int flags, int[] codes, int langCode ) {
520     defineFontInfo( fontId, fontName, flags, codes, langCode );    
521   }
522 
523     
524     /**
525      * SWFTagTypes interface
526      */ 
527     public SWFVectors tagDefineFont2( int id, int flags, String name, int numGlyphs,
528                                       int ascent, int descent, int leading,
529                                       int[] codes, int[] advances, Rect[] bounds,
530                                       int[] kernCodes1, int[] kernCodes2,
531                                       int[] kernAdjustments ) throws IOException
532     {
533         boolean hasMetrics = ((flags & SWFConstants.FONT2_HAS_LAYOUT) != 0 );
534         boolean isShiftJIS = ((flags & SWFConstants.FONT2_SHIFTJIS  ) != 0 );
535         boolean isUnicode  = ((flags & SWFConstants.FONT2_UNICODE   ) != 0 );
536         boolean isAnsi     = ((flags & SWFConstants.FONT2_ANSI      ) != 0 );
537         boolean isItalic   = ((flags & SWFConstants.FONT2_ITALIC    ) != 0 );
538         boolean isBold     = ((flags & SWFConstants.FONT2_BOLD      ) != 0 );        
539         
540         FontDefinition fontDef = new FontDefinition( 
541                                      name, 
542                                      ((double)ascent)/SWFConstants.TWIPS,
543                                      ((double)descent)/SWFConstants.TWIPS,
544                                      ((double)leading)/SWFConstants.TWIPS,
545                                      isUnicode, isShiftJIS, isAnsi, isItalic,
546                                      isBold, hasMetrics);
547                                      
548         Font font = new Font( fontDef );        
549         saveSymbol( id, font );
550         
551         //--save the kerning info
552         if( hasMetrics && kernCodes1 != null )
553         {
554             List kerns = fontDef.getKerningPairList();
555             
556             for( int i = 0; i < kernCodes1.length; i++ )
557             {
558                 FontDefinition.KerningPair pair = 
559                     new FontDefinition.KerningPair( 
560                                kernCodes1[i],
561                                kernCodes2[i], 
562                                ((double)kernAdjustments[i])/SWFConstants.TWIPS );
563                 
564                 kerns.add( pair );
565             }
566         }
567         
568         return new GlyphBuilder( fontDef, font, codes, advances, bounds );
569     }
570     
571     /**
572      * SWFTagTypes interface
573      */ 
574     public void tagDefineTextField( int fieldId, String fieldName,
575                     String initialText, Rect boundary, int flags,
576                     AlphaColor textColor, int alignment, int fontId, int fontSize, 
577                     int charLimit, int leftMargin, int rightMargin, int indentation,
578                     int lineSpacing ) 
579         throws IOException
580     {
581         Symbol f = getSymbol( fontId );
582         if( f == null || !(f instanceof Font)) return;
583         
584         Font font = (Font)f;
585         
586         EditField field = new EditField( fieldName, initialText, font, 
587                                          ((double)fontSize)/SWFConstants.TWIPS,
588                                          ((double)boundary.getMinX())/SWFConstants.TWIPS,
589                                          ((double)boundary.getMinY())/SWFConstants.TWIPS,
590                                          ((double)boundary.getMaxX())/SWFConstants.TWIPS,
591                                          ((double)boundary.getMaxY())/SWFConstants.TWIPS);
592         
593         field.setTextColor( textColor );
594         field.setAlignment( alignment );
595         field.setCharLimit( charLimit );
596         field.setLeftMargin ( ((double)leftMargin )/SWFConstants.TWIPS );
597         field.setRightMargin( ((double)rightMargin)/SWFConstants.TWIPS );
598         field.setIndentation( ((double)indentation)/SWFConstants.TWIPS );
599         field.setLineSpacing( ((double)lineSpacing)/SWFConstants.TWIPS );
600         
601         boolean isSelectable   = ((flags & SWFConstants.TEXTFIELD_NO_SELECTION ) == 0 );
602         boolean hasBorder      = ((flags & SWFConstants.TEXTFIELD_DRAW_BORDER  ) != 0 ); 
603         boolean isHtml         = ((flags & SWFConstants.TEXTFIELD_HTML         ) != 0 ); 
604         boolean usesSystemFont = ((flags & SWFConstants.TEXTFIELD_FONT_GLYPHS  ) == 0 ); 
605         boolean hasWordWrap    = ((flags & SWFConstants.TEXTFIELD_WORD_WRAP    ) != 0 ); 
606         boolean isMultiline    = ((flags & SWFConstants.TEXTFIELD_IS_MULTILINE ) != 0 ); 
607         boolean isPassword     = ((flags & SWFConstants.TEXTFIELD_IS_PASSWORD  ) != 0 ); 
608         boolean isEditable     = ((flags & SWFConstants.TEXTFIELD_DISABLE_EDIT ) == 0 );         
609          
610         field.setProperties( isSelectable, hasBorder, isHtml, usesSystemFont,
611                              hasWordWrap, isMultiline, isPassword, isEditable );
612         
613         saveSymbol( fieldId, field );
614     }
615 
616     /**
617      * SWFTagTypes interface
618      */ 
619     public SWFText tagDefineText( int id, Rect bounds, Matrix matrix )
620         throws IOException
621     { 
622         Text text = new Text( new Transform(matrix) );
623         saveSymbol( id, text );        
624         
625         return new TextBuilder( text );
626     }
627 
628     /**
629      * SWFTagTypes interface
630      */ 
631     public SWFText tagDefineText2( int id, Rect bounds, Matrix matrix ) throws IOException
632     { 
633         Text text = new Text( new Transform(matrix) );
634         saveSymbol( id, text );        
635         
636         return new TextBuilder( text );
637     }
638     
639     /**
640      * SWFTagTypes interface
641      */ 
642     public SWFActions tagDefineButton( int id, Vector buttonRecords )
643         throws IOException
644     {
645         Button but = new Button( false );
646         saveSymbol( id, but );
647         
648         for( Enumeration e = buttonRecords.elements(); e.hasMoreElements(); )
649         {
650             ButtonRecord rec = (ButtonRecord)e.nextElement();
651             
652             Symbol s = getSymbol( rec.getCharId() );
653             if( s == null ) continue;
654             
655             int flags = rec.getFlags();
656             boolean hit  = (( flags & ButtonRecord.BUTTON_HITTEST ) != 0 );
657             boolean up   = (( flags & ButtonRecord.BUTTON_UP      ) != 0 );
658             boolean over = (( flags & ButtonRecord.BUTTON_OVER    ) != 0 );
659             boolean down = (( flags & ButtonRecord.BUTTON_DOWN    ) != 0 );
660             
661             but.addLayer( s, new Transform( rec.getMatrix()), null, 
662                           rec.getLayer(), 
663                           hit, up, down, over );
664         }
665         
666         return new ButtonActionBuilder( but, movie.getVersion() );
667     }
668     
669     /**
670      * SWFTagTypes interface
671      */ 
672     public void tagButtonCXForm( int buttonId, ColorTransform transform ) 
673         throws IOException
674     {
675         Symbol s = getSymbol( buttonId );
676         if( s == null || !(s instanceof Button )) return;
677         
678         Button but = (Button)s;
679         
680         List layers = but.getButtonLayers();
681         
682         //apply the transform to all the layers of the button
683         for( Iterator it = layers.iterator(); it.hasNext(); )
684         {
685             Button.Layer layer = (Button.Layer)it.next();
686             
687             layer.setColoring( new AlphaTransform( transform ));
688         }
689     }
690         
691     /**
692      * SWFTagTypes interface
693      */ 
694     public SWFActions tagDefineButton2( int id, 
695                                         boolean trackAsMenu, 
696                                         Vector buttonRecord2s )
697         throws IOException
698     {
699         Button but = new Button( trackAsMenu );
700         saveSymbol( id, but );
701         
702         for( Enumeration e = buttonRecord2s.elements(); e.hasMoreElements(); )
703         {
704             ButtonRecord2 rec = (ButtonRecord2)e.nextElement();
705             
706             Symbol s = getSymbol( rec.getCharId() );
707             if( s == null ) continue;
708             
709             int flags = rec.getFlags();
710             boolean hit  = (( flags & ButtonRecord.BUTTON_HITTEST ) != 0 );
711             boolean up   = (( flags & ButtonRecord.BUTTON_UP      ) != 0 );
712             boolean over = (( flags & ButtonRecord.BUTTON_OVER    ) != 0 );
713             boolean down = (( flags & ButtonRecord.BUTTON_DOWN    ) != 0 );
714             
715             but.addLayer( s, new Transform( rec.getMatrix()), rec.getTransform(), 
716                           rec.getLayer(), 
717                           hit, up, down, over );
718         }
719         
720         return new ButtonActionBuilder( but, movie.getVersion() );
721     }
722 
723     /**
724      * SWFTagTypes interface
725      */ 
726     public void tagExport( String[] names, int[] ids ) throws IOException
727     {
728         Symbol[] symbols = new Symbol[ ids.length ];
729         
730         for( int i = 0; i < ids.length; i++ )
731         {
732             symbols[i] = getSymbol(ids[i]);
733         }
734         
735         movie.exportSymbols( names, symbols );
736     }
737     
738     /**
739      * SWFTagTypes interface
740      */ 
741     public void tagImport( String movieName, String[] names, int[] ids ) 
742         throws IOException
743     {
744         movie.importSymbols( movieName, names );
745     }
746     
747     /**
748      * SWFTagTypes interface
749      */ 
750     public void tagDefineQuickTimeMovie( int id, String filename ) throws IOException
751     {
752         saveSymbol( id, new QTMovie( filename ) );
753     }
754     
755     /**
756      * SWFTagTypes interface
757      */ 
758     public void tagDefineBitsJPEG2( int id, byte[] data ) throws IOException
759     {
760         saveSymbol( id, new Image.JPEG( data ) );
761     }
762     
763     /**
764      * SWFTagTypes interface
765      */ 
766     public void tagDefineBitsJPEG2( int id, InputStream jpegImage ) throws IOException
767     {
768         saveSymbol( id, new Image.JPEG( jpegImage ) );
769     }
770     
771     /**
772      * SWFTagTypes interface
773      */ 
774     public void tagDefineBitsLossless( int id, int format, int width, int height,
775                                        Color[] colors, byte[] imageData )
776         throws IOException
777     {
778         saveSymbol( id, new Image.Lossless( colors, imageData, 
779                                             ((double)width)/SWFConstants.TWIPS,
780                                             ((double)height)/SWFConstants.TWIPS,
781                                             false, format ));
782     }
783     
784     /**
785      * SWFTagTypes interface
786      */ 
787     public void tagDefineBitsLossless2( int id, int format, int width, int height,
788                                         Color[] colors, byte[] imageData )
789         throws IOException
790     {
791         saveSymbol( id, new Image.Lossless( colors, imageData, 
792                                             ((double)width)/SWFConstants.TWIPS,
793                                             ((double)height)/SWFConstants.TWIPS,
794                                             true, format ));
795     }
796     
797     /**
798      * SWFTagTypes interface
799      */ 
800     public SWFShape tagDefineMorphShape( int id, Rect startBounds, Rect endBounds ) 
801         throws IOException
802     {
803         return new MorphShapeBuilder( id, startBounds, endBounds );
804     }    
805     
806     /**
807      * A SWFActions implementation that breaks multiple action arrays into
808      * separate Actions objects
809      */
810     protected static class ActionsBuilder extends SWFActionsImpl 
811     {
812         protected int version;
813         protected Vector actions = new Vector();
814         
815         protected ActionsBuilder( int flashVersion )
816         {
817             super( null );
818             version = flashVersion;
819         }
820         
821         public Actions[] getActions()
822         {
823             Actions[] a = new Actions[ actions.size() ];
824             actions.copyInto( a );
825             return a;
826         }
827         
828         public void start( int conditions )
829         {
830             acts = new Actions( conditions, version );
831             actions.addElement( acts );
832         }    
833     }
834     
835     protected class ButtonActionBuilder extends MovieBuilder.ActionsBuilder 
836     {
837         protected Button but;
838         
839         protected ButtonActionBuilder( Button b, int flashVersion )
840         {
841             super( flashVersion );
842             but = b;
843         }
844         
845         public void start( int conditions )
846         {
847             //--DefineButton has implicit conditions..
848             if( conditions == 0 ) conditions = SWFConstants.BUTTON2_OVERDOWN2OVERUP;
849             
850             acts = but.addActions( conditions, version );
851         }        
852     }
853     
854     protected class ClipActionBuilder extends MovieBuilder.ActionsBuilder
855     {
856         protected Symbol symbol;
857         protected Transform matrix;
858         protected AlphaTransform cxform;
859         protected String name;
860         protected int depth;
861         protected boolean isMove;
862 
863         protected ClipActionBuilder( Symbol symbol, Matrix matrix, 
864                                      AlphaTransform cxform, int depth,
865                                      String name, int version, boolean isMove )
866         {
867             super( version );
868             this.symbol = symbol;
869             this.matrix = (matrix != null) ? new Transform(matrix) : null;
870             this.cxform = cxform;
871             this.name   = name;            
872             this.depth  = depth;
873             this.isMove = isMove;
874         }
875         
876         /**
877          * All actions are done - place the instance
878          */
879         public void done() throws IOException
880         {
881             Frame frame = currentFrame();
882             
883             Instance inst = null;
884             
885             if( isMove )
886             {
887                 frame.replaceMovieClip( symbol, depth, matrix, cxform, name, getActions() );
888             }
889             else
890             {
891                 timeline.setAvailableDepth( depth );
892             
893                 frame.placeMovieClip( symbol, matrix, cxform, name, getActions() );
894             }
895             
896             saveInstance( depth, inst );
897         }                
898     }
899 
900     /**
901      * SWFShape implementation that builds a Shape
902      */
903     protected class ShapeBuilder implements SWFShape 
904     {
905         protected Shape s;
906         protected int currx, curry;
907         
908         protected ShapeBuilder( Shape s )
909         {
910             this.s = s;
911         }
912 
913         public void done()
914         {
915             //nothing
916         }
917     
918         public void line( int dx, int dy )
919         {
920             currx += dx;
921             curry += dy;
922             
923             s.line( ((double)currx) / SWFConstants.TWIPS,
924                     ((double)curry) / SWFConstants.TWIPS );
925         }
926     
927         public void curve( int cx, int cy, int dx, int dy )
928         {
929             cx += currx;
930             cy += curry;
931             
932             currx = cx + dx;
933             curry = cy + dy;
934             
935             s.curve( ((double)currx) / SWFConstants.TWIPS,
936                      ((double)curry) / SWFConstants.TWIPS,
937                      ((double)cx   ) / SWFConstants.TWIPS,
938                      ((double)cy   ) / SWFConstants.TWIPS );
939         }
940     
941         public void move( int x, int y )
942         {
943             currx = x;
944             curry = y;
945             
946             s.move( ((double)currx) / SWFConstants.TWIPS,
947                     ((double)curry) / SWFConstants.TWIPS );
948         }
949         
950         public void setFillStyle0( int styleIndex )
951         {
952             s.setLeftFillStyle( styleIndex );
953         }
954     
955         public void setFillStyle1( int styleIndex )
956         {
957             s.setRightFillStyle( styleIndex );
958         }
959     
960         public void setLineStyle( int styleIndex )
961         {
962             s.setLineStyle( styleIndex );
963         }
964 
965         public void defineFillStyle( Color color )
966         {
967             s.defineFillStyle( color );
968         }
969 
970         public void defineFillStyle( Matrix matrix, int[] ratios,
971                                      Color[] colors, boolean radial )
972         {
973             s.defineFillStyle( colors, ratios, new Transform(matrix), radial );
974         }
975 
976         public void defineFillStyle( int bitmapId, Matrix matrix, boolean clipped )
977         {
978             Symbol image = getSymbol( bitmapId );           
979             s.defineFillStyle( image, new Transform(matrix), clipped );
980         }
981     
982         public void defineLineStyle( int width, Color color )
983         {
984             s.defineLineStyle( ((double)width)/SWFConstants.TWIPS, color );
985         }
986     }
987     
988     protected class MorphShapeBuilder extends MovieBuilder.ShapeBuilder 
989     {
990         protected int id;
991         protected Rect startBounds;
992         protected Rect endBounds;
993         protected Shape shape1;
994         
995         protected MorphShapeBuilder( int id, Rect startBounds, Rect endBounds )
996         {
997             super( new Shape() );
998             this.id          = id;
999             this.startBounds = startBounds;
1000            this.endBounds   = endBounds;
1001        }
1002                
1003        public void done()
1004        {
1005            if( shape1 == null )
1006            {
1007                shape1 = s;
1008                s = new Shape();
1009                return;
1010            }
1011            
1012            Shape shape2 = s;
1013            
1014            MorphShape morph = new MorphShape( shape1, shape2 );
1015            saveSymbol( id, morph );
1016        }        
1017    }
1018    
1019    protected class GlyphBuilder extends MovieBuilder.ShapeBuilder 
1020    {
1021        protected FontDefinition fontDef;
1022        protected Font   font;
1023        protected int    count;
1024        protected int[]  advances;
1025        protected int[]  codes;
1026        protected Rect[] bounds;
1027        protected List defGlyphs;
1028        protected List fontGlyphs;
1029        protected int index = 0;
1030        
1031        public GlyphBuilder( FontDefinition fontDef, Font font, int glyphCount )
1032        {
1033            super( new Shape() );
1034
1035            this.fontDef = fontDef;
1036            this.font    = font;
1037            this.count   = glyphCount;
1038            
1039            defGlyphs  = fontDef.getGlyphList();
1040            fontGlyphs = font.getGlyphList();
1041        }
1042
1043        public GlyphBuilder( FontDefinition fontDef, Font font, int[] codes,
1044                             int[] advances, Rect[] bounds )
1045        {
1046            this( fontDef, font, codes.length );
1047            this.codes    = codes;
1048            this.advances = advances;
1049            this.bounds   = bounds;
1050        }
1051        
1052        public void done()
1053        {
1054            if( index >= count ) return;
1055            
1056            if( bounds != null )
1057            {
1058                Rect r = bounds[index];
1059                s.setBoundingRectangle( ((double)r.getMinX())/SWFConstants.TWIPS, 
1060                                        ((double)r.getMinY())/SWFConstants.TWIPS,
1061                                        ((double)r.getMaxX())/SWFConstants.TWIPS,
1062                                        ((double)r.getMaxY())/SWFConstants.TWIPS );
1063            }
1064            
1065            double advance = (advances != null) ?
1066                                 (((double)advances[index])/SWFConstants.TWIPS ) :
1067                                 0.0;
1068            
1069            int code = (codes != null) ? codes[index] : 0;
1070            
1071            FontDefinition.Glyph g = new FontDefinition.Glyph( s, advance, code ); 
1072            
1073            defGlyphs .add( g );
1074            font.addGlyph( g );
1075            
1076            index++;
1077            
1078            if( index < count ) s = new Shape();
1079        }        
1080    }
1081    
1082    /**
1083     * A SWFText implementation that builds a Text object
1084     */
1085    protected class TextBuilder implements SWFText 
1086    {
1087        protected Text t;
1088        protected Font font;
1089        protected double size;
1090        protected Color color;
1091        protected double x;
1092        protected double y;
1093        protected boolean hasX;
1094        protected boolean hasY;
1095        
1096        protected TextBuilder( Text text )
1097        {
1098            t = text;
1099        }
1100
1101        /**
1102         * SWFText interface
1103         */
1104        public void font( int fontId, int textHeight )
1105        {
1106            Symbol f = getSymbol( fontId );
1107            if( f == null || !(f instanceof Font)) return;
1108            
1109            font = (Font)f;
1110            size = ((double)textHeight)/SWFConstants.TWIPS;
1111        }
1112    
1113        /**
1114         * SWFText interface
1115         */
1116        public void color( Color color )
1117        {
1118            this.color = color;
1119        }
1120    
1121        /**
1122         * SWFText interface
1123         */
1124        public void setX( int x )
1125        {
1126            hasX = true;
1127            this.x = ((double)x)/SWFConstants.TWIPS;
1128        }
1129
1130        /**
1131         * SWFText interface
1132         */
1133        public void setY( int y )
1134        {
1135            hasY = true;
1136            this.y = ((double)y)/SWFConstants.TWIPS;
1137        }
1138    
1139        /**
1140         * SWFText interface
1141         */
1142        public void text( int[] glyphIndices, int[] glyphAdvances )
1143        {
1144            List glyphs = font.getGlyphList();
1145            char[] chars = new char[ glyphIndices.length ];
1146            
1147            for( int i = 0; i < glyphIndices.length; i++ )
1148            {
1149                int index = glyphIndices[i];
1150                double advance = ((double)glyphAdvances[i])/SWFConstants.TWIPS;
1151                
1152                //normalize the advance
1153                advance = advance * (1024.0/SWFConstants.TWIPS)/size;
1154                
1155                FontDefinition.Glyph g = (FontDefinition.Glyph)glyphs.get(index);
1156                
1157                chars[i] = (char)g.getCode();
1158                                                
1159                //--retrofit the glyph advance - this will tend to cancel out
1160                // any kerning (unfortunately)
1161                if( advance > g.getAdvance() ) g.setAdvance( advance );
1162            }
1163            
1164            try
1165            {
1166                Font.Chars cc = font.chars( new String(chars), size );
1167            
1168                t.row( cc, color, x, y, hasX, hasY );
1169            }
1170            catch( Font.NoGlyphException nge ) {}
1171            
1172            color = null;
1173            hasX = false;
1174            hasY = false;
1175        }
1176    
1177        /**
1178         * SWFText interface
1179         */