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 */