You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-commits@xmlgraphics.apache.org by de...@apache.org on 2005/09/25 21:53:33 UTC

svn commit: r291468 [2/19] - in /xmlgraphics/batik/trunk: ./ samples/tests/resources/wmf/ sources/org/apache/batik/ext/awt/geom/ sources/org/apache/batik/svggen/ sources/org/apache/batik/transcoder/ sources/org/apache/batik/transcoder/wmf/ sources/org/...

Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/transcoder/wmf/tosvg/WMFPainter.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/trunk/sources/org/apache/batik/transcoder/wmf/tosvg/WMFPainter.java?rev=291468&r1=291467&r2=291468&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/transcoder/wmf/tosvg/WMFPainter.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/transcoder/wmf/tosvg/WMFPainter.java Sun Sep 25 12:51:54 2005
@@ -11,126 +11,194 @@
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+  
+ */
 
- */package org.apache.batik.transcoder.wmf.tosvg;
+package org.apache.batik.transcoder.wmf.tosvg;
 
 import java.awt.BasicStroke;
+import java.awt.Stroke;
 import java.awt.Color;
 import java.awt.Font;
+import java.awt.Paint;
+import java.awt.Image;
+import java.awt.Dimension;
+import java.awt.TexturePaint;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Polygon;
 import java.awt.Shape;
+import java.awt.Toolkit;
+import java.awt.image.BufferedImage;
+import java.awt.image.ImageObserver;
 import java.awt.font.FontRenderContext;
 import java.awt.font.TextLayout;
+import java.awt.font.TextAttribute;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.GeneralPath;
 import java.awt.geom.Point2D;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+import java.awt.geom.Ellipse2D;
+import java.text.AttributedString;
+import java.text.AttributedCharacterIterator;
 import java.io.BufferedInputStream;
 import java.util.Stack;
 import java.util.Vector;
+import java.util.Iterator;
 
 import org.apache.batik.transcoder.wmf.WMFConstants;
-
+import org.apache.batik.ext.awt.geom.Polygon2D;
+import org.apache.batik.ext.awt.geom.Polyline2D;
 /**
   * Core class for rendering the WMF image. It is able to render a
   * WMF file in a <tt>Graphics</tt> object.
   *
-  *
   * @version $Id$
   * @author <a href="mailto:luano@asd.ie">Luan O'Carroll</a>
   */
-public class WMFPainter {
-    private static final String WMF_FILE_EXTENSION = ".wmf";
-
+public class WMFPainter extends AbstractWMFPainter {
     /**
      * Size of the buffer used for reading input WMF files
      */
     private static final int INPUT_BUFFER_SIZE = 30720;
-
+    
+    private float scale, scaleX, scaleY, conv;
+    private float xOffset, yOffset;
+    private float vpX, vpY, vpW, vpH;
+    
+    private Color frgdColor;
+    private Color bkgdColor;
+    private boolean opaque = false;
+    private transient boolean firstEffectivePaint = true;     
+    
     private static BasicStroke solid
         = new BasicStroke( 1.0f,
                            BasicStroke.CAP_BUTT,
                            BasicStroke.JOIN_ROUND );
+    
+    private static BasicStroke textSolid
+        = new BasicStroke( 1.0f,
+                           BasicStroke.CAP_BUTT,
+                           BasicStroke.JOIN_ROUND );
+    
+    private transient ImageObserver observer = new ImageObserver() {
+        public boolean imageUpdate(Image img, int flags, int x, 
+            int y, int width, int height) {
+                return false;
+        }        
+    };    
+
+    /** Basic constructor.
+     *  @param currentStore where the WMF records are stored
+     *  @param scale the scale of the image
+     */
+    public WMFPainter(WMFRecordStore currentStore, float scale) {
+        this(currentStore, 0, 0, scale);
+    }
 
-    /**
-     * Basic constructor, initializes the storage.
+    /** Basic constructor.
+     *  @param scale the scale of the image
+     *  @param currentStore where the WMF records are stored
+     *  @param xOffset x value for offset
+     *  @param yOffset y value for offset
      */
-    public WMFPainter(WMFRecordStore currentStore) {
+    public WMFPainter(WMFRecordStore currentStore, int xOffset, int yOffset, float scale) {
         setRecordStore(currentStore);
-    }
+        TextureFactory.getInstance().reset();
+        this.conv = scale;
+        this.xOffset = -xOffset;
+        this.yOffset = -yOffset;
+        this.scale = (float)currentStore.getWidthPixels() / (float)currentStore.getWidthUnits() * scale;
+        this.scale = this.scale * (float)currentStore.getWidthPixels() / (float)currentStore.getVpW() ;
+        float xfactor  = (float)currentStore.getVpW() / (float)currentStore.getWidthPixels() 
+            * (float)currentStore.getWidthUnits() / (float)currentStore.getWidthPixels();
+        float yfactor  = (float)currentStore.getVpH() / (float)currentStore.getHeightPixels() 
+            * (float)currentStore.getHeightUnits() / (float)currentStore.getHeightPixels();        
+        this.xOffset = this.xOffset * xfactor;
+        this.yOffset = this.yOffset * yfactor;
+        scaleX = this.scale;
+        scaleY = this.scale;
+    }    
 
     /**
      * Renders the WMF image(s).
      */
     public void paint( Graphics g ) {
         // Objects on DC stack;
-        int           fontHeight = 10;
-        int           fontAngle = 0;
-        int           penWidth = 0;
-        int           startX = 0;
-        int           startY = 0;
-        int           brushObject = -1;
-        int           penObject = -1;
-        int           fontObject = -1;
-        Color         frgdColor;
-        Color         bkgdColor;
-        Font          font = null;
-        int           vpX, vpY, vpW, vpH;
-        Stack         dcStack = new Stack();
+        float fontHeight = 10;
+        float fontAngle = 0;
+        float penWidth = 0;
+        float startX = 0;
+        float startY = 0;
+        int brushObject = -1;
+        int penObject = -1;
+        int fontObject = -1;
+        Font font = null;
+        int lastObjectIdx;
+        Stack dcStack = new Stack();
 
         int numRecords = currentStore.getNumRecords();
         int numObjects = currentStore.getNumObjects();
-        vpX = currentStore.getVpX();
-        vpY = currentStore.getVpY();
-        vpW = currentStore.getVpW();
-        vpH = currentStore.getVpH();
+        vpX = currentStore.getVpX() * scale;
+        vpY = currentStore.getVpY() * scale;
+        vpW = currentStore.getVpW() * scale;
+        vpH = currentStore.getVpH() * scale;
 
         if ( !currentStore.isReading()) {
             GdiObject gdiObj;
             int gdiIndex;
             g.setPaintMode();
+            
+            /** added stroke definition for lines
+             */
+            Graphics2D g2d = (Graphics2D)g;
+            g2d.setStroke(solid);            
 
             brushObject = -1;
             penObject = -1;
             fontObject = -1;
             frgdColor = null;
-            bkgdColor = null;
+            bkgdColor = Color.white;
             for ( int i = 0; i < numObjects; i++ ) {
                 gdiObj = currentStore.getObject( i );
-                gdiObj.Clear();
+                gdiObj.clear();
             }
 
-            int w = vpW;
-            int h = vpH;
-
-            g.setColor( Color.white );
-            g.fillRect( 0, 0, w, h );
-            g.setColor( Color.black );
+            float w = vpW;
+            float h = vpH;
 
-            double scaleX = (double)w / vpW;
-            double scaleY = (double)h / vpH;
+            g2d.setColor( Color.black );
 
             for ( int iRec = 0; iRec < numRecords; iRec++ ) {
                 MetaRecord mr = currentStore.getRecord( iRec );
 
                 switch ( mr.functionId ) {
                 case WMFConstants.META_SETWINDOWORG:
-                    currentStore.setVpX( vpX = -mr.ElementAt( 0 ).intValue());
-                    currentStore.setVpY( vpY = -mr.ElementAt( 1 ).intValue());
+                    currentStore.setVpX( vpX = -(float)mr.ElementAt( 0 ).intValue());
+                    currentStore.setVpY( vpY = -(float)mr.ElementAt( 1 ).intValue());
+                    vpX = vpX * scale;
+                    vpY = vpY * scale;                    
                     break;
 
                 case WMFConstants.META_SETWINDOWORG_EX: // ???? LOOKS SUSPICIOUS
-                case WMFConstants.META_SETWINDOWEXT:
-                    currentStore.setVpW( vpW = mr.ElementAt( 0 ).intValue());
-                    currentStore.setVpH( vpH = mr.ElementAt( 1 ).intValue());
-                    scaleX = (double)w / vpW;
-                    scaleY = (double)h / vpH;
+                case WMFConstants.META_SETWINDOWEXT:                    
+                    vpW = (float)mr.ElementAt( 0 ).intValue();
+                    vpH = (float)mr.ElementAt( 1 ).intValue();
+                    
+
+                    scaleX = scale;
+                    scaleY = scale;
+                    solid = new BasicStroke(scaleX*2,
+                           BasicStroke.CAP_BUTT,
+                           BasicStroke.JOIN_ROUND );
 
-                    // Handled in the read function.
-                    break;
+                      // Handled in the read function.
+                      break;
 
                 case WMFConstants.META_SETVIEWPORTORG:
                 case WMFConstants.META_SETVIEWPORTEXT:
@@ -138,8 +206,7 @@
                 case WMFConstants.META_SCALEWINDOWEXT:
                 case WMFConstants.META_OFFSETVIEWPORTORG:
                 case WMFConstants.META_SCALEVIEWPORTEXT:
-                    break;
-
+                    break;                    
 
                 case WMFConstants.META_SETPOLYFILLMODE:
                     break;
@@ -147,77 +214,104 @@
                 case WMFConstants.META_CREATEPENINDIRECT:
                     {
                         int objIndex = 0;
-                        try {
-                            objIndex = mr.ElementAt( 5 ).intValue();
-                        }
-                        catch ( Exception e ) {}
-                        int penStyle = mr.ElementAt( 0 ).intValue();
+                        int penStyle = (int)mr.ElementAt( 0 ).intValue();
                         Color newClr;
-                        if ( penStyle == 5 ) {
+                        if ( penStyle == WMFConstants.META_PS_NULL ) {
                             newClr = new Color( 255, 255, 255 );
-                            objIndex = numObjects + 8;
-                            addObjectAt( currentStore, NULL_PEN, newClr, objIndex );
+                            //objIndex = numObjects + 8;
+                            objIndex = addObjectAt( currentStore, NULL_PEN, newClr, objIndex );
+                        } else {
+                            penWidth = (int)mr.ElementAt( 4 ).intValue();
+                            setStroke(g2d, penStyle, penWidth, scaleX);
+                            newClr = new Color( (int)mr.ElementAt( 1 ).intValue(),
+                                            (int)mr.ElementAt( 2 ).intValue(),
+                                            (int)mr.ElementAt( 3 ).intValue());
+                            objIndex = addObjectAt( currentStore, PEN, newClr, objIndex );
                         }
-                        else {
-                            newClr = new Color( mr.ElementAt( 1 ).intValue(),
-                                                mr.ElementAt( 2 ).intValue(),
-                                                mr.ElementAt( 3 ).intValue());
-                            addObjectAt( currentStore, PEN, newClr, objIndex );
-                        }
-                        penWidth = mr.ElementAt( 4 ).intValue();
                     }
                     break;
 
                 case WMFConstants.META_CREATEBRUSHINDIRECT:
                     {
                         int objIndex = 0;
-                        try {
-                            objIndex = mr.ElementAt( 5 ).intValue();
-                        }
-                        catch ( Exception e ) {}
-                        int brushStyle = mr.ElementAt( 0 ).intValue();
-                        if ( brushStyle == 0 ) {
-                            addObjectAt(currentStore, BRUSH,
-                                        new Color(mr.ElementAt( 1 ).intValue(),
-                                                  mr.ElementAt( 2 ).intValue(),
-                                                  mr.ElementAt( 3 ).intValue()),
-                                        objIndex );
+                        int brushStyle = (int)mr.ElementAt( 0 ).intValue();
+                        Color clr = new Color( (int)mr.ElementAt( 1 ).intValue(),
+                                               (int)mr.ElementAt( 2 ).intValue(),
+                                               (int)mr.ElementAt( 3 ).intValue());
+                        if ( brushStyle == WMFConstants.BS_SOLID ) {
+                            objIndex = addObjectAt( currentStore, BRUSH, clr, objIndex );                                
+                        } else if (brushStyle == WMFConstants.BS_HATCHED) {
+                            int hatch = (int)mr.ElementAt( 4 ).intValue();
+                            Paint paint;
+                            if (! opaque) 
+                                paint = TextureFactory.getInstance().getTexture(hatch, clr);
+                            else 
+                                paint = TextureFactory.getInstance().getTexture(hatch, clr, bkgdColor);
+                            if (paint != null) 
+                                objIndex = addObjectAt( currentStore, BRUSH, paint, objIndex ); 
+                            else {
+                                clr = new Color( 0,0,0 );
+                                objIndex = addObjectAt( currentStore, NULL_BRUSH, clr, objIndex );                                                                
+                            }
+                        } else {
+                            clr = new Color( 0,0,0 );
+                            objIndex = addObjectAt( currentStore, NULL_BRUSH, clr, objIndex );
                         }
-                        else
-                            addObjectAt( currentStore, NULL_BRUSH, new Color( 0,0,0 ), objIndex );
                     }
                     break;
-
+                    
                 case WMFConstants.META_CREATEFONTINDIRECT:
                     {
-                        int style =(mr.ElementAt( 1 ).intValue() > 0 ? Font.ITALIC : Font.PLAIN );
-                        style |=   (mr.ElementAt( 2 ).intValue() > 400 ? Font.BOLD : Font.PLAIN );
+                        float size = (int)( scaleY * ( mr.ElementAt( 0 ).intValue()));
+                        int charset = (int)mr.ElementAt( 3 ).intValue();
 
-                        int size = (int)( scaleY * ( mr.ElementAt( 0 ).intValue()));
-                        String face = ((StringRecord)mr).text;
-                        if ( size < 0 )
-                            size = (int)(size * -1.3 );
+                        int italic = (int)mr.ElementAt( 1 ).intValue();
+                        int weight = (int)mr.ElementAt( 2 ).intValue();                        
+                        int style = italic > 0 ? Font.ITALIC : Font.PLAIN;
+                        style |= (weight > 400) ? Font.BOLD : Font.PLAIN; 
+                        
+                        String face = ((MetaRecord.StringRecord)mr).text;
+                        // management of font names
+                        int d = 0;
+                        while   ((d < face.length()) && 
+                                ((Character.isLetterOrDigit(face.charAt(d))) ||
+                                 (Character.isWhitespace(face.charAt(d))))) d++;
+                        if (d > 0) face = face.substring(0,d);
+                        else face = "System";
+                        
+                        if ( size < 0 ) size = -size /* * -1.3 */;
                         int objIndex = 0;
-                        try {
-                            objIndex = mr.ElementAt( 3 ).intValue();
-                        }
-                        catch ( Exception e ) {}
+
                         fontHeight = size;
-                        //fontAngle = mr.ElementAt( 5 ).intValue();
-                        //if ( fontAngle > 0 )
-                        //  size = ( size *12 ) / 10;
-                        addObjectAt( currentStore, FONT, font = new Font( face, style, size ), objIndex );
+
+                        Font f = new Font(face, style, (int)size);
+                        f = f.deriveFont(size);
+                        
+                        int underline = (int)mr.ElementAt( 4 ).intValue();
+                        int strikeOut = (int)mr.ElementAt( 5 ).intValue();
+                        int orient = (int)mr.ElementAt( 6 ).intValue();
+                        int escape = (int)mr.ElementAt( 7 ).intValue();
+                        
+                        WMFFont wf = new WMFFont(f, charset, underline, 
+                            strikeOut, italic, weight, orient, escape);
+                        objIndex = addObjectAt( currentStore, FONT, wf , objIndex );
                     }
                     break;
 
-                case WMFConstants.META_DIBCREATEPATTERNBRUSH:
                 case WMFConstants.META_CREATEBRUSH:
                 case WMFConstants.META_CREATEPATTERNBRUSH:
                 case WMFConstants.META_CREATEBITMAPINDIRECT:
                 case WMFConstants.META_CREATEBITMAP:
-                case WMFConstants.META_CREATEREGION:
-                case WMFConstants.META_CREATEPALETTE:
-                    addObjectAt( currentStore, PALETTE, new Integer( 0 ), 0 );
+                case WMFConstants.META_CREATEREGION: {
+                    int objIndex = 0;
+                    objIndex = addObjectAt( currentStore, PALETTE, new Integer( 0 ), 0 );
+                    }
+                    break;
+
+                case WMFConstants.META_CREATEPALETTE: {
+                    int objIndex = 0;
+                    objIndex = addObjectAt( currentStore, OBJ_REGION, new Integer( 0 ), 0 );
+                    }
                     break;
 
                 case WMFConstants.META_SELECTPALETTE:
@@ -233,6 +327,7 @@
                         break;
                     if ( gdiIndex >= numObjects ) {
                         gdiIndex -= numObjects;
+                        
                         switch ( gdiIndex ) {
                         case WMFConstants.META_OBJ_NULL_BRUSH:
                             brushObject = -1;
@@ -263,16 +358,22 @@
                         break;
                     switch( gdiObj.type ) {
                     case PEN:
-                        g.setColor( (Color)gdiObj.obj );
+                        g2d.setColor( (Color)gdiObj.obj );
                         penObject = gdiIndex;
                         break;
                     case BRUSH:
-                        g.setColor( (Color)gdiObj.obj );
+                        if (gdiObj.obj instanceof Color) g2d.setColor( (Color)gdiObj.obj );
+                        else if (gdiObj.obj instanceof Paint) {
+                            g2d.setPaint((Paint)gdiObj.obj);
+                        } else g2d.setPaint(getPaint((byte[])(gdiObj.obj)));
                         brushObject = gdiIndex;
                         break;
-                    case FONT:
-                        g.setFont( font = (Font)gdiObj.obj );
+                    case FONT: {
+                        this.wmfFont =  ((WMFFont)gdiObj.obj);
+                        Font f = this.wmfFont.font;
+                        g2d.setFont(f);
                         fontObject = gdiIndex;
+                        }
                         break;
                     case NULL_PEN:
                         penObject = -1;
@@ -286,76 +387,80 @@
                 case WMFConstants.META_DELETEOBJECT:
                     gdiIndex = mr.ElementAt( 0 ).intValue();
                     gdiObj = currentStore.getObject( gdiIndex );
-                    if ( gdiIndex == brushObject )
-                        brushObject = -1;
-                    else if ( gdiIndex == penObject )
-                        penObject = -1;
-                    else if ( gdiIndex == fontObject )
-                        fontObject = -1;
-                    gdiObj.Clear();
+                    if ( gdiIndex == brushObject ) brushObject = -1;
+                    else if ( gdiIndex == penObject ) penObject = -1;
+                    else if ( gdiIndex == fontObject ) fontObject = -1;
+                    gdiObj.clear();
                     break;
 
                 case WMFConstants.META_POLYPOLYGON:
                     {
-                      int numPolygons = mr.ElementAt( 0 ).intValue();
-                      int[] pts = new int[ numPolygons ];
-                      for ( int ip = 0; ip < numPolygons; ip++ )
-                          pts[ ip ] = mr.ElementAt( ip + 1 ).intValue();
-
-                      GeneralPath gp = new GeneralPath();
-                      int offset = numPolygons+1;
-                      for ( int j = 0; j < numPolygons; j++ ) {
-                          int count = pts[ j ];
-                          int[] xpts = new int[ count ];
-                          int[] ypts = new int[ count ];
-                          for ( int k = 0; k < count; k++ ) {
-                              xpts[k] = (int)(  scaleX * ( vpX + mr.ElementAt( offset + k*2 ).intValue()));
-                              ypts[k] = (int)( scaleY * ( vpY + mr.ElementAt( offset + k*2+1 ).intValue()));
-                          }
-                          offset += count;
-                          Polygon p = new Polygon(xpts, ypts, count);
-                          gp.append( p, true );
-                      }
-                      if ( brushObject >= 0 ) {
-                          setBrushColor( currentStore, g, brushObject );
-                          ( (Graphics2D) g).fill(gp);
-                      }
-                      setPenColor( currentStore, g, penObject );
-                      ( (Graphics2D) g).draw(gp);
+                        int numPolygons = mr.ElementAt( 0 ).intValue();
+                        int[] pts = new int[ numPolygons ];
+                        for ( int ip = 0; ip < numPolygons; ip++ )
+                            pts[ ip ] = mr.ElementAt( ip + 1 ).intValue();
+
+                        int offset = numPolygons+1;
+                        Vector v = new Vector(1);
+                        for ( int j = 0; j < numPolygons; j++ ) {
+                            int count = pts[ j ];
+                            float[] xpts = new float[count];
+                            float[] ypts = new float[count];
+                            for ( int k = 0; k < count; k++ ) {
+                                xpts[k] = scaleX * (vpX + (
+                                    float)(xOffset + mr.ElementAt( offset + k*2 ).intValue()));
+                                ypts[k] = scaleY * (vpY + 
+                                    (float)(yOffset + mr.ElementAt( offset + k*2+1 ).intValue()));
+                            }
+
+                            offset += count*2;
+                            Polygon2D pol = new Polygon2D(xpts, ypts, count);
+                            v.add(pol);
+                        }
+                        /* need to do this for POLYPOLYGON, because only
+                         * GeneralPaths can handle filling for complex WMF shapes, so
+                         * we need to get all the Polygons and then convert them to a GeneralPath
+                         */                    
+                        if ( brushObject >= 0 ) {
+                            setBrushPaint( currentStore, g2d, brushObject );
+                            fillPolyPolygon(g2d, v);
+                            firstEffectivePaint = false;
+                        }
+                        // painting with NULL PEN
+                        if (penObject >= 0) {                            
+                            setPenColor( currentStore, g2d, penObject );
+                            drawPolyPolygon(g2d, v);
+                            firstEffectivePaint = false;                            
+                        }
+                        break;
                     }
-                    break;
 
                 case WMFConstants.META_POLYGON:
                     {
                         int count = mr.ElementAt( 0 ).intValue();
-                        int[] _xpts = new int[ count+1 ];
-                        int[] _ypts = new int[ count+1 ];
+                        float[] _xpts = new float[ count ];
+                        float[] _ypts = new float[ count ];
                         for ( int k = 0; k < count; k++ ) {
-                            _xpts[k] = (int)( scaleX * ( vpX + mr.ElementAt( k*2+1 ).intValue()));
-                            _ypts[k] = (int)( scaleY * ( vpY + mr.ElementAt( k*2+2 ).intValue()));
+                            _xpts[k] = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( k*2+1 ).intValue()));
+                            _ypts[k] = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( k*2+2 ).intValue()));
                         }
-                        _xpts[count] = _xpts[0];
-                        _ypts[count] = _ypts[0];
-                        if ( brushObject >= 0 ) {
-                            setBrushColor( currentStore, g, brushObject );
-                            g.fillPolygon( _xpts, _ypts, count );
-                        }
-                        setPenColor( currentStore, g, penObject );
-                        g.drawPolygon( _xpts, _ypts, count+1 );
+                        Polygon2D pol = new Polygon2D(_xpts, _ypts, count);
+                        paint(brushObject, penObject, pol, g2d);
                     }
                     break;
 
                 case WMFConstants.META_MOVETO:
-                    startX = (int)( scaleX * ( vpX + mr.ElementAt( 0 ).intValue()));
-                    startY = (int)( scaleY * ( vpY + mr.ElementAt( 1 ).intValue()));
+                    startX = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( 0 ).intValue()));
+                    startY = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( 1 ).intValue()));
                     break;
 
                 case WMFConstants.META_LINETO:
                     {
-                        int endX = (int)( scaleX * ( vpX + mr.ElementAt( 0 ).intValue()));
-                        int endY = (int)( scaleY * ( vpY + mr.ElementAt( 1 ).intValue()));
-                        setPenColor( currentStore, g, penObject );
-                        g.drawLine( startX, startY, endX, endY );
+                        float endX = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( 0 ).intValue()));
+                        float endY = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( 1 ).intValue()));
+                        // painting with NULL PEN
+                        Line2D.Float line = new Line2D.Float(startX, startY, endX, endY);
+                        paintWithPen(penObject, line, g2d);                          
                         startX = endX;
                         startY = endY;
                     }
@@ -363,163 +468,217 @@
 
                 case WMFConstants.META_POLYLINE:
                     {
-                        setPenColor( currentStore, g, penObject );
                         int count = mr.ElementAt( 0 ).intValue();
-                        int endX, endY;
-                        int _startX, _startY;
-                        _startX = (int)( scaleX * ( vpX + mr.ElementAt( 1 ).intValue()));
-                        _startY = (int)( scaleY * ( vpY + mr.ElementAt( 2 ).intValue()));
-                        for ( int j = 1; j < count; j++ ) {
-                            endX = (int)( scaleX * ( vpX + mr.ElementAt( j*2+1 ).intValue()));
-                            endY = (int)( scaleY * ( vpY + mr.ElementAt( j*2+2 ).intValue()));
-                            g.drawLine( _startX, _startY, endX, endY );
-                            _startX = endX;
-                            _startY = endY;
+                        float[] _xpts = new float[ count ];
+                        float[] _ypts = new float[ count ];
+                        for ( int k = 0; k < count; k++ ) {
+                            _xpts[k] = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( k*2+1 ).intValue()));
+                            _ypts[k] = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( k*2+2 ).intValue()));
                         }
+                        Polyline2D pol = new Polyline2D(_xpts, _ypts, count);
+                        paintWithPen(penObject, pol, g2d);                        
                     }
                     break;
 
                 case WMFConstants.META_RECTANGLE:
                     {
-                        int x1, y1, x2, y2;
-                        x1 = (int)( scaleX * ( vpX + mr.ElementAt( 0 ).intValue()));
-                        x2 = (int)( scaleX * ( vpX + mr.ElementAt( 2 ).intValue()));
-                        y1 = (int)( scaleY * ( vpY + mr.ElementAt( 1 ).intValue()));
-                        y2 = (int)( scaleY * ( vpY + mr.ElementAt( 3 ).intValue()));
-
-                        if ( brushObject >= 0 ) {
-                            setBrushColor( currentStore, g, brushObject );
-                            g.fillRect( x1, y1, x2-x1-1, y2-y1-1 );
-                        }
-                        setPenColor( currentStore, g, penObject );
-                        g.drawRect( x1, y1, x2-x1-1, y2-y1-1 );
+                        float x1, y1, x2, y2;
+                        x1 = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( 0 ).intValue()));
+                        x2 = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( 2 ).intValue()));
+                        y1 = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( 1 ).intValue()));
+                        y2 = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( 3 ).intValue()));
+                        
+                        Rectangle2D.Float rec = new Rectangle2D.Float(x1, y1, x2-x1, y2-y1);
+                        paint(brushObject, penObject, rec, g2d);
                     }
                     break;
 
                 case WMFConstants.META_ROUNDRECT:
                     {
-                        int x1, y1, x2, y2, x3, y3;
-                        x1 = (int)( scaleX * ( vpX + mr.ElementAt( 0 ).intValue()));
-                        x2 = (int)( scaleX * ( vpX + mr.ElementAt( 2 ).intValue()));
-                        x3 = (int)( scaleX * ( mr.ElementAt( 4 ).intValue()));
-                        y1 = (int)( scaleY * ( vpY + mr.ElementAt( 1 ).intValue()));
-                        y2 = (int)( scaleY * ( vpY + mr.ElementAt( 3 ).intValue()));
-                        y3 = (int)( scaleY * ( mr.ElementAt( 5 ).intValue()));
+                        float x1, y1, x2, y2, x3, y3;
+                        x1 = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( 0 ).intValue()));
+                        x2 = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( 2 ).intValue()));
+                        x3 = scaleX * (float)(mr.ElementAt( 4 ).intValue());
+                        y1 = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( 1 ).intValue()));
+                        y2 = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( 3 ).intValue()));
+                        y3 = scaleY * (float)(mr.ElementAt( 5 ).intValue());
+                        
+                        RoundRectangle2D rec = 
+                            new RoundRectangle2D.Float(x1, y1, x2-x1, y2-y1, x3, y3);
 
-                        if ( brushObject >= 0 ) {
-                            setBrushColor( currentStore, g, brushObject );
-                            g.fillRoundRect( x1, y1, x2-x1, y2-y1, x3, y3 );
-                        }
-                        setPenColor( currentStore, g, penObject );
-                        g.drawRoundRect( x1, y1, x2-x1, y2-y1, x3, y3 );
+                        paint(brushObject, penObject, rec, g2d);
                     }
                     break;
 
                 case WMFConstants.META_ELLIPSE:
                     {
-                        int x1, y1, x2, y2;
-                        x1 = (int)( scaleX * ( vpX + mr.ElementAt( 0 ).intValue()));
-                        x2 = (int)( scaleX * ( vpX + mr.ElementAt( 2 ).intValue()));
-                        y1 = (int)( scaleY * ( vpY + mr.ElementAt( 1 ).intValue()));
-                        y2 = (int)( scaleY * ( vpY + mr.ElementAt( 3 ).intValue()));
-
-                        if ( brushObject >= 0 ) {
-                            setBrushColor( currentStore, g, brushObject );
-                            g.fillOval( x1, y1, x2-x1, y2-y1 );
-                        }
-                        setPenColor( currentStore, g, penObject );
-                        g.drawOval( x1, y1, x2-x1-1, y2-y1-1 );
+                        float x1, y1, x2, y2;
+                        x1 = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( 0 ).intValue()));
+                        x2 = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( 2 ).intValue()));
+                        y1 = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( 1 ).intValue()));
+                        y2 = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( 3 ).intValue()));
+                        
+                        Ellipse2D.Float el = new Ellipse2D.Float(x1, y1, x2-x1, y2-y1);
+                        paint(brushObject, penObject, el, g2d);
                     }
                     break;
-
+                    
+                case WMFConstants.META_SETTEXTALIGN:
+                    currentAlign = 
+                        getHorizontalAlignement((int)mr.ElementAt( 0 ).intValue());
+                    break;                
+                    
                 case WMFConstants.META_SETTEXTCOLOR:
-                    frgdColor = new Color(mr.ElementAt( 0 ).intValue(),
-                                          mr.ElementAt( 1 ).intValue(),
-                                          mr.ElementAt( 2 ).intValue());
+                    frgdColor = new Color( (int)mr.ElementAt( 0 ).intValue(),
+                                           (int)mr.ElementAt( 1 ).intValue(),
+                                           (int)mr.ElementAt( 2 ).intValue());
+                    g2d.setColor(frgdColor);
                     break;
 
                 case WMFConstants.META_SETBKCOLOR:
-                    bkgdColor = new Color(mr.ElementAt( 0 ).intValue(),
-                                          mr.ElementAt( 1 ).intValue(),
-                                          mr.ElementAt( 2 ).intValue());
+                    bkgdColor = new Color( (int)mr.ElementAt( 0 ).intValue(),
+                                           (int)mr.ElementAt( 1 ).intValue(),
+                                           (int)mr.ElementAt( 2 ).intValue());
+                    g2d.setColor(bkgdColor);
                     break;
 
                 case WMFConstants.META_EXTTEXTOUT:
+                    try {
+                        float x, y;
+                        byte[] bstr = ((MetaRecord.ByteRecord)mr).bstr;
+                        String sr = decodeString(bstr);
+
+                        x = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( 0 ).intValue()));
+                        y = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( 1 ).intValue()));
+                        if ( frgdColor != null ) g2d.setColor( frgdColor );
+                        else g2d.setColor( Color.black );
+
+                        FontRenderContext frc = g2d.getFontRenderContext();
+
+                        Point2D.Double pen = new Point2D.Double( 0, 0 );
+                        GeneralPath gp = new GeneralPath( GeneralPath.WIND_NON_ZERO );
+                        TextLayout layout = new TextLayout( sr, g2d.getFont(), frc );
+                        pen.y += layout.getAscent();
+                        
+                        int flag = mr.ElementAt( 2 ).intValue();
+                        int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
+                        boolean clipped = false;
+                        Shape clip = null;
+                        // process clipped texts
+                        if ((flag & WMFConstants.ETO_CLIPPED) != 0) {
+                            clipped = true; 
+                            x1 = mr.ElementAt( 3 ).intValue();
+                            y1 = mr.ElementAt( 3 ).intValue();
+                            x2 = mr.ElementAt( 4 ).intValue();
+                            y2 = mr.ElementAt( 5 ).intValue();
+                            clip = g2d.getClip();
+                            g2d.setClip(x1, y1, x2, y2);
+                        }
+                        
+                        firstEffectivePaint = false; 
+                        drawString(flag, g2d, 
+                            getCharacterIterator(g2d, sr, wmfFont, currentAlign), x, y, layout, 
+                            wmfFont, currentAlign);
+                        if (clipped) g2d.setClip(clip);
+                    } catch ( Exception e ) {
+                    }          
+                    break;
+                    
                 case WMFConstants.META_TEXTOUT:
                 case WMFConstants.META_DRAWTEXT:
-                    try
-                        {
-                            Graphics2D g2 = (Graphics2D)g;
-                            int x, y;
-                            x = (int)( scaleX * ( vpX + mr.ElementAt( 0 ).intValue()));
-                            y = (int)( fontHeight + scaleY * ( vpY + mr.ElementAt( 1 ).intValue()));
-                            if ( frgdColor != null )
-                                g.setColor( frgdColor );
-                            else
-                                g.setColor( Color.black );
-                            StringRecord sr = (StringRecord)mr;
-
-                            FontRenderContext frc = g2.getFontRenderContext();
-
-                            Point2D.Double pen = new Point2D.Double( 0, 0 );
-                            GeneralPath gp = new GeneralPath( GeneralPath.WIND_NON_ZERO );
-                            TextLayout layout = new TextLayout( sr.text, font, frc );
-                            pen.y += layout.getAscent();
-
-                            if (( fontAngle != 0 ) || sr.text.startsWith("Sono una scala verticale di prevalenza") ) {
-                                AffineTransform at = new AffineTransform();
-                                float height = (float)layout.getBounds().getHeight();
-
-                                AffineTransform textAt = new AffineTransform();
-                                textAt.translate( x, y);
-                                textAt.rotate(Math.toRadians(270));
-                                textAt.translate(0, height);
-                                Shape shape = layout.getOutline(textAt);
-                                gp.append( at.createTransformedShape( shape )/*layout.getOutline( null ))*/, false );
-                                g2.draw( shape );
-                            }
-                            else
-                                g.drawString( sr.text, x, y );
-                        }
-                    catch ( Exception e )
-                        {
-                        }
+                    try {
+                        float x, y;
+                        byte[] bstr = ((MetaRecord.ByteRecord)mr).bstr;
+                        String sr = decodeString(bstr);
+
+                        x = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( 0 ).intValue()));
+                        y = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( 1 ).intValue()));
+                        if ( frgdColor != null ) g2d.setColor( frgdColor );
+                        else g2d.setColor( Color.black );
+
+                        FontRenderContext frc = g2d.getFontRenderContext();
+
+                        Point2D.Double pen = new Point2D.Double( 0, 0 );
+                        GeneralPath gp = new GeneralPath( GeneralPath.WIND_NON_ZERO );
+                        TextLayout layout = new TextLayout( sr, g2d.getFont(), frc );
+                        
+                        pen.y += layout.getAscent();
+                        firstEffectivePaint = false;                         
+                        
+                        drawString(-1, g2d, 
+                            getCharacterIterator(g2d, sr, wmfFont), 
+                            x, y, layout, wmfFont, currentAlign);
+                    } catch ( Exception e ) {
+                    }
                     break;
 
                 case WMFConstants.META_ARC:
                 case WMFConstants.META_PIE:
                     {
-                        int x1, y1, x2, y2, x3, y3, x4, y4;
-                        x1 = (int)( scaleX * ( vpX + mr.ElementAt( 0 ).intValue()));
-                        x2 = (int)( scaleX * ( vpX + mr.ElementAt( 2 ).intValue()));
-                        x3 = (int)( scaleX * ( mr.ElementAt( 4 ).intValue()));
-                        x4 = (int)( scaleX * ( mr.ElementAt( 6 ).intValue()));
-                        y1 = (int)( scaleY * ( vpY + mr.ElementAt( 1 ).intValue()));
-                        y2 = (int)( scaleY * ( vpY + mr.ElementAt( 3 ).intValue()));
-                        y3 = (int)( scaleY * ( mr.ElementAt( 5 ).intValue()));
-                        y4 = (int)( scaleY * ( mr.ElementAt( 7 ).intValue()));
-                        setBrushColor( currentStore, g, brushObject );
-
-                        int mx = x1+(x2-x1)/2;
-                        int my = y1+(y2-y1)/2;
-                        int startAngle = (int)Math.atan( (y3-my)/(x3-mx));
-                        int endAngle = (int)Math.atan( (y4-my)/(x4-mx));
-                        if ( mr.functionId == 0x0817 )
-                            g.drawArc( x1, y1, x2-x1, y2-y1, startAngle, endAngle );
-                        else
-                            g.fillArc( x1, y1, x2-x1, y2-y1, startAngle, endAngle );
-
+                        double left, top, right, bottom; 
+                        double xstart, ystart, xend, yend;
+                        left = scaleX * ( vpX + xOffset + mr.ElementAt( 0 ).doubleValue());
+                        top = scaleY * ( vpY + yOffset + mr.ElementAt( 1 ).doubleValue());
+                        right = scaleX * ( vpX + xOffset + mr.ElementAt( 2 ).doubleValue());
+                        bottom = scaleY * ( vpY + yOffset + mr.ElementAt( 3 ).doubleValue());
+                        xstart = scaleX * ( vpX + xOffset + mr.ElementAt( 4 ).doubleValue());
+                        ystart = scaleY * ( vpY + yOffset + mr.ElementAt( 5 ).doubleValue());
+                        xend = scaleX * ( vpX + xOffset + mr.ElementAt( 6 ).doubleValue());
+                        yend = scaleY * ( vpY + yOffset + mr.ElementAt( 7 ).doubleValue());
+                        setBrushPaint( currentStore, g2d, brushObject );                        
+                        
+                        double cx = left + (right - left)/2;
+                        double cy = top + (bottom - top)/2;
+                        double startAngle = -(double)(180d/Math.PI * Math.atan2(ystart - cy, xstart - cx));
+                        double endAngle = -(double)(180d/Math.PI * Math.atan2(yend - cy, xend - cx));
+                                                
+                        double extentAngle = endAngle - startAngle;
+                        if (extentAngle < 0) extentAngle += 360;
+                        if (startAngle < 0) startAngle +=360;
+                        
+                        Arc2D.Double arc = new Arc2D.Double(left, top, right - left, bottom - top,
+                            startAngle, extentAngle, Arc2D.OPEN);
+                        if ( mr.functionId == WMFConstants.META_ARC ) g2d.draw(arc);
+                        else g2d.fill(arc);
+                        firstEffectivePaint = false;
                     }
                     break;
 
 
                 case WMFConstants.META_CHORD:
+                {
+                        double left, top, right, bottom; 
+                        double xstart, ystart, xend, yend;
+                        left = scaleX * ( vpX + xOffset + mr.ElementAt( 0 ).doubleValue());
+                        top = scaleY * ( vpY + yOffset + mr.ElementAt( 1 ).doubleValue());
+                        right = scaleX * ( vpX + xOffset + mr.ElementAt( 2 ).doubleValue());
+                        bottom = scaleY * ( vpY + yOffset + mr.ElementAt( 3 ).doubleValue());
+                        xstart = scaleX * ( vpX + xOffset + mr.ElementAt( 4 ).doubleValue());
+                        ystart = scaleY * ( vpY + yOffset + mr.ElementAt( 5 ).doubleValue());
+                        xend = scaleX * ( vpX + xOffset + mr.ElementAt( 6 ).doubleValue());
+                        yend = scaleY * ( vpY + yOffset + mr.ElementAt( 7 ).doubleValue());
+                        setBrushPaint( currentStore, g2d, brushObject );                        
+                        
+                        double cx = left + (right - left)/2;
+                        double cy = top + (bottom - top)/2;
+                        double startAngle = -(double)(180d/Math.PI * Math.atan2(ystart - cy, xstart - cx));
+                        double endAngle = -(double)(180d/Math.PI * Math.atan2(yend - cy, xend - cx));
+                                                
+                        double extentAngle = endAngle - startAngle;
+                        if (extentAngle < 0) extentAngle += 360;
+                        if (startAngle < 0) startAngle +=360;
+                        
+                        Arc2D.Double arc = new Arc2D.Double(left, top, right - left, bottom - top,
+                            startAngle, extentAngle, Arc2D.CHORD);
+                        paint(brushObject, penObject, arc, g2d);
+                        firstEffectivePaint = false; 
+                    }
                     break;
 
                 case WMFConstants.META_SAVEDC:
-                    dcStack.push( new Integer( penWidth ));
-                    dcStack.push( new Integer( startX ));
-                    dcStack.push( new Integer( startY ));
+                    dcStack.push( new Float( penWidth ));
+                    dcStack.push( new Float( startX ));
+                    dcStack.push( new Float( startY ));
                     dcStack.push( new Integer( brushObject ));
                     dcStack.push( new Integer( penObject ));
                     dcStack.push( new Integer( fontObject ));
@@ -533,16 +692,15 @@
                     fontObject = ((Integer)(dcStack.pop())).intValue();
                     penObject = ((Integer)(dcStack.pop())).intValue();
                     brushObject = ((Integer)(dcStack.pop())).intValue();
-                    startY = ((Integer)(dcStack.pop())).intValue();
-                    startX = ((Integer)(dcStack.pop())).intValue();
-                    penWidth = ((Integer)(dcStack.pop())).intValue();
+                    startY = ((Float)(dcStack.pop())).floatValue();
+                    startX = ((Float)(dcStack.pop())).floatValue();
+                    penWidth = ((Float)(dcStack.pop())).floatValue();
                     break;
 
                 case WMFConstants.META_POLYBEZIER16:
                     try
                         {
-                            Graphics2D g2 = (Graphics2D)g;
-                            setPenColor( currentStore, g, penObject );
+                            setPenColor( currentStore, g2d, penObject );
 
                             int pointCount = mr.ElementAt( 0 ).intValue();
                             int bezierCount = ( pointCount-1 ) / 3;
@@ -550,32 +708,32 @@
                             float cp1X, cp1Y;
                             float cp2X, cp2Y;
                             float _startX, _startY;
-                            _startX = (float)( scaleX * ( vpX + mr.ElementAt( 1 ).intValue()));
-                            _startY = (float)( scaleY * ( vpY + mr.ElementAt( 2 ).intValue()));
+                            _startX = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( 1 ).intValue()));
+                            _startY = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( 2 ).intValue()));
 
                             GeneralPath gp = new GeneralPath( GeneralPath.WIND_NON_ZERO );
                             gp.moveTo( _startX, _startY );
 
                             for ( int j = 0; j < bezierCount; j++ ) {
-                                cp1X = (float)( scaleX * ( vpX + mr.ElementAt( j*6+3 ).intValue()));
-                                cp1Y = (float)( scaleY * ( vpY + mr.ElementAt( j*6+4 ).intValue()));
+                                cp1X = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( j*6+3 ).intValue()));
+                                cp1Y = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( j*6+4 ).intValue()));
 
-                                cp2X = (float)( scaleX * ( vpX + mr.ElementAt( j*6+5 ).intValue()));
-                                cp2Y = (float)( scaleY * ( vpY + mr.ElementAt( j*6+6 ).intValue()));
+                                cp2X = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( j*6+5 ).intValue()));
+                                cp2Y = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( j*6+6 ).intValue()));
 
-                                endX = (float)( scaleX * ( vpX + mr.ElementAt( j*6+7 ).intValue()));
-                                endY = (float)( scaleY * ( vpY + mr.ElementAt( j*6+8 ).intValue()));
+                                endX = scaleX * ( vpX + (float)(xOffset + mr.ElementAt( j*6+7 ).intValue()));
+                                endY = scaleY * ( vpY + (float)(yOffset + mr.ElementAt( j*6+8 ).intValue()));
 
                                 gp.curveTo( cp1X, cp1Y, cp2X, cp2Y, endX, endY );
                                 _startX = endX;
                                 _startY = endY;
                             }
                                 //gp.closePath();
-                            g2.setStroke( solid );
-                            g2.draw( gp );
+                            g2d.setStroke( solid );
+                            g2d.draw( gp );
+                            firstEffectivePaint = false;
                         }
                     catch ( Exception e ) {
-                        System.out.println( "Unable to draw static text as a 2D graphics context is required" );
                     }
                     break;
 
@@ -585,15 +743,121 @@
                 case WMFConstants.META_OFFSETCLIPRGN:
                 case WMFConstants.META_SELECTCLIPREGION:
 
-                case WMFConstants.META_SETBKMODE:
                 case WMFConstants.META_SETMAPMODE:
-                case WMFConstants.META_SETROP2:
                 case WMFConstants.META_SETRELABS:
                 case WMFConstants.META_SETSTRETCHBLTMODE:
                 case WMFConstants.META_SETTEXTCHAREXTRA:
                 case WMFConstants.META_SETTEXTJUSTIFICATION:
                 case WMFConstants.META_FLOODFILL:
+                    break;
+
+                case WMFConstants.META_SETBKMODE:
+                    {
+                        int mode = mr.ElementAt( 0 ).intValue();
+                        if (mode == WMFConstants.OPAQUE) opaque = true;
+                        else opaque = false;
+                    }
+                    break;
+                
+                    //UPDATED : added SETROP2                    
+                case WMFConstants.META_SETROP2:
+                    {
+                        float rop = (float)(mr.ElementAt( 0 ).intValue());
+                        Paint paint = null;
+                        boolean ok = false;
+                        if (rop == WMFConstants.META_BLACKNESS) {
+                            paint = Color.black;
+                            ok = true;
+                        } else if (rop == WMFConstants.META_WHITENESS) {
+                            paint = Color.white;
+                            ok = true;
+                        } else if (rop == WMFConstants.META_PATCOPY) {
+                            if ( brushObject >= 0 ) {                            
+                                paint = getStoredPaint(currentStore, brushObject);
+                                ok = true;
+                            }
+                        }
+                        
+                        if (ok) {
+                            if (paint != null) {
+                                g2d.setPaint(paint);
+                            } else {
+                                setBrushPaint( currentStore, g2d, brushObject );
+                            }
+                        }
+                    }
+                    break;
                 case WMFConstants.META_PATBLT:
+                    {
+                        float rop = (float)(mr.ElementAt( 0 ).intValue());
+                        float height = scaleY * (float)(mr.ElementAt( 1 ).intValue());
+                        float width = scaleX * (float)(mr.ElementAt( 2 ).intValue());
+                        float left = scaleX * (vpX + (float)(xOffset + mr.ElementAt( 3 ).intValue()));
+                        float top = scaleY * (vpY + (float)(yOffset + mr.ElementAt( 4 ).intValue()));
+                        
+                        Paint paint = null;
+                        boolean ok = false;
+                        if (rop == WMFConstants.META_BLACKNESS) {
+                            paint = Color.black;
+                            ok = true;
+                        } else if (rop == WMFConstants.META_WHITENESS) {
+                            paint = Color.white;
+                            ok = true;
+                        } else if (rop == WMFConstants.META_PATCOPY) {
+                            if ( brushObject >= 0 ) {
+                                paint = getStoredPaint(currentStore, brushObject);
+                                ok = true;
+                            }
+                        }
+                        if (ok) {
+                            Color oldClr = g2d.getColor();
+                            if (paint != null) {
+                                g2d.setPaint(paint);
+                            } else {
+                                setBrushPaint( currentStore, g2d, brushObject );
+                            }
+                            
+                            /* avoid to draw a huge rectangle on beginning of the drawing
+                             * This is caused by the fact that a WMF file always seems to contain
+                             * a META_PATBLT rectangle at its beginning.
+                             */
+                            Rectangle2D.Float rec = new Rectangle2D.Float(left, top, width, height);
+                            g2d.fill(rec);
+                            g2d.setColor(oldClr);
+                        }
+                    }
+                    break;
+                case WMFConstants.META_DIBSTRETCHBLT:
+                    {
+                        int height = mr.ElementAt( 1 ).intValue();
+                        int width = mr.ElementAt( 2 ).intValue();
+                        int sy = mr.ElementAt( 3 ).intValue();
+                        int sx = mr.ElementAt( 4 ).intValue();
+                        float dy = conv * currentStore.getVpWFactor() * 
+                            (vpY + yOffset + (float)mr.ElementAt( 7 ).intValue());
+                        float dx = conv * currentStore.getVpHFactor() * 
+                            (vpX + xOffset + (float)mr.ElementAt( 8 ).intValue());                        
+                        float heightDst = (float)(mr.ElementAt( 5 ).intValue());
+                        float widthDst = (float)(mr.ElementAt( 6 ).intValue());
+                        widthDst = widthDst * conv * currentStore.getVpWFactor();
+                        heightDst = heightDst * conv * currentStore.getVpHFactor();
+                        byte[] bitmap = ((MetaRecord.ByteRecord)mr).bstr;
+                        
+                        BufferedImage img = getImage(bitmap, width, height);
+                        if (img != null) {
+                            g2d.drawImage(img, (int)dx, (int)dy, (int)(dx + widthDst),
+                            (int)(dy + heightDst), sx, sy, sx + width,
+                            sy + height, bkgdColor, observer);
+                        }
+                    }
+                    break;  
+            case WMFConstants.META_DIBCREATEPATTERNBRUSH:
+                {
+                    int objIndex = 0;
+                    byte[] bitmap = ((MetaRecord.ByteRecord)mr).bstr;
+                    objIndex = addObjectAt( currentStore, BRUSH, bitmap, objIndex );
+                }    
+            break;
                 case WMFConstants.META_SETPIXEL:
                 case WMFConstants.META_BITBLT:
                 case WMFConstants.META_STRETCHBLT:
@@ -602,21 +866,12 @@
                 case WMFConstants.META_FRAMEREGION:
                 case WMFConstants.META_INVERTREGION:
                 case WMFConstants.META_PAINTREGION:
-                case WMFConstants.META_SETTEXTALIGN:
                 case WMFConstants.META_SETMAPPERFLAGS:
                 case WMFConstants.META_SETDIBTODEV:
                 case WMFConstants.META_DIBBITBLT:
-                case WMFConstants.META_DIBSTRETCHBLT:
                 case WMFConstants.META_STRETCHDIB:
                 default:
                     {
-                        //int count = sizeof( MetaFunctions ) / sizeof( EMFMETARECORDS );
-                        //for ( int i = 0; i < count; i++ ) {
-                        //  if ( MetaFunctions[ i ].value == lpMFR->rdFunction ) {
-                        //  os << MetaFunctions[ i ].szFuncName;
-                        //  break;
-                        //  }
-                        //}
                     }
                     //os << " ------Unknown Function------";
                     break;
@@ -625,34 +880,221 @@
 
         }
     }
+    
+    private Paint getPaint(byte[] bit) {
+        Dimension d = getImageDimension(bit);
+        BufferedImage img = getImage(bit);
+        Rectangle2D rec = new Rectangle2D.Float(0, 0, (float)d.width, (float)d.height);
+        TexturePaint paint = new TexturePaint(img, rec);
+        return paint;       
+    }
+    
+    /** Draw an AttributedCharacterIterator taking into account the following characteristics. :
+     *  <ul>
+     *  <li>the orientation (escapement) of the WMF Font</li>
+     *  <li>the aligment of the text</li>
+     *  </ul>
+     *  <p>The other characteristics of the text, deriving from the WMF Font, must have been
+     *  collected before to constitute the AttributedCharacterIterator.</p>
+     */
+    private void drawString(int flag, Graphics2D g2d, AttributedCharacterIterator ati, 
+        float x, float y, TextLayout layout, WMFFont wmfFont, int align) {
+            
+        if (wmfFont.escape == 0) {
+            if (flag != -1) fillTextBackground(-1, flag, g2d, x, y, 0, layout);
+            float width = (float)(layout.getBounds().getWidth()); 
+            if (align == WMFConstants.TA_CENTER) {
+                g2d.drawString(ati, x-width/2, y);
+            } else if (align == WMFConstants.TA_RIGHT) {
+                g2d.drawString(ati, x-width, y);
+            } else {
+                g2d.drawString(ati, x, y);
+            }            
+        } else {
+            AffineTransform tr = g2d.getTransform();   
+            float angle = - (float)(wmfFont.escape * Math.PI / 1800f);
+            
+            float width = (float)(layout.getBounds().getWidth()); 
+            float height = (float)(layout.getBounds().getHeight());             
+            if (align == WMFConstants.TA_CENTER) {
+                g2d.translate(-width/2, height/2);
+                g2d.rotate(angle, x - width/2, y);
+            } else if (align == WMFConstants.TA_RIGHT) {
+                g2d.translate(-width/2, height/2);
+                g2d.rotate(angle, x - width, y);
+            } else {
+                g2d.translate(0, height/2);                
+                g2d.rotate(angle, x, y);
+            }
+            if (flag != -1) fillTextBackground(align, flag, g2d, x, y, width, layout);
+            Stroke _st = g2d.getStroke();
+            g2d.setStroke(textSolid);
+            g2d.drawString(ati, x, y);
+            g2d.setStroke(_st);
+            g2d.setTransform(tr);
+        }        
+    }
+    
+    private void fillTextBackground(int align, int flag, Graphics2D g2d, float x, float y, 
+        float width, TextLayout layout) {
+
+        float _x = x;
+        if (align == WMFConstants.TA_CENTER) _x = x-width/2;
+        else if (align == WMFConstants.TA_RIGHT) _x = x - width;                            
+            
+        if ((flag & WMFConstants.ETO_OPAQUE) != 0) {
+            Color c = g2d.getColor();
+            AffineTransform tr = g2d.getTransform();
+            g2d.setColor(bkgdColor);
+            g2d.translate(_x, y);
+            g2d.fill(layout.getBounds());
+            g2d.setColor(c);
+            g2d.setTransform(tr);
+        } else if (opaque) {
+            Color c = g2d.getColor();
+            AffineTransform tr = g2d.getTransform();
+            g2d.setColor(bkgdColor);
+            g2d.translate(_x, y);
+            g2d.fill(layout.getBounds());
+            g2d.setColor(c);
+            g2d.setTransform(tr);
+        }                    
+    } 
+
+    /** Just to be consistent with PolyPolygon filling.   
+     */    
+    private void drawPolyPolygon(Graphics2D g2d, Vector pols) {
+        Iterator it = pols.iterator();
+        while (it.hasNext()) {
+            Polygon2D pol = (Polygon2D)(it.next());
+            g2d.draw(pol);
+        }
+    }
 
-    private void setPenColor( WMFRecordStore currentStore, Graphics g, int penObject) {
+    /** Need to do this for POLYPOLYGON, because only GeneralPaths can handle complex
+     * WMF shapes.    
+     */
+    private void fillPolyPolygon(Graphics2D g2d, Vector pols) {
+        // if there is only one Polygon, there is no need of a path
+        if (pols.size() == 1) g2d.fill((Polygon2D)(pols.get(0)));
+        // the real stuff : we create an EVEN_ODD path, and add all the Shapes to it
+        else {
+            GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);            
+            for (int i = 0; i < pols.size(); i++) {
+                Polygon2D pol = (Polygon2D)(pols.get(i));
+                path.append(pol, false);
+            }
+            g2d.fill(path);            
+        }
+    }    
+        
+    private void setStroke(Graphics2D g2d, int penStyle, float penWidth, float scale) {
+        float _width;
+        if (penWidth == 0) _width = 1;
+        else _width = penWidth;
+        float _scale = (float)Toolkit.getDefaultToolkit().getScreenResolution() /
+            currentStore.getMetaFileUnitsPerInch();
+        // need to do this, to put the width in sync with the general scale of the image
+        float factor = scale  / _scale;
+        _width = _width * _scale * factor;
+        _scale = currentStore.getWidthPixels() * 1f/350f; // necessary to handle dash patterns
+        
+        BasicStroke stroke;
+        if (penStyle == WMFConstants.META_PS_SOLID) {
+            stroke = new BasicStroke(_width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
+            g2d.setStroke(stroke);
+        } else if (penStyle == WMFConstants.META_PS_DOT) {
+            float[] dash = {1f * _scale, 5f * _scale};
+            stroke = new BasicStroke(_width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 10f * _scale, dash, 0f);
+            g2d.setStroke(stroke);
+        } else if (penStyle == WMFConstants.META_PS_DASH) {
+            float[] dash = {5f * _scale, 2f * _scale};
+            stroke = new BasicStroke(_width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 10f * _scale, dash, 0f);
+            g2d.setStroke(stroke);
+        } else if (penStyle == WMFConstants.META_PS_DASHDOT) {
+            float[] dash = {5f * _scale, 2f * _scale, 1f * _scale, 2f * _scale};
+            stroke = new BasicStroke(_width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 10f * _scale, dash, 0f);
+            g2d.setStroke(stroke);
+        } else if (penStyle == WMFConstants.META_PS_DASHDOTDOT) {
+            float[] dash = {5f * _scale, 2f * _scale, 1f * _scale, 2f * _scale, 1f * _scale, 2f * _scale};
+            stroke = new BasicStroke(_width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 15f * _scale, dash, 0f);
+            g2d.setStroke(stroke);
+        } else {
+            stroke = new BasicStroke(_width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
+            g2d.setStroke(stroke);
+        }        
+    }
+    
+    private void setPenColor( WMFRecordStore currentStore, Graphics2D g2d, int penObject) {
         if ( penObject >= 0 ) {
             GdiObject gdiObj = currentStore.getObject( penObject );
-            g.setColor( (Color)gdiObj.obj );
+            g2d.setColor( (Color)gdiObj.obj );
             penObject = -1;
         }
     }
+    
+    private int getHorizontalAlignement(int align) {
+        int v = align;
+        v = v % 24; // skip baseline alignment
+        v = v % 8;  // skip bottom aligment
+        if (v >= 6) return WMFConstants.TA_CENTER;
+        else if (v >= 2) return WMFConstants.TA_RIGHT;
+        else return WMFConstants.TA_LEFT;
+    }
 
-    private void setBrushColor( WMFRecordStore currentStore, Graphics g, int brushObject) {
+    private void setBrushPaint( WMFRecordStore currentStore, Graphics2D g2d, int brushObject) {
         if ( brushObject >= 0 ) {
             GdiObject gdiObj = currentStore.getObject( brushObject );
-            g.setColor( (Color)gdiObj.obj );
+            if (gdiObj.obj instanceof Color) g2d.setColor( (Color)gdiObj.obj );
+            else if (gdiObj.obj instanceof Paint) g2d.setPaint( (Paint)gdiObj.obj );
+            else g2d.setPaint(getPaint((byte[])gdiObj.obj));
             brushObject = -1;
         }
     }
-
-    /**
-     * Sets the WMFRecordStore this WMFPainter should use to render
+    
+    private Paint getStoredPaint(WMFRecordStore currentStore, int object) {
+        if ( object >= 0 ) {
+            GdiObject gdiObj = currentStore.getObject( object );
+            if (gdiObj.obj instanceof Paint) return (Paint)gdiObj.obj;
+            else return getPaint((byte[])gdiObj.obj);
+        } else return null;
+    }
+    
+    /** Draw or / and fill the Shape, depending on the pen or brush Objects selected.
      */
-    public void setRecordStore(WMFRecordStore currentStore){
-        if(currentStore == null){
-            throw new IllegalArgumentException();
+    private void paint(int brushObject, int penObject, Shape shape, Graphics2D g2d) {
+        if ( brushObject >= 0 ) {
+            Paint paint = getStoredPaint(currentStore, brushObject);
+            if (!((firstEffectivePaint) && (paint.equals(Color.white)))) {
+                setBrushPaint( currentStore, g2d, brushObject );
+                g2d.fill(shape);
+                firstEffectivePaint = false; 
+            }
         }
-
-        this.currentStore = currentStore;
+        // FIXED : painting with NULL PEN
+        if (penObject >= 0) {      
+            Paint paint = getStoredPaint(currentStore, penObject);
+            if (!((firstEffectivePaint) && (paint.equals(Color.white)))) {
+                setPenColor( currentStore, g2d, penObject );
+                g2d.draw(shape);
+                firstEffectivePaint = false;
+            }
+        } 
     }
 
+    /** Draw the Shape, depending on the pen or brush Objects selected.
+     */    
+    private void paintWithPen(int penObject, Shape shape, Graphics2D g2d) {
+        if (penObject >= 0) {      
+            Paint paint = getStoredPaint(currentStore, penObject);
+            if (!((firstEffectivePaint) && (paint.equals(Color.white)))) {
+                setPenColor( currentStore, g2d, penObject );
+                g2d.draw(shape);
+                firstEffectivePaint = false;
+            }
+        } 
+    }    
+
     /**
      * Returns the WMFRecordStore this WMFPainter renders
      */
@@ -660,92 +1102,8 @@
         return currentStore;
     }
 
-    private void addObject( WMFRecordStore currentStore, int type, Object obj ) {
-        currentStore.addObject( type, obj );
-    }
-
-    private void addObjectAt( WMFRecordStore currentStore, int type, Object obj, int idx ) {
-        currentStore.addObjectAt( type, obj, idx );
-    }
-
-    public static final int PEN = 1;
-    public static final int BRUSH = 2;
-    public static final int FONT = 3;
-    public static final int NULL_PEN = 4;
-    public static final int NULL_BRUSH = 5;
-    public static final int PALETTE = 6;
-
-    private WMFRecordStore currentStore;
-    transient private boolean bReadingWMF = true;
     transient private BufferedInputStream bufStream = null;
 
-}
-
-
-class MetaRecord /*implements Serializable*/
-{
-        public int	functionId;
-        public int	numPoints;
-
-        private Vector	ptVector;
-
-        public MetaRecord()
-        {
-                ptVector = new Vector();
-        }
-
-        public void EnsureCapacity( int cc )
-        {
-                ptVector.ensureCapacity( cc );
-        }
-
-        public void AddElement( Object obj )
-        {
-                ptVector.addElement( obj );
-        }
-
-        public Integer ElementAt( int offset )
-        {
-                return (Integer)ptVector.elementAt( offset );
-        }
-}
-
-class StringRecord extends MetaRecord /*implements Serializable*/
-{
-        public String	text;
-
-        public StringRecord( String newText )
-        {
-                text = new String( newText );
-        }
-}
-
-class GdiObject /*implements Serializable*/
-{
-        GdiObject( int _id, boolean _used )
-        {
-        id = _id;
-        used = _used;
-        type = 0;
-        }
-
-        public void Clear()
-        {
-        used = false;
-        type = 0;
-        }
-
-        public void Setup( int _type, Object _obj )
-        {
-        obj = _obj;
-        type = _type;
-        used = true;
-        }
-
-        int id;
-        boolean used;
-        Object obj;
-        int type = 0;
 }