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 2015/12/29 01:45:59 UTC

svn commit: r1722046 [2/3] - in /poi/trunk/src/scratchpad: src/org/apache/poi/hwmf/draw/ src/org/apache/poi/hwmf/record/ src/org/apache/poi/hwmf/usermodel/ testcases/org/apache/poi/hwmf/

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java?rev=1722046&r1=1722045&r2=1722046&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java Tue Dec 29 00:45:59 2015
@@ -17,13 +17,27 @@
 
 package org.apache.poi.hwmf.record;
 
+import java.awt.geom.Path2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
 import java.io.IOException;
 
+import javax.imageio.ImageIO;
+
+import org.apache.poi.hwmf.draw.HwmfGraphics;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
 public class HwmfFill {
     /**
+     * A record which contains an image (to be extracted)
+     */
+    public interface HwmfImageRecord {
+        BufferedImage getImage();
+    }
+    
+    
+    /**
      * The META_FILLREGION record fills a region using a specified brush.
      */
     public static class WmfFillRegion implements HwmfRecord {
@@ -32,23 +46,30 @@ public class HwmfFill {
          * A 16-bit unsigned integer used to index into the WMF Object Table to get
          * the region to be filled.
          */
-        int region;
+        private int region;
 
         /**
          * A 16-bit unsigned integer used to index into the WMF Object Table to get the
          * brush to use for filling the region.
          */
-        int brush;
+        private int brush;
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.fillRegion;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             region = leis.readUShort();
             brush = leis.readUShort();
             return 2*LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            
+        }
     }
 
     /**
@@ -71,6 +92,11 @@ public class HwmfFill {
             region = leis.readUShort();
             return LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            
+        }
     }
     
     
@@ -83,23 +109,25 @@ public class HwmfFill {
         /**
          * A 32-bit ColorRef Object that defines the color value.
          */
-        HwmfColorRef colorRef;
+        private HwmfColorRef colorRef;
         /**
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the
          * point where filling is to start.
          */
-        int yStart;
+        private int yStart;
         /**
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the
          * point where filling is to start.
          */
-        int xStart;
+        private int xStart;
         
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.floodFill;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             colorRef = new HwmfColorRef();
             int size = colorRef.init(leis);
@@ -107,6 +135,11 @@ public class HwmfFill {
             xStart = leis.readShort();
             return size+2*LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            
+        }
     }
 
     /**
@@ -114,21 +147,57 @@ public class HwmfFill {
      * graphics operations that fill polygons.
      */
     public static class WmfSetPolyfillMode implements HwmfRecord {
+        /**
+         * A 16-bit unsigned integer that defines polygon fill mode.
+         * This MUST be one of the values: ALTERNATE = 0x0001, WINDING = 0x0002
+         */
+        public enum HwmfPolyfillMode {
+            /**
+             * Selects alternate mode (fills the area between odd-numbered and
+             * even-numbered polygon sides on each scan line).
+             */
+            ALTERNATE(0x0001, Path2D.WIND_EVEN_ODD),
+            /**
+             * Selects winding mode (fills any region with a nonzero winding value).
+             */
+            WINDING(0x0002, Path2D.WIND_NON_ZERO);
+
+            public int wmfFlag;
+            public int awtFlag;
+            HwmfPolyfillMode(int wmfFlag, int awtFlag) {
+                this.wmfFlag = wmfFlag;
+                this.awtFlag = awtFlag;
+            }
+
+            static HwmfPolyfillMode valueOf(int wmfFlag) {
+                for (HwmfPolyfillMode pm : values()) {
+                    if (pm.wmfFlag == wmfFlag) return pm;
+                }
+                return null;
+            }
+        }
         
         /**
          * A 16-bit unsigned integer that defines polygon fill mode.
          * This MUST be one of the values: ALTERNATE = 0x0001, WINDING = 0x0002
          */
-        int polyFillMode;
+        private HwmfPolyfillMode polyfillMode;
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.setPolyFillMode;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            polyFillMode = leis.readUShort();
+            polyfillMode = HwmfPolyfillMode.valueOf(leis.readUShort());
             return LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            ctx.getProperties().setPolyfillMode(polyfillMode);
+        }
     }
 
 
@@ -151,29 +220,31 @@ public class HwmfFill {
          * Filling continues outward in all directions as long as the color is encountered.
          * This style is useful for filling areas with multicolored boundaries.
          */
-        int mode;
+        private int mode;
         
         /**
          * A 32-bit ColorRef Object that defines the color value.
          */
-        HwmfColorRef colorRef;
+        private HwmfColorRef colorRef;
         
         /**
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the point
          * to be set.
          */
-        int y;
+        private int y;
         
         /**
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the point
          * to be set.
          */
-        int x;  
+        private int x;  
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.extFloodFill;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             mode = leis.readUShort();
             colorRef = new HwmfColorRef();
@@ -182,6 +253,11 @@ public class HwmfFill {
             x = leis.readShort();
             return size+3*LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            
+        }
     }
 
     /**
@@ -193,16 +269,23 @@ public class HwmfFill {
          * A 16-bit unsigned integer used to index into the WMF Object Table to get
          * the region to be inverted.
          */
-        int region;
+        private int region;
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.invertRegion;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             region = leis.readUShort();
             return LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            
+        }
     }
     
 
@@ -217,39 +300,41 @@ public class HwmfFill {
          * A 32-bit unsigned integer that defines the raster operation code.
          * This code MUST be one of the values in the Ternary Raster Operation enumeration table.
          */
-        HwmfTernaryRasterOp rasterOperation;
+        private HwmfTernaryRasterOp rasterOperation;
         
         /**
          * A 16-bit signed integer that defines the height, in logical units, of the rectangle.
          */
-        int height;
+        private int height;
         
         /**
          * A 16-bit signed integer that defines the width, in logical units, of the rectangle.
          */
-        int width;
+        private int width;
         
         /**
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the
          * upper-left corner of the rectangle to be filled.
          */
-        int yLeft;
+        private int yLeft;
         
         /**
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the
          * upper-left corner of the rectangle to be filled.
          */
-        int xLeft;
+        private int xLeft;
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.patBlt;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            int rasterOpIndex = leis.readUShort();
             int rasterOpCode = leis.readUShort();
+            int rasterOpIndex = leis.readUShort();
 
-            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
             assert(rasterOpCode == rasterOperation.opCode);
             
             height = leis.readShort();
@@ -259,6 +344,11 @@ public class HwmfFill {
 
             return 6*LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            
+        }
     }
 
     /**
@@ -269,44 +359,44 @@ public class HwmfFill {
          * in the playback device context, and the destination pixels are to be combined to form the new 
          * image. This code MUST be one of the values in the Ternary Raster Operation Enumeration
          */
-        HwmfTernaryRasterOp rasterOperation;
+        private HwmfTernaryRasterOp rasterOperation;
         
         /**
          * A 16-bit signed integer that defines the height, in logical units, of the source rectangle.
          */
-        int srcHeight; 
+        private int srcHeight; 
         /**
          * A 16-bit signed integer that defines the width, in logical units, of the source rectangle.
          */
-        int srcWidth; 
+        private int srcWidth; 
         /**
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left corner 
          * of the source rectangle.
          */
-        int ySrc;
+        private int ySrc;
         /**
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left corner 
          * of the source rectangle.
          */
-        int xSrc;
+        private int xSrc;
         /**
          * A 16-bit signed integer that defines the height, in logical units, of the destination rectangle.
          */
-        int destHeight;
+        private int destHeight;
         /**
          * A 16-bit signed integer that defines the width, in logical units, of the destination rectangle.
          */
