You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ki...@apache.org on 2018/10/27 00:51:20 UTC

svn commit: r1844931 - in /poi/branches/hemf/src/scratchpad: src/org/apache/poi/hemf/draw/ src/org/apache/poi/hemf/record/emf/ src/org/apache/poi/hwmf/draw/ src/org/apache/poi/hwmf/record/ testcases/org/apache/poi/hemf/usermodel/

Author: kiwiwings
Date: Sat Oct 27 00:51:19 2018
New Revision: 1844931

URL: http://svn.apache.org/viewvc?rev=1844931&view=rev
Log:
#60656 - Support export file that contains emf and render it correctly

Removed:
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfBounded.java
Modified:
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFill.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordType.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfWindowing.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java
    poi/branches/hemf/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfPictureTest.java

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java?rev=1844931&r1=1844930&r2=1844931&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfDrawProperties.java Sat Oct 27 00:51:19 2018
@@ -17,6 +17,7 @@
 
 package org.apache.poi.hemf.draw;
 
+import java.awt.Shape;
 import java.awt.geom.Path2D;
 
 import org.apache.poi.hwmf.draw.HwmfDrawProperties;
@@ -25,6 +26,8 @@ public class HemfDrawProperties extends
 
     /** Path for path bracket operations */
     protected Path2D path = null;
+    protected Shape clip = null;
+    protected boolean usePathBracket = false;
 
 
     public HemfDrawProperties() {
@@ -33,6 +36,8 @@ public class HemfDrawProperties extends
     public HemfDrawProperties(HemfDrawProperties other) {
         super(other);
         path = (other.path != null) ? (Path2D)other.path.clone() : null;
+        // TODO: check how to clone
+        clip = other.clip;
     }
 
     /**
@@ -55,7 +60,19 @@ public class HemfDrawProperties extends
      * @return {@code true}, if the drawing should go to the path bracket,
      *      if {@code false} draw directly to the graphics context
      */
-    public boolean usePathBracket() {
-        return path != null;
+    public boolean getUsePathBracket() {
+        return usePathBracket;
+    }
+
+    public void setUsePathBracket(boolean usePathBracket) {
+        this.usePathBracket = usePathBracket;
+    }
+
+    public Shape getClip() {
+        return clip;
+    }
+
+    public void setClip(Shape shape) {
+        clip = shape;
     }
 }

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java?rev=1844931&r1=1844930&r2=1844931&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/draw/HemfGraphics.java Sat Oct 27 00:51:19 2018
@@ -22,15 +22,15 @@ import static org.apache.poi.hwmf.record
 
 import java.awt.Color;
 import java.awt.Graphics2D;
+import java.awt.Shape;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
 import java.awt.geom.Path2D;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
-import java.util.ArrayDeque;
-import java.util.Deque;
 import java.util.function.Consumer;
 
-import org.apache.poi.hemf.record.emf.HemfBounded;
+import org.apache.poi.hemf.record.emf.HemfFill;
 import org.apache.poi.hemf.record.emf.HemfRecord;
 import org.apache.poi.hwmf.draw.HwmfGraphics;
 import org.apache.poi.hwmf.record.HwmfColorRef;
@@ -47,13 +47,13 @@ public class HemfGraphics extends HwmfGr
     private static final HwmfColorRef BLACK = new HwmfColorRef(Color.BLACK);
 
 
-    private final Deque<AffineTransform> transforms = new ArrayDeque<>();
+    private final AffineTransform initTrans;
 
     public HemfGraphics(Graphics2D graphicsCtx, Rectangle2D bbox) {
         super(graphicsCtx,bbox);
-        // add dummy entry for object index 0, as emf is 1-based
+        // add dummy entry for object ind ex 0, as emf is 1-based
         objectIndexes.set(0);
-        saveTransform();
+        initTrans = new AffineTransform(graphicsCtx.getTransform());
     }
 
     @Override
@@ -66,48 +66,34 @@ public class HemfGraphics extends HwmfGr
 
     @Override
     public void saveProperties() {
-        propStack.add(getProperties());
-        prop = new HemfDrawProperties((HemfDrawProperties)prop);
+        final HemfDrawProperties oldProp = getProperties();
+        oldProp.setClip(graphicsCtx.getClip());
+        propStack.add(oldProp);
+        prop = new HemfDrawProperties(oldProp);
     }
 
     @Override
-    public void updateWindowMapMode() {
-        // ignore window settings
+    public void restoreProperties(int index) {
+        super.restoreProperties(index);
+        HemfDrawProperties newProp = getProperties();
+        graphicsCtx.setClip(newProp.getClip());
     }
 
     public void draw(HemfRecord r) {
-        if (r instanceof HemfBounded) {
-            saveTransform();
-            final HemfBounded bounded = (HemfBounded)r;
-            final Rectangle2D tgt = bounded.getRecordBounds();
-            if (tgt != null && !tgt.isEmpty()) {
-                final Rectangle2D src = bounded.getShapeBounds(this);
-                if (src != null && !src.isEmpty()) {
-//                    graphicsCtx.translate(tgt.getCenterX() - src.getCenterX(), tgt.getCenterY() - src.getCenterY());
-//                    graphicsCtx.translate(src.getCenterX(), src.getCenterY());
-//                    graphicsCtx.scale(tgt.getWidth() / src.getWidth(), tgt.getHeight() / src.getHeight());
-//                    graphicsCtx.translate(-src.getCenterX(), -src.getCenterY());
-                }
-            }
-        }
-
         r.draw(this);
-
-        if (r instanceof HemfBounded) {
-            restoreTransform();
-        }
     }
 
     @Internal
-    public void draw(Consumer<Path2D> pathConsumer) {
+    public void draw(Consumer<Path2D> pathConsumer, FillDrawStyle fillDraw) {
         final HemfDrawProperties prop = getProperties();
-        final boolean useBracket = prop.usePathBracket();
+        final boolean useBracket = prop.getUsePathBracket();
 
         final Path2D path;
         if (useBracket) {
             path = prop.getPath();
         } else {
             path = new Path2D.Double();
+            path.setWindingRule(prop.getWindingRule());
             Point2D pnt = prop.getLocation();
             path.moveTo(pnt.getX(),pnt.getY());
         }
@@ -124,8 +110,18 @@ public class HemfGraphics extends HwmfGr
 
         prop.setLocation(path.getCurrentPoint());
         if (!useBracket) {
-            // TODO: when to use draw vs. fill?
-            super.draw(path);
+            switch (fillDraw) {
+                case FILL:
+                    super.fill(path);
+                    break;
+                case DRAW:
+                    super.draw(path);
+                    break;
+                case FILL_DRAW:
+                    super.fill(path);
+                    super.draw(path);
+                    break;
+            }
         }
 
     }
@@ -273,7 +269,7 @@ public class HemfGraphics extends HwmfGr
      * @return the initial AffineTransform, when this graphics context was created
      */
     public AffineTransform getInitTransform() {
-        return new AffineTransform(transforms.peekFirst());
+        return new AffineTransform(initTrans);
     }
 
     /**
@@ -291,13 +287,41 @@ public class HemfGraphics extends HwmfGr
         graphicsCtx.setTransform(tx);
     }
 
-    /** saves the current affine transform on the stack */
-    private void saveTransform() {
-        transforms.push(graphicsCtx.getTransform());
-    }
+    public void setClip(Shape clip, HemfFill.HemfRegionMode regionMode) {
+        Shape oldClip = graphicsCtx.getClip();
 
-    /** restore the last saved affine transform */
-    private void restoreTransform() {
-        graphicsCtx.setTransform(transforms.pop());
+        switch (regionMode) {
+            case RGN_AND:
+                graphicsCtx.clip(clip);
+                break;
+            case RGN_OR:
+                if (oldClip == null) {
+                    graphicsCtx.setClip(clip);
+                } else {
+                    Area area = new Area(oldClip);
+                    area.add(new Area(clip));
+                    graphicsCtx.setClip(area);
+                }
+                break;
+            case RGN_XOR:
+                if (oldClip == null) {
+                    graphicsCtx.setClip(clip);
+                } else {
+                    Area area = new Area(oldClip);
+                    area.exclusiveOr(new Area(clip));
+                    graphicsCtx.setClip(area);
+                }
+                break;
+            case RGN_DIFF:
+                if (oldClip != null) {
+                    Area area = new Area(oldClip);
+                    area.subtract(new Area(clip));
+                    graphicsCtx.setClip(area);
+                }
+                break;
+            case RGN_COPY:
+                graphicsCtx.setClip(clip);
+                break;
+        }
     }
 }

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java?rev=1844931&r1=1844930&r2=1844931&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfDraw.java Sat Oct 27 00:51:19 2018
@@ -17,8 +17,10 @@
 
 package org.apache.poi.hemf.record.emf;
 
+import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
+
+import java.awt.Shape;
 import java.awt.geom.Arc2D;
-import java.awt.geom.Area;
 import java.awt.geom.Dimension2D;
 import java.awt.geom.Path2D;
 import java.awt.geom.PathIterator;
@@ -28,6 +30,7 @@ import java.io.IOException;
 
 import org.apache.poi.hemf.draw.HemfDrawProperties;
 import org.apache.poi.hemf.draw.HemfGraphics;
+import org.apache.poi.hwmf.draw.HwmfGraphics.FillDrawStyle;
 import org.apache.poi.hwmf.record.HwmfDraw;
 import org.apache.poi.hwmf.record.HwmfDraw.WmfSelectObject;
 import org.apache.poi.util.LittleEndianConsts;
@@ -88,7 +91,7 @@ public class HemfDraw {
 
 
     /** The EMR_POLYBEZIER record specifies one or more Bezier curves. */
-    public static class EmfPolyBezier extends HwmfDraw.WmfPolygon implements HemfRecord, HemfBounded {
+    public static class EmfPolyBezier extends HwmfDraw.WmfPolygon implements HemfRecord {
         private final Rectangle2D bounds = new Rectangle2D.Double();
 
         @Override
@@ -120,7 +123,7 @@ public class HemfDraw {
             final int points = Math.min(count, 16384);
             size += LittleEndianConsts.INT_SIZE;
 
-            poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, points);
+            poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, points+2);
 
             /* Cubic Bezier curves are defined using the endpoints and control points
              * specified by the points field. The first curve is drawn from the first
@@ -135,8 +138,8 @@ public class HemfDraw {
             Point2D pnt[] = { new Point2D.Double(), new Point2D.Double(), new Point2D.Double() };
 
             // points-1 because of the first point
-            final int pointCnt = hasStartPoint() ? points-1 : points;
-            for (int i=0; i+3<pointCnt; i+=3) {
+            final int pointCnt = hasStartPoint() ? points-2 : points;
+            for (int i=0; i+2<pointCnt; i+=3) {
                 // x (4 bytes): A 32-bit signed integer that defines the horizontal (x) coordinate of the point.
                 // y (4 bytes): A 32-bit signed integer that defines the vertical (y) coordinate of the point.
                 if (i==0) {
@@ -162,25 +165,23 @@ public class HemfDraw {
             return size;
         }
 
-        @Override
-        public Rectangle2D getRecordBounds() {
-            return bounds;
-        }
-
-        @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            if (!hasStartPoint()) {
-                throw new IllegalStateException("shape bounds not valid for path bracket based record: "+getClass().getName());
-            }
-            return poly.getBounds2D();
-        }
-
         /**
          * @return true, if start point is in the list of points. false, if start point is taken from the context
          */
         protected boolean hasStartPoint() {
             return true;
         }
+
+        @Override
+        protected FillDrawStyle getFillDrawStyle() {
+            // The cubic Bezier curves SHOULD be drawn using the current pen.
+            return FillDrawStyle.DRAW;
+        }
+
+        @Override
+        public void draw(HemfGraphics ctx) {
+            ctx.draw(path -> path.append(poly, !hasStartPoint()), getFillDrawStyle());
+        }
     }
 
     /**
@@ -203,7 +204,7 @@ public class HemfDraw {
      * The EMR_POLYGON record specifies a polygon consisting of two or more vertexes connected by
      * straight lines.
      */
-    public static class EmfPolygon extends HwmfDraw.WmfPolygon implements HemfRecord, HemfBounded {
+    public static class EmfPolygon extends HwmfDraw.WmfPolygon implements HemfRecord {
         private final Rectangle2D bounds = new Rectangle2D.Double();
 
         @Override
@@ -246,25 +247,25 @@ public class HemfDraw {
             return size;
         }
 
-        @Override
-        public Rectangle2D getRecordBounds() {
-            return bounds;
-        }
-
-        @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            if (!hasStartPoint()) {
-                throw new IllegalStateException("shape bounds not valid for path bracket based record: "+getClass().getName());
-            }
-            return poly.getBounds2D();
-        }
-
         /**
          * @return true, if start point is in the list of points. false, if start point is taken from the context
          */
         protected boolean hasStartPoint() {
             return true;
         }
+
+        @Override
+        protected FillDrawStyle getFillDrawStyle() {
+            // The polygon SHOULD be outlined using the current pen and filled using the current brush and
+            // polygon fill mode. The polygon SHOULD be closed automatically by drawing a line from the last
+            // vertex to the first.
+            return FillDrawStyle.FILL_DRAW;
+        }
+
+        @Override
+        public void draw(HemfGraphics ctx) {
+            ctx.draw(path -> path.append(poly, false), getFillDrawStyle());
+        }
     }
 
     /**
@@ -295,8 +296,9 @@ public class HemfDraw {
         }
 
         @Override
-        protected boolean isFill() {
-            return false;
+        protected FillDrawStyle getFillDrawStyle() {
+            // The line segments SHOULD be drawn using the current pen.
+            return FillDrawStyle.DRAW;
         }
     }
 
@@ -333,14 +335,7 @@ public class HemfDraw {
 
         @Override
         public void draw(HemfGraphics ctx) {
-            polyTo(ctx, poly);
-        }
-
-        @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            // should be called in a beginPath/endPath bracket, so the shape bounds
-            // of this path segment are irrelevant
-            return null;
+            polyTo(ctx, poly, getFillDrawStyle());
         }
     }
 
@@ -374,14 +369,7 @@ public class HemfDraw {
 
         @Override
         public void draw(HemfGraphics ctx) {
-            polyTo(ctx, poly);
-        }
-
-        @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            // should be called in a beginPath/endPath bracket, so the shape bounds
-            // of this path segment are irrelevant
-            return null;
+            polyTo(ctx, poly, getFillDrawStyle());
         }
     }
 
@@ -406,7 +394,7 @@ public class HemfDraw {
     /**
      * The EMR_POLYPOLYGON record specifies a series of closed polygons.
      */
-    public static class EmfPolyPolygon extends HwmfDraw.WmfPolyPolygon implements HemfRecord, HemfBounded {
+    public static class EmfPolyPolygon extends HwmfDraw.WmfPolyPolygon implements HemfRecord {
         private final Rectangle2D bounds = new Rectangle2D.Double();
 
         @Override
@@ -461,22 +449,15 @@ public class HemfDraw {
             return size;
         }
 
-        /**
-         * @return true, if a polyline should be closed, i.e. is a polygon
-         */
-        protected boolean isClosed() {
-            return true;
-        }
 
         @Override
-        public Rectangle2D getRecordBounds() {
-            return bounds;
-        }
+        public void draw(HemfGraphics ctx) {
+            Shape shape = getShape(ctx);
+            if (shape == null) {
+                return;
+            }
 
-        @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            Area area = getShape(ctx);
-            return area == null ? bounds : area.getBounds2D();
+            ctx.draw(path -> path.append(shape, false), getFillDrawStyle());
         }
     }
 
@@ -512,8 +493,8 @@ public class HemfDraw {
         }
 
         @Override
-        protected boolean isFill() {
-            return false;
+        protected FillDrawStyle getFillDrawStyle() {
+            return FillDrawStyle.DRAW;
         }
     }
 
@@ -563,12 +544,12 @@ public class HemfDraw {
 
         @Override
         public void draw(final HemfGraphics ctx) {
-            ctx.draw((path) -> path.moveTo(point.getX(), point.getY()));
+            ctx.draw((path) -> path.moveTo(point.getX(), point.getY()), FillDrawStyle.NONE);
         }
     }
 
     /**
-     * The EMR_ARCTO record specifies an elliptical arc.
+     * The EMR_ARC record specifies an elliptical arc.
      * It resets the current position to the end point of the arc.
      */
     public static class EmfArc extends HwmfDraw.WmfArc implements HemfRecord {
@@ -587,8 +568,7 @@ public class HemfDraw {
 
         @Override
         public void draw(HemfGraphics ctx) {
-            super.draw(ctx);
-            ctx.getProperties().setLocation(endPoint);
+            ctx.draw(path -> path.append(getShape(), false), getFillDrawStyle());
         }
     }
 
@@ -610,6 +590,11 @@ public class HemfDraw {
             size += readPointL(leis, endPoint);
             return size;
         }
+
+        @Override
+        public void draw(HemfGraphics ctx) {
+            ctx.draw(path -> path.append(getShape(), false), getFillDrawStyle());
+        }
     }
 
     /**
@@ -629,6 +614,11 @@ public class HemfDraw {
             size += readPointL(leis, endPoint);
             return size;
         }
+
+        @Override
+        public void draw(HemfGraphics ctx) {
+            ctx.draw(path -> path.append(getShape(), false), getFillDrawStyle());
+        }
     }
 
     /**
@@ -646,6 +636,11 @@ public class HemfDraw {
         public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
             return readRectL(leis, bounds);
         }
+
+        @Override
+        public void draw(HemfGraphics ctx) {
+            ctx.draw(path -> path.append(getShape(), false), FillDrawStyle.FILL_DRAW);
+        }
     }
 
     /**
@@ -662,6 +657,11 @@ public class HemfDraw {
         public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
             return readRectL(leis, bounds);
         }
+
+        @Override
+        public void draw(HemfGraphics ctx) {
+            ctx.draw(path -> path.append(bounds, false), FillDrawStyle.FILL_DRAW);
+        }
     }
 
     /**
@@ -684,6 +684,11 @@ public class HemfDraw {
 
             return size + 2*LittleEndianConsts.INT_SIZE;
         }
+
+        @Override
+        public void draw(HemfGraphics ctx) {
+            ctx.draw(path -> path.append(getShape(), false), FillDrawStyle.FILL_DRAW);
+        }
     }
 
     /**
@@ -703,7 +708,7 @@ public class HemfDraw {
 
         @Override
         public void draw(final HemfGraphics ctx) {
-            ctx.draw((path) -> path.lineTo(point.getX(), point.getY()));
+            ctx.draw((path) -> path.lineTo(point.getX(), point.getY()), FillDrawStyle.DRAW);
         }
     }
 
@@ -728,12 +733,12 @@ public class HemfDraw {
         @Override
         public void draw(final HemfGraphics ctx) {
             final Arc2D arc = getShape();
-            ctx.draw((path) -> path.append(arc, true));
+            ctx.draw((path) -> path.append(arc, true), getFillDrawStyle());
         }
     }
 
     /** The EMR_POLYDRAW record specifies a set of line segments and Bezier curves. */
-    public static class EmfPolyDraw extends HwmfDraw.WmfPolygon implements HemfRecord, HemfBounded {
+    public static class EmfPolyDraw extends HwmfDraw.WmfPolygon implements HemfRecord {
         private final Rectangle2D bounds = new Rectangle2D.Double();
 
         @Override
@@ -808,13 +813,14 @@ public class HemfDraw {
         }
 
         @Override
-        public Rectangle2D getRecordBounds() {
-            return bounds;
+        protected FillDrawStyle getFillDrawStyle() {
+            // Draws a set of line segments and Bezier curves.
+            return FillDrawStyle.DRAW;
         }
 
         @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            return poly.getBounds2D();
+        public void draw(HemfGraphics ctx) {
+            ctx.draw(path -> path.append(poly, false), getFillDrawStyle());
         }
     }
 
@@ -854,6 +860,7 @@ public class HemfDraw {
         public void draw(HemfGraphics ctx) {
             final HemfDrawProperties prop = ctx.getProperties();
             prop.setPath(new Path2D.Double());
+            prop.setUsePathBracket(true);
         }
 
         @Override
@@ -878,6 +885,12 @@ public class HemfDraw {
         }
 
         @Override
+        public void draw(HemfGraphics ctx) {
+            final HemfDrawProperties prop = ctx.getProperties();
+            prop.setUsePathBracket(false);
+        }
+
+        @Override
         public String toString() {
             return "{}";
         }
@@ -901,6 +914,7 @@ public class HemfDraw {
         public void draw(HemfGraphics ctx) {
             final HemfDrawProperties prop = ctx.getProperties();
             prop.setPath(null);
+            prop.setUsePathBracket(false);
         }
 
         @Override
@@ -995,7 +1009,7 @@ public class HemfDraw {
     /**
      * The EMR_STROKEPATH record renders the specified path by using the current pen.
      */
-    public static class EmfStrokePath implements HemfRecord, HemfBounded {
+    public static class EmfStrokePath implements HemfRecord {
         protected final Rectangle2D bounds = new Rectangle2D.Double();
 
         @Override
@@ -1006,29 +1020,64 @@ public class HemfDraw {
         @Override
         public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
             // A 128-bit WMF RectL object, which specifies bounding rectangle, in device units
-            return readRectL(leis, bounds);
+            return (recordSize == 0) ? 0 : readRectL(leis, bounds);
         }
 
         @Override
         public void draw(HemfGraphics ctx) {
             HemfDrawProperties props = ctx.getProperties();
-            ctx.draw(props.getPath());
+            Path2D path = props.getPath();
+            path.setWindingRule(ctx.getProperties().getWindingRule());
+            ctx.draw(path);
         }
 
         @Override
-        public Rectangle2D getRecordBounds() {
-            return bounds;
+        public String toString() {
+            return boundsToString(bounds);
         }
+    }
+
 
+    /**
+     * The EMR_FILLPATH record closes any open figures in the current path and fills the path's interior by
+     * using the current brush and polygon-filling mode.
+     */
+    public static class EmfFillPath extends EmfStrokePath {
         @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            HemfDrawProperties props = ctx.getProperties();
-            return props.getPath().getBounds2D();
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.fillPath;
         }
 
         @Override
-        public String toString() {
-            return "{ bounds: { x: "+bounds.getX()+", y: "+bounds.getY()+", w: "+bounds.getWidth()+", h: "+bounds.getHeight()+" }";
+        public void draw(HemfGraphics ctx) {
+            final HemfDrawProperties prop = ctx.getProperties();
+            final Path2D path = (Path2D)prop.getPath().clone();
+            path.closePath();
+            path.setWindingRule(ctx.getProperties().getWindingRule());
+            ctx.fill(path);
+        }
+    }
+
+    /**
+     * The EMR_STROKEANDFILLPATH record closes any open figures in a path, strokes the outline of the
+     * path by using the current pen, and fills its interior by using the current brush.
+     */
+    public static class EmfStrokeAndFillPath extends EmfStrokePath {
+        protected final Rectangle2D bounds = new Rectangle2D.Double();
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.strokeAndFillPath;
+        }
+
+        @Override
+        public void draw(HemfGraphics ctx) {
+            HemfDrawProperties props = ctx.getProperties();
+            Path2D path = props.getPath();
+            path.closePath();
+            path.setWindingRule(ctx.getProperties().getWindingRule());
+            ctx.fill(path);
+            ctx.draw(path);
         }
     }
 
@@ -1080,7 +1129,7 @@ public class HemfDraw {
         return 2*LittleEndianConsts.INT_SIZE;
     }
 
-    private static void polyTo(final HemfGraphics ctx, final Path2D poly) {
+    private static void polyTo(final HemfGraphics ctx, final Path2D poly, FillDrawStyle fillDrawStyle) {
         if (poly.getCurrentPoint() == null) {
             return;
         }
@@ -1092,6 +1141,6 @@ public class HemfDraw {
             return;
         }
 
-        ctx.draw((path) -> path.append(pi, true));
+        ctx.draw((path) -> path.append(pi, true), fillDrawStyle);
     }
 }

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFill.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFill.java?rev=1844931&r1=1844930&r2=1844931&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFill.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFill.java Sat Oct 27 00:51:19 2018
@@ -51,10 +51,29 @@ public class HemfFill {
     private static final int MAX_RECORD_LENGTH = 10_000_000;
 
     public enum HemfRegionMode {
+        /**
+         * The new clipping region includes the intersection (overlapping areas)
+         * of the current clipping region and the current path (or new region).
+         */
         RGN_AND(0x01),
+        /**
+         * The new clipping region includes the union (combined areas)
+         * of the current clipping region and the current path (or new region).
+         */
         RGN_OR(0x02),
+        /**
+         * The new clipping region includes the union of the current clipping region
+         * and the current path (or new region) but without the overlapping areas
+         */
         RGN_XOR(0x03),
+        /**
+         * The new clipping region includes the areas of the current clipping region
+         * with those of the current path (or new region) excluded.
+         */
         RGN_DIFF(0x04),
+        /**
+         * The new clipping region is the current path (or the new region).
+         */
         RGN_COPY(0x05);
 
         int flag;
@@ -114,7 +133,7 @@ public class HemfFill {
      * optionally in combination with a brush pattern, according to a specified raster operation, stretching or
      * compressing the output to fit the dimensions of the destination, if necessary.
      */
-    public static class EmfStretchBlt extends HwmfFill.WmfBitBlt implements HemfRecord, HemfBounded {
+    public static class EmfStretchBlt extends HwmfFill.WmfBitBlt implements HemfRecord {
         protected final Rectangle2D bounds = new Rectangle2D.Double();
 
         /** An XForm object that specifies a world-space to page-space transform to apply to the source bitmap. */
@@ -196,16 +215,6 @@ public class HemfFill {
             return size;
         }
 
-        @Override
-        public Rectangle2D getRecordBounds() {
-            return bounds;
-        }
-
-        @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            return dstBounds;
-        }
-
         protected boolean srcEqualsDstDimension() {
             return false;
         }
@@ -226,7 +235,7 @@ public class HemfFill {
      * destination rectangle, optionally in combination with a brush pattern, according to a specified raster
      * operation, stretching or compressing the output to fit the dimensions of the destination, if necessary.
      */
-    public static class EmfStretchDiBits extends HwmfFill.WmfStretchDib implements HemfRecord, HemfBounded {
+    public static class EmfStretchDiBits extends HwmfFill.WmfStretchDib implements HemfRecord {
         protected final Rectangle2D bounds = new Rectangle2D.Double();
 
         @Override
@@ -286,16 +295,6 @@ public class HemfFill {
 
             return size;
         }
-
-        @Override
-        public Rectangle2D getRecordBounds() {
-            return bounds;
-        }
-
-        @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            return dstBounds;
-        }
     }
 
     /**
@@ -316,7 +315,7 @@ public class HemfFill {
 
 
     /** The EMR_FRAMERGN record draws a border around the specified region using the specified brush. */
-    public static class EmfFrameRgn extends HwmfDraw.WmfFrameRegion implements HemfRecord, HemfBounded {
+    public static class EmfFrameRgn extends HwmfDraw.WmfFrameRegion implements HemfRecord {
         private final Rectangle2D bounds = new Rectangle2D.Double();
         private final List<Rectangle2D> rgnRects = new ArrayList<>();
 
@@ -347,23 +346,13 @@ public class HemfFill {
             ctx.fill(getShape());
         }
 
-        @Override
-        public Rectangle2D getRecordBounds() {
-            return bounds;
-        }
-
-        @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            return getShape().getBounds2D();
-        }
-
         protected Area getShape() {
             return getRgnShape(rgnRects);
         }
     }
 
     /** The EMR_INVERTRGN record inverts the colors in the specified region. */
-    public static class EmfInvertRgn implements HemfRecord, HemfBounded {
+    public static class EmfInvertRgn implements HemfRecord {
         protected final Rectangle2D bounds = new Rectangle2D.Double();
         protected final List<Rectangle2D> rgnRects = new ArrayList<>();
 
@@ -382,16 +371,6 @@ public class HemfFill {
             return size;
         }
 
-        @Override
-        public Rectangle2D getRecordBounds() {
-            return bounds;
-        }
-
-        @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            return getShape().getBounds2D();
-        }
-
         protected Area getShape() {
             return getRgnShape(rgnRects);
         }
@@ -409,7 +388,7 @@ public class HemfFill {
     }
 
     /** The EMR_FILLRGN record fills the specified region by using the specified brush. */
-    public static class EmfFillRgn extends HwmfFill.WmfFillRegion implements HemfRecord, HemfBounded {
+    public static class EmfFillRgn extends HwmfFill.WmfFillRegion implements HemfRecord {
         protected final Rectangle2D bounds = new Rectangle2D.Double();
         protected final List<Rectangle2D> rgnRects = new ArrayList<>();
 
@@ -429,16 +408,6 @@ public class HemfFill {
             return size;
         }
 
-        @Override
-        public Rectangle2D getRecordBounds() {
-            return bounds;
-        }
-
-        @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            return getShape().getBounds2D();
-        }
-
         protected Area getShape() {
             return getRgnShape(rgnRects);
         }
@@ -474,7 +443,7 @@ public class HemfFill {
         }
     }
 
-    public static class EmfAlphaBlend implements HemfRecord, HemfBounded {
+    public static class EmfAlphaBlend implements HemfRecord {
         /** the destination bounding rectangle in device units */
         protected final Rectangle2D bounds = new Rectangle2D.Double();
         /** the destination rectangle */
@@ -583,24 +552,13 @@ public class HemfFill {
 
             return size;
         }
-
-
-        @Override
-        public Rectangle2D getRecordBounds() {
-            return bounds;
-        }
-
-        @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            return destRect;
-        }
     }
 
     /**
      * The EMR_SETDIBITSTODEVICE record specifies a block transfer of pixels from specified scanlines of
      * a source bitmap to a destination rectangle.
      */
-    public static class EmfSetDiBitsToDevice implements HemfRecord, HemfBounded {
+    public static class EmfSetDiBitsToDevice implements HemfRecord {
         protected final Rectangle2D bounds = new Rectangle2D.Double();
         protected final Point2D dest = new Point2D.Double();
         protected final Rectangle2D src = new Rectangle2D.Double();
@@ -645,16 +603,6 @@ public class HemfFill {
 
             return size;
         }
-
-        @Override
-        public Rectangle2D getRecordBounds() {
-            return bounds;
-        }
-
-        @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            return new Rectangle2D.Double(dest.getX(), dest.getY(), src.getWidth(), src.getHeight());
-        }
     }
 
     static long readBitmap(final LittleEndianInputStream leis, final HwmfBitmapDib bitmap,
@@ -769,52 +717,6 @@ public class HemfFill {
         return 6 * LittleEndian.INT_SIZE;
     }
 
-    /**
-     * The EMR_FILLPATH record closes any open figures in the current path and fills the path's interior by
-     * using the current brush and polygon-filling mode.
-     */
-    public static class EmfFillPath implements HemfRecord, HemfBounded {
-        protected final Rectangle2D bounds = new Rectangle2D.Double();
-
-        @Override
-        public HemfRecordType getEmfRecordType() {
-            return HemfRecordType.fillPath;
-        }
-
-        @Override
-        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
-            // A 128-bit WMF RectL object, which specifies bounding rectangle, in device units
-            return (recordSize == 0) ? 0 : readRectL(leis, bounds);
-        }
-
-        @Override
-        public Rectangle2D getRecordBounds() {
-            return bounds;
-        }
-
-        @Override
-        public Rectangle2D getShapeBounds(HemfGraphics ctx) {
-            final HemfDrawProperties prop = ctx.getProperties();
-            final Path2D path = prop.getPath();
-            return path.getBounds2D();
-        }
-
-        @Override
-        public void draw(HemfGraphics ctx) {
-            final HemfDrawProperties prop = ctx.getProperties();
-            if (!prop.usePathBracket()) {
-                return;
-            }
-            final Path2D path = (Path2D)prop.getPath().clone();
-            path.setWindingRule(ctx.getProperties().getWindingRule());
-            if (prop.getBrushStyle() == HwmfBrushStyle.BS_NULL) {
-                ctx.draw(path);
-            } else {
-                ctx.fill(path);
-            }
-        }
-    }
-
     protected static Area getRgnShape(List<Rectangle2D> rgnRects) {
         final Area frame = new Area();
         rgnRects.forEach((rct) -> frame.add(new Area(rct)));

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordType.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordType.java?rev=1844931&r1=1844930&r2=1844931&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordType.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordType.java Sat Oct 27 00:51:19 2018
@@ -85,8 +85,8 @@ public enum HemfRecordType {
     beginPath(0x0000003B, HemfDraw.EmfBeginPath::new),
     endPath(0x0000003C, HemfDraw.EmfEndPath::new),
     closeFigure(0x0000003D, HemfDraw.EmfCloseFigure::new),
-    fillPath(0x0000003E, HemfFill.EmfFillPath::new),
-    strokeandfillpath(0x0000003F, UnimplementedHemfRecord::new),
+    fillPath(0x0000003E, HemfDraw.EmfFillPath::new),
+    strokeAndFillPath(0x0000003F, HemfDraw.EmfStrokeAndFillPath::new),
     strokePath(0x00000040, HemfDraw.EmfStrokePath::new),
     flattenPath(0x00000041, HemfDraw.EmfFlattenPath::new),
     widenPath(0x00000042, HemfDraw.EmfWidenPath::new),

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfWindowing.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfWindowing.java?rev=1844931&r1=1844930&r2=1844931&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfWindowing.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfWindowing.java Sat Oct 27 00:51:19 2018
@@ -17,8 +17,13 @@
 
 package org.apache.poi.hemf.record.emf;
 
+import static org.apache.poi.hemf.record.emf.HemfDraw.readDimensionInt;
+import static org.apache.poi.hemf.record.emf.HemfDraw.readPointL;
+
 import java.io.IOException;
 
+import org.apache.poi.hemf.draw.HemfDrawProperties;
+import org.apache.poi.hemf.draw.HemfGraphics;
 import org.apache.poi.hemf.record.emf.HemfFill.HemfRegionMode;
 import org.apache.poi.hwmf.record.HwmfWindowing;
 import org.apache.poi.util.LittleEndianConsts;
@@ -37,13 +42,7 @@ public class HemfWindowing {
 
         @Override
         public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
-            // cx (4 bytes): A 32-bit unsigned integer that defines the x-coordinate of the point.
-            int width = (int)leis.readUInt();
-            // cy (4 bytes): A 32-bit unsigned integer that defines the y-coordinate of the point.
-            int height = (int)leis.readUInt();
-            size.setSize(width, height);
-
-            return 2*LittleEndianConsts.INT_SIZE;
+            return readDimensionInt(leis, size);
         }
     }
 
@@ -58,12 +57,7 @@ public class HemfWindowing {
 
         @Override
         public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
-            // x (4 bytes): A 32-bit signed integer that defines the horizontal (x) coordinate of the point.
-            x = leis.readInt();
-            // y (4 bytes): A 32-bit signed integer that defines the vertical (y) coordinate of the point.
-            y = leis.readInt();
-
-            return 2*LittleEndianConsts.INT_SIZE;
+            return readPointL(leis, origin);
         }
     }
 
@@ -78,12 +72,7 @@ public class HemfWindowing {
 
         @Override
         public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
-            // cx (4 bytes): A 32-bit unsigned integer that defines the x-coordinate of the point.
-            width = (int)leis.readUInt();
-            // cy (4 bytes): A 32-bit unsigned integer that defines the y-coordinate of the point.
-            height = (int)leis.readUInt();
-
-            return 2*LittleEndianConsts.INT_SIZE;
+            return readDimensionInt(leis, extents);
         }
     }
 
@@ -98,12 +87,7 @@ public class HemfWindowing {
 
         @Override
         public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
-            // x (4 bytes): A 32-bit signed integer that defines the horizontal (x) coordinate of the point.
-            x = leis.readInt();
-            // y (4 bytes): A 32-bit signed integer that defines the vertical (y) coordinate of the point.
-            y = leis.readInt();
-
-            return 2*LittleEndianConsts.INT_SIZE;
+            return readPointL(leis, origin);
         }
     }
 
@@ -119,12 +103,7 @@ public class HemfWindowing {
 
         @Override
         public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
-            // x (4 bytes): A 32-bit signed integer that defines the horizontal (x) coordinate of the point.
-            xOffset = leis.readInt();
-            // y (4 bytes): A 32-bit signed integer that defines the vertical (y) coordinate of the point.
-            yOffset = leis.readInt();
-
-            return 2*LittleEndianConsts.INT_SIZE;
+            return readPointL(leis, offset);
         }
     }
 
@@ -172,10 +151,11 @@ public class HemfWindowing {
 
         @Override
         public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
-            xNum = leis.readInt();
-            xDenom = leis.readInt();
-            yNum = leis.readInt();
-            yDenom = leis.readInt();
+            double xNum = leis.readInt();
+            double xDenom = leis.readInt();
+            double yNum = leis.readInt();
+            double yDenom = leis.readInt();
+            scale.setSize(xNum / xDenom, yNum / yDenom);
             return 4*LittleEndianConsts.INT_SIZE;
         }
     }
@@ -192,10 +172,13 @@ public class HemfWindowing {
 
         @Override
         public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
-            xNum = leis.readInt();
-            xDenom = leis.readInt();
-            yNum = leis.readInt();
-            yDenom = leis.readInt();
+            double xNum = leis.readInt();
+            double xDenom = leis.readInt();
+            double yNum = leis.readInt();
+            double yDenom = leis.readInt();
+
+            scale.setSize(xNum / xDenom, yNum / yDenom);
+
             return 4*LittleEndianConsts.INT_SIZE;
         }
     }
@@ -220,6 +203,17 @@ public class HemfWindowing {
 
             return LittleEndianConsts.INT_SIZE;
         }
+
+        @Override
+        public void draw(HemfGraphics ctx) {
+            HemfDrawProperties props = ctx.getProperties();
+            ctx.setClip(props.getPath(), regionMode);
+        }
+
+        @Override
+        public String toString() {
+            return "{ regionMode: '"+regionMode+"' }";
+        }
     }
 
 }
\ No newline at end of file

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java?rev=1844931&r1=1844930&r2=1844931&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java Sat Oct 27 00:51:19 2018
@@ -57,6 +57,10 @@ import org.apache.poi.util.LocaleUtil;
 
 public class HwmfGraphics {
 
+    public enum FillDrawStyle {
+        NONE, FILL, DRAW, FILL_DRAW
+    }
+
     protected final List<HwmfDrawProperties> propStack = new LinkedList<>();
     protected HwmfDrawProperties prop;
     protected final Graphics2D graphicsCtx;
@@ -297,6 +301,7 @@ public class HwmfGraphics {
      */
     public void updateWindowMapMode() {
         Rectangle2D win = getProperties().getWindow();
+        Rectangle2D view = getProperties().getViewport();
         HwmfMapMode mapMode = getProperties().getMapMode();
         graphicsCtx.setTransform(initialAT);
 
@@ -304,8 +309,10 @@ public class HwmfGraphics {
         default:
         case MM_ANISOTROPIC:
             // scale window bounds to output bounds
-            graphicsCtx.scale(bbox.getWidth()/win.getWidth(), bbox.getHeight()/win.getHeight());
-            graphicsCtx.translate(-win.getX(), -win.getY());
+            if (view != null) {
+                graphicsCtx.translate(view.getX() - win.getX(), view.getY() - win.getY());
+                graphicsCtx.scale(view.getWidth() / win.getWidth(), view.getHeight() / win.getHeight());
+            }
             break;
         case MM_ISOTROPIC:
             // TODO: to be validated ...

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java?rev=1844931&r1=1844930&r2=1844931&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java Sat Oct 27 00:51:19 2018
@@ -234,20 +234,33 @@ public class HwmfBitmapDib {
 
         leis.reset();
 
-        assert( headerSize != 0x0C || ((((headerWidth * headerPlanes * headerBitCount.flag + 31) & ~31) / 8) * Math.abs(headerHeight)) == headerImageSize);
+        // The size and format of this data is determined by information in the DIBHeaderInfo field. If
+        // it is a BitmapCoreHeader, the size in bytes MUST be calculated as follows:
 
-        if (headerImageSize < headerSize) {
-            imageData = IOUtils.safelyAllocate(recordSize, MAX_RECORD_LENGTH);
-            leis.readFully(imageData);
-            return recordSize;
-        } else {
-            int fileSize = (int)Math.min(introSize+headerImageSize,recordSize);
+        int bodySize = ((((headerWidth * headerPlanes * headerBitCount.flag + 31) & ~31) / 8) * Math.abs(headerHeight));
+
+        // This formula SHOULD also be used to calculate the size of aData when DIBHeaderInfo is a
+        // BitmapInfoHeader Object, using values from that object, but only if its Compression value is
+        // BI_RGB, BI_BITFIELDS, or BI_CMYK.
+        // Otherwise, the size of aData MUST be the BitmapInfoHeader Object value ImageSize.
+
+        assert( headerSize != 0x0C || bodySize == headerImageSize);
+
+        if (headerSize == 0x0C ||
+            headerCompression == Compression.BI_RGB ||
+            headerCompression == Compression.BI_BITFIELDS ||
+            headerCompression == Compression.BI_CMYK) {
+            int fileSize = (int)Math.min(introSize+bodySize,recordSize);
             imageData = IOUtils.safelyAllocate(fileSize, MAX_RECORD_LENGTH);
             leis.readFully(imageData, 0, introSize);
             leis.skipFully(recordSize-fileSize);
             // emfs are sometimes truncated, read as much as possible
             int readBytes = leis.read(imageData, introSize, fileSize-introSize);
             return introSize+(recordSize-fileSize)+readBytes;
+        } else {
+            imageData = IOUtils.safelyAllocate(recordSize, MAX_RECORD_LENGTH);
+            leis.readFully(imageData);
+            return recordSize;
         }
     }
 

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java?rev=1844931&r1=1844930&r2=1844931&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java Sat Oct 27 00:51:19 2018
@@ -32,6 +32,8 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.poi.hwmf.draw.HwmfGraphics;
+import org.apache.poi.hwmf.draw.HwmfGraphics.FillDrawStyle;
+import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
@@ -61,7 +63,7 @@ public class HwmfDraw {
 
         @Override
         public String toString() {
-            return "{ x: "+point.getX()+", y: "+point.getY()+" }";
+            return pointToString(point);
         }
     }
 
@@ -93,7 +95,7 @@ public class HwmfDraw {
 
         @Override
         public String toString() {
-            return "{ x: "+point.getX()+", y: "+point.getY()+" }";
+            return pointToString(point);
         }
     }
 
@@ -139,10 +141,17 @@ public class HwmfDraw {
             Path2D p = (Path2D)poly.clone();
             // don't close the path
             p.setWindingRule(ctx.getProperties().getWindingRule());
-            if (isFill()) {
-                ctx.fill(p);
-            } else {
-                ctx.draw(p);
+            switch (getFillDrawStyle()) {
+                case FILL:
+                    ctx.fill(p);
+                    break;
+                case DRAW:
+                    ctx.draw(p);
+                    break;
+                case FILL_DRAW:
+                    ctx.fill(p);
+                    ctx.draw(p);
+                    break;
             }
         }
 
@@ -154,8 +163,8 @@ public class HwmfDraw {
         /**
          * @return true, if the shape should be filled
          */
-        protected boolean isFill() {
-            return true;
+        protected FillDrawStyle getFillDrawStyle() {
+            return FillDrawStyle.FILL;
         }
     }
 
@@ -171,8 +180,8 @@ public class HwmfDraw {
         }
 
         @Override
-        protected boolean isFill() {
-            return false;
+        protected FillDrawStyle getFillDrawStyle() {
+            return FillDrawStyle.DRAW;
         }
     }
 
@@ -196,8 +205,16 @@ public class HwmfDraw {
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            Shape s = new Ellipse2D.Double(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight());
-            ctx.fill(s);
+            ctx.fill(getShape());
+        }
+
+        protected Ellipse2D getShape() {
+            return new Ellipse2D.Double(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight());
+        }
+
+        @Override
+        public String toString() {
+            return boundsToString(bounds);
         }
     }
 
@@ -264,7 +281,7 @@ public class HwmfDraw {
      */
     public static class WmfPolyPolygon implements HwmfRecord {
 
-        protected List<Path2D> polyList = new ArrayList<>();
+        protected final List<Path2D> polyList = new ArrayList<>();
         
         @Override
         public HwmfRecordType getWmfRecordType() {
@@ -316,41 +333,82 @@ public class HwmfDraw {
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            Area area = getShape(ctx);
-            if (area == null) {
+            Shape shape = getShape(ctx);
+            if (shape == null) {
                 return;
             }
-            
-            if (isFill()) {
-                ctx.fill(area);
-            } else {
-                ctx.draw(area);
-            }
-        }
 
-        protected Area getShape(HwmfGraphics ctx) {
-            int windingRule = ctx.getProperties().getWindingRule();
-            Area area = null;
-            for (Path2D poly : polyList) {
-                Path2D p = (Path2D)poly.clone();
-                p.setWindingRule(windingRule);
-                Area newArea = new Area(p);
-                if (area == null) {
-                    area = newArea;
-                } else {
-                    area.exclusiveOr(newArea);
-                }
+            switch (getFillDrawStyle()) {
+                case DRAW:
+                    ctx.draw(shape);
+                    break;
+                case FILL:
+                    ctx.fill(shape);
+                    break;
+                case FILL_DRAW:
+                    ctx.fill(shape);
+                    ctx.draw(shape);
+                    break;
             }
+        }
 
-            return area;
+        protected FillDrawStyle getFillDrawStyle() {
+            // Each polygon SHOULD be outlined using the current pen, and filled using the current brush and
+            // polygon fill mode that are defined in the playback device context. The polygons defined by this
+            // record can overlap.
+            return FillDrawStyle.FILL_DRAW;
         }
 
         /**
-         * @return true, if the shape should be filled
+         * @return true, if a polyline should be closed, i.e. is a polygon
          */
-        protected boolean isFill() {
+        protected boolean isClosed() {
             return true;
         }
+
+        protected Shape getShape(HwmfGraphics ctx) {
+            int windingRule = ctx.getProperties().getWindingRule();
+
+            if (isClosed()) {
+                Area area = null;
+                for (Path2D poly : polyList) {
+                    Path2D p = (Path2D)poly.clone();
+                    p.setWindingRule(windingRule);
+                    Area newArea = new Area(p);
+                    if (area == null) {
+                        area = newArea;
+                    } else {
+                        area.exclusiveOr(newArea);
+                    }
+                }
+                return area;
+            } else {
+                Path2D path = new Path2D.Double();
+                path.setWindingRule(windingRule);
+                for (Path2D poly : polyList) {
+                    path.append(poly, false);
+                }
+                return path;
+            }
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder();
+            sb.append("{ polyList: [");
+            boolean isFirst = true;
+            for (Path2D p : polyList) {
+                if (!isFirst) {
+                    sb.append(",");
+                }
+                isFirst = false;
+                sb.append("{ points: ");
+                sb.append(polyToString(p));
+                sb.append(" }");
+            }
+            sb.append(" }");
+            return sb.toString();
+        }
     }
 
     /**
@@ -377,12 +435,7 @@ public class HwmfDraw {
 
         @Override
         public String toString() {
-            return
-                "{ bounds: " +
-                "{ x: "+bounds.getX()+
-                ", y: "+bounds.getY()+
-                ", w: "+bounds.getWidth()+
-                ", h: "+bounds.getHeight()+" } }";
+            return boundsToString(bounds);
         }
     }
 
@@ -450,8 +503,11 @@ public class HwmfDraw {
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            Shape s = new RoundRectangle2D.Double(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), width, height);
-            ctx.fill(s);
+            ctx.fill(getShape());
+        }
+
+        protected RoundRectangle2D getShape() {
+            return new RoundRectangle2D.Double(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), width, height);
         }
     }
 
@@ -487,15 +543,28 @@ public class HwmfDraw {
         @Override
         public void draw(HwmfGraphics ctx) {
             Shape s = getShape();
+            switch (getFillDrawStyle()) {
+                case FILL:
+                    ctx.fill(s);
+                    break;
+                case DRAW:
+                    ctx.draw(s);
+                    break;
+                case FILL_DRAW:
+                    ctx.fill(s);
+                    ctx.draw(s);
+                    break;
+            }
+        }
+
+        protected FillDrawStyle getFillDrawStyle() {
             switch (getWmfRecordType()) {
                 default:
                 case arc:
-                    ctx.draw(s);
-                    break;
+                    return FillDrawStyle.DRAW;
                 case chord:
                 case pie:
-                    ctx.fill(s);
-                    break;
+                    return FillDrawStyle.FILL_DRAW;
             }
         }
 
@@ -665,4 +734,14 @@ public class HwmfDraw {
         sb.append("]");
         return sb.toString();
     }
+
+    @Internal
+    public static String pointToString(Point2D point) {
+        return "{ x: "+point.getX()+", y: "+point.getY()+" }";
+    }
+
+    @Internal
+    public static String boundsToString(Rectangle2D bounds) {
+        return "{ x: "+bounds.getX()+", y: "+bounds.getY()+", w: "+bounds.getWidth()+", h: "+bounds.getHeight()+" }";
+    }
 }

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java?rev=1844931&r1=1844930&r2=1844931&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java Sat Oct 27 00:51:19 2018
@@ -17,6 +17,7 @@
 
 package org.apache.poi.hwmf.record;
 
+import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
 import static org.apache.poi.hwmf.record.HwmfDraw.readPointS;
 
 import java.awt.Shape;
@@ -420,8 +421,8 @@ public class HwmfFill {
         public String toString() {
             return
                 "{ rasterOperation: '"+rasterOperation+"'"+
-                ", srcBounds: { x: "+srcBounds.getX()+", y: "+srcBounds.getY()+", w: "+srcBounds.getWidth()+", h: "+srcBounds.getHeight()+" }"+
-                ", dstBounds: { x: "+dstBounds.getX()+", y: "+dstBounds.getY()+", w: "+dstBounds.getWidth()+", h: "+dstBounds.getHeight()+" }"+
+                ", srcBounds: "+boundsToString(srcBounds)+
+                ", dstBounds: "+boundsToString(dstBounds)+
                 "}";
         }
     }

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java?rev=1844931&r1=1844930&r2=1844931&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java Sat Oct 27 00:51:19 2018
@@ -244,6 +244,11 @@ public class HwmfMisc {
             ctx.getProperties().setMapMode(mapMode);
             ctx.updateWindowMapMode();
         }
+
+        @Override
+        public String toString() {
+            return "{ mapMode: '"+mapMode+"' }";
+        }
     }
 
     /**
@@ -275,6 +280,11 @@ public class HwmfMisc {
         public void draw(HwmfGraphics ctx) {
 
         }
+
+        @Override
+        public String toString() {
+            return "{ mapperValues: "+mapperValues+" }";
+        }
     }
 
     /**
@@ -379,6 +389,11 @@ public class HwmfMisc {
         public void draw(HwmfGraphics ctx) {
 
         }
+
+        @Override
+        public String toString() {
+            return "{ stretchBltMode: '"+stretchBltMode+"' }";
+        }
     }
 
     /**

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java?rev=1844931&r1=1844930&r2=1844931&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java Sat Oct 27 00:51:19 2018
@@ -17,6 +17,8 @@
 
 package org.apache.poi.hwmf.record;
 
+import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
+import static org.apache.poi.hwmf.record.HwmfDraw.pointToString;
 import static org.apache.poi.hwmf.record.HwmfDraw.readPointS;
 import static org.apache.poi.hwmf.record.HwmfDraw.readRectS;
 
@@ -422,8 +424,8 @@ public class HwmfText {
             }
 
             return
-                "{ reference: { x: "+reference.getX()+", y: "+reference.getY()+" }"+
-                ", bounds: { x: "+bounds.getX()+", y: "+bounds.getY()+", w: "+bounds.getWidth()+", h: "+bounds.getHeight()+"}"+
+                "{ reference: " + pointToString(reference) +
+                ", bounds: " + boundsToString(bounds) +
                 ", text: '"+text.replaceAll("\\p{Cntrl}",".")+"'"+
                 "}";
         }

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java?rev=1844931&r1=1844930&r2=1844931&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java Sat Oct 27 00:51:19 2018
@@ -17,11 +17,15 @@
 
 package org.apache.poi.hwmf.record;
 
+import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
+import static org.apache.poi.hwmf.record.HwmfDraw.pointToString;
 import static org.apache.poi.hwmf.record.HwmfDraw.readBounds;
+import static org.apache.poi.hwmf.record.HwmfDraw.readPointS;
 
 import java.awt.Shape;
 import java.awt.geom.Area;
 import java.awt.geom.Dimension2D;
+import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.io.IOException;
 
@@ -37,11 +41,7 @@ public class HwmfWindowing {
      */
     public static class WmfSetViewportOrg implements HwmfRecord {
 
-        /** A signed integer that defines the vertical offset, in device units. */
-        protected int y;
-
-        /** A signed integer that defines the horizontal offset, in device units. */
-        protected int x;
+        protected final Point2D origin = new Point2D.Double();
 
         @Override
         public HwmfRecordType getWmfRecordType() {
@@ -50,14 +50,18 @@ public class HwmfWindowing {
 
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            y = leis.readShort();
-            x = leis.readShort();
-            return 2*LittleEndianConsts.SHORT_SIZE;
+            return readPointS(leis, origin);
         }
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            ctx.getProperties().setViewportOrg(x, y);
+            ctx.getProperties().setViewportOrg(origin.getX(), origin.getY());
+            ctx.updateWindowMapMode();
+        }
+
+        @Override
+        public String toString() {
+            return pointToString(origin);
         }
     }
 
@@ -67,11 +71,7 @@ public class HwmfWindowing {
      */
     public static class WmfSetViewportExt implements HwmfRecord {
 
-        /** A signed integer that defines the vertical extent of the viewport in device units. */
-        protected int height;
-
-        /** A signed integer that defines the horizontal extent of the viewport in device units. */
-        protected int width;
+        protected final Dimension2D extents = new Dimension2DDouble();
 
         @Override
         public HwmfRecordType getWmfRecordType() {
@@ -80,14 +80,23 @@ public class HwmfWindowing {
 
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            height = leis.readShort();
-            width = leis.readShort();
+            // A signed integer that defines the vertical extent of the viewport in device units.
+            int height = leis.readShort();
+            // A signed integer that defines the horizontal extent of the viewport in device units.
+            int width = leis.readShort();
+            extents.setSize(width, height);
             return 2*LittleEndianConsts.SHORT_SIZE;
         }
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            ctx.getProperties().setViewportExt(width, height);
+            ctx.getProperties().setViewportExt(extents.getWidth(), extents.getHeight());
+            ctx.updateWindowMapMode();
+        }
+
+        @Override
+        public String toString() {
+            return "{ width: "+extents.getWidth()+", height: "+extents.getHeight()+" }";
         }
     }
 
@@ -97,15 +106,7 @@ public class HwmfWindowing {
      */
     public static class WmfOffsetViewportOrg implements HwmfRecord {
 
-        /**
-         * A 16-bit signed integer that defines the vertical offset, in device units.
-         */
-        private int yOffset;
-
-        /**
-         * A 16-bit signed integer that defines the horizontal offset, in device units.
-         */
-        private int xOffset;
+        protected final Point2D offset = new Point2D.Double();
 
         @Override
         public HwmfRecordType getWmfRecordType() {
@@ -114,9 +115,7 @@ public class HwmfWindowing {
 
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            yOffset = leis.readShort();
-            xOffset = leis.readShort();
-            return 2*LittleEndianConsts.SHORT_SIZE;
+            return readPointS(leis, offset);
         }
 
         @Override
@@ -124,7 +123,12 @@ public class HwmfWindowing {
             Rectangle2D viewport = ctx.getProperties().getViewport();
             double x = (viewport == null) ? 0 : viewport.getX();
             double y = (viewport == null) ? 0 : viewport.getY();
-            ctx.getProperties().setViewportOrg(x+xOffset, y+yOffset);
+            ctx.getProperties().setViewportOrg(x+offset.getX(), y+offset.getY());
+        }
+
+        @Override
+        public String toString() {
+            return pointToString(offset);
         }
     }
 
@@ -133,11 +137,7 @@ public class HwmfWindowing {
      */
     public static class WmfSetWindowOrg implements HwmfRecord {
 
-        /** A signed integer that defines the y-coordinate, in logical units. */
-        protected int y;
-
-        /** A signed integer that defines the x-coordinate, in logical units. */
-        protected int x;
+        protected final Point2D origin = new Point2D.Double();
 
         @Override
         public HwmfRecordType getWmfRecordType() {
@@ -146,23 +146,26 @@ public class HwmfWindowing {
 
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            y = leis.readShort();
-            x = leis.readShort();
-            return 2*LittleEndianConsts.SHORT_SIZE;
+            return readPointS(leis, origin);
         }
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            ctx.getProperties().setWindowOrg(x, y);
+            ctx.getProperties().setWindowOrg(getX(), getY());
             ctx.updateWindowMapMode();
         }
 
-        public int getY() {
-            return y;
+        public double getY() {
+            return origin.getY();
         }
 
-        public int getX() {
-            return x;
+        public double getX() {
+            return origin.getX();
+        }
+
+        @Override
+        public String toString() {
+            return pointToString(origin);
         }
     }
 
@@ -198,6 +201,11 @@ public class HwmfWindowing {
         public Dimension2D getSize() {
             return size;
         }
+
+        @Override
+        public String toString() {
+            return "{ width: "+size.getWidth()+", height: "+size.getHeight()+" }";
+        }
     }
 
     /**
@@ -206,15 +214,7 @@ public class HwmfWindowing {
      */
     public static class WmfOffsetWindowOrg implements HwmfRecord {
 
-        /**
-         * A 16-bit signed integer that defines the vertical offset, in device units.
-         */
-        private int yOffset;
-
-        /**
-         * A 16-bit signed integer that defines the horizontal offset, in device units.
-         */
-        private int xOffset;
+        protected final Point2D offset = new Point2D.Double();
 
         @Override
         public HwmfRecordType getWmfRecordType() {
@@ -223,17 +223,20 @@ public class HwmfWindowing {
 
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            yOffset = leis.readShort();
-            xOffset = leis.readShort();
-            return 2*LittleEndianConsts.SHORT_SIZE;
+            return readPointS(leis, offset);
         }
 
         @Override
         public void draw(HwmfGraphics ctx) {
             Rectangle2D window = ctx.getProperties().getWindow();
-            ctx.getProperties().setWindowOrg(window.getX()+xOffset, window.getY()+yOffset);
+            ctx.getProperties().setWindowOrg(window.getX()+offset.getX(), window.getY()+offset.getY());
             ctx.updateWindowMapMode();
         }
+
+        @Override
+        public String toString() {
+            return pointToString(offset);
+        }
     }
 
     /**
@@ -242,29 +245,7 @@ public class HwmfWindowing {
      */
     public static class WmfScaleWindowExt implements HwmfRecord {
 
-        /**
-         * A signed integer that defines the amount by which to divide the
-         * result of multiplying the current y-extent by the value of the yNum member.
-         */
-        protected int yDenom;
-
-        /**
-         * A signed integer that defines the amount by which to multiply the
-         * current y-extent.
-         */
-        protected int yNum;
-
-        /**
-         * A signed integer that defines the amount by which to divide the
-         * result of multiplying the current x-extent by the value of the xNum member.
-         */
-        protected int xDenom;
-
-        /**
-         * A signed integer that defines the amount by which to multiply the
-         * current x-extent.
-         */
-        protected int xNum;
+        protected final Dimension2D scale = new Dimension2DDouble();
 
         @Override
         public HwmfRecordType getWmfRecordType() {
@@ -273,21 +254,37 @@ public class HwmfWindowing {
 
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            yDenom = leis.readShort();
-            yNum = leis.readShort();
-            xDenom = leis.readShort();
-            xNum = leis.readShort();
+            // A signed integer that defines the amount by which to divide the
+            // result of multiplying the current y-extent by the value of the yNum member.
+            double yDenom = leis.readShort();
+            // A signed integer that defines the amount by which to multiply the
+            // current y-extent.
+            double yNum = leis.readShort();
+            // A signed integer that defines the amount by which to divide the
+            // result of multiplying the current x-extent by the value of the xNum member.
+            double xDenom = leis.readShort();
+            // A signed integer that defines the amount by which to multiply the
+            // current x-extent.
+            double xNum = leis.readShort();
+
+            scale.setSize(xNum / xDenom, yNum / yDenom);
+
             return 4*LittleEndianConsts.SHORT_SIZE;
         }
 
         @Override
         public void draw(HwmfGraphics ctx) {
             Rectangle2D window = ctx.getProperties().getWindow();
-            double width = window.getWidth() * xNum / xDenom;
-            double height = window.getHeight() * yNum / yDenom;
+            double width = window.getWidth() * scale.getWidth();
+            double height = window.getHeight() * scale.getHeight();
             ctx.getProperties().setWindowExt(width, height);
             ctx.updateWindowMapMode();
         }
+
+        @Override
+        public String toString() {
+            return "{ scaleX: "+scale.getWidth()+", scaleY: "+scale.getHeight()+" }";
+        }
     }
 
 
@@ -298,29 +295,7 @@ public class HwmfWindowing {
      */
     public static class WmfScaleViewportExt implements HwmfRecord {
 
-        /**
-         * A signed integer that defines the amount by which to divide the
-         * result of multiplying the current y-extent by the value of the yNum member.
-         */
-        protected int yDenom;
-
-        /**
-         * A signed integer that defines the amount by which to multiply the
-         * current y-extent.
-         */
-        protected int yNum;
-
-        /**
-         * A signed integer that defines the amount by which to divide the
-         * result of multiplying the current x-extent by the value of the xNum member.
-         */
-        protected int xDenom;
-
-        /**
-         * A signed integer that defines the amount by which to multiply the
-         * current x-extent.
-         */
-        protected int xNum;
+        protected final Dimension2D scale = new Dimension2DDouble();
 
         @Override
         public HwmfRecordType getWmfRecordType() {
@@ -329,10 +304,21 @@ public class HwmfWindowing {
 
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            yDenom = leis.readShort();
-            yNum = leis.readShort();
-            xDenom = leis.readShort();
-            xNum = leis.readShort();
+            // A signed integer that defines the amount by which to divide the
+            // result of multiplying the current y-extent by the value of the yNum member.
+            double yDenom = leis.readShort();
+            // A signed integer that defines the amount by which to multiply the
+            // current y-extent.
+            double yNum = leis.readShort();
+            // A signed integer that defines the amount by which to divide the
+            // result of multiplying the current x-extent by the value of the xNum member.
+            double xDenom = leis.readShort();
+            // A signed integer that defines the amount by which to multiply the
+            // current x-extent.
+            double xNum = leis.readShort();
+
+            scale.setSize(xNum / xDenom, yNum / yDenom);
+
             return 4*LittleEndianConsts.SHORT_SIZE;
         }
 
@@ -342,10 +328,15 @@ public class HwmfWindowing {
             if (viewport == null) {
                 viewport = ctx.getProperties().getWindow();
             }
-            double width = viewport.getWidth() * xNum / xDenom;
-            double height = viewport.getHeight() * yNum / yDenom;
+            double width = viewport.getWidth() * scale.getWidth();
+            double height = viewport.getHeight() * scale.getHeight();
             ctx.getProperties().setViewportExt(width, height);
         }
+
+        @Override
+        public String toString() {
+            return "{ scaleX: "+scale.getWidth()+", scaleY: "+scale.getHeight()+" }";
+        }
     }
 
     /**
@@ -354,15 +345,7 @@ public class HwmfWindowing {
      */
     public static class WmfOffsetClipRgn implements HwmfRecord, HwmfObjectTableEntry {
 
-        /**
-         * A signed integer that defines the number of logical units to move up or down.
-         */
-        protected int yOffset;
-
-        /**
-         * A signed integer that defines the number of logical units to move left or right.
-         */
-        protected int xOffset;
+        protected final Point2D offset = new Point2D.Double();
 
         @Override
         public HwmfRecordType getWmfRecordType() {
@@ -371,9 +354,7 @@ public class HwmfWindowing {
 
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            yOffset = leis.readShort();
-            xOffset = leis.readShort();
-            return 2*LittleEndianConsts.SHORT_SIZE;
+            return readPointS(leis, offset);
         }
 
         @Override
@@ -384,6 +365,11 @@ public class HwmfWindowing {
         @Override
         public void applyObject(HwmfGraphics ctx) {
         }
+
+        @Override
+        public String toString() {
+            return pointToString(offset);
+        }
     }
 
     /**
@@ -402,20 +388,7 @@ public class HwmfWindowing {
 
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            // A 16-bit signed integer that defines the y-coordinate, in logical units, of the
-            // lower-right corner of the rectangle.
-            final int bottom = leis.readShort();
-            // A 16-bit signed integer that defines the x-coordinate, in logical units, of the
-            // lower-right corner of the rectangle.
-            final int right = leis.readShort();
-            // A 16-bit signed integer that defines the y-coordinate, in logical units, of the
-            // upper-left corner of the rectangle.
-            final int top = leis.readShort();
-            // A 16-bit signed integer that defines the x-coordinate, in logical units, of the
-            // upper-left corner of the rectangle.
-            final int left = leis.readShort();
-            bounds.setRect(left, top, right-left, bottom-top);
-            return 4*LittleEndianConsts.SHORT_SIZE;
+            return readBounds(leis, bounds);
         }
 
         @Override
@@ -426,6 +399,11 @@ public class HwmfWindowing {
         @Override
         public void applyObject(HwmfGraphics ctx) {
         }
+
+        @Override
+        public String toString() {
+            return boundsToString(bounds);
+        }
     }
 
 
@@ -459,12 +437,7 @@ public class HwmfWindowing {
 
         @Override
         public String toString() {
-            return
-                "{ x: "+bounds.getX()+
-                ", y: "+bounds.getY()+
-                ", w: "+bounds.getWidth()+
-                ", h: "+bounds.getHeight()+
-                "}";
+            return boundsToString(bounds);
         }
     }
 
@@ -572,29 +545,7 @@ public class HwmfWindowing {
          */
         private int maxScan;
 
-        /**
-         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the
-         * lower-right corner of the rectangle.
-         */
-        private int bottom;
-
-        /**
-         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the
-         * lower-right corner of the rectangle.
-         */
-        private int right;
-
-        /**
-         * A 16-bit signed integer that defines the y-coordinate, in logical units, of the
-         * upper-left corner of the rectangle.
-         */
-        private int top;
-
-        /**
-         * A 16-bit signed integer that defines the x-coordinate, in logical units, of the
-         * upper-left corner of the rectangle.
-         */
-        private int left;
+        private Rectangle2D bounds = new Rectangle2D.Double();
 
         /**
          * An array of Scan objects that define the scanlines in the region.
@@ -614,10 +565,19 @@ public class HwmfWindowing {
             regionSize = leis.readShort();
             scanCount = leis.readShort();
             maxScan = leis.readShort();
-            left = leis.readShort();
-            top = leis.readShort();
-            right = leis.readShort();
-            bottom = leis.readShort();
+            // A 16-bit signed integer that defines the x-coordinate, in logical units, of the
+            // upper-left corner of the rectangle.
+            double left = leis.readShort();
+            // A 16-bit signed integer that defines the y-coordinate, in logical units, of the
+            // upper-left corner of the rectangle.
+            double top = leis.readShort();
+            // A 16-bit signed integer that defines the x-coordinate, in logical units, of the
+            // lower-right corner of the rectangle.
+            double right = leis.readShort();
+            // A 16-bit signed integer that defines the y-coordinate, in logical units, of the
+            // lower-right corner of the rectangle.
+            double bottom = leis.readShort();
+            bounds.setRect(left, top, right-left, bottom-top);
             
             int size = 9*LittleEndianConsts.SHORT_SIZE+LittleEndianConsts.INT_SIZE;
 

Modified: poi/branches/hemf/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfPictureTest.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfPictureTest.java?rev=1844931&r1=1844930&r2=1844931&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfPictureTest.java (original)
+++ poi/branches/hemf/src/scratchpad/testcases/org/apache/poi/hemf/usermodel/HemfPictureTest.java Sat Oct 27 00:51:19 2018
@@ -63,7 +63,13 @@ public class HemfPictureTest {
     public void paint() throws IOException {
         byte buf[] = new byte[50_000_000];
 
-        final boolean writeLog = false;
+        // good test samples to validate rendering:
+        // emfs/commoncrawl2/NB/NBWN2YH5VFCLZRFDQU7PB7IDD4UKY7DN_2.emf
+        // emfs/govdocs1/777/777525.ppt_0.emf
+        // emfs/govdocs1/844/844795.ppt_2.emf
+        // emfs/commoncrawl2/TO/TOYZSTNUSW5OFCFUQ6T5FBLIDLCRF3NH_0.emf
+
+        final boolean writeLog = true;
         final boolean dumpRecords = false;
         final boolean savePng = true;
 
@@ -257,7 +263,7 @@ public class HemfPictureTest {
             long fudgeFactorX = 1000;
             StringBuilder sb = new StringBuilder();
             for (HemfRecord record : pic) {
-                if (record.getEmfRecordType().equals(HemfRecordType.exttextoutw)) {
+                if (record.getEmfRecordType().equals(HemfRecordType.extTextOutW)) {
                     HemfText.EmfExtTextOutW extTextOutW = (HemfText.EmfExtTextOutW) record;
                     Point2D reference = extTextOutW.getReference();
                     if (lastY > -1 && lastY != reference.getY()) {
@@ -291,7 +297,7 @@ public class HemfPictureTest {
             expectedParts.add("testPDF.pdf");
             int foundExpected = 0;
             for (HemfRecord record : pic) {
-                if (record.getEmfRecordType().equals(HemfRecordType.exttextoutw)) {
+                if (record.getEmfRecordType().equals(HemfRecordType.extTextOutW)) {
                     HemfText.EmfExtTextOutW extTextOutW = (HemfText.EmfExtTextOutW) record;
                     Point2D reference = extTextOutW.getReference();
                     if (lastY > -1 && lastY != reference.getY()) {



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org