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/30 22:35:45 UTC

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

Author: kiwiwings
Date: Tue Oct 30 22:35:45 2018
New Revision: 1845291

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

Added:
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRegionMode.java   (with props)
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/HemfHeader.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfWindowing.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfPicture.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.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/HwmfText.java
    poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.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=1845291&r1=1845290&r2=1845291&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 Tue Oct 30 22:35:45 2018
@@ -26,7 +26,6 @@ public class HemfDrawProperties extends
 
     /** Path for path bracket operations */
     protected Path2D path = null;
-    protected Shape clip = null;
     protected boolean usePathBracket = false;
 
 
@@ -67,12 +66,4 @@ public class HemfDrawProperties extends
     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=1845291&r1=1845290&r2=1845291&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 Tue Oct 30 22:35:45 2018
@@ -22,16 +22,13 @@ 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.function.Consumer;
 
-import org.apache.poi.hemf.record.emf.HemfFill;
 import org.apache.poi.hemf.record.emf.HemfRecord;
+import org.apache.poi.hwmf.draw.HwmfDrawProperties;
 import org.apache.poi.hwmf.draw.HwmfGraphics;
 import org.apache.poi.hwmf.record.HwmfColorRef;
 import org.apache.poi.hwmf.record.HwmfObjectTableEntry;
@@ -47,36 +44,22 @@ public class HemfGraphics extends HwmfGr
     private static final HwmfColorRef BLACK = new HwmfColorRef(Color.BLACK);
 
 
-    private final AffineTransform initTrans;
-
     public HemfGraphics(Graphics2D graphicsCtx, Rectangle2D bbox) {
         super(graphicsCtx,bbox);
         // add dummy entry for object ind ex 0, as emf is 1-based
         objectIndexes.set(0);
-        initTrans = new AffineTransform(graphicsCtx.getTransform());
     }
 
     @Override
     public HemfDrawProperties getProperties() {
-        if (prop == null) {
-            prop = new HemfDrawProperties();
-        }
-        return (HemfDrawProperties)prop;
+        return (HemfDrawProperties)super.getProperties();
     }
 
     @Override
-    public void saveProperties() {
-        final HemfDrawProperties oldProp = getProperties();
-        oldProp.setClip(graphicsCtx.getClip());
-        propStack.add(oldProp);
-        prop = new HemfDrawProperties(oldProp);
-    }
-
-    @Override
-    public void restoreProperties(int index) {
-        super.restoreProperties(index);
-        HemfDrawProperties newProp = getProperties();
-        graphicsCtx.setClip(newProp.getClip());
+    protected HemfDrawProperties newProperties(HwmfDrawProperties oldProps) {
+        return (oldProps == null)
+            ? new HemfDrawProperties()
+            : new HemfDrawProperties((HemfDrawProperties)oldProps);
     }
 
     public void draw(HemfRecord r) {
@@ -94,8 +77,12 @@ public class HemfGraphics extends HwmfGr
         } else {
             path = new Path2D.Double();
             path.setWindingRule(prop.getWindingRule());
+        }
+
+        // add dummy move-to at start, to handle invalid emfs not containing that move-to
+        if (path.getCurrentPoint() == null) {
             Point2D pnt = prop.getLocation();
-            path.moveTo(pnt.getX(),pnt.getY());
+            path.moveTo(pnt.getX(), pnt.getY());
         }
 
         try {
@@ -108,7 +95,12 @@ public class HemfGraphics extends HwmfGr
             pathConsumer.accept(path);
         }
 
-        prop.setLocation(path.getCurrentPoint());
+        Point2D curPnt = path.getCurrentPoint();
+        if (curPnt == null) {
+            return;
+        }
+
+        prop.setLocation(curPnt);
         if (!useBracket) {
             switch (fillDraw) {
                 case FILL:
@@ -264,64 +256,4 @@ public class HemfGraphics extends HwmfGr
                 break;
         }
     }
-
-    /**
-     * @return the initial AffineTransform, when this graphics context was created
-     */
-    public AffineTransform getInitTransform() {
-        return new AffineTransform(initTrans);
-    }
-
-    /**
-     * @return the current AffineTransform
-     */
-    public AffineTransform getTransform() {
-        return new AffineTransform(graphicsCtx.getTransform());
-    }
-
-    /**
-     * Set the current AffineTransform
-     * @param tx the current AffineTransform
-     */
-    public void setTransform(AffineTransform tx) {
-        graphicsCtx.setTransform(tx);
-    }
-
-    public void setClip(Shape clip, HemfFill.HemfRegionMode regionMode) {
-        Shape oldClip = graphicsCtx.getClip();
-
-        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=1845291&r1=1845290&r2=1845291&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 Tue Oct 30 22:35:45 2018
@@ -1051,7 +1051,11 @@ public class HemfDraw {
         @Override
         public void draw(HemfGraphics ctx) {
             final HemfDrawProperties prop = ctx.getProperties();
-            final Path2D path = (Path2D)prop.getPath().clone();
+            final Path2D origPath = prop.getPath();
+            if (origPath.getCurrentPoint() == null) {
+                return;
+            }
+            final Path2D path = (Path2D)origPath.clone();
             path.closePath();
             path.setWindingRule(ctx.getProperties().getWindingRule());
             ctx.fill(path);

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=1845291&r1=1845290&r2=1845291&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 Tue Oct 30 22:35:45 2018
@@ -20,10 +20,11 @@ package org.apache.poi.hemf.record.emf;
 import static org.apache.poi.hemf.record.emf.HemfDraw.readPointL;
 import static org.apache.poi.hemf.record.emf.HemfDraw.readRectL;
 import static org.apache.poi.hemf.record.emf.HemfRecordIterator.HEADER_SIZE;
+import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
 
+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.io.ByteArrayInputStream;
@@ -36,11 +37,11 @@ import org.apache.poi.hemf.draw.HemfDraw
 import org.apache.poi.hemf.draw.HemfGraphics;
 import org.apache.poi.hwmf.draw.HwmfGraphics;
 import org.apache.poi.hwmf.record.HwmfBitmapDib;
-import org.apache.poi.hwmf.record.HwmfBrushStyle;
 import org.apache.poi.hwmf.record.HwmfColorRef;
 import org.apache.poi.hwmf.record.HwmfDraw;
 import org.apache.poi.hwmf.record.HwmfFill;
 import org.apache.poi.hwmf.record.HwmfFill.ColorUsage;
+import org.apache.poi.hwmf.record.HwmfRegionMode;
 import org.apache.poi.hwmf.record.HwmfTernaryRasterOp;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.LittleEndian;
@@ -50,47 +51,6 @@ import org.apache.poi.util.LittleEndianI
 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;
-        HemfRegionMode(int flag) {
-            this.flag = flag;
-        }
-
-        public static HemfRegionMode valueOf(int flag) {
-            for (HemfRegionMode rm : values()) {
-                if (rm.flag == flag) return rm;
-            }
-            return null;
-        }
-
-    }
-
-
     /**
      * The EMR_SETPOLYFILLMODE record defines polygon fill mode.
      */
@@ -105,7 +65,7 @@ public class HemfFill {
         public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
             // A 32-bit unsigned integer that specifies the polygon fill mode and
             // MUST be in the PolygonFillMode enumeration.
-            polyfillMode = HwmfPolyfillMode.valueOf((int)leis.readUInt());
+            polyFillMode = HwmfPolyfillMode.valueOf((int)leis.readUInt());
             return LittleEndianConsts.INT_SIZE;
         }
     }
@@ -133,7 +93,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 {
+    public static class EmfStretchBlt extends HwmfFill.WmfStretchDib 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. */
@@ -142,14 +102,6 @@ public class HemfFill {
         /** A WMF ColorRef object that specifies the background color of the source bitmap. */
         protected final HwmfColorRef bkColorSrc = new HwmfColorRef();
 
-        /**
-         * A 32-bit unsigned integer that specifies how to interpret values in the color table in
-         * the source bitmap header. This value MUST be in the DIBColors enumeration
-         */
-        protected int usageSrc;
-
-        protected final HwmfBitmapDib bitmap = new HwmfBitmapDib();
-
         @Override
         public HemfRecordType getEmfRecordType() {
             return HemfRecordType.stretchBlt;
@@ -168,7 +120,7 @@ public class HemfFill {
             // rectangle and optionally a brush pattern, to achieve the final color.
             int rasterOpIndex = (int)leis.readUInt();
 
-            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex >>> 16);
 
             size += LittleEndianConsts.INT_SIZE;
 
@@ -179,7 +131,7 @@ public class HemfFill {
 
             size += bkColorSrc.init(leis);
 
-            usageSrc = (int)leis.readUInt();
+            colorUsage = ColorUsage.valueOf((int)leis.readUInt());
 
             // A 32-bit unsigned integer that specifies the offset, in bytes, from the
             // start of this record to the source bitmap header in the BitmapBuffer field.
@@ -188,7 +140,7 @@ public class HemfFill {
             // A 32-bit unsigned integer that specifies the size, in bytes, of the source bitmap header.
             final int cbBmiSrc = (int)leis.readUInt();
             size += 3*LittleEndianConsts.INT_SIZE;
-            if (size <= recordSize) {
+            if (size >= recordSize) {
                 return size;
             }
 
@@ -198,9 +150,12 @@ public class HemfFill {
 
             // A 32-bit unsigned integer that specifies the size, in bytes, of the source bitmap bits.
             final int cbBitsSrc = (int)leis.readUInt();
-
             size += 2*LittleEndianConsts.INT_SIZE;
 
+            if (size >= recordSize) {
+                return size;
+            }
+
             if (srcEqualsDstDimension()) {
                 srcBounds.setRect(srcPnt.getX(), srcPnt.getY(), dstBounds.getWidth(), dstBounds.getHeight());
             } else {
@@ -220,13 +175,19 @@ public class HemfFill {
         }
 
         @Override
+        public void draw(HemfGraphics ctx) {
+            HemfDrawProperties prop = ctx.getProperties();
+            prop.setBackgroundColor(this.bkColorSrc);
+            super.draw(ctx);
+        }
+
+        @Override
         public String toString() {
             return
-                "{ bounds: { x: "+bounds.getX()+", y: "+bounds.getY()+", w: "+bounds.getWidth()+", h: "+bounds.getHeight()+"}"+
+                "{ bounds: "+boundsToString(bounds)+
                 ", xFormSrc: { scaleX: "+xFormSrc.getScaleX()+", shearX: "+xFormSrc.getShearX()+", transX: "+xFormSrc.getTranslateX()+", scaleY: "+xFormSrc.getScaleY()+", shearY: "+xFormSrc.getShearY()+", transY: "+xFormSrc.getTranslateY()+" }"+
                 ", bkColorSrc: "+bkColorSrc+
-                ", usageSrc: "+usageSrc+", "
-                + super.toString().substring(1);
+                ","+super.toString().substring(1);
         }
     }
 
@@ -279,7 +240,8 @@ public class HemfFill {
             // These codes define how the color data of the source rectangle is to be combined with the color data
             // of the destination rectangle and optionally a brush pattern, to achieve the final color.
             // The value MUST be in the WMF Ternary Raster Operation enumeration
-            rasterOperation = HwmfTernaryRasterOp.valueOf(leis.readInt());
+            int rasterOpIndex = (int)leis.readUInt();
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex >>> 16);
 
             // A 32-bit signed integer that specifies the logical width of the destination rectangle.
             int cxDest = leis.readInt();
@@ -291,7 +253,7 @@ public class HemfFill {
 
             size += 8*LittleEndianConsts.INT_SIZE;
 
-            size += readBitmap(leis, dib, startIdx, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc);
+            size += readBitmap(leis, bitmap, startIdx, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc);
 
             return size;
         }
@@ -346,7 +308,7 @@ public class HemfFill {
             ctx.fill(getShape());
         }
 
-        protected Area getShape() {
+        protected Shape getShape() {
             return getRgnShape(rgnRects);
         }
     }
@@ -371,7 +333,7 @@ public class HemfFill {
             return size;
         }
 
-        protected Area getShape() {
+        protected Shape getShape() {
             return getRgnShape(rgnRects);
         }
     }
@@ -408,13 +370,13 @@ public class HemfFill {
             return size;
         }
 
-        protected Area getShape() {
+        protected Shape getShape() {
             return getRgnShape(rgnRects);
         }
     }
 
     public static class EmfExtSelectClipRgn implements HemfRecord {
-        protected HemfRegionMode regionMode;
+        protected HwmfRegionMode regionMode;
         protected final List<Rectangle2D> rgnRects = new ArrayList<>();
 
         @Override
@@ -427,20 +389,43 @@ public class HemfFill {
             // A 32-bit unsigned integer that specifies the size of region data in bytes
             long rgnDataSize = leis.readUInt();
             // A 32-bit unsigned integer that specifies the way to use the region.
-            regionMode = HemfRegionMode.valueOf((int)leis.readUInt());
+            regionMode = HwmfRegionMode.valueOf((int)leis.readUInt());
             long size = 2* LittleEndianConsts.INT_SIZE;
 
             // If RegionMode is RGN_COPY, this data can be omitted and the clip region
             // SHOULD be set to the default (NULL) clip region.
-            if (regionMode != HemfRegionMode.RGN_COPY) {
+            if (regionMode != HwmfRegionMode.RGN_COPY) {
                 size += readRgnData(leis, rgnRects);
             }
             return size;
         }
 
-        protected Area getShape() {
+        protected Shape getShape() {
             return getRgnShape(rgnRects);
         }
+
+        @Override
+        public void draw(HemfGraphics ctx) {
+            HemfDrawProperties prop = ctx.getProperties();
+            ctx.setClip(getShape(), regionMode, true);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("{ regionMode: '"+regionMode+"'");
+            sb.append(", regions: [");
+            boolean isFirst = true;
+            for (Rectangle2D r : rgnRects) {
+                if (!isFirst) {
+                    sb.append(",");
+                }
+                isFirst = false;
+                sb.append(boundsToString(r));
+            }
+            sb.append("]}");
+            return sb.toString();
+        }
     }
 
     public static class EmfAlphaBlend implements HemfRecord {
@@ -717,7 +702,10 @@ public class HemfFill {
         return 6 * LittleEndian.INT_SIZE;
     }
 
-    protected static Area getRgnShape(List<Rectangle2D> rgnRects) {
+    protected static Shape getRgnShape(List<Rectangle2D> rgnRects) {
+        if (rgnRects.size() == 1) {
+            return rgnRects.get(0);
+        }
         final Area frame = new Area();
         rgnRects.forEach((rct) -> frame.add(new Area(rct)));
         return frame;

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfHeader.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfHeader.java?rev=1845291&r1=1845290&r2=1845291&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfHeader.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfHeader.java Tue Oct 30 22:35:45 2018
@@ -20,6 +20,8 @@ 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.readRectL;
 import static org.apache.poi.hemf.record.emf.HemfRecordIterator.HEADER_SIZE;
+import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
+import static org.apache.poi.hwmf.record.HwmfDraw.dimToString;
 
 import java.awt.geom.Dimension2D;
 import java.awt.geom.Rectangle2D;
@@ -119,21 +121,21 @@ public class HemfHeader implements HemfR
     @Override
     public String toString() {
         return "HemfHeader{" +
-                "boundsRectangle=" + boundsRectangle +
-                ", frameRectangle=" + frameRectangle +
-                ", bytes=" + bytes +
-                ", records=" + records +
-                ", handles=" + handles +
-                ", description=" + description +
-                ", nPalEntries=" + nPalEntries +
-                ", hasExtension1=" + hasExtension1 +
-                ", cbPixelFormat=" + cbPixelFormat +
-                ", offPixelFormat=" + offPixelFormat +
-                ", bOpenGL=" + bOpenGL +
-                ", hasExtension2=" + hasExtension2 +
-                ", deviceDimension=" + deviceDimension +
-                ", microDimension=" + microDimension +
-                ", milliDimension=" + milliDimension +
+                "boundsRectangle: " + boundsToString(boundsRectangle) +
+                ", frameRectangle: " + boundsToString(frameRectangle) +
+                ", bytes: " + bytes +
+                ", records: " + records +
+                ", handles: " + handles +
+                ", description: '" + description + "'" +
+                ", nPalEntries: " + nPalEntries +
+                ", hasExtension1: " + hasExtension1 +
+                ", cbPixelFormat: " + cbPixelFormat +
+                ", offPixelFormat: " + offPixelFormat +
+                ", bOpenGL: " + bOpenGL +
+                ", hasExtension2: " + hasExtension2 +
+                ", deviceDimension: " + dimToString(deviceDimension) +
+                ", microDimension: " + dimToString(microDimension) +
+                ", milliDimension: " + dimToString(milliDimension) +
                 '}';
     }
 

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java?rev=1845291&r1=1845290&r2=1845291&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java Tue Oct 30 22:35:45 2018
@@ -191,7 +191,7 @@ public class HemfText {
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            ctx.drawString(rawTextBytes, reference, bounds, dx, isUnicode());
+            ctx.drawString(rawTextBytes, reference, bounds, options, dx, isUnicode());
         }
 
         @Override

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=1845291&r1=1845290&r2=1845291&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 Tue Oct 30 22:35:45 2018
@@ -24,7 +24,7 @@ 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.HwmfRegionMode;
 import org.apache.poi.hwmf.record.HwmfWindowing;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
@@ -188,7 +188,7 @@ public class HemfWindowing {
      * device context, combining the new region with any existing clipping region using the specified mode.
      */
     public static class EmfSelectClipPath implements HemfRecord {
-        protected HemfRegionMode regionMode;
+        protected HwmfRegionMode regionMode;
 
         @Override
         public HemfRecordType getEmfRecordType() {
@@ -199,15 +199,15 @@ public class HemfWindowing {
         public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
             // A 32-bit unsigned integer that specifies the way to use the path.
             // The value MUST be in the RegionMode enumeration
-            regionMode = HemfRegionMode.valueOf(leis.readInt());
+            regionMode = HwmfRegionMode.valueOf(leis.readInt());
 
             return LittleEndianConsts.INT_SIZE;
         }
 
         @Override
         public void draw(HemfGraphics ctx) {
-            HemfDrawProperties props = ctx.getProperties();
-            ctx.setClip(props.getPath(), regionMode);
+            HemfDrawProperties prop = ctx.getProperties();
+            ctx.setClip(prop.getPath(), regionMode, false);
         }
 
         @Override

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfPicture.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfPicture.java?rev=1845291&r1=1845290&r2=1845291&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfPicture.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfPicture.java Tue Oct 30 22:35:45 2018
@@ -113,7 +113,7 @@ public class HemfPicture implements Iter
             height = 100;
         }
 
-        return new Dimension2DDouble(width*coeff, height*coeff);
+        return new Dimension2DDouble(Math.abs(width*coeff), Math.abs(height*coeff));
     }
 
     public void draw(Graphics2D ctx, Rectangle2D graphicsBounds) {

Modified: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.java?rev=1845291&r1=1845290&r2=1845291&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.java Tue Oct 30 22:35:45 2018
@@ -19,6 +19,7 @@ package org.apache.poi.hwmf.draw;
 
 import java.awt.Color;
 import java.awt.Shape;
+import java.awt.geom.AffineTransform;
 import java.awt.geom.Area;
 import java.awt.geom.Path2D;
 import java.awt.geom.Point2D;
@@ -67,6 +68,8 @@ public class HwmfDrawProperties {
     private HwmfTextAlignment textAlignAsian;
     private HwmfTextVerticalAlignment textVAlignAsian;
     private HwmfTernaryRasterOp rasterOp;
+    protected Shape clip;
+    protected final AffineTransform transform = new AffineTransform();
 
     public HwmfDrawProperties() {
         window = new Rectangle2D.Double(0, 0, 1, 1);
@@ -89,6 +92,7 @@ public class HwmfDrawProperties {
         textAlignAsian = HwmfTextAlignment.RIGHT;
         textVAlignAsian = HwmfTextVerticalAlignment.TOP;
         rasterOp = HwmfTernaryRasterOp.PATCOPY;
+        clip = null;
     }
     
     public HwmfDrawProperties(HwmfDrawProperties other) {
@@ -126,6 +130,8 @@ public class HwmfDrawProperties {
         this.textAlignAsian = other.textAlignAsian;
         this.textVAlignAsian = other.textVAlignAsian;
         this.rasterOp = other.rasterOp;
+        this.transform.setTransform(other.transform);
+        this.clip = other.clip;
     }
     
     public void setViewportExt(double width, double height) {
@@ -387,4 +393,20 @@ public class HwmfDrawProperties {
     public void setRasterOp(HwmfTernaryRasterOp rasterOp) {
         this.rasterOp = rasterOp;
     }
+
+    public AffineTransform getTransform() {
+        return transform;
+    }
+
+    public void setTransform(AffineTransform transform) {
+        this.transform.setTransform(transform);
+    }
+
+    public Shape getClip() {
+        return clip;
+    }
+
+    public void setClip(Shape clip) {
+        this.clip = clip;
+    }
 }

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=1845291&r1=1845290&r2=1845291&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 Tue Oct 30 22:35:45 2018
@@ -29,6 +29,7 @@ import java.awt.font.FontRenderContext;
 import java.awt.font.TextAttribute;
 import java.awt.font.TextLayout;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
@@ -50,7 +51,9 @@ import org.apache.poi.hwmf.record.HwmfMi
 import org.apache.poi.hwmf.record.HwmfObjectTableEntry;
 import org.apache.poi.hwmf.record.HwmfPenStyle;
 import org.apache.poi.hwmf.record.HwmfPenStyle.HwmfLineDash;
+import org.apache.poi.hwmf.record.HwmfRegionMode;
 import org.apache.poi.hwmf.record.HwmfText;
+import org.apache.poi.hwmf.record.HwmfText.WmfExtTextOutOptions;
 import org.apache.poi.sl.draw.DrawFactory;
 import org.apache.poi.sl.draw.DrawFontManager;
 import org.apache.poi.util.LocaleUtil;
@@ -66,11 +69,12 @@ public class HwmfGraphics {
     protected final Graphics2D graphicsCtx;
     protected final BitSet objectIndexes = new BitSet();
     protected final TreeMap<Integer,HwmfObjectTableEntry> objectTable = new TreeMap<>();
+    protected final AffineTransform initialAT = new AffineTransform();
+
 
     private static final Charset DEFAULT_CHARSET = LocaleUtil.CHARSET_1252;
     /** Bounding box from the placeable header */
     private final Rectangle2D bbox;
-    private final AffineTransform initialAT;
 
     /**
      * Initialize a graphics context for wmf rendering
@@ -81,16 +85,20 @@ public class HwmfGraphics {
     public HwmfGraphics(Graphics2D graphicsCtx, Rectangle2D bbox) {
         this.graphicsCtx = graphicsCtx;
         this.bbox = (Rectangle2D)bbox.clone();
-        this.initialAT = graphicsCtx.getTransform();
+        this.initialAT.setTransform(graphicsCtx.getTransform());
     }
 
     public HwmfDrawProperties getProperties() {
         if (prop == null) {
-            prop = new HwmfDrawProperties();
+            prop = newProperties(null);
         }
         return prop;
     }
 
+    protected HwmfDrawProperties newProperties(HwmfDrawProperties oldProps) {
+        return (oldProps == null) ? new HwmfDrawProperties() : new HwmfDrawProperties(oldProps);
+    }
+
     public void draw(Shape shape) {
         HwmfPenStyle ps = getProperties().getPenStyle();
         if (ps == null) {
@@ -119,14 +127,18 @@ public class HwmfGraphics {
     }
 
     public void fill(Shape shape) {
-        if (getProperties().getBrushStyle() != HwmfBrushStyle.BS_NULL) {
-//            GeneralPath gp = new GeneralPath(shape);
-//            gp.setWindingRule(getProperties().getPolyfillMode().awtFlag);
+        HwmfDrawProperties prop = getProperties();
+        if (prop.getBrushStyle() != HwmfBrushStyle.BS_NULL) {
+            if (prop.getBkMode() == HwmfBkMode.OPAQUE) {
+                graphicsCtx.setPaint(prop.getBackgroundColor().getColor());
+                graphicsCtx.fill(shape);
+            }
+
             graphicsCtx.setPaint(getFill());
             graphicsCtx.fill(shape);
         }
 
-        draw(shape);
+//        draw(shape);
     }
 
     protected BasicStroke getStroke() {
@@ -264,8 +276,10 @@ public class HwmfGraphics {
     public void saveProperties() {
         final HwmfDrawProperties p = getProperties();
         assert(p != null);
+        p.setTransform(graphicsCtx.getTransform());
+        p.setClip(graphicsCtx.getClip());
         propStack.add(p);
-        prop = new HwmfDrawProperties(p);
+        prop = newProperties(p);
     }
     
     /**
@@ -291,7 +305,16 @@ public class HwmfGraphics {
             // roll to last when curIdx == 0
             stackIndex = propStack.size()-1;
         }
-        prop = propStack.get(stackIndex);
+
+        // The playback device context is restored by popping state information off a stack that was created by
+        // prior SAVEDC records
+        // ... so because being a stack, we will remove all entries having a greater index than the stackIndex
+        for (int i=propStack.size()-1; i>=stackIndex; i--) {
+            prop = propStack.remove(i);
+        }
+
+        graphicsCtx.setTransform(prop.getTransform());
+        graphicsCtx.setClip(prop.getClip());
     }
 
     /**
@@ -338,13 +361,14 @@ public class HwmfGraphics {
         }
     }
 
-    public void drawString(byte[] text, Point2D reference, Rectangle2D clip) {
-        drawString(text, reference, clip, null, false);
+    public void drawString(byte[] text, Point2D reference) {
+        drawString(text, reference, null, null, null, false);
     }
 
-    public void drawString(byte[] text, Point2D reference, Rectangle2D clip, List<Integer> dx, boolean isUnicode) {
+    public void drawString(byte[] text, Point2D reference, Rectangle2D clip, WmfExtTextOutOptions opts, List<Integer> dx, boolean isUnicode) {
+        final HwmfDrawProperties prop = getProperties();
 
-        HwmfFont font = getProperties().getFont();
+        HwmfFont font = prop.getFont();
         if (font == null || text == null || text.length == 0) {
             return;
         }
@@ -446,21 +470,31 @@ public class HwmfGraphics {
         Point2D dst = new Point2D.Double();
         tx.transform(src, dst);
 
-        // TODO: implement clipping on bounds
+        final Shape clipShape = graphicsCtx.getClip();
         final AffineTransform at = graphicsCtx.getTransform();
         try {
+            if (clip != null) {
+                graphicsCtx.translate(-clip.getCenterX(), -clip.getCenterY());
+                graphicsCtx.rotate(angle);
+                graphicsCtx.translate(clip.getCenterX(), clip.getCenterY());
+                if (prop.getBkMode() == HwmfBkMode.OPAQUE && opts.isOpaque()) {
+                    graphicsCtx.setPaint(prop.getBackgroundColor().getColor());
+                    graphicsCtx.fill(clip);
+                }
+                if (opts.isClipped()) {
+                    graphicsCtx.setClip(clip);
+                }
+                graphicsCtx.setTransform(at);
+            }
+
             graphicsCtx.translate(reference.getX(), reference.getY());
             graphicsCtx.rotate(angle);
             graphicsCtx.translate(dst.getX(), dst.getY());
-            if (getProperties().getBkMode() == HwmfBkMode.OPAQUE && clip != null) {
-                // TODO: validate bounds
-                graphicsCtx.setBackground(getProperties().getBackgroundColor().getColor());
-                graphicsCtx.fill(new Rectangle2D.Double(0, 0, clip.getWidth(), clip.getHeight()));
-            }
-            graphicsCtx.setColor(getProperties().getTextColor().getColor());
+            graphicsCtx.setColor(prop.getTextColor().getColor());
             graphicsCtx.drawString(as.getIterator(), 0, 0);
         } finally {
             graphicsCtx.setTransform(at);
+            graphicsCtx.setClip(clipShape);
         }
     }
 
@@ -498,18 +532,136 @@ public class HwmfGraphics {
     }
 
     public void drawImage(BufferedImage img, Rectangle2D srcBounds, Rectangle2D dstBounds) {
-        // prop.getRasterOp();
-        graphicsCtx.drawImage(img,
-            (int)dstBounds.getX(),
-            (int)dstBounds.getY(),
-            (int)(dstBounds.getX()+dstBounds.getWidth()),
-            (int)(dstBounds.getY()+dstBounds.getHeight()),
-            (int)srcBounds.getX(),
-            (int)srcBounds.getY(),
-            (int)(srcBounds.getX()+srcBounds.getWidth()),
-            (int)(srcBounds.getY()+srcBounds.getHeight()),
-            null, // getProperties().getBackgroundColor().getColor(),
-            null
-        );
+        HwmfDrawProperties prop = getProperties();
+
+        // handle raster op
+        // currently the raster op as described in https://docs.microsoft.com/en-us/windows/desktop/gdi/ternary-raster-operations
+        // are not supported, as we would need to extract the destination image area from the underlying buffered image
+        // and therefore would make it mandatory that the graphics context must be from a buffered image
+        // furthermore I doubt the purpose of bitwise image operations on non-black/white images
+        switch (prop.getRasterOp()) {
+            case D:
+                // keep destination, i.e. do nothing
+                break;
+            case PATCOPY:
+                graphicsCtx.setPaint(getFill());
+                graphicsCtx.fill(dstBounds);
+                break;
+            case BLACKNESS:
+                graphicsCtx.setPaint(Color.BLACK);
+                graphicsCtx.fill(dstBounds);
+                break;
+            case WHITENESS:
+                graphicsCtx.setPaint(Color.WHITE);
+                graphicsCtx.fill(dstBounds);
+                break;
+            default:
+            case SRCCOPY:
+                final Shape clip = graphicsCtx.getClip();
+
+                // add clipping in case of a source subimage, i.e. a clipped source image
+                // some dstBounds are horizontal or vertical flipped, so we need to normalize the images
+                Rectangle2D normalized = new Rectangle2D.Double(
+                    dstBounds.getWidth() >= 0 ? dstBounds.getMinX() : dstBounds.getMaxX(),
+                    dstBounds.getHeight() >= 0 ? dstBounds.getMinY() : dstBounds.getMaxY(),
+                    Math.abs(dstBounds.getWidth()),
+                    Math.abs(dstBounds.getHeight()));
+                graphicsCtx.clip(normalized);
+                final AffineTransform at = graphicsCtx.getTransform();
+
+                final Rectangle2D imgBounds = new Rectangle2D.Double(0,0,img.getWidth(),img.getHeight());
+                final boolean isImgBounds = (srcBounds.equals(new Rectangle2D.Double()));
+                final Rectangle2D srcBounds2 = isImgBounds ? imgBounds : srcBounds;
+
+                // TODO: apply emf transform
+                graphicsCtx.translate(dstBounds.getX(), dstBounds.getY());
+                graphicsCtx.scale(dstBounds.getWidth()/srcBounds2.getWidth(), dstBounds.getHeight()/srcBounds2.getHeight());
+                graphicsCtx.translate(-srcBounds2.getX(), -srcBounds2.getY());
+
+                graphicsCtx.drawImage(img, 0, 0, prop.getBackgroundColor().getColor(), null);
+
+                graphicsCtx.setTransform(at);
+                graphicsCtx.setClip(clip);
+                break;
+        }
+
+    }
+
+    /**
+     * @return the initial AffineTransform, when this graphics context was created
+     */
+    public AffineTransform getInitTransform() {
+        return new AffineTransform(initialAT);
+    }
+
+    /**
+     * @return the current AffineTransform
+     */
+    public AffineTransform getTransform() {
+        return new AffineTransform(graphicsCtx.getTransform());
+    }
+
+    /**
+     * Set the current AffineTransform
+     * @param tx the current AffineTransform
+     */
+    public void setTransform(AffineTransform tx) {
+        graphicsCtx.setTransform(tx);
+    }
+
+    private static int clipCnt = 0;
+
+    public void setClip(Shape clip, HwmfRegionMode regionMode, boolean useInitialAT) {
+        final AffineTransform at = graphicsCtx.getTransform();
+        if (useInitialAT) {
+            graphicsCtx.setTransform(initialAT);
+        }
+        final Shape oldClip = graphicsCtx.getClip();
+        final boolean isEmpty = clip.getBounds2D().isEmpty();
+        switch (regionMode) {
+            case RGN_AND:
+                if (!isEmpty) {
+                    graphicsCtx.clip(clip);
+                }
+                break;
+            case RGN_OR:
+                if (!isEmpty) {
+                    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 (!isEmpty) {
+                    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 (!isEmpty) {
+                    if (oldClip != null) {
+                        Area area = new Area(oldClip);
+                        area.subtract(new Area(clip));
+                        graphicsCtx.setClip(area);
+                    }
+                }
+                break;
+            case RGN_COPY: {
+                graphicsCtx.setClip(isEmpty ? null : clip);
+                break;
+            }
+        }
+        if (useInitialAT) {
+            graphicsCtx.setTransform(at);
+        }
     }
 }

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=1845291&r1=1845290&r2=1845291&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 Tue Oct 30 22:35:45 2018
@@ -413,7 +413,7 @@ public class HwmfBitmapDib {
         return new ByteArrayInputStream(getBMPData());
     }
 
-    private byte[] getBMPData() {
+    public byte[] getBMPData() {
         if (imageData == null) {
             throw new RecordFormatException("bitmap not initialized ... need to call init() before");
         }

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=1845291&r1=1845290&r2=1845291&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 Tue Oct 30 22:35:45 2018
@@ -20,6 +20,7 @@ package org.apache.poi.hwmf.record;
 import java.awt.Shape;
 import java.awt.geom.Arc2D;
 import java.awt.geom.Area;
+import java.awt.geom.Dimension2D;
 import java.awt.geom.Ellipse2D;
 import java.awt.geom.Line2D;
 import java.awt.geom.Path2D;
@@ -744,4 +745,11 @@ public class HwmfDraw {
     public static String boundsToString(Rectangle2D bounds) {
         return "{ x: "+bounds.getX()+", y: "+bounds.getY()+", w: "+bounds.getWidth()+", h: "+bounds.getHeight()+" }";
     }
+
+    @Internal
+    public static String dimToString(Dimension2D dim) {
+        return "{ w: "+dim.getWidth()+", h: "+dim.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=1845291&r1=1845290&r2=1845291&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 Tue Oct 30 22:35:45 2018
@@ -27,6 +27,7 @@ import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.io.IOException;
 
+import org.apache.poi.hwmf.draw.HwmfDrawProperties;
 import org.apache.poi.hwmf.draw.HwmfGraphics;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
@@ -222,7 +223,7 @@ public class HwmfFill {
          * An unsigned integer that defines polygon fill mode.
          * This MUST be one of the values: ALTERNATE = 0x0001, WINDING = 0x0002
          */
-        protected HwmfPolyfillMode polyfillMode;
+        protected HwmfPolyfillMode polyFillMode;
         
         @Override
         public HwmfRecordType getWmfRecordType() {
@@ -231,13 +232,18 @@ public class HwmfFill {
         
         @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            polyfillMode = HwmfPolyfillMode.valueOf(leis.readUShort() & 3);
+            polyFillMode = HwmfPolyfillMode.valueOf(leis.readUShort() & 3);
             return LittleEndianConsts.SHORT_SIZE;
         }
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            ctx.getProperties().setPolyfillMode(polyfillMode);
+            ctx.getProperties().setPolyfillMode(polyFillMode);
+        }
+
+        @Override
+        public String toString() {
+            return "{ polyFillMode: '"+ polyFillMode +"' }";
         }
     }
 
@@ -458,7 +464,7 @@ public class HwmfFill {
          * A variable-sized DeviceIndependentBitmap Object (section 2.2.2.9) that is the 
          * source of the color data.
          */
-        protected final HwmfBitmapDib dib = new HwmfBitmapDib();
+        protected final HwmfBitmapDib bitmap = new HwmfBitmapDib();
         
         @Override
         public HwmfRecordType getWmfRecordType() {
@@ -481,22 +487,36 @@ public class HwmfFill {
             size += readBounds2(leis, srcBounds);
             size += readBounds2(leis, dstBounds);
 
-            size += dib.init(leis, (int)(recordSize-6-size));
+            size += bitmap.init(leis, (int)(recordSize-6-size));
 
             return size;
         }        
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            if (dib.isValid()) {
-                ctx.getProperties().setRasterOp(rasterOperation);
+            HwmfDrawProperties prop = ctx.getProperties();
+            prop.setRasterOp(rasterOperation);
+            if (bitmap.isValid()) {
                 ctx.drawImage(getImage(), srcBounds, dstBounds);
+            } else {
+                BufferedImage bi = new BufferedImage((int)dstBounds.getWidth(), (int)dstBounds.getHeight(), BufferedImage.TYPE_INT_ARGB);
+                ctx.drawImage(bi, dstBounds, dstBounds);
             }
         }
 
         @Override
         public BufferedImage getImage() {
-            return dib.getImage();
+            return bitmap.getImage();
+        }
+
+        @Override
+        public String toString() {
+            return
+                "{ rasterOperation: '"+rasterOperation+"'"+
+                ", colorUsage: '"+colorUsage+"'"+
+                ", srcBounds: "+boundsToString(srcBounds)+
+                ", dstBounds: "+boundsToString(dstBounds)+
+                "}";
         }
     }
     

Added: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRegionMode.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRegionMode.java?rev=1845291&view=auto
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRegionMode.java (added)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRegionMode.java Tue Oct 30 22:35:45 2018
@@ -0,0 +1,59 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   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.
+==================================================================== */
+
+package org.apache.poi.hwmf.record;
+
+import org.apache.poi.hemf.record.emf.HemfFill;
+
+public enum HwmfRegionMode {
+    /**
+     * 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;
+    HwmfRegionMode(int flag) {
+        this.flag = flag;
+    }
+
+    public static HwmfRegionMode valueOf(int flag) {
+        for (HwmfRegionMode rm : values()) {
+            if (rm.flag == flag) return rm;
+        }
+        return null;
+    }
+}

Propchange: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRegionMode.java
------------------------------------------------------------------------------
    svn:eol-style = native

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=1845291&r1=1845290&r2=1845291&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 Tue Oct 30 22:35:45 2018
@@ -191,7 +191,7 @@ public class HwmfText {
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            ctx.drawString(getTextBytes(), reference, null);
+            ctx.drawString(getTextBytes(), reference);
         }
 
         public String getText(Charset charset) {
@@ -396,7 +396,7 @@ public class HwmfText {
 
         @Override
         public void draw(HwmfGraphics ctx) {
-            ctx.drawString(rawTextBytes, reference, bounds, dx, false);
+            ctx.drawString(rawTextBytes, reference, bounds, options, dx, false);
         }
 
         public String getText(Charset charset) throws IOException {

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=1845291&r1=1845290&r2=1845291&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 Tue Oct 30 22:35:45 2018
@@ -433,6 +433,7 @@ public class HwmfWindowing {
         
         @Override
         public void applyObject(HwmfGraphics ctx) {
+            ctx.setClip(bounds, HwmfRegionMode.RGN_AND, true);
         }
 
         @Override



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