-        int destWidth;
+        private int destWidth;
         /**
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left 
          * corner of the destination rectangle.
          */
-        int yDest;
+        private int yDest;
         /**
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left 
          * corner of the destination rectangle.
          */
-        int xDest;
+        private int xDest;
         
         /**
          * A variable-sized Bitmap16 Object that defines source image content.
@@ -314,19 +404,21 @@ public class HwmfFill {
          */
         HwmfBitmap16 target;
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.stretchBlt;
         }
         
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
 
             int size = 0;
-            int rasterOpIndex = leis.readUShort();
             int rasterOpCode = leis.readUShort();
+            int rasterOpIndex = leis.readUShort();
             
-            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
             assert(rasterOpCode == rasterOperation.opCode);
 
             srcHeight = leis.readShort();
@@ -351,6 +443,11 @@ public class HwmfFill {
             
             return size;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            
+        }
     }
 
     /**
@@ -360,13 +457,13 @@ public class HwmfFill {
      * The source of the color data is a DIB, and the destination of the transfer is
      * the current output region in the playback device context.
      */
-    public static class WmfStretchDib implements HwmfRecord {
+    public static class WmfStretchDib implements HwmfRecord, HwmfImageRecord {
         /**
          * A 32-bit unsigned integer that defines how the source pixels, the current brush in
          * the playback device context, and the destination pixels are to be combined to
          * form the new image.
          */
-        HwmfTernaryRasterOp rasterOperation;
+        private HwmfTernaryRasterOp rasterOperation;
 
         /**
          * A 16-bit unsigned integer that defines whether the Colors field of the
@@ -376,63 +473,65 @@ public class HwmfFill {
          * DIB_PAL_COLORS = 0x0001,
          * DIB_PAL_INDICES = 0x0002
          */
-        int colorUsage;
+        private int colorUsage;
         /**
          * A 16-bit signed integer that defines the height, in logical units, of the
          * source rectangle.
          */
-        int srcHeight;
+        private int srcHeight;
         /**
          * A 16-bit signed integer that defines the width, in logical units, of the
          * source rectangle.
          */
-        int srcWidth; 
+        private int srcWidth; 
         /**
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the
          * source rectangle.
          */
-        int ySrc;
+        private int ySrc;
         /**
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the 
          * source rectangle.
          */
-        int xSrc;
+        private int xSrc;
         /**
          * A 16-bit signed integer that defines the height, in logical units, of the 
          * destination rectangle.
          */
-        int destHeight;
+        private int destHeight;
         /**
          * A 16-bit signed integer that defines the width, in logical units, of the 
          * destination rectangle.
          */
-        int destWidth;
+        private int destWidth;
         /**
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the 
          * upper-left corner of the destination rectangle.
          */
-        int yDst;
+        private int yDst;
         /**
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the 
          * upper-left corner of the destination rectangle.
          */
-        int xDst;
+        private int xDst;
         /**
          * A variable-sized DeviceIndependentBitmap Object (section 2.2.2.9) that is the 
          * source of the color data.
          */
-        HwmfBitmapDib dib;
+        private HwmfBitmapDib dib;
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.stretchDib;
         }
         
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            int rasterOpIndex = leis.readUShort();
             int rasterOpCode = leis.readUShort();
+            int rasterOpIndex = leis.readUShort();
             
-            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
             assert(rasterOpCode == rasterOperation.opCode);
 
             colorUsage = leis.readUShort();
@@ -447,9 +546,20 @@ public class HwmfFill {
             
             int size = 11*LittleEndianConsts.SHORT_SIZE;
             dib = new HwmfBitmapDib();
-            size += dib.init(leis);
+            size += dib.init(leis, (int)(recordSize-6-size));
+
             return size;
         }        
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            
+        }
+
+        @Override
+        public BufferedImage getImage() {
+            return dib.getImage();
+        }
     }
     
     public static class WmfBitBlt implements HwmfRecord {
@@ -458,57 +568,59 @@ public class HwmfFill {
          * A 32-bit unsigned integer that defines how the source pixels, the current brush in the playback 
          * device context, and the destination pixels are to be combined to form the new image.
          */
-        HwmfTernaryRasterOp rasterOperation;
+        private HwmfTernaryRasterOp rasterOperation;
         
         /**
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left corner 
         of the source rectangle.
          */
-        int ySrc; 
+        private int ySrc; 
         /**
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left corner 
         of the source rectangle.
          */
-        int xSrc; 
+        private int xSrc; 
         /**
          * A 16-bit signed integer that defines the height, in logical units, of the source and 
         destination rectangles.
          */
-        int height;
+        private int height;
         /**
          * A 16-bit signed integer that defines the width, in logical units, of the source and destination 
         rectangles.
          */
-        int width;
+        private int width;
         /**
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left 
         corner of the destination rectangle.
          */
-        int yDest;
+        private int yDest;
         /**
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left 
         corner of the destination rectangle.
          */
-        int xDest;
+        private int xDest;
         
         /**
          * A variable-sized Bitmap16 Object that defines source image content.
          * This object MUST be specified, even if the raster operation does not require a source.
          */
-        HwmfBitmap16 target;
+        private HwmfBitmap16 target;
 
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.bitBlt;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
 
             int size = 0;
-            int rasterOpIndex = leis.readUShort();
             int rasterOpCode = leis.readUShort();
+            int rasterOpIndex = leis.readUShort();
             
-            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
             assert(rasterOpCode == rasterOperation.opCode);
 
             ySrc = leis.readShort();
@@ -535,6 +647,11 @@ public class HwmfFill {
             
             return size;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            
+        }
     }
 
 
@@ -543,7 +660,7 @@ public class HwmfFill {
      * using deviceindependent color data.
      * The source of the color data is a DIB
      */
-    public static class WmfSetDibToDev implements HwmfRecord {
+    public static class WmfSetDibToDev implements HwmfRecord, HwmfImageRecord {
 
         /**
          * A 16-bit unsigned integer that defines whether the Colors field of the
@@ -553,55 +670,57 @@ public class HwmfFill {
          * DIB_PAL_COLORS = 0x0001,
          * DIB_PAL_INDICES = 0x0002
          */
-        int colorUsage;  
+        private int colorUsage;  
         /**
          * A 16-bit unsigned integer that defines the number of scan lines in the source.
          */
-        int scanCount;
+        private int scanCount;
         /**
          * A 16-bit unsigned integer that defines the starting scan line in the source.
          */
-        int startScan;  
+        private int startScan;  
         /**
          * A 16-bit unsigned integer that defines the y-coordinate, in logical units, of the
          * source rectangle.
          */
-        int yDib;  
+        private int yDib;  
         /**
          * A 16-bit unsigned integer that defines the x-coordinate, in logical units, of the
          * source rectangle.
          */
-        int xDib;  
+        private int xDib;  
         /**
          * A 16-bit unsigned integer that defines the height, in logical units, of the
          * source and destination rectangles.
          */
-        int height;
+        private int height;
         /**
          * A 16-bit unsigned integer that defines the width, in logical units, of the
          * source and destination rectangles.
          */
-        int width;
+        private int width;
         /**
          * A 16-bit unsigned integer that defines the y-coordinate, in logical units, of the
          * upper-left corner of the destination rectangle.
          */
-        int yDest;
+        private int yDest;
         /**
          * A 16-bit unsigned integer that defines the x-coordinate, in logical units, of the
          * upper-left corner of the destination rectangle.
          */
-        int xDest;
+        private int xDest;
         /**
          * A variable-sized DeviceIndependentBitmap Object that is the source of the color data.
          */
-        HwmfBitmapDib dib;        
+        private HwmfBitmapDib dib;        
         
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.setDibToDev;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             colorUsage = leis.readUShort();
             scanCount = leis.readUShort();
@@ -615,14 +734,24 @@ public class HwmfFill {
             
             int size = 9*LittleEndianConsts.SHORT_SIZE;
             dib = new HwmfBitmapDib();
-            size += dib.init(leis);
+            size += dib.init(leis, (int)(recordSize-6-size));
             
             return size;
         }        
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            
+        }
+
+        @Override
+        public BufferedImage getImage() {
+            return dib.getImage();
+        }
     }
 
 
-    public static class WmfDibBitBlt implements HwmfRecord {
+    public static class WmfDibBitBlt implements HwmfRecord, HwmfImageRecord {
 
         /**
          * A 32-bit unsigned integer that defines how the source pixels, the current brush
@@ -633,51 +762,53 @@ public class HwmfFill {
         /**
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the source rectangle.
          */
-        int ySrc;
+        private int ySrc;
         /**
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the source rectangle.
          */
-        int xSrc;
+        private int xSrc;
         /**
          * A 16-bit signed integer that defines the height, in logical units, of the source and 
          * destination rectangles.
          */
-        int height;
+        private int height;
         /**
          * A 16-bit signed integer that defines the width, in logical units, of the source and destination
          * rectangles.
          */
-        int width;
+        private int width;
         /**
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the upper-left
          * corner of the destination rectangle.
          */
-        int yDest;
+        private int yDest;
         /**
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the upper-left 
          * corner of the destination rectangle.
          */
-        int xDest;
+        private int xDest;
         
         /**
          * A variable-sized DeviceIndependentBitmap Object that defines image content.
          * This object MUST be specified, even if the raster operation does not require a source.
          */
-        HwmfBitmapDib target;
+        private HwmfBitmapDib target;
         
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.dibBitBlt;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
 
             int size = 0;
-            int rasterOpIndex = leis.readUShort();
             int rasterOpCode = leis.readUShort();
+            int rasterOpIndex = leis.readUShort();
             
-            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
             assert(rasterOpCode == rasterOperation.opCode);
 
             ySrc = leis.readShort();
@@ -696,76 +827,88 @@ public class HwmfFill {
             size += 4*LittleEndianConsts.SHORT_SIZE;
             if (hasBitmap) {
                 target = new HwmfBitmapDib();
-                size += target.init(leis);
+                size += target.init(leis, (int)(recordSize-6-size));
             }
             
             return size;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            
+        }
+
+        @Override
+        public BufferedImage getImage() {
+            return target.getImage();
+        }
     }
 
-    public static class WmfDibStretchBlt implements HwmfRecord {
+    public static class WmfDibStretchBlt implements HwmfRecord, HwmfImageRecord {
         /**
          * A 32-bit unsigned integer that defines how the source pixels, the current brush
          * in the playback device context, and the destination pixels are to be combined to form the
          * new image. This code MUST be one of the values in the Ternary Raster Operation Enumeration.
          */
-        HwmfTernaryRasterOp rasterOperation;
+        private HwmfTernaryRasterOp rasterOperation;
         /**
          * A 16-bit signed integer that defines the height, in logical units, of the source rectangle.
          */
-        int srcHeight;
+        private int srcHeight;
         /**
          * A 16-bit signed integer that defines the width, in logical units, of the source rectangle.
          */
-        int srcWidth;
+        private int srcWidth;
         /**
          * A 16-bit signed integer that defines the y-coordinate, in logical units, of the
          * upper-left corner of the source rectangle.
          */
-        int ySrc;
+        private int ySrc;
         /**
          * A 16-bit signed integer that defines the x-coordinate, in logical units, of the
          * upper-left corner of the source rectangle.
          */
-        int xSrc;
+        private int xSrc;
         /**
          * A 16-bit signed integer that defines the height, in logical units, of the
          * destination rectangle.
          */
-        int destHeight;
+        private int destHeight;
         /**
          * A 16-bit signed integer that defines the width, in logical units, of the
          * destination rectangle.
          */
-        int destWidth;
+        private int destWidth;
         /**
          * A 16-bit signed integer that defines the y-coordinate, in logical units,
          * of the upper-left corner of the destination rectangle.
          */
-        int yDest;
+        private int yDest;
         /**
          * A 16-bit signed integer that defines the x-coordinate, in logical units,
          * of the upper-left corner of the destination rectangle.
          */
-        int xDest;
+        private int xDest;
         /**
          * A variable-sized DeviceIndependentBitmap Object that defines image content.
          * This object MUST be specified, even if the raster operation does not require a source.
          */
         HwmfBitmapDib target;
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.dibStretchBlt;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
 
             int size = 0;
-            int rasterOpIndex = leis.readUShort();
             int rasterOpCode = leis.readUShort();
+            int rasterOpIndex = leis.readUShort();
             
-            rasterOperation = HwmfTernaryRasterOp.fromOpIndex(rasterOpIndex);
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
             assert(rasterOpCode == rasterOperation.opCode);
 
             srcHeight = leis.readShort();
@@ -785,10 +928,20 @@ public class HwmfFill {
             size += 4*LittleEndianConsts.SHORT_SIZE;
             if (hasBitmap) {
                 target = new HwmfBitmapDib();
-                size += target.init(leis);
+                size += target.init(leis, (int)(recordSize-6-size));
             }
             
             return size;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            
+        }
+
+        @Override
+        public BufferedImage getImage() {
+            return target.getImage();
+        }
     }
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java?rev=1722046&r1=1722045&r2=1722046&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java Tue Dec 29 00:45:59 2015
@@ -20,6 +20,7 @@ package org.apache.poi.hwmf.record;
 import java.io.IOException;
 import java.nio.charset.Charset;
 
+import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
 /**
@@ -440,7 +441,7 @@ public class HwmfFont {
      *
      * @see WmfClipPrecision
      */
-    int clipPrecision;
+    WmfClipPrecision clipPrecision;
 
     /**
      * An 8-bit unsigned integer that defines the output quality.
@@ -477,22 +478,23 @@ public class HwmfFont {
         strikeOut = leis.readByte() != 0;
         charSet = WmfCharset.valueOf(leis.readUByte());
         outPrecision = WmfOutPrecision.valueOf(leis.readUByte());
+        clipPrecision = WmfClipPrecision.valueOf(leis.readUByte());
         quality = WmfFontQuality.valueOf(leis.readUByte());
         int pitchAndFamily = leis.readUByte();
         family = WmfFontFamilyClass.valueOf(pitchAndFamily & 0xF);
         pitch = WmfFontPitch.valueOf((pitchAndFamily >>> 6) & 3);
         
-        byte buf[] = new byte[32], readBytes;
-        for (readBytes = 0; readBytes < 32; readBytes++) {
-            if ((buf[readBytes] = leis.readByte()) == 0) {
-                break;
+        byte buf[] = new byte[32], b, readBytes = 0;
+        do {
+            if (readBytes == 32) {
+                throw new IOException("Font facename can't be determined.");
             }
-        }
-        if (readBytes == 1 || readBytes == 32) {
-            throw new IOException("Font facename can't be determined.");
-        }
+
+            buf[readBytes++] = b = leis.readByte();
+        } while (b != 0 && b != -1 && readBytes <= 32);
+        
         facename = new String(buf, 0, readBytes-1, Charset.forName("ISO-8859-1"));
         
-        return 17+readBytes;
+        return 5*LittleEndianConsts.SHORT_SIZE+8*LittleEndianConsts.BYTE_SIZE+readBytes;
     }
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHatchStyle.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHatchStyle.java?rev=1722046&r1=1722045&r2=1722046&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHatchStyle.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfHatchStyle.java Tue Dec 29 00:45:59 2015
@@ -21,17 +21,17 @@ package org.apache.poi.hwmf.record;
  * The HatchStyle Enumeration specifies the hatch pattern.
  */
 public enum HwmfHatchStyle {
-    /** A horizontal hatch */
+    /** ----- - A horizontal hatch */
     HS_HORIZONTAL(0x0000),
-    /** A vertical hatch */
+    /** ||||| - A vertical hatch */
     HS_VERTICAL(0x0001),
-    /** A 45-degree downward, left-to-right hatch. */
+    /** \\\\\ - A 45-degree downward, left-to-right hatch. */
     HS_FDIAGONAL(0x0002),
-    /** A 45-degree upward, left-to-right hatch. */
+    /** ///// - A 45-degree upward, left-to-right hatch. */
     HS_BDIAGONAL(0x0003),
-    /** A horizontal and vertical cross-hatch. */
+    /** +++++ - A horizontal and vertical cross-hatch. */
     HS_CROSS(0x0004),
-    /** A 45-degree crosshatch. */
+    /** xxxxx - A 45-degree crosshatch. */
     HS_DIAGCROSS(0x0005);
 
     int flag;

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMapMode.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMapMode.java?rev=1722046&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMapMode.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMapMode.java Tue Dec 29 00:45:59 2015
@@ -0,0 +1,114 @@
+/* ====================================================================
+   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;
+
+/**
+ * A 16-bit unsigned integer that defines the mapping mode.
+ *
+ * The MapMode defines how logical units are mapped to physical units;
+ * that is, assuming that the origins in both the logical and physical coordinate systems
+ * are at the same point on the drawing surface, what is the physical coordinate (x',y')
+ * that corresponds to logical coordinate (x,y).
+ *
+ * For example, suppose the mapping mode is MM_TEXT. Given the following definition of that
+ * mapping mode, and an origin (0,0) at the top left corner of the drawing surface, logical
+ * coordinate (4,5) would map to physical coordinate (4,5) in pixels.
+ *
+ * Now suppose the mapping mode is MM_LOENGLISH, with the same origin as the previous
+ * example. Given the following definition of that mapping mode, logical coordinate (4,-5)
+ * would map to physical coordinate (0.04,0.05) in inches.
+ */
+public enum HwmfMapMode {
+    /**
+     *  Each logical unit is mapped to one device pixel.
+     *  Positive x is to the right; positive y is down.
+     */
+    MM_TEXT(0x0001, 0),
+    
+    /**
+     *  Each logical unit is mapped to 0.1 millimeter.
+     *  Positive x is to the right; positive y is up.
+     */
+    MM_LOMETRIC(0x0002, 254),
+    
+    /**
+     *  Each logical unit is mapped to 0.01 millimeter.
+     *  Positive x is to the right; positive y is up.
+     */
+    MM_HIMETRIC(0x0003, 2540),
+    
+    /**
+     *  Each logical unit is mapped to 0.01 inch.
+     *  Positive x is to the right; positive y is up.
+     */
+    MM_LOENGLISH(0x0004, 100),
+    
+    /**
+     *  Each logical unit is mapped to 0.001 inch.
+     *  Positive x is to the right; positive y is up.
+     */
+    MM_HIENGLISH(0x0005, 1000),
+    
+    /**
+     *  Each logical unit is mapped to one twentieth (1/20) of a point.
+     *  In printing, a point is 1/72 of an inch; therefore, 1/20 of a point is 1/1440 of an inch.
+     *  This unit is also known as a "twip".
+     *  Positive x is to the right; positive y is up.
+     */
+    MM_TWIPS(0x0006, 1440),
+    
+    /**
+     *  Logical units are mapped to arbitrary device units with equally scaled axes;
+     *  that is, one unit along the x-axis is equal to one unit along the y-axis.
+     *  The META_SETWINDOWEXT and META_SETVIEWPORTEXT records specify the units and the
+     *  orientation of the axes.
+     *  The processing application SHOULD make adjustments as necessary to ensure the x and y
+     *  units remain the same size. For example, when the window extent is set, the viewport
+     *  SHOULD be adjusted to keep the units isotropic.
+     */
+    MM_ISOTROPIC(0x0007, -1),
+    
+    /**
+     *  Logical units are mapped to arbitrary units with arbitrarily scaled axes.
+     */
+    MM_ANISOTROPIC(0x0008, -1);
+    
+    /**
+     * native flag
+     */
+    public final int flag;
+    
+    /**
+     * transformation units - usually scale relative to current dpi.
+     * when scale == 0, then don't scale
+     * when scale == -1, then scale relative to window dimension. 
+     */
+    public final int scale;
+    
+    HwmfMapMode(int flag, int scale) {
+        this.flag = flag;
+        this.scale = scale;
+    }
+
+    static HwmfMapMode valueOf(int flag) {
+        for (HwmfMapMode mm : values()) {
+            if (mm.flag == flag) return mm;
+        }
+        return null;
+    }        
+}
\ No newline at end of file

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java?rev=1722046&r1=1722045&r2=1722046&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java Tue Dec 29 00:45:59 2015
@@ -17,8 +17,12 @@
 
 package org.apache.poi.hwmf.record;
 
+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.hwmf.record.HwmfFill.HwmfImageRecord;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
@@ -28,22 +32,38 @@ public class HwmfMisc {
      * The META_SAVEDC record saves the playback device context for later retrieval.
      */
     public static class WmfSaveDc implements HwmfRecord {
-        public HwmfRecordType getRecordType() { return HwmfRecordType.saveDc; }
+        @Override
+        public HwmfRecordType getRecordType() {
+            return HwmfRecordType.saveDc;
+        }
 
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             return 0;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 
     /**
      * The META_SETRELABS record is reserved and not supported.
      */
     public static class WmfSetRelabs implements HwmfRecord {
-        public HwmfRecordType getRecordType() { return HwmfRecordType.setRelabs; }
+        public HwmfRecordType getRecordType() {
+            return HwmfRecordType.setRelabs;
+        }
 
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             return 0;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 
     /**
@@ -57,16 +77,23 @@ public class HwmfMisc {
          * member is positive, nSavedDC represents a specific instance of the state to be restored. If
          * this member is negative, nSavedDC represents an instance relative to the current state.
          */
-        int nSavedDC;
+        private int nSavedDC;
 
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.restoreDc;
         }
 
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             nSavedDC = leis.readShort();
             return LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 
     /**
@@ -75,16 +102,23 @@ public class HwmfMisc {
      */
     public static class WmfSetBkColor implements HwmfRecord {
 
-        HwmfColorRef colorRef;
+        private HwmfColorRef colorRef;
 
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.setBkColor;
         }
 
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             colorRef = new HwmfColorRef();
             return colorRef.init(leis);
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            ctx.getProperties().setBackgroundColor(colorRef);
+        }
     }
 
     /**
@@ -96,18 +130,38 @@ public class HwmfMisc {
 
         /**
          * A 16-bit unsigned integer that defines background mix mode.
-         * This MUST be either TRANSPARENT = 0x0001 or OPAQUE = 0x0002
          */
-        int bkMode;
+        public enum HwmfBkMode {
+            TRANSPARENT(0x0001), OPAQUE(0x0002);
+
+            int flag;
+            HwmfBkMode(int flag) {
+                this.flag = flag;
+            }
+
+            static HwmfBkMode valueOf(int flag) {
+                for (HwmfBkMode bs : values()) {
+                    if (bs.flag == flag) return bs;
+                }
+                return null;
+            }
+        }
+
+        private HwmfBkMode bkMode;
 
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.setBkMode;
         }
 
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            bkMode = leis.readUShort();
+            bkMode = HwmfBkMode.valueOf(leis.readUShort());
             return LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            ctx.getProperties().setBkMode(bkMode);
+        }
     }
 
     /**
@@ -122,19 +176,26 @@ public class HwmfMisc {
          * LAYOUT_RTL = 0x0001
          * LAYOUT_BITMAPORIENTATIONPRESERVED = 0x0008
          */
-        int layout;
+        private int layout;
 
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.setLayout;
         }
 
         @SuppressWarnings("unused")
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             layout = leis.readUShort();
             // A 16-bit field that MUST be ignored.
             int reserved = leis.readShort();
             return 2*LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 
     /**
@@ -144,72 +205,23 @@ public class HwmfMisc {
      */
     public static class WmfSetMapMode implements HwmfRecord {
 
-        /**
-         * A 16-bit unsigned integer that defines the mapping mode.
-         *
-         * The MapMode defines how logical units are mapped to physical units;
-         * that is, assuming that the origins in both the logical and physical coordinate systems
-         * are at the same point on the drawing surface, what is the physical coordinate (x',y')
-         * that corresponds to logical coordinate (x,y).
-         *
-         * For example, suppose the mapping mode is MM_TEXT. Given the following definition of that
-         * mapping mode, and an origin (0,0) at the top left corner of the drawing surface, logical
-         * coordinate (4,5) would map to physical coordinate (4,5) in pixels.
-         *
-         * Now suppose the mapping mode is MM_LOENGLISH, with the same origin as the previous
-         * example. Given the following definition of that mapping mode, logical coordinate (4,-5)
-         * would map to physical coordinate (0.04,0.05) in inches.
-         *
-         * This MUST be one of the following:
-         *
-         * MM_TEXT (= 0x0001):
-         *  Each logical unit is mapped to one device pixel.
-         *  Positive x is to the right; positive y is down.
-         *
-         * MM_LOMETRIC (= 0x0002):
-         *  Each logical unit is mapped to 0.1 millimeter.
-         *  Positive x is to the right; positive y is up.
-         *
-         * MM_HIMETRIC (= 0x0003):
-         *  Each logical unit is mapped to 0.01 millimeter.
-         *  Positive x is to the right; positive y is up.
-         *
-         * MM_LOENGLISH (= 0x0004):
-         *  Each logical unit is mapped to 0.01 inch.
-         *  Positive x is to the right; positive y is up.
-         *
-         * MM_HIENGLISH (= 0x0005):
-         *  Each logical unit is mapped to 0.001 inch.
-         *  Positive x is to the right; positive y is up.
-         *
-         * MM_TWIPS (= 0x0006):
-         *  Each logical unit is mapped to one twentieth (1/20) of a point.
-         *  In printing, a point is 1/72 of an inch; therefore, 1/20 of a point is 1/1440 of an inch.
-         *  This unit is also known as a "twip".
-         *  Positive x is to the right; positive y is up.
-         *
-         * MM_ISOTROPIC (= 0x0007):
-         *  Logical units are mapped to arbitrary device units with equally scaled axes;
-         *  that is, one unit along the x-axis is equal to one unit along the y-axis.
-         *  The META_SETWINDOWEXT and META_SETVIEWPORTEXT records specify the units and the
-         *  orientation of the axes.
-         *  The processing application SHOULD make adjustments as necessary to ensure the x and y
-         *  units remain the same size. For example, when the window extent is set, the viewport
-         *  SHOULD be adjusted to keep the units isotropic.
-         *
-         * MM_ANISOTROPIC (= 0x0008):
-         *  Logical units are mapped to arbitrary units with arbitrarily scaled axes.
-         */
-        int mapMode;
+        private HwmfMapMode mapMode;
 
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.setMapMode;
         }
 
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            mapMode = leis.readUShort();
+            mapMode = HwmfMapMode.valueOf(leis.readUShort());
             return LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            ctx.getProperties().setMapMode(mapMode);
+        }
     }
 
     /**
@@ -223,16 +235,23 @@ public class HwmfMisc {
          * match a font's aspect ratio to the current device's aspect ratio. If bit 0 is
          * set, the mapper selects only matching fonts.
          */
-        long mapperValues;
+        private long mapperValues;
 
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.setMapperFlags;
         }
 
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             mapperValues = leis.readUInt();
             return LittleEndianConsts.INT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 
     /**
@@ -262,16 +281,23 @@ public class HwmfMisc {
          * R2_MERGEPEN = 0x000F,
          * R2_WHITE = 0x0010
          */
-        int drawMode;
+        private int drawMode;
 
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.setRop2;
         }
 
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             drawMode = leis.readUShort();
             return LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 
     /**
@@ -288,25 +314,32 @@ public class HwmfMisc {
          * COLORONCOLOR = 0x0003,
          * HALFTONE = 0x0004
          */
-        int setStretchBltMode;
+        private int setStretchBltMode;
 
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.setStretchBltMode;
         }
 
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             setStretchBltMode = leis.readUShort();
             return LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 
     /**
      * The META_DIBCREATEPATTERNBRUSH record creates a Brush Object with a
      * pattern specified by a DeviceIndependentBitmap (DIB) Object
      */
-    public static class WmfDibCreatePatternBrush implements HwmfRecord {
+    public static class WmfDibCreatePatternBrush implements HwmfRecord, HwmfImageRecord {
 
-        HwmfBrushStyle style;
+        private HwmfBrushStyle style;
 
         /**
          * A 16-bit unsigned integer that defines whether the Colors field of a DIB
@@ -320,15 +353,17 @@ public class HwmfMisc {
          * DIB_PAL_COLORS = 0x0001,
          * DIB_PAL_INDICES = 0x0002
          */
-        int colorUsage;
+        private int colorUsage;
 
-        HwmfBitmapDib patternDib;
-        HwmfBitmap16 pattern16;
+        private HwmfBitmapDib patternDib;
+        private HwmfBitmap16 pattern16;
 
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.dibCreatePatternBrush;
         }
 
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             style = HwmfBrushStyle.valueOf(leis.readUShort());
             colorUsage = leis.readUShort();
@@ -339,12 +374,9 @@ public class HwmfMisc {
             case BS_DIBPATTERN:
             case BS_DIBPATTERNPT:
             case BS_HATCHED:
-                patternDib = new HwmfBitmapDib();
-                size += patternDib.init(leis);
-                break;
             case BS_PATTERN:
-                pattern16 = new HwmfBitmap16();
-                size += pattern16.init(leis);
+                patternDib = new HwmfBitmapDib();
+                size += patternDib.init(leis, (int)(recordSize-6-size));
                 break;
             case BS_INDEXED:
             case BS_DIBPATTERN8X8:
@@ -354,6 +386,24 @@ public class HwmfMisc {
             }
             return size;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            HwmfDrawProperties prop = ctx.getProperties();
+            prop.setBrushStyle(style);
+            prop.setBrushBitmap(getImage());
+        }
+
+        @Override
+        public BufferedImage getImage() {
+            if (patternDib != null) {
+                return patternDib.getImage();
+            } else if (pattern16 != null) {
+                return pattern16.getImage();
+            } else {
+                return null;
+            }
+        }
     }
 
     /**
@@ -364,84 +414,94 @@ public class HwmfMisc {
     public static class WmfDeleteObject implements HwmfRecord {
         /**
          * A 16-bit unsigned integer used to index into the WMF Object Table to
-        get the object to be deleted.
+         * get the object to be deleted.
          */
-        int objectIndex;
+        private int objectIndex;
 
-        public HwmfRecordType getRecordType() { return HwmfRecordType.deleteObject; }
+        @Override
+        public HwmfRecordType getRecordType() {
+            return HwmfRecordType.deleteObject;
+        }
 
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             objectIndex = leis.readUShort();
             return LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 
     public static class WmfCreatePatternBrush implements HwmfRecord {
 
-        HwmfBitmap16 pattern;
+        private HwmfBitmap16 pattern;
 
-        public HwmfRecordType getRecordType() { return HwmfRecordType.createPatternBrush; }
+        @Override
+        public HwmfRecordType getRecordType() {
+            return HwmfRecordType.createPatternBrush;
+        }
 
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             pattern = new HwmfBitmap16(true);
             return pattern.init(leis);
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 
     public static class WmfCreatePenIndirect implements HwmfRecord {
 
-        /**
-         * A 16-bit unsigned integer that specifies the pen style.
-         * The value MUST be defined from the PenStyle Enumeration table.
-         *
-         * PS_COSMETIC = 0x0000,
-         * PS_ENDCAP_ROUND = 0x0000,
-         * PS_JOIN_ROUND = 0x0000,
-         * PS_SOLID = 0x0000,
-         * PS_DASH = 0x0001,
-         * PS_DOT = 0x0002,
-         * PS_DASHDOT = 0x0003,
-         * PS_DASHDOTDOT = 0x0004,
-         * PS_NULL = 0x0005,
-         * PS_INSIDEFRAME = 0x0006,
-         * PS_USERSTYLE = 0x0007,
-         * PS_ALTERNATE = 0x0008,
-         * PS_ENDCAP_SQUARE = 0x0100,
-         * PS_ENDCAP_FLAT = 0x0200,
-         * PS_JOIN_BEVEL = 0x1000,
-         * PS_JOIN_MITER = 0x2000
-         */
-        int penStyle;
+        private HwmfPenStyle penStyle;
         /**
          * A 32-bit PointS Object that specifies a point for the object dimensions.
          * The xcoordinate is the pen width. The y-coordinate is ignored.
          */
-        int xWidth, yWidth;
+        private int xWidth;
+        @SuppressWarnings("unused")
+        private int yWidth;
         /**
          * A 32-bit ColorRef Object that specifies the pen color value.
          */
-        HwmfColorRef colorRef;
+        private HwmfColorRef colorRef;
 
-        public HwmfRecordType getRecordType() { return HwmfRecordType.createPenIndirect; }
+        @Override
+        public HwmfRecordType getRecordType() {
+            return HwmfRecordType.createPenIndirect;
+        }
 
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
-            penStyle = leis.readUShort();
+            penStyle = HwmfPenStyle.valueOf(leis.readUShort());
             xWidth = leis.readShort();
             yWidth = leis.readShort();
             colorRef = new HwmfColorRef();
-            int size = 3*LittleEndianConsts.SHORT_SIZE;
-            size += colorRef.init(leis);
-            return size;
+            int size = colorRef.init(leis);
+            return size+3*LittleEndianConsts.SHORT_SIZE;
+        }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            HwmfDrawProperties p = ctx.getProperties();
+            p.setPenStyle(penStyle);
+            p.setPenColor(colorRef);
+            p.setPenWidth(xWidth);
         }
     }
 
     /**
      * The META_CREATEBRUSHINDIRECT record creates a Brush Object
      * from a LogBrush Object.
-     * 
+     *
      * The following table shows the relationship between values in the BrushStyle,
      * ColorRef and BrushHatch fields in a LogBrush Object. Only supported brush styles are listed.
-     * 
+     *
      * <table>
      * <tr>
      *   <th>BrushStyle</th>
@@ -481,26 +541,37 @@ public class HwmfMisc {
      * </table>
      */
     public static class WmfCreateBrushIndirect implements HwmfRecord {
-        HwmfBrushStyle brushStyle;
+        private HwmfBrushStyle brushStyle;
 
-        HwmfColorRef colorRef;
+        private HwmfColorRef colorRef;
 
         /**
          * A 16-bit field that specifies the brush hatch type.
          * Its interpretation depends on the value of BrushStyle.
-         * 
+         *
          */
-        HwmfHatchStyle brushHatch;
+        private HwmfHatchStyle brushHatch;
 
-        public HwmfRecordType getRecordType() { return HwmfRecordType.createBrushIndirect; }
+        @Override
+        public HwmfRecordType getRecordType() {
+            return HwmfRecordType.createBrushIndirect;
+        }
 
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             brushStyle = HwmfBrushStyle.valueOf(leis.readUShort());
             colorRef = new HwmfColorRef();
             int size = colorRef.init(leis);
             brushHatch = HwmfHatchStyle.valueOf(leis.readUShort());
-            size += 4;
-            return size;
+            return size+2*LittleEndianConsts.SHORT_SIZE;
+        }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            HwmfDrawProperties p = ctx.getProperties();
+            p.setBrushStyle(brushStyle);
+            p.setBrushColor(colorRef);
+            p.setBrushHatch(brushHatch);
         }
     }
 }
\ No newline at end of file

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java?rev=1722046&r1=1722045&r2=1722046&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java Tue Dec 29 00:45:59 2015
@@ -19,6 +19,7 @@ package org.apache.poi.hwmf.record;
 
 import java.io.IOException;
 
+import org.apache.poi.hwmf.draw.HwmfGraphics;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
@@ -30,7 +31,7 @@ public class HwmfPalette {
         // Blue (1 byte): An 8-bit unsigned integer that defines the blue intensity value for the palette entry.
         // Green (1 byte): An 8-bit unsigned integer that defines the green intensity value for the palette entry.
         // Red (1 byte): An 8-bit unsigned integer that defines the red intensity value for the palette entry.
-        int values, blue, green, red;
+        private int values, blue, green, red;
         
         public int init(LittleEndianInputStream leis) throws IOException {
             values = leis.readUByte();
@@ -48,16 +49,17 @@ public class HwmfPalette {
          * used with the META_SETPALENTRIES and META_ANIMATEPALETTE record types.
          * When used with META_CREATEPALETTE, it MUST be 0x0300
          */
-        int start;
+        private int start;
         
         /**
          * NumberOfEntries (2 bytes):  A 16-bit unsigned integer that defines the number of objects in
          * aPaletteEntries.  
          */
-        int numberOfEntries;
+        private int numberOfEntries;
         
         PaletteEntry entries[];
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             start = leis.readUShort();
             numberOfEntries = leis.readUShort();
@@ -69,15 +71,26 @@ public class HwmfPalette {
             }
             return size;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
     
     /**
      * The META_CREATEPALETTE record creates a Palette Object
      */
     public static class WmfCreatePalette extends WmfPaletteParent {
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.createPalette;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 
     /**
@@ -85,9 +98,15 @@ public class HwmfPalette {
      * palette that is defined in the playback device context.
      */
     public static class WmfSetPaletteEntries extends WmfPaletteParent {
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.setPalEntries;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
     
     /**
@@ -101,14 +120,21 @@ public class HwmfPalette {
          */
         int numberOfEntries;
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.resizePalette;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             numberOfEntries = leis.readUShort();
             return LittleEndianConsts.SHORT_SIZE;
         }        
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 
     /**
@@ -119,16 +145,23 @@ public class HwmfPalette {
          * A 16-bit unsigned integer used to index into the WMF Object Table to get
          * the Palette Object to be selected.
          */
-        int palette;
+        private int palette;
 
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.selectPalette;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             palette = leis.readUShort();
             return LittleEndianConsts.SHORT_SIZE;
         }        
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 
     /**
@@ -136,11 +169,20 @@ public class HwmfPalette {
      * is defined in the playback device context to the system palette.
      */
     public static class WmfRealizePalette implements HwmfRecord {
-        public HwmfRecordType getRecordType() { return HwmfRecordType.realizePalette; }
+        @Override
+        public HwmfRecordType getRecordType() {
+            return HwmfRecordType.realizePalette;
+        }
 
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             return 0;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 
     /**
@@ -156,8 +198,14 @@ public class HwmfPalette {
      * this record SHOULD have no effect.
      */
     public static class WmfAnimatePalette extends WmfPaletteParent {
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.animatePalette;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 }

Added: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java?rev=1722046&view=auto
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java (added)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPenStyle.java Tue Dec 29 00:45:59 2015
@@ -0,0 +1,171 @@
+/* ====================================================================
+   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 java.awt.BasicStroke;
+
+import org.apache.poi.util.BitField;
+import org.apache.poi.util.BitFieldFactory;
+
+/**
+ * The 16-bit PenStyle Enumeration is used to specify different types of pens
+ * that can be used in graphics operations.
+ * 
+ * Various styles can be combined by using a logical OR statement, one from
+ * each subsection of Style, EndCap, Join, and Type (Cosmetic).
+ * 
+ * The defaults in case the other values of the subsection aren't set are
+ * solid, round end caps, round joins and cosmetic type.
+ */
+public class HwmfPenStyle {
+    public enum HwmfLineCap {
+        /** Rounded ends */
+        ROUND(0, BasicStroke.CAP_ROUND),
+        /** Square protrudes by half line width */
+        SQUARE(1, BasicStroke.CAP_SQUARE),
+        /** Line ends at end point*/
+        FLAT(2, BasicStroke.CAP_BUTT);        
+
+        public int wmfFlag;
+        public int awtFlag;
+        HwmfLineCap(int wmfFlag, int awtFlag) {
+            this.wmfFlag = wmfFlag;
+            this.awtFlag = awtFlag;
+        }
+
+        static HwmfLineCap valueOf(int wmfFlag) {
+            for (HwmfLineCap hs : values()) {
+                if (hs.wmfFlag == wmfFlag) return hs;
+            }
+            return null;
+        }    
+    }
+    
+    public enum HwmfLineJoin {
+        /**Line joins are round. */
+        ROUND(0, BasicStroke.JOIN_ROUND),
+        /** Line joins are beveled. */
+        BEVEL(1, BasicStroke.JOIN_BEVEL),
+        /**
+         * Line joins are mitered when they are within the current limit set by the
+         * SETMITERLIMIT META_ESCAPE record. A join is beveled when it would exceed the limit
+         */
+        MITER(2, BasicStroke.JOIN_MITER);
+
+        public int wmfFlag;
+        public int awtFlag;
+        HwmfLineJoin(int wmfFlag, int awtFlag) {
+            this.wmfFlag = wmfFlag;
+            this.awtFlag = awtFlag;
+        }
+
+        static HwmfLineJoin valueOf(int wmfFlag) {
+            for (HwmfLineJoin hs : values()) {
+                if (hs.wmfFlag == wmfFlag) return hs;
+            }
+            return null;
+        }    
+    }
+    
+    public enum HwmfLineDash {
+        /**
+         * The pen is solid.
+         */
+        SOLID(0x0000, 10),
+        /**
+         * The pen is dashed. (-----) 
+         */
+        DASH(0x0001, 10, 8),
+        /**
+         * The pen is dotted. (.....)
+         */
+        DOT(0x0002, 2, 4),
+        /**
+         * The pen has alternating dashes and dots. (_._._._)
+         */
+        DASHDOT(0x0003, 10, 8, 2, 8),
+        /**
+         * The pen has dashes and double dots. (_.._.._)
+         */
+        DASHDOTDOT(0x0004, 10, 4, 2, 4, 2, 4),
+        /**
+         * The pen is invisible.
+         */
+        NULL(0x0005),
+        /**
+         * The pen is solid. When this pen is used in any drawing record that takes a
+         * bounding rectangle, the dimensions of the figure are shrunk so that it fits
+         * entirely in the bounding rectangle, taking into account the width of the pen.
+         */
+        INSIDEFRAME(0x0006, 10),
+        /**
+         * The pen uses a styling array supplied by the user.
+         * (this is currently not supported and drawn as solid ... no idea where the user
+         * styling is supposed to come from ...)
+         */
+        USERSTYLE(0x0007, 10);
+        
+
+        public int wmfFlag;
+        public float[] dashes;
+        HwmfLineDash(int wmfFlag, float... dashes) {
+            this.wmfFlag = wmfFlag;
+            this.dashes = dashes;
+        }
+
+        static HwmfLineDash valueOf(int wmfFlag) {
+            for (HwmfLineDash hs : values()) {
+                if (hs.wmfFlag == wmfFlag) return hs;
+            }
+            return null;
+        }    
+    }
+    
+    private static final BitField SUBSECTION_DASH      = BitFieldFactory.getInstance(0x0007);
+    private static final BitField SUBSECTION_ALTERNATE = BitFieldFactory.getInstance(0x0008);
+    private static final BitField SUBSECTION_ENDCAP    = BitFieldFactory.getInstance(0x0300);
+    private static final BitField SUBSECTION_JOIN      = BitFieldFactory.getInstance(0x3000);
+    
+    private int flag;
+    
+    public static HwmfPenStyle valueOf(int flag) {
+        HwmfPenStyle ps = new HwmfPenStyle();
+        ps.flag = flag;
+        return ps;
+    }
+    
+    public HwmfLineCap getLineCap() {
+        return HwmfLineCap.valueOf(SUBSECTION_ENDCAP.getValue(flag));
+    }
+
+    public HwmfLineJoin getLineJoin() {
+        return HwmfLineJoin.valueOf(SUBSECTION_JOIN.getValue(flag));
+    }
+    
+    public HwmfLineDash getLineDash() {
+        return HwmfLineDash.valueOf(SUBSECTION_DASH.getValue(flag));
+    }
+    
+
+    /**
+     * The pen sets every other pixel (this style is applicable only for cosmetic pens).
+     */
+    public boolean isAlternateDash() {
+        return SUBSECTION_ALTERNATE.isSet(flag);
+    }
+}

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecord.java?rev=1722046&r1=1722045&r2=1722046&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecord.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfRecord.java Tue Dec 29 00:45:59 2015
@@ -19,6 +19,7 @@ package org.apache.poi.hwmf.record;
 
 import java.io.IOException;
 
+import org.apache.poi.hwmf.draw.HwmfGraphics;
 import org.apache.poi.util.LittleEndianInputStream;
 
 public interface HwmfRecord {
@@ -32,4 +33,11 @@ public interface HwmfRecord {
      * @throws IOException
      */
     int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException;
+    
+    /**
+     * Apply the record settings to the graphics context
+     *
+     * @param ctx the graphics context to modify
+     */
+    void draw(HwmfGraphics ctx);
 }

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfTernaryRasterOp.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfTernaryRasterOp.java?rev=1722046&r1=1722045&r2=1722046&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfTernaryRasterOp.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfTernaryRasterOp.java Tue Dec 29 00:45:59 2015
@@ -285,7 +285,7 @@ public enum HwmfTernaryRasterOp {
         this.opCmd=opCmd;
     }
     
-    public static HwmfTernaryRasterOp fromOpIndex(int opIndex) {
+    public static HwmfTernaryRasterOp valueOf(int opIndex) {
         for (HwmfTernaryRasterOp bb : HwmfTernaryRasterOp.values()) {
             if (bb.opIndex == opIndex) {
                 return bb;

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java?rev=1722046&r1=1722045&r2=1722046&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java Tue Dec 29 00:45:59 2015
@@ -19,9 +19,12 @@ package org.apache.poi.hwmf.record;
 
 import java.io.IOException;
 
+import org.apache.poi.hwmf.draw.HwmfGraphics;
 import org.apache.poi.hwmf.record.HwmfMisc.WmfSetMapMode;
 import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
+import org.apache.poi.util.LocaleUtil;
+import org.apache.poi.util.RecordFormatException;
 
 public class HwmfText {
 
@@ -38,16 +41,23 @@ public class HwmfText {
          * this value is transformed and rounded to the nearest pixel. For details about setting the
          * mapping mode, see META_SETMAPMODE
          */
-        int charExtra;
+        private int charExtra;
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.setTextCharExtra;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             charExtra = leis.readUShort();
             return LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
     
     /**
@@ -55,16 +65,23 @@ public class HwmfText {
      */
     public static class WmfSetTextColor implements HwmfRecord {
         
-        HwmfColorRef colorRef;
+        private HwmfColorRef colorRef;
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.setTextColor;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             colorRef = new HwmfColorRef();
             return colorRef.init(leis);
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
     
     /**
@@ -76,7 +93,7 @@ public class HwmfText {
         /**
          * A 16-bit unsigned integer that specifies the number of space characters in the line.
          */
-        int breakCount;
+        private int breakCount;
         
         /**
          * A 16-bit unsigned integer that specifies the total extra space, in logical
@@ -84,17 +101,24 @@ public class HwmfText {
          * identified by the BreakExtra member is transformed and rounded to the nearest pixel. For
          * details about setting the mapping mode, see {@link WmfSetMapMode}.
          */
-        int breakExtra;
+        private int breakExtra;
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.setBkColor;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             breakCount = leis.readUShort();
             breakExtra = leis.readUShort();
             return 2*LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
     
     /**
@@ -105,7 +129,7 @@ public class HwmfText {
         /**
          * A 16-bit signed integer that defines the length of the string, in bytes, pointed to by String.
          */
-        int stringLength;
+        private int stringLength;
         /**
          * The size of this field MUST be a multiple of two. If StringLength is an odd
          * number, then this field MUST be of a size greater than or equal to StringLength + 1.
@@ -114,31 +138,38 @@ public class HwmfText {
          * length of the string.
          * The string is written at the location specified by the XStart and YStart fields.
          */
-        String text;
+        private String text;
         /**
          * A 16-bit signed integer that defines the vertical (y-axis) coordinate, in logical
          * units, of the point where drawing is to start.
          */
-        int yStart;
+        private int yStart;
         /**
          * A 16-bit signed integer that defines the horizontal (x-axis) coordinate, in
          * logical units, of the point where drawing is to start.
          */
-        int xStart;  
+        private int xStart;  
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.textOut;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             stringLength = leis.readShort();
-            byte buf[] = new byte[stringLength+(stringLength%2)];
+            byte buf[] = new byte[stringLength+(stringLength&1)];
             leis.readFully(buf);
-            text = new String(buf, "UTF16-LE").trim();
+            text = new String(buf, 0, stringLength, LocaleUtil.CHARSET_1252).trim();
             yStart = leis.readShort();
             xStart = leis.readShort();
             return 3*LittleEndianConsts.SHORT_SIZE+buf.length;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
     
     /**
@@ -152,16 +183,16 @@ public class HwmfText {
          * A 16-bit signed integer that defines the y-coordinate, in logical units, where the 
         text string is to be located.
          */
-        int y;  
+        private int y;  
         /**
          * A 16-bit signed integer that defines the x-coordinate, in logical units, where the 
         text string is to be located.
          */
-        int x;  
+        private int x;  
         /**
          * A 16-bit signed integer that defines the length of the string.
          */
-        int stringLength;
+        private int stringLength;
         /**
          * A 16-bit unsigned integer that defines the use of the application-defined 
          * rectangle. This member can be a combination of one or more values in the 
@@ -196,7 +227,7 @@ public class HwmfText {
          * Indicates that both horizontal and vertical character displacement values 
          * SHOULD be provided.
          */
-        int fwOpts;
+        private int fwOpts;
         /**
          * An optional 8-byte Rect Object (section 2.2.2.18) that defines the 
          * dimensions, in logical coordinates, of a rectangle that is used for clipping, opaquing, or both.
@@ -205,43 +236,58 @@ public class HwmfText {
          * Each value is a 16-bit signed integer that defines the coordinate, in logical coordinates, of 
          * the upper-left corner of the rectangle
          */
-        int left,top,right,bottom;
+        private int left,top,right,bottom;
         /**
          * A variable-length string that specifies the text to be drawn. The string does 
          * not need to be null-terminated, because StringLength specifies the length of the string. If 
          * the length is odd, an extra byte is placed after it so that the following member (optional Dx) is 
          * aligned on a 16-bit boundary.
          */
-        String text;
+        private String text;
         /**
          * An optional array of 16-bit signed integers that indicate the distance between 
          * origins of adjacent character cells. For example, Dx[i] logical units separate the origins of 
          * character cell i and character cell i + 1. If this field is present, there MUST be the same 
          * number of values as there are characters in the string.
          */
-        int dx[];
+        private int dx[];
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.extTextOut;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             y = leis.readShort();
             x = leis.readShort();
             stringLength = leis.readShort();
             fwOpts = leis.readUShort();
-            left = leis.readShort();
-            top = leis.readShort();
-            right = leis.readShort();
-            bottom = leis.readShort();
             
-            byte buf[] = new byte[stringLength+(stringLength%2)];
+            int size = 4*LittleEndianConsts.SHORT_SIZE;
+            
+            if (fwOpts != 0) {
+                // the bounding rectangle is optional and only read when fwOpts are given
+                left = leis.readShort();
+                top = leis.readShort();
+                right = leis.readShort();
+                bottom = leis.readShort();
+                size += 4*LittleEndianConsts.SHORT_SIZE;
+            }
+            
+            byte buf[] = new byte[stringLength+(stringLength&1)];
             leis.readFully(buf);
-            text = new String(buf, "UTF16-LE");
+            text = new String(buf, 0, stringLength, LocaleUtil.CHARSET_1252);
+            size += buf.length;
             
-            int size = 8*LittleEndianConsts.SHORT_SIZE+buf.length;
-            if (size < recordSize) {
-                dx = new int[text.length()];
+            // -6 bytes of record function and length header
+            int remainingRecordSize = (int)(recordSize-6);
+            if (size < remainingRecordSize) {
+                if (size + stringLength*LittleEndianConsts.SHORT_SIZE < remainingRecordSize) {
+                    throw new RecordFormatException("can't read Dx array - given recordSize doesn't contain enough values for string length "+stringLength);
+                }
+                
+                dx = new int[stringLength];
                 for (int i=0; i<dx.length; i++) {
                     dx[i] = leis.readShort();
                 }
@@ -250,6 +296,11 @@ public class HwmfText {
             
             return size;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
     
 
@@ -320,28 +371,42 @@ public class HwmfText {
          * VTA_BASELINE (0x0018):
          * The reference point MUST be on the baseline of the text.
          */
-        int textAlignmentMode;
+        private int textAlignmentMode;
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.setTextAlign;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             textAlignmentMode = leis.readUShort();
             return LittleEndianConsts.SHORT_SIZE;
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
     
     public static class WmfCreateFontIndirect implements HwmfRecord {
-        HwmfFont font;
+        private HwmfFont font;
         
+        @Override
         public HwmfRecordType getRecordType() {
             return HwmfRecordType.createFontIndirect;
         }
         
+        @Override
         public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
             font = new HwmfFont();
             return font.init(leis);
         }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+
+        }
     }
 }



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