001: /*
002: * $Id: FOPScriptBuilder.java,v 1.4 2002/03/19 22:19:55 skavish Exp $
003: *
004: * ==========================================================================
005:
006: * The JGenerator Software License, Version 1.0
007: *
008: * Copyright (c) 2000 Dmitry Skavish (skavish@usa.net). All rights reserved.
009: *
010: * Redistribution and use in source and binary forms, with or without
011: * modification, are permitted provided that the following conditions are met:
012: *
013: * 1. Redistributions of source code must retain the above copyright
014: * notice, this list of conditions and the following disclaimer.
015: *
016: * 2. Redistributions in binary form must reproduce the above copyright
017: * notice, this list of conditions and the following disclaimer in
018: * the documentation and/or other materials provided with the
019: * distribution.
020: *
021: * 3. The end-user documentation included with the redistribution, if
022: * any, must include the following acknowlegement:
023: * "This product includes software developed by Dmitry Skavish
024: * (skavish@usa.net, http://www.flashgap.com/)."
025: * Alternately, this acknowlegement may appear in the software itself,
026: * if and wherever such third-party acknowlegements normally appear.
027: *
028: * 4. The name "The JGenerator" must not be used to endorse or promote
029: * products derived from this software without prior written permission.
030: * For written permission, please contact skavish@usa.net.
031: *
032: * 5. Products derived from this software may not be called "The JGenerator"
033: * nor may "The JGenerator" appear in their names without prior written
034: * permission of Dmitry Skavish.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL DMITRY SKAVISH OR THE OTHER
040: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: *
049: */
050:
051: package org.openlaszlo.iv.flash.fop;
052:
053: import org.openlaszlo.iv.flash.api.*;
054: import org.openlaszlo.iv.flash.api.shape.*;
055: import org.openlaszlo.iv.flash.api.action.*;
056: import org.openlaszlo.iv.flash.api.button.*;
057: import org.openlaszlo.iv.flash.api.text.*;
058: import org.openlaszlo.iv.flash.parser.*;
059: import org.openlaszlo.iv.flash.util.*;
060:
061: import java.io.*;
062: import java.util.*;
063: import java.awt.geom.*;
064:
065: /**
066: * This is a helper class for the SWFRenderer, this does all
067: * JGen specific calls, like drawing lines etc etc.
068: *
069: * @author Johan "Spocke" Sörlin
070: * @author James Taylor
071: */
072:
073: public class FOPScriptBuilder {
074: private Script script;
075: private Frame currentFrame;
076:
077: // Name of actionscript function to handle links ( should take one
078: // string argument )
079:
080: private String linkHandler = null;
081:
082: private Font currentFont;
083:
084: private int layerCount = 2;
085:
086: // Dimensions of the current page
087:
088: private int pageWidth = 0;
089: private int pageHeight = 0;
090:
091: // Dimensions of the largest page
092:
093: private int maxPageWidth = 0;
094: private int maxPageHeight = 0;
095:
096: /**
097: * Constructs a new FOPScriptBuilder
098: *
099: */
100:
101: public FOPScriptBuilder() {
102: script = new Script(0);
103: }
104:
105: /**
106: * Sets the name of the function used to handle links. This should be a
107: * function defined on the timeline containing this script.
108: *
109: * FIXME: Need to evaluate other ways to do this, to allow the most
110: * flexibility
111: */
112:
113: public void setLinkHandler(String methodName) {
114: linkHandler = methodName;
115: }
116:
117: public void startPage(int width, int height) {
118: pageWidth = millipointsToTwixels(width);
119: pageHeight = millipointsToTwixels(height);
120:
121: maxPageWidth = (pageWidth > maxPageWidth) ? pageWidth
122: : maxPageWidth;
123: maxPageHeight = (pageHeight > maxPageHeight) ? pageHeight
124: : maxPageHeight;
125:
126: currentFrame = script.newFrame();
127:
128: // Start with a blank frame
129:
130: script.removeAllInstances(currentFrame);
131: }
132:
133: public Script getScript() {
134: return script;
135: }
136:
137: public Rectangle2D getMaxPageBounds() {
138: return GeomHelper.newRectangle(0, 0, maxPageWidth,
139: maxPageHeight);
140: }
141:
142: /**
143: * Adds a new line shape to the FlashMovie.
144: *
145: * @param x1 x1 position in FOP points
146: * @param y1 y1 position in FOP points
147: * @param x2 x2 position in FOP points
148: * @param y1 y1 position in FOP points
149: * @param th thickness in FOP points
150: * @param r red color channel
151: * @param g green color channel
152: * @param b blue color channel
153: */
154:
155: public void addLine(int x1, int y1, int x2, int y2, int th,
156: float r, float g, float b) {
157: x1 = millipointsToTwixels(x1);
158: y1 = millipointsToTwixels(y1);
159: x2 = millipointsToTwixels(x2);
160: y2 = millipointsToTwixels(y2);
161:
162: th = millipointsToTwixels(th);
163:
164: // Translate y axis geometry
165:
166: y1 = pageHeight - y1;
167: y2 = pageHeight - y2;
168:
169: // Build shape
170:
171: Shape shape = new Shape();
172:
173: shape.setLineStyle(new LineStyle(th, new AlphaColor(r, g, b)));
174: shape.drawLine(x1, y2, x2, y2);
175: shape.setBounds(x1, y1, x2 - x1, y2 - y1);
176:
177: currentFrame.addInstance(shape, layerCount++,
178: new AffineTransform(), null);
179: }
180:
181: /**
182: * Adds a new filled rectangle shape to the FlashMovie.
183: *
184: * @param x x position in FOP points
185: * @param y y position in FOP points
186: * @param w width in FOP points
187: * @param h height in FOP points
188: * @param r red color channel
189: * @param g green color channel
190: * @param b blue color channel
191: */
192:
193: public void addRect(int x, int y, int w, int h, float r, float g,
194: float b) {
195: x = millipointsToTwixels(x);
196: y = millipointsToTwixels(y);
197: w = millipointsToTwixels(w);
198: h = millipointsToTwixels(h);
199:
200: // Translate y axis geometry
201:
202: h = -h;
203: y = pageHeight - y;
204:
205: // Build shape
206:
207: Shape shape = new Shape();
208:
209: shape
210: .setFillStyle0(FillStyle.newSolid(new AlphaColor(r, g,
211: b)));
212:
213: Rectangle2D movieRect = GeomHelper.newRectangle(x, y, w, h);
214: shape.drawRectangle(movieRect);
215: shape.setBounds(movieRect);
216:
217: currentFrame.addInstance(shape, layerCount++,
218: new AffineTransform(), null);
219: }
220:
221: public void addLink(int x, int y, int w, int h, String destination) {
222: x = millipointsToTwixels(x);
223: y = millipointsToTwixels(y);
224: w = millipointsToTwixels(w);
225: h = millipointsToTwixels(h);
226:
227: y = pageHeight - y;
228:
229: Button2 button = new Button2();
230:
231: // Hit area
232:
233: Shape shape = new Shape();
234:
235: shape.setFillStyle0(FillStyle.newSolid(new AlphaColor(0x31,
236: 0x63, 0x9c, 0x60)));
237: Rectangle2D r = GeomHelper.newRectangle(0, 0, w, h);
238: shape.drawRectangle(r);
239: shape.setBounds(r);
240:
241: AffineTransform shapeMatrix = new AffineTransform();
242:
243: ButtonRecord hitState = new ButtonRecord(ButtonRecord.HitTest,
244: shape, 1, shapeMatrix, CXForm.newIdentity(true));
245:
246: button.addButtonRecord(hitState);
247:
248: // Up state -- good for debug
249:
250: // ButtonRecord upState =
251: // new ButtonRecord( ButtonRecord.Up, shape, 1, shapeMatrix, CXForm.newDefault(true) );
252:
253: // button.addButtonRecord( upState );
254:
255: // Action
256:
257: Program p = new Program();
258:
259: if (linkHandler != null) {
260: p.push(destination);
261: p.push(1);
262: p.push("_parent");
263: p.eval();
264: p.push(linkHandler);
265: p.callMethod();
266: } else {
267: p.getURL(destination, "_blank");
268: }
269:
270: ActionCondition onRelease = new ActionCondition(
271: ActionCondition.OverDownToOverUp, p);
272:
273: button.addActionCondition(onRelease);
274:
275: AffineTransform instMatrix = AffineTransform
276: .getTranslateInstance(x, y);
277:
278: currentFrame
279: .addInstance(button, layerCount++, instMatrix, null);
280: }
281:
282: /**
283: * Adds a new text element to the FlashMovie.
284: *
285: * @param string String to place in text element
286: * @param pos_x x position in FOP points
287: * @param pos_y y position in FOP points
288: * @param r red color channel
289: * @param g green color channel
290: * @param b blue color channel
291: * @param fontMetric font metric
292: * @param size font size in FOP points
293: * @param underlined underlined text element
294: */
295:
296: public void addText(String string, int x, int y, float r, float g,
297: float b, SWFFontMetric fontMetric, int size, int width) {
298: x = millipointsToTwixels(x);
299: y = millipointsToTwixels(y);
300:
301: size = millipointsToTwixels(size);
302: width = millipointsToTwixels(width);
303:
304: // Translate y axis geometry
305:
306: y = pageHeight - y;
307:
308: /*
309:
310: // DEBUG: This draws the boxes where words should be rendered, for
311: // debugging the baseline position
312:
313: Shape shape = new Shape();
314:
315: shape.setFillStyle0( FillStyle.newSolid( new AlphaColor( 64, 64, 128 ) ) );
316:
317: Rect movieRect = new Rect( x, y, x + width, y - size );
318: shape.drawRectangle( movieRect );
319: shape.setBounds( movieRect );
320:
321: currentFrame.addInstance( shape, layerCount++, new Matrix(), null );
322:
323: */
324:
325: // Build text
326: currentFont = fontMetric.getFont();
327:
328: // FIXME: This is a gross hack! It appears that when fop draws a text
329: // at a given y position it expects that position to correspond
330: // to the baseline. However in flash, the position correponds to
331: // the bottom of the EM square. This seems to compensate well
332: // for all fonts ( that have been tested ) but I don't know WHY!
333:
334: y += (currentFont.descent - currentFont.leading) / 5;
335:
336: Text text = Text.newText();
337:
338: TextItem item = new TextItem(string, currentFont, size,
339: new AlphaColor(r, g, b));
340:
341: text.addTextItem(item);
342:
343: text.setBounds(0, 0, width + 10, size);
344:
345: AffineTransform position = AffineTransform
346: .getTranslateInstance(x, y - size);
347:
348: currentFrame.addInstance(text, layerCount++, position, null);
349: }
350:
351: /**
352: * Convert millipoints ( unit of formatting used by most parts of FOP ) to
353: * twixels ( unit used by flash ).
354: *
355: * 1000 points = 1 pixel = 20 twixels, thus 1 point = .02 twixels
356: */
357:
358: private int millipointsToTwixels(int points) {
359: return Math.round(points * 0.02f);
360: }
361:
362: }
|