001: /*****************************************************************************
002: * SWFFile.java
003: * ****************************************************************************/package org.openlaszlo.compiler;
004:
005: import org.openlaszlo.sc.ScriptCompiler;
006: import org.openlaszlo.utils.ChainedException;
007:
008: import org.openlaszlo.iv.flash.util.*;
009: import org.openlaszlo.iv.flash.api.*;
010: import org.openlaszlo.iv.flash.api.button.*;
011: import org.openlaszlo.iv.flash.api.action.*;
012: import org.openlaszlo.iv.flash.api.image.*;
013: import org.openlaszlo.iv.flash.api.sound.*;
014: import org.openlaszlo.iv.flash.api.text.*;
015: import org.openlaszlo.iv.flash.api.shape.*;
016:
017: import java.awt.geom.Rectangle2D;
018: import java.awt.geom.AffineTransform;
019:
020: import java.io.*;
021:
022: import java.util.Properties;
023:
024: import org.apache.log4j.*;
025:
026: /**
027: * Extension of JGenerator FlashFile api used to
028: * constructs the Base SWF Library for an LZX output SWF.
029: *
030: * @author <a href="mailto:bloch@laszlosystems.com">Eric Bloch</a>
031: */
032: class SWFFile extends FlashFile {
033:
034: public static final int TWIP = 20;
035: public static final int KEYCODE_ENTER = 13;
036: public static final int KEYCODE_TAB = 18;
037:
038: private Properties mProperties = null;
039:
040: /**
041: * Return a ActionBlock from the given text.
042: */
043: protected DoAction actionBlock(String s) {
044: return new DoAction(program(s));
045: }
046:
047: /**
048: * Return a program from the given text.
049: */
050: protected Program program(String s) {
051: byte[] action = ScriptCompiler.compileToByteArray(s,
052: mProperties);
053: return new Program(action, 0, action.length);
054: }
055:
056: /**
057: * Export the given def with the given name
058: * @param n name
059: * @param def def
060: */
061: protected void export(String n, FlashDef def) {
062: addDef(def);
063: ExportAssets ea = new ExportAssets();
064: ea.addAsset(n, def);
065: Frame frame = getMainScript().getFrameAt(0);
066: frame.addFlashObject(ea);
067: }
068:
069: /**
070: * Make a 100x100 rectangle
071: */
072: private Shape rectangle() {
073: Shape shape = new Shape();
074: shape.setFillStyle1(FillStyle.newSolid(AlphaColor.white));
075: Rectangle2D r = new Rectangle2D.Double(0, 0, 100 * TWIP,
076: 100 * TWIP);
077: shape.drawRectangle(r);
078: shape.setBounds(r);
079: return shape;
080: }
081:
082: /**
083: * Create the LFC Base Library
084: * @param path to base LFC bytecode library
085: * @param props properties affecting construction
086: */
087: public SWFFile(String path, Properties props) {
088:
089: mProperties = props;
090:
091: try {
092:
093: String s;
094: Script movieClip, empty;
095: ClipActions ca;
096: Instance inst;
097: DoAction block;
098: Frame f0, f1;
099: Program p;
100: Button2 but;
101: VideoStream video;
102: Shape shape;
103: AffineTransform at = new AffineTransform();
104: AffineTransform offScreen = new AffineTransform();
105: int states;
106:
107: Script mainScript = new Script(1);
108: mainScript.setMain();
109: setMainScript(mainScript);
110: Frame frame = getMainScript().getFrameAt(0);
111: Shape rectShape = rectangle();
112:
113: // 1. Button moved offscreen so that it's not vis. rectangle with actions
114: but = new Button2();
115: states = ButtonRecord.HitTest;
116: but.addButtonRecord(new ButtonRecord(states, rectShape, 1,
117: at, new CXForm()));
118: // '18' is the key code for "tab", not sure why.
119: but.addActionCondition(new ActionCondition(
120: KEYCODE_TAB << 9,
121: program("_root.LzKeys.gotKeyDown(9, 'extra');")));
122: offScreen.scale(.1, .1);
123: offScreen.translate(-200 * TWIP, -200 * TWIP);
124: // NOTE: mimic old laszlolibrary.swf; put at depth 9
125: frame.addInstance(but, 9, offScreen, null,
126: "__offscreenkeyclip");
127:
128: // 2. Movieclip called 'entercontrol' with 2 frames.
129: movieClip = new Script(2);
130: // First frame of this movieclip has a stop
131: movieClip.getFrameAt(0).addStopAction();
132: // Second frame of this movieclip has a button with an empty action
133: but = new Button2();
134: states = ButtonRecord.HitTest;
135: but.addButtonRecord(new ButtonRecord(states, rectShape, 1,
136: at, new CXForm()));
137: but.addActionCondition(new ActionCondition(
138: KEYCODE_ENTER << 9, new Program()));
139: movieClip.getFrameAt(1).addInstance(but, 1, null, null);
140: // NOTE: mimic old laszlolibrary.swf; put at depth 11
141: frame.addInstance(movieClip, 11, offScreen, null,
142: "entercontrol");
143:
144: // 3. movieclip called "frameupdate" which has two frames and some clip actions:
145: movieClip = new Script(2);
146: // NOTE: depth=2 required in order for this to work in swf6 for some
147: // unknown reason!
148: inst = frame.addInstance(movieClip, 2, null, null,
149: "frameupdate");
150: ca = new ClipActions();
151: ca.setMask(ClipAction.KEY_DOWN | ClipAction.KEY_UP
152: | ClipAction.MOUSE_DOWN | ClipAction.MOUSE_UP);
153: s = "_root.LzKeyboardKernel.__keyboardEvent(Key.getCode(), 'onkeydown')";
154: ca
155: .addAction(new ClipAction(ClipAction.KEY_DOWN,
156: program(s)));
157: s = "_root.LzKeyboardKernel.__keyboardEvent(Key.getCode(), 'onkeyup')";
158: ca.addAction(new ClipAction(ClipAction.KEY_UP, program(s)));
159: s = "_root.LzMouseKernel.__mouseEvent('onmousedown')";
160: ca.addAction(new ClipAction(ClipAction.MOUSE_DOWN,
161: program(s)));
162: s = "_root.LzMouseKernel.__mouseEvent('onmouseup')";
163: ca
164: .addAction(new ClipAction(ClipAction.MOUSE_UP,
165: program(s)));
166: inst.actions = ca;
167:
168: // 4. A movieclip with the export identifier "empty" that has 1 frame with nothing in it
169: empty = movieClip = new Script(1);
170: export("empty", movieClip);
171:
172: /* No longer required for swf6 and greater
173: // 5. A movieclip with the export identifier "LzMask" that has 1 frame and three layers.
174: // *First layer is a mask layer which has:
175: // A 100x100 square rectangle
176: // *Second layer is an empty movieclip which is named "mask_sub"
177: // *Third layer is a movieclip named "meas" which contains a 100x100 rectangle and these actions:
178: // onClipEvent( load ){
179: // this._visible = false;
180: // }
181: // NOTE: mimic depths from old laszlolibrary.swf
182: movieClip = new Script(1);
183: export("LzMask", movieClip);
184: f0 = movieClip.getFrameAt(0);
185:
186: // 3rd layer: NOT NEEDED according to adam.
187: movieClip = new Script(1);
188: movieClip.getFrameAt(0).addInstance(rectShape, 1, at, null);
189: inst = f0.addInstance(movieClip, 1, at, null, "meas");
190: ca = new ClipActions();
191: ca.setMask(ClipAction.LOAD);
192: ca.addAction(new ClipAction(ClipAction.LOAD, program("this._visible = false;")));
193: inst.actions = ca;
194:
195: // 2nd layer
196: f0.addInstance(empty, 4, null, null, "mask_sub");
197:
198: // 1st layer
199: inst = f0.addInstance(rectShape, 3, at, null, "mask_container");
200: inst.clip = 6; // NOTE: [2004-02-17 bloch] mimic depth from old laszlolibrary.swf
201:
202: */
203:
204: // 6. A movieclip with the export identifier "LzMouseEvents" that has a 100x100
205: // button with no visible region and several actions
206: movieClip = new Script(1);
207: export("LzMouseEvents", movieClip);
208: but = new Button2();
209: states = ButtonRecord.HitTest;
210:
211: // important for accessibility
212: but.addButtonRecord(new ButtonRecord(ButtonRecord.Up,
213: rectShape, 1, at, new CXForm()));
214: but.addButtonRecord(new ButtonRecord(states, rectShape, 1,
215: at, new CXForm()));
216: but
217: .addActionCondition(ActionCondition
218: .onPress(program("_root.LzModeManager.handleMouseButton( myView, 'onmousedown')")));
219: but
220: .addActionCondition(ActionCondition
221: .onRelease(program("_root.LzModeManager.handleMouseButton( myView, 'onmouseup');"
222: + "_root.LzModeManager.handleMouseEvent( myView, 'onclick')")));
223: but
224: .addActionCondition(ActionCondition
225: .onReleaseOutside(program("_root.LzModeManager.handleMouseButton( myView, 'onmouseup');"
226: + "_root.LzModeManager.handleMouseEvent( myView, 'onmouseupoutside')")));
227: but
228: .addActionCondition(ActionCondition
229: .onRollOver(program("_root.LzModeManager.handleMouseEvent( myView, 'onmouseover')")));
230: but
231: .addActionCondition(ActionCondition
232: .onRollOut(program("_root.LzModeManager.handleMouseEvent( myView, 'onmouseout')")));
233: but
234: .addActionCondition(ActionCondition
235: .onDragOut(program("_root.LzModeManager.handleMouseEvent( myView, 'onmouseout');"
236: + "_root.LzModeManager.handleMouseEvent( myView, 'onmousedragout')")));
237: but
238: .addActionCondition(ActionCondition
239: .onDragOver(program("_root.LzModeManager.handleMouseEvent( myView, 'onmouseover');"
240: + "_root.LzModeManager.handleMouseEvent( myView, 'onmousedragin')")));
241: movieClip.getFrameAt(0)
242: .addInstance(but, 1, at, null, "but");
243:
244: // 7. A movieclip with the export identifier "swatch" which has a white 100x100 rectangle.
245: movieClip = new Script(1);
246: export("swatch", movieClip);
247: f0 = movieClip.getFrameAt(0);
248: f0.addInstance(rectShape, 1, at, null);
249:
250: // 8. Was krank, now obsolete
251:
252: // 9. A movieclip with the export identifier "LZprofiler" which has 2 frames:
253: String profile = mProperties
254: .getProperty(CompilationEnvironment.PROFILE_PROPERTY);
255: if ("true".equals(profile)) {
256: movieClip = new Script(2);
257: export("__LZprofiler", movieClip);
258: block = actionBlock("_root.$lzprofiler.dump()");
259: movieClip.getFrameAt(0).addFlashObject(block);
260: movieClip.getFrameAt(1).addFlashObject(block);
261: }
262:
263: // 9.1 A movieclip with the export identifier "LZdebugger" which has 2 frames:
264: String debug = mProperties
265: .getProperty(CompilationEnvironment.DEBUG_PROPERTY);
266: if ("true".equals(debug)) {
267: movieClip = new Script(2);
268: export("__LZdebugger", movieClip);
269: block = actionBlock("_root.__LzDebug.background()");
270: movieClip.getFrameAt(0).addFlashObject(block);
271: movieClip.getFrameAt(1).addFlashObject(block);
272: }
273:
274: // 9.2 A definevideostream tag inside a movieClip so we can attach video streams
275: movieClip = new Script(1); // add single frame movieClip
276: export("__LZvideo", movieClip);
277: video = new VideoStream(160, 120);
278: movieClip.getFrameAt(0).addInstance(video, 8, offScreen,
279: null, "__lzvideo");
280:
281: // 9.3 A movieclip for receiving javascript events from the browser
282: movieClip = new Script(2);
283: export("__LZjsevent", movieClip);
284: block = actionBlock("_root.DojoExternalInterface._gatewayReady();stop();");
285: movieClip.getFrameAt(0).addFlashObject(block);
286: block = actionBlock("_root.DojoExternalInterface._handleJSCall();stop();");
287: movieClip.getFrameAt(1).addFlashObject(block);
288:
289: // 10. The LFC ActionScript block, the only def in the incoming file
290: FlashFile oldLibrary = FlashFile.parse(path);
291: IVVector objs = oldLibrary.getMainScript().getFrameAt(0);
292: block = (DoAction) objs.elementAt(0);
293: if (block == null) {
294: throw new ChainedException("no DoAction block in "
295: + path);
296: }
297: frame.addFlashObject(block);
298:
299: // 11. Add in end-of-LFC marker for qa
300: block = actionBlock("global[ '$endOfLFCMarker' ];");
301: frame.addFlashObject(block);
302:
303: } catch (IVException e) {
304: throw new ChainedException(e);
305: } catch (FileNotFoundException e) {
306: throw new ChainedException(e);
307: } catch (IOException e) {
308: throw new ChainedException(e);
309: }
310: }
311:
312: /**
313: * Create a SWFBaseLibrary that has no assets or logic in it
314: */
315: public SWFFile(Properties props) {
316: mProperties = props;
317: }
318:
319: /**
320: * Add the preloader frame to
321: */
322: void addPreloaderFrame(String preloadLibPath) {
323:
324: try {
325: // Insert a blank frame for the preloader
326: Timeline tm = getMainScript().getTimeline();
327: tm.insertFrames(0, 1);
328:
329: // Make heartbeat movieclip
330: Script hbClip = new Script(1);
331: hbClip.getFrameAt(0);
332: hbClip.setName("lzpreloader._heartbeat");
333: addDef(hbClip);
334:
335: // Make preloader movieclip
336: Script prelClip = new Script(1);
337: prelClip.setName("lzpreloader");
338: Frame frame = prelClip.getFrameAt(0);
339: // Get preload lib
340: FlashFile lib = FlashFile.parse(preloadLibPath);
341: IVVector objs = lib.getMainScript().getFrameAt(0);
342: DoAction block = (DoAction) objs.elementAt(0);
343: frame.addFlashObject(block);
344: // Add instance
345: Instance inst = frame.addInstance(hbClip, 1, null, null,
346: "_heartbeat");
347: ClipActions ca = new ClipActions();
348: ca.setMask(ClipAction.ENTER_FRAME);
349: ca.addAction(new ClipAction(ClipAction.ENTER_FRAME,
350: program("_parent.heartbeat()")));
351: inst.actions = ca;
352: // Export me
353: export("lzpreloader", prelClip);
354:
355: // Insert me
356: tm.getFrameAt(0).addInstance(prelClip, 1, null, null,
357: "lzpreloader");
358:
359: } catch (IVException e) {
360: throw new ChainedException(e);
361: } catch (FileNotFoundException e) {
362: throw new ChainedException(e);
363: } catch (IOException e) {
364: throw new ChainedException(e);
365: }
366: }
367: }
|