KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > iv > flash > api > shape > Shape


1 /*
2  * $Id: Shape.java,v 1.2 2002/02/15 23:44:28 skavish Exp $
3  *
4  * ==========================================================================
5  *
6  * The JGenerator Software License, Version 1.0
7  *
8  * Copyright (c) 2000 Dmitry Skavish (skavish@usa.net). All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if
22  * any, must include the following acknowlegement:
23  * "This product includes software developed by Dmitry Skavish
24  * (skavish@usa.net, http://www.flashgap.com/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The name "The JGenerator" must not be used to endorse or promote
29  * products derived from this software without prior written permission.
30  * For written permission, please contact skavish@usa.net.
31  *
32  * 5. Products derived from this software may not be called "The JGenerator"
33  * nor may "The JGenerator" appear in their names without prior written
34  * permission of Dmitry Skavish.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL DMITRY SKAVISH OR THE OTHER
40  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  *
49  */

50
51 package org.openlaszlo.iv.flash.api.shape;
52
53 import java.io.PrintStream JavaDoc;
54 import java.awt.geom.*;
55 import java.util.*;
56
57 import org.openlaszlo.iv.flash.parser.*;
58 import org.openlaszlo.iv.flash.util.*;
59 import org.openlaszlo.iv.flash.api.*;
60
61 /**
62  * Shape.
63  * <P>
64  * Shapes are defined by a list of edges called a path. A path may be closed - where the start
65  * and end of the path meet to close the figure, or open - where the path forms an
66  * open-ended stroke. A path may contain a mixture of straight edges, curved edges, and
67  * "pen up and move" commands. The latter allows multiple disconnected figures to be
68  * described by a single shape structure. (see MoveTo flag)
69  * <P>
70  * A fill style defines the appearance of an area enclosed by a path. Fill styles supported
71  * by SWF include a color, a gradient, or a bitmapped image.<BR>
72  * A line style defines the appearance of the outline of a path. The line style may be a stroke
73  * of any thickness and color.
74  * <P>
75  * SWF format allows each edge to have its own line and fill style.
76  * This can have unpredictable results when fill styles change in the middle of a path.
77  * <P>
78  * Flash also supports two fill styles per edge, one for each side of the edge:
79  * FillStyle0 and FillStyle1. FillStyle0 should always be used first and then
80  * FillStyle1 if the shape is filled on both sides of the edge.
81  * <P>
82  * A shape is comprised of the following elements:
83  * <UL>
84  * <LI>CharacterId - A 16-bit value that uniquely identifies this shape as a
85  * 'character' in the dictionary. The CharacterId can be referred to in
86  * control tags such as PlaceObject. Characters can be re-used and combined
87  * with other characters to make more complex shapes.
88  * <LI>Bounding box - The rectangle that completely encloses the shape.
89  * <LI>Fill style array - A list of all the fill styles used in a shape.
90  * <LI>Line style array - A list of all the line styles used in a shape.
91  * <LI>Shape-record array - A list of shape-records. Shape-records can define straight
92  * or curved edges, style changes, or move the drawing position.
93  * </UL>
94  * Note: Line and fill styles are defined once only, and may be used (and re-used) by
95  * any of the edges in the shape.
96  * <p>
97  * Note that objects of this class will always be generated as DefineShape3 tags which
98  * means that all the colors used in the shape (in line and fillstyles) have to be AlphaColors!
99  *
100  * @author Dmitry Skavish
101  */

102 public final class Shape extends FlashDef /*implements Drawable*/ {
103
104     private StyleBlock style_block;
105     private Rectangle2D bounds; // bounding box of this shape
106
private int tagcode; // tag of this shape
107

108     /**
109      * Creates new empty shape (Shape3 - all colors with alpha)
110      */

111     public Shape() {
112         this( Tag.DEFINESHAPE3 );
113         newStyleBlock();
114     }
115
116     /**
117      * Returns shape styles
118      *
119      * @return object representing array of shape styles
120      */

121     public ShapeStyles getShapeStyles() {
122         return style_block.shapeStyles;
123     }
124
125     /**
126      * Returns shape records
127      *
128      * @return object representing array of shape records
129      */

130     public ShapeRecords getShapeRecords() {
131         return style_block.shapeRecords;
132     }
133
134     /**
135      * Adds specified fill style to the array of shape styles.
136      * <p>
137      * Note: colors used in the specified fillstyle have to be AlphaColors
138      *
139      * @param fillStyle specified fill style
140      * @return index of added fill style in the array
141      */

142     public int addFillStyle( FillStyle fillStyle ) {
143         return getShapeStyles().addFillStyle( fillStyle );
144     }
145
146     /**
147      * Adds specified line style to the array of shape styles
148      * <p>
149      * Note: colors used in the specified linestyle have to be AlphaColors
150      *
151      * @param lineStyle specified line style
152      * @return index of added line style in the array
153      */

154     public int addLineStyle( LineStyle lineStyle ) {
155         return getShapeStyles().addLineStyle( lineStyle );
156     }
157
158     /**
159      * Sets specified fillstyle as current fillstyle0.
160      * <P>
161      * If the specified fillstyle is not in the shapestyle array
162      * then it's added, if it's already there it's reused.
163      * <p>
164      * Note: colors used in the specified fillstyle have to be AlphaColors
165      *
166      * @param fillStyle specified fillstyle
167      * @return index of specified fillstyle in the shapestyle array
168      */

169     public int setFillStyle0( FillStyle fillStyle ) {
170         int fs = getShapeStyles().getFillStyleIndex( fillStyle );
171         if( fs == -1 ) fs = addFillStyle( fillStyle );
172         setFillStyle0( fs );
173         return fs;
174     }
175
176     /**
177      * Sets specified fillstyle as current fillstyle1.
178      * <P>
179      * If the specified fillstyle is not in the shapestyle array
180      * then it's added, if it's already there it's reused.
181      * <p>
182      * Note: colors used in the specified fillstyle have to be AlphaColors
183      *
184      * @param fillStyle specified fillstyle
185      * @return index of specified fillstyle in the shapestyle array
186      */

187     public int setFillStyle1( FillStyle fillStyle ) {
188         int fs = getShapeStyles().getFillStyleIndex( fillStyle );
189         if( fs == -1 ) fs = addFillStyle( fillStyle );
190         setFillStyle1( fs );
191         return fs;
192     }
193
194     /**
195      * Sets specified linestyle as current linestyle.
196      * <P>
197      * If the specified linestyle is not in the shapestyle array
198      * then it's added, if it's already there it's reused.
199      * <p>
200      * Note: color used in the specified linestyle has to be AlphaColor
201      *
202      * @param lineStyle specified linestyle
203      * @return index of specified linestyle in the shapestyle array
204      */

205     public int setLineStyle( LineStyle lineStyle ) {
206         int ls = getShapeStyles().getLineStyleIndex( lineStyle );
207         if( ls == -1 ) ls = addLineStyle( lineStyle );
208         setLineStyle( ls );
209         return ls;
210     }
211
212     /**
213      * Sets current fillstyle0 by its index in shapestyle array.
214      *
215      * @param fillStyle index of fillstyle in shapestyle array to be set as current fillstyle0
216      */

217     public void setFillStyle0( int fillStyle ) {
218         StyleChangeRecord sc = getStyleChange();
219         sc.addFlags( StyleChangeRecord.FILLSTYLE0 );
220         sc.setFillStyle0( fillStyle );
221     }
222
223     /**
224      * Sets current fillstyle1 by its index in shapestyle array.
225      *
226      * @param fillStyle index of fillstyle in shapestyle array to be set as current fillstyle1
227      */

228     public void setFillStyle1( int fillStyle ) {
229         StyleChangeRecord sc = getStyleChange();
230         sc.addFlags( StyleChangeRecord.FILLSTYLE1 );
231         sc.setFillStyle1( fillStyle );
232     }
233
234     /**
235      * Sets current linestyle by its index in shapestyle array.
236      *
237      * @param lineStyle index of linestyle in shapestyle array to be set as current linestyle
238      */

239     public void setLineStyle( int lineStyle ) {
240         StyleChangeRecord sc = getStyleChange();
241         sc.addFlags( StyleChangeRecord.LINESTYLE );
242         sc.setLineStyle( lineStyle );
243     }
244
245     /**
246      * Returns index of current line style
247      *
248      * @return index of currently used line style
249      */

250     public int getLineStyleIndex() {
251         StyleChangeRecord sc = getStyleChange();
252         return sc.getLineStyle();
253     }
254
255     /**
256      * Returns current line style
257      *
258      * @return currently used line style
259      */

260     public LineStyle getLineStyle() {
261         int idx = getLineStyleIndex();
262         return getShapeStyles().getLineStyle(idx);
263     }
264
265     /**
266      * Returns index of current fill style 0
267      *
268      * @return index of currently used fill style 0
269      */

270     public int getFillStyle0Index() {
271         StyleChangeRecord sc = getStyleChange();
272         return sc.getFillStyle0();
273     }
274
275     /**
276      * Returns current fill style 0
277      *
278      * @return currently used fill style 0
279      */

280     public FillStyle getFillStyle0() {
281         int idx = getFillStyle0Index();
282         return getShapeStyles().getFillStyle(idx);
283     }
284
285     /**
286      * Returns index of current fill style 1
287      *
288      * @return index of currently used fill style 1
289      */

290     public int getFillStyle1Index() {
291         StyleChangeRecord sc = getStyleChange();
292         return sc.getFillStyle1();
293     }
294
295     /**
296      * Returns current fill style 1
297      *
298      * @return currently used fill style 1
299      */

300     public FillStyle getFillStyle1() {
301         int idx = getFillStyle1Index();
302         return getShapeStyles().getFillStyle(idx);
303     }
304
305     /**
306      * Creates new style block
307      * <P>
308      * Each style block contains styles and records which use
309      * these styles. Records cannot use styles from different
310      * style blocks. It means that after this call one cannot
311      * use styles (and style indexes) from previous style blocks.
312      */

313     public void newStyleBlock() {
314         StyleBlock sb = new StyleBlock();
315         sb.prev = style_block;
316
317         // check whether last style block has stylechange with flag NEW_STYLES
318
// add this record if there is no such stylechange
319
if( style_block != null ) {
320             IVVector shape_records = style_block.shapeRecords.getShapeRecords();
321             if( shape_records.size() > 0 ) {
322                 Object JavaDoc o = shape_records.elementAt(shape_records.size()-1);
323                 if( o instanceof StyleChangeRecord ) {
324                     StyleChangeRecord sr = (StyleChangeRecord) o;
325                     sr.addFlags(StyleChangeRecord.NEW_STYLES);
326                 } else {
327                     StyleChangeRecord sr = new StyleChangeRecord();
328                     sr.addFlags(StyleChangeRecord.NEW_STYLES);
329                     shape_records.addElement(sr);
330                 }
331             }
332         }
333
334         style_block = sb;
335     }
336
337    /**
338      * Creates new Shape defined by tag DEFINESHAPE
339      *
340      * @return new Shape
341      */

342     public static Shape newShape1() {
343         Shape shape = new Shape(Tag.DEFINESHAPE);
344         shape.newStyleBlock();
345         return shape;
346     }
347
348     /**
349      * Creates new Shape defined by tag DEFINESHAPE2
350      *
351      * @return new Shape
352      */

353     public static Shape newShape2() {
354         Shape shape = new Shape(Tag.DEFINESHAPE2);
355         shape.newStyleBlock();
356         return shape;
357     }
358
359     /**
360      * Creates new Shape defined by tag DEFINESHAPE3
361      *
362      * @return new Shape
363      */

364     public static Shape newShape3() {
365         Shape shape = new Shape(Tag.DEFINESHAPE3);
366         shape.newStyleBlock();
367         return shape;
368     }
369
370     /**
371      * Creates new Shape3 from provided shape styles and records
372      *
373      * @return new Shape
374      */

375     public static Shape newShape3( ShapeStyles styles, ShapeRecords records ) {
376         Shape shape = new Shape(Tag.DEFINESHAPE3);
377         shape.style_block = new StyleBlock(styles, records);
378         return shape;
379     }
380
381     /**
382      * Creates empty Shape (DEFINESHAPE tag)
383      *
384      * @return empty shape
385      */

386     public static Shape newEmptyShape1() {
387         Shape emptyShape = newShape1();
388         emptyShape.setLineStyle( new LineStyle(1, new Color(0,0,0) ) );
389         emptyShape.movePenTo(0,0);
390         emptyShape.setBounds( GeomHelper.newRectangle(0,0,0,0) );
391         return emptyShape;
392     }
393
394     public int getTag() {
395         return tagcode;
396     }
397
398     public void collectDeps( DepsCollector dc ) {
399         StyleBlock sb = style_block;
400         while( sb != null ) {
401             sb.shapeStyles.collectDeps(dc);
402             sb = sb.prev;
403         }
404     }
405
406     protected StyleChangeRecord getStyleChange() {
407         return getShapeRecords().getStyleChange();
408     }
409
410     /**
411      * Parses Shape
412      *
413      * @param p Parser
414      * @return parsed shape
415      */

416     public static Shape parse( Parser p ) {
417
418         int tagCode = p.getTagCode();
419         Shape shape = new Shape( tagCode );
420         shape.setID( p.getUWord() );
421         shape.bounds = p.getRect();
422
423         boolean withAlpha = shape.isWithAlpha();
424
425         // parse first styles
426
ShapeStyles shape_styles = ShapeStyles.parse(p, withAlpha);
427
428         IVVector shape_records = new IVVector();
429
430         // parse shape records
431
int nBits = p.getUByte();
432         int nFillBits = (nBits&0xf0)>>4;
433         int nLineBits = nBits&0x0f;
434         p.initBits();
435         for(;;) {
436             if( p.getBool() ) { // edge record
437
if( p.getBool() ) { // stright edge
438
int nb = p.getBits(4)+2;
439                     if( p.getBool() ) { // general line
440
int deltaX = p.getSBits(nb);
441                         int deltaY = p.getSBits(nb);
442                         shape_records.addElement( StrightEdgeRecord.newLine(deltaX, deltaY) );
443                     } else if( p.getBool() ) { // vertical line
444
int deltaY = p.getSBits(nb);
445                         shape_records.addElement( StrightEdgeRecord.newVLine(deltaY) );
446                     } else { // horizontal line
447
int deltaX = p.getSBits(nb);
448                         shape_records.addElement( StrightEdgeRecord.newHLine(deltaX) );
449                     }
450                 } else { // curved edge
451
int nb = p.getBits(4)+2;
452                     int cx = p.getSBits(nb);
453                     int cy = p.getSBits(nb);
454                     int ax = p.getSBits(nb);
455                     int ay = p.getSBits(nb);
456                     shape_records.addElement( new CurvedEdgeRecord(cx, cy, ax, ay) );
457                 }
458             } else { // style-change record (non-edge)
459
int flags = p.getBits(5);
460                 if( flags == 0 ) break; // end record
461
StyleChangeRecord scr = new StyleChangeRecord();
462                 scr.setFlags( flags );
463
464                 if( (flags & StyleChangeRecord.MOVETO) != 0 ) {
465                     int nMoveBits = p.getBits(5);
466                     scr.setDeltaX( p.getSBits(nMoveBits) );
467                     scr.setDeltaY( p.getSBits(nMoveBits) );
468                 }
469
470                 if( (flags & StyleChangeRecord.FILLSTYLE0) != 0 ) {
471                     scr.setFillStyle0( p.getBits(nFillBits) );
472                 }
473
474                 if( (flags & StyleChangeRecord.FILLSTYLE1) != 0 ) {
475                     scr.setFillStyle1( p.getBits(nFillBits) );
476                 }
477
478                 if( (flags & StyleChangeRecord.LINESTYLE) != 0 ) {
479                     scr.setLineStyle( p.getBits(nLineBits) );
480                 }
481
482                 if( (flags & StyleChangeRecord.NEW_STYLES) != 0 ) {
483
484                     // add this style change as first record to new block
485
shape_records.addElement(scr);
486
487                     // new styles are to be defined
488
// save all already parsed records and styles in style block
489
// and reset data to parse next style blosk
490

491                     StyleBlock new_style_block = new StyleBlock(shape_styles, shape_records);
492                     new_style_block.prev = shape.style_block;
493                     shape.style_block = new_style_block;
494
495                     // parse new styles
496
shape_styles = ShapeStyles.parse(p, withAlpha);
497                     // create new records vector
498
shape_records = new IVVector();
499
500                     // parse new fill and line number of bits
501
nBits = p.getUByte();
502                     nFillBits = (nBits&0xf0)>>4;
503                     nLineBits = nBits&0x0f;
504                     p.initBits();
505
506                 } else {
507                     shape_records.addElement(scr);
508                 }
509
510                 if( (flags&0x80) != 0 ) {
511                     break;
512                 }
513             }
514         }
515
516         // save parsed records in style block
517
StyleBlock new_style_block = new StyleBlock(shape_styles, shape_records);
518         new_style_block.prev = shape.style_block;
519         shape.style_block = new_style_block;
520
521         return shape;
522     }
523
524     public boolean isWithAlpha() {
525         return getTag() == Tag.DEFINESHAPE3;
526     }
527
528     /**
529      * This class represents style block: set of styles and set of corresponding
530      * records which use these styles. It also holds reference to previous
531      * style block. Shape may contain several different style blocks.
532      * This class is not supposed to be used externally and reflects inner
533      * Shape structure.
534      */

535     private static class StyleBlock {
536
537         StyleBlock prev;
538         ShapeStyles shapeStyles; // collection of fill and line styles
539
ShapeRecords shapeRecords; // collection of shape records
540

541         StyleBlock() {
542             this.shapeStyles = new ShapeStyles();
543             this.shapeRecords = new ShapeRecords();
544         }
545
546         StyleBlock( ShapeStyles styles, IVVector records ) {
547             this(styles, new ShapeRecords(records));
548         }
549
550         StyleBlock( ShapeStyles styles, ShapeRecords records ) {
551             this.shapeStyles = styles;
552             this.shapeRecords = records;
553         }
554
555         private void write_block( FlashOutput fob ) {
556             if( prev != null ) {
557                 prev.write_block(fob);
558                 fob.flushBits();
559             }
560
561             shapeStyles.write(fob);
562
563             int nFillBits = shapeStyles.calcNFillBits();
564             int nLineBits = shapeStyles.calcNLineBits();
565             fob.writeByte( (nFillBits<<4) | nLineBits );
566             shapeRecords.write(fob, nFillBits, nLineBits);
567         }
568
569         public void write( FlashOutput fob ) {
570             write_block(fob);
571             fob.writeBits(0, 6);
572             fob.flushBits();
573         }
574
575         public void printContent( PrintStream JavaDoc out, String JavaDoc indent ) {
576             if( prev != null ) {
577                 prev.printContent(out, indent );
578                 out.println( indent+" new styleblock:" );
579             }
580             shapeStyles.printContent(out, indent+" " );
581             shapeRecords.printContent(out, indent+" " );
582         }
583
584         public StyleBlock getCopy( ScriptCopier copier ) {
585             StyleBlock my_prev = null;
586             if( prev != null ) {
587                 my_prev = prev.getCopy(copier);
588             }
589             StyleBlock my_block = new StyleBlock(
590                 (ShapeStyles) shapeStyles.getCopy(copier),
591                 (ShapeRecords) shapeRecords.getCopy(copier)
592             );
593             my_block.prev = my_prev;
594             return my_block;
595         }
596     }
597
598     public void write( FlashOutput main ) {
599         FlashOutput fob = new FlashOutput(main,100);
600
601         // set userdata to this shape, so that styles know which color to write
602
fob.setUserData(this);
603         fob.write( bounds );
604
605         style_block.write(fob);
606
607         main.writeTag( getTag(), 2+fob.getSize() );
608         main.writeDefID( this );
609         main.writeFOB( fob );
610     }
611
612     public void printContent( PrintStream JavaDoc out, String JavaDoc indent ) {
613         out.println( indent+"Shape("+Tag.tagNames[getTag()]+"): id="+getID()+", name='"+getName()+"'" );
614         out.println( indent+" "+bounds );
615         style_block.printContent(out, indent);
616     }
617
618     public boolean isConstant() {
619         return true;
620     }
621
622     /**
623      * Returns Shape bounds
624      *
625      * @return shape bounds
626      */

627     public Rectangle2D getBounds() {
628         return bounds;
629     }
630
631     /**
632      * Sets bounding box for this shape.
633      *
634      * @param bounds new bounding box
635      */

636     public void setBounds( Rectangle2D bounds ) {
637         this.bounds = bounds;
638     }
639
640     /**
641      * Sets bounding box for this shape.
642      *
643      */

644     public void setBounds( int x, int y, int width, int height ) {
645         setBounds( GeomHelper.newRectangle(x,y,width,height) );
646     }
647
648     protected FlashItem copyInto( FlashItem item, ScriptCopier copier ) {
649         super.copyInto( item, copier );
650         ((Shape)item).bounds = (Rectangle2D) bounds.clone();
651         ((Shape)item).style_block = (StyleBlock) style_block.getCopy(copier);
652         ((Shape)item).tagcode = tagcode;
653         return item;
654     }
655
656     public FlashItem getCopy( ScriptCopier copier ) {
657         return copyInto( new Shape(), copier );
658     }
659
660     private Shape( int tagcode ) {
661         this.tagcode = tagcode;
662     }
663
664     /* ----------------------------------------------------------------------------------- */
665     /* D R A W I N G */
666     /* ----------------------------------------------------------------------------------- */
667
668     /**
669      * Draws curve record.<p>
670      * All coordinates are in twixels.
671      *
672      * @param cx X control point
673      * @param cy Y control point
674      * @param ax X anchor point
675      * @param ay Y anchor point
676      */

677     public void drawCurveTo( int cx, int cy, int ax, int ay ) {
678         getShapeRecords().drawCurveTo(cx, cy, ax, ay);
679     }
680
681     /**
682      * Draws curve record.<p>
683      * All coordinates are in twixels.
684      *
685      * @param ax1 X anchor point 1
686      * @param ay1 Y anchor point 1
687      * @param cx X control point
688      * @param cy Y control point
689      * @param ax2 X anchor point 2
690      * @param ay2 Y anchor point 2
691      */

692     public void drawCurve( int ax1, int ay1, int cx, int cy, int ax2, int ay2 ) {
693         getShapeRecords().drawCurve(ax1, ay1, cx, cy, ax2, ay2);
694     }
695
696     /**
697      * Draws curve record.<p>
698      * All coordinates are in twixels.
699      *
700      * @param anchor0 first anchor point
701      * @param control control point
702      * @param anchor1 second anchor point
703      */

704     public void drawCurve( Point2D anchor1, Point2D control, Point2D anchor2 ) {
705         getShapeRecords().drawCurve(anchor1, control, anchor2);
706     }
707
708     /**
709      * Draws a straight line from current position to the specified one.<p>
710      * All coordinates are in twixels.
711      *
712      * @param x X of end of line
713      * @param y Y of end of line
714      */

715     public void drawLineTo( int x, int y ) {
716         getShapeRecords().drawLineTo(x, y);
717     }
718
719     /**
720      * Draws a straight line from current position to the specified one.<p>
721      * All coordinates are in twixels.
722      *
723      * @param p1 end of line
724      */

725     public void drawLineTo( Point2D p1 ) {
726         getShapeRecords().drawLineTo(p1);
727     }
728
729     /**
730      * Draws a straight line specified by two points.
731      * <P>
732      * All coordinates are in twixels.
733      *
734      * @param x1 X of the beginning of the line
735      * @param y1 Y of the beginning of the line
736      * @param x2 X of the end of the line
737      * @param y2 Y of the end of the line
738      */

739     public void drawLine( int x1, int y1, int x2, int y2 ) {
740         getShapeRecords().drawLine(x1, y1, x2, y2);
741     }
742
743     /**
744      * Draws a straight line specified by two points.
745      * <P>
746      * All coordinates are in twixels.
747      *
748      * @param p0 first point
749      * @param p1 second point
750      */

751     public void drawLine( Point2D p0, Point2D p1 ) {
752         getShapeRecords().drawLine(p0, p1);
753     }
754
755     /**
756      * Draws a rectangle specified by its top-left corner and width and height
757      * <p>
758      * All coordinates are in twixels.
759      *
760      * @param x x coordinates of top-left corner of the rectangle
761      * @param y y coordinates of top-left corner of the rectangle
762      * @param width width of the rectangle
763      * @param height height of the rectangle
764      */

765     public void drawRectangle( int x, int y, int width, int height ) {
766         getShapeRecords().drawRectangle(x, y, width, height);
767     }
768
769     /**
770      * Draws a rectangle specified by {@link java.awt.geom.Rectangle2D}
771      * <p>
772      * All coordinates are in twixels.
773      *
774      * @param r specified rectangle
775      */

776     public void drawRectangle( Rectangle2D r ) {
777         getShapeRecords().drawRectangle(r);
778     }
779
780     /**
781      * Moves pen to the specified position.<p>
782      * All coordinates are ABSOLUTE and are in twixels.
783      *
784      * @param x new current X
785      * @param y new current Y
786      */

787     public void movePenTo( int x, int y ) {
788         getShapeRecords().movePenTo(x, y);
789     }
790
791     /**
792      * Moves pen to the specified point.<p>
793      * All coordinates are ABSOLUTE and are in twixels!
794      *
795      * @param p new pen position
796      */

797     public void movePenTo( Point2D p ) {
798         getShapeRecords().movePenTo(p);
799     }
800
801     /**
802      * Draw AWT Shape
803      * <P>
804      * All shape coordinates are in twixels!
805      *
806      * @param shape AWT shape
807      */

808     public void drawAWTShape( java.awt.Shape JavaDoc shape ) {
809         getShapeRecords().drawAWTShape(shape);
810     }
811
812     /**
813      * Draw AWT Shape
814      * <P>
815      * All shape coordinates are in twixels!
816      *
817      * @param shape AWT shape
818      */

819     public void drawAWTShape( java.awt.Shape JavaDoc shape, AffineTransform matrix ) {
820         getShapeRecords().drawAWTShape(shape, matrix);
821     }
822
823     /**
824      * Draw AWT PathIterator
825      * <P>
826      * All coordinates are in twixels!
827      *
828      * @param pi AWT PathIterator
829      */

830     public void drawAWTPathIterator( java.awt.geom.PathIterator JavaDoc pi ) {
831         getShapeRecords().drawAWTPathIterator(pi);
832     }
833
834     /**
835      * Returns current pen position
836      *
837      * @return current pen position
838      */

839     public Point2D getCurrentPos() {
840         return getShapeRecords().getCurrentPos();
841     }
842
843     /**
844      * Returns first pen position (first moveTo)
845      *
846      * @return first pen position
847      */

848     public Point2D getFirstPos() {
849         return getShapeRecords().getFirstPos();
850     }
851
852     /* --------------------------------------------------------------------------------------- */
853     /* AWT Stuff */
854     /* --------------------------------------------------------------------------------------- */
855
856     //
857
// THE FOLLOWING CODE IS JUST AN EXPERIMENT!
858
// IT IS NOT INDENDED TO BE USED IN ANY WAY!
859
// IT IS IN A VERY FIRST STAGE OF DEVELOPMENT
860
//
861

862
863     private static class Painter {
864         java.awt.Graphics2D JavaDoc g2;
865         GeneralPath gp_line;
866         GeneralPath gp_fill;
867         java.awt.Paint JavaDoc[] lstyle_paints;
868         java.awt.Stroke JavaDoc[] lstyle_strokes;
869         java.awt.Paint JavaDoc[] fstyle_paints;
870         ShapeStyles ss;
871         int line_idx;
872         int fill_idx;
873
874         Painter( java.awt.Graphics2D JavaDoc g2, GeneralPath gp_fill, GeneralPath gp_line, ShapeStyles ss ) {
875             this.g2 = g2;
876             this.ss = ss;
877             this.gp_line = gp_line;
878             this.gp_fill = gp_fill;
879
880             line_idx = -1;
881             fill_idx = -1;
882             lstyle_paints = new java.awt.Paint JavaDoc[ss.lineStyles.size()];
883             lstyle_strokes = new java.awt.Stroke JavaDoc[ss.lineStyles.size()];
884             fstyle_paints = new java.awt.Paint JavaDoc[ss.fillStyles.size()];
885         }
886
887         void paint_line() {
888             if( line_idx >= 0 && gp_line != null ) {
889                 java.awt.Paint JavaDoc paint = lstyle_paints[line_idx];
890                 java.awt.Stroke JavaDoc stroke = lstyle_strokes[line_idx];
891                 if( paint == null ) {
892                     LineStyle lstyle = ss.getLineStyle(line_idx);
893
894                     int width = lstyle.getWidth();
895                     //if( width < 20 ) width = 20;
896
stroke = new java.awt.BasicStroke JavaDoc(width);//, java.awt.BasicStroke.CAP_ROUND,
897
paint = lstyle.getColor().getAWTColor();
898
899                     lstyle_paints[line_idx] = paint;
900                     lstyle_strokes[line_idx] = stroke;
901                 }
902
903                 g2.setPaint(paint);
904                 g2.setStroke(stroke);
905
906                 g2.draw(gp_line);
907                 gp_line.reset();
908             }
909         }
910
911         void paint_fill() {
912             if( fill_idx >= 0 && gp_fill != null ) {
913                 java.awt.Paint JavaDoc paint = fstyle_paints[fill_idx];
914                 if( paint == null ) {
915                     FillStyle fstyle = ss.getFillStyle(fill_idx);
916
917                     switch( fstyle.getType() ) {
918                         case FillStyle.SOLID: {
919                             paint = fstyle.getColor().getAWTColor();
920                             break;
921                         }
922                         case FillStyle.LINEAR_GRADIENT: {
923                             Gradient grad = fstyle.getGraduent();
924                             paint = grad.getColors()[0].getAWTColor();
925                             break;
926                         }
927                     }
928                     fstyle_paints[fill_idx] = paint;
929                 }
930
931                 if( paint != null ) g2.setPaint(paint);
932
933                 g2.fill(gp_fill);
934                 gp_fill.reset();
935             }
936         }
937
938     }
939
940     /**
941      * Draws itself into specified graphics
942      *
943      * @param g graphics object
944      */

945     public void draw( java.awt.Graphics2D JavaDoc g2 ) {
946         IVVector blocks = new IVVector();
947
948         StyleBlock sb = style_block;
949         while( sb.prev != null ) {
950             blocks.addElement(sb);
951             sb = sb.prev;
952         }
953         blocks.addElement(sb);
954
955         float x = 0f;
956         float y = 0f;
957
958         GeneralPath gp_line = null;
959         GeneralPath gp_fill = null;
960         for( int blk=blocks.size(); --blk>=0; ) {
961             sb = (StyleBlock) blocks.elementAt(blk);
962             ShapeRecords shaperecords = sb.shapeRecords;
963
964             boolean isFills = sb.shapeStyles.fillStyles.size()>0;
965             boolean isLines = sb.shapeStyles.lineStyles.size()>0;
966
967             if( isFills && gp_fill == null ) gp_fill = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
968             if( isLines && gp_line == null ) gp_line = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
969
970             Painter painter = new Painter(g2, gp_fill, gp_line, sb.shapeStyles);
971
972             IVVector records = shaperecords.getShapeRecords();
973             boolean isGpEmpty = true;
974             for( int r=0; r<records.size(); r++ ) {
975                 Object JavaDoc o = records.elementAt(r);
976                 if( o instanceof StyleChangeRecord ) {
977                     StyleChangeRecord sr = (StyleChangeRecord) o;
978                     int f = sr.getFlags();
979
980                     boolean isGpEmpty1 = isGpEmpty;
981
982                     if( (f&(StyleChangeRecord.FILLSTYLE1|StyleChangeRecord.FILLSTYLE0)) != 0 ) {
983                         if( !isGpEmpty ) painter.paint_fill();
984                         int idx = sr.getFillStyle0()-1;
985                         if( idx < 0 ) idx = sr.getFillStyle1()-1;
986                         painter.fill_idx = idx;
987                         isGpEmpty1 = true;
988                     }
989
990                     if( (f&StyleChangeRecord.LINESTYLE) != 0 ) {
991                         if( !isGpEmpty ) painter.paint_line();
992                         painter.line_idx = sr.getLineStyle()-1;
993                         isGpEmpty1 = true;
994                     }
995                     isGpEmpty = isGpEmpty1;
996
997                     if( (f&StyleChangeRecord.MOVETO) != 0 ) {
998                         x = sr.getDeltaX();
999                         y = sr.getDeltaY();
1000                    }
1001
1002                    if( isFills ) gp_fill.moveTo(x, y);
1003                    if( isLines ) gp_line.moveTo(x, y);
1004
1005                } else if( o instanceof StrightEdgeRecord ) {
1006                    StrightEdgeRecord se = (StrightEdgeRecord) o;
1007                    x += se.getDeltaX();
1008                    y += se.getDeltaY();
1009                    if( isFills ) gp_fill.lineTo(x, y);
1010                    if( isLines ) gp_line.lineTo(x, y);
1011                    isGpEmpty = false;
1012                } else {
1013                    CurvedEdgeRecord ce = (CurvedEdgeRecord) o;
1014                    float xx = x+ce.getControlDeltaX();
1015                    float yy = y+ce.getControlDeltaY();
1016                    x = xx+ce.getAnchorDeltaX();
1017                    y = yy+ce.getAnchorDeltaY();
1018                    if( isFills ) gp_fill.quadTo(xx, yy, x, y);
1019                    if( isLines ) gp_line.quadTo(xx, yy, x, y);
1020                    isGpEmpty = false;
1021                }
1022            }
1023            if( !isGpEmpty ) {
1024                painter.paint_fill();
1025                painter.paint_line();
1026            }
1027        }
1028    }
1029}
1030
Popular Tags