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/09/14 21:37:38 UTC

svn commit: r1840956 [2/5] - in /poi/branches/hemf/src: java/org/apache/poi/util/ ooxml/java/org/apache/poi/xdgf/geom/ ooxml/java/org/apache/poi/xdgf/usermodel/ ooxml/java/org/apache/poi/xdgf/util/ scratchpad/src/org/apache/poi/hemf/draw/ scratchpad/sr...

Added: 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=1840956&view=auto
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFill.java (added)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFill.java Fri Sep 14 21:37:37 2018
@@ -0,0 +1,620 @@
+/* ====================================================================
+   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.hemf.record.emf;
+
+import static org.apache.poi.hemf.record.emf.HemfDraw.readRectL;
+import static org.apache.poi.hemf.record.emf.HemfDraw.readPointL;
+import static org.apache.poi.hemf.record.emf.HemfRecordIterator.HEADER_SIZE;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hwmf.draw.HwmfGraphics;
+import org.apache.poi.hwmf.record.HwmfBitmapDib;
+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.HwmfTernaryRasterOp;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianConsts;
+import org.apache.poi.util.LittleEndianInputStream;
+
+public class HemfFill {
+    private static final int MAX_RECORD_LENGTH = 10_000_000;
+
+    public enum HemfRegionMode {
+        RGN_AND(0x01),
+        RGN_OR(0x02),
+        RGN_XOR(0x03),
+        RGN_DIFF(0x04),
+        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.
+     */
+    public static class EmfSetPolyfillMode extends HwmfFill.WmfSetPolyfillMode implements HemfRecord {
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.setPolyfillMode;
+        }
+
+        @Override
+        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());
+            return LittleEndianConsts.INT_SIZE;
+        }
+    }
+
+    public static class EmfExtFloodFill extends HwmfFill.WmfExtFloodFill implements HemfRecord {
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.extFloodFill;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            long size = readPointL(leis, start);
+            size = colorRef.init(leis);
+            // A 32-bit unsigned integer that specifies how to use the Color value to determine the area for
+            // the flood fill operation. The value MUST be in the FloodFill enumeration
+            mode = (int)leis.readUInt();
+            return size + LittleEndianConsts.INT_SIZE;
+        }
+    }
+
+    /**
+     * The EMR_STRETCHBLT record specifies a block transfer of pixels from a source bitmap to a destination rectangle,
+     * optionally in combination with a brush pattern, according to a specified raster operation, stretching or
+     * compressing the output to fit the dimensions of the destination, if necessary.
+     */
+    public static class EmfStretchBlt extends HwmfFill.WmfBitBlt implements HemfRecord {
+        protected final Rectangle2D bounds = new Rectangle2D.Double();
+
+        /** An XForm object that specifies a world-space to page-space transform to apply to the source bitmap. */
+        protected final byte[] xformSrc = new byte[24];
+
+        /** 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;
+
+        /** The source bitmap header. */
+        protected byte[] bmiSrc;
+
+        /** The source bitmap bits. */
+        protected byte[] bitsSrc;
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.stretchBlt;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            long size = readRectL(leis, bounds);
+
+            size += readBounds2(leis, this.dstBounds);
+
+            // A 32-bit unsigned integer that specifies the raster operation code. This code defines 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.
+            int rasterOpIndex = (int)leis.readUInt();
+
+            rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
+
+            size += LittleEndianConsts.INT_SIZE;
+
+            final Point2D srcPnt = new Point2D.Double();
+            size += readPointL(leis, srcPnt);
+
+            leis.readFully(xformSrc);
+            size += 24;
+
+            size += bkColorSrc.init(leis);
+
+            usageSrc = (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.
+            final int offBmiSrc = (int)leis.readUInt();
+
+            // A 32-bit unsigned integer that specifies the size, in bytes, of the source bitmap header.
+            final int cbBmiSrc = (int)leis.readUInt();
+
+            // A 32-bit unsigned integer that specifies the offset, in bytes, from the
+            // start of this record to the source bitmap bits in the BitmapBuffer field.
+            final int offBitsSrc = (int)leis.readUInt();
+
+            // A 32-bit unsigned integer that specifies the size, in bytes, of the source bitmap bits.
+            final int cbBitsSrc = (int)leis.readUInt();
+
+            size += 5*LittleEndianConsts.INT_SIZE;
+
+            if (srcEqualsDstDimension()) {
+                srcBounds.setRect(srcPnt.getX(), srcPnt.getY(), dstBounds.getWidth(), dstBounds.getHeight());
+            } else {
+                int srcWidth = leis.readInt();
+                int srcHeight = leis.readInt();
+                size += 2 * LittleEndianConsts.INT_SIZE;
+                srcBounds.setRect(srcPnt.getX(), srcPnt.getY(), srcWidth, srcHeight);
+            }
+
+            // size + type and size field
+            final int undefinedSpace1 = (int)(offBmiSrc - size - HEADER_SIZE);
+            assert(undefinedSpace1 >= 0);
+            leis.skipFully(undefinedSpace1);
+            size += undefinedSpace1;
+
+            bmiSrc = IOUtils.safelyAllocate(cbBmiSrc, MAX_RECORD_LENGTH);
+            leis.readFully(bmiSrc);
+            size += cbBmiSrc;
+
+            final int undefinedSpace2 = (int)(offBitsSrc - size - HEADER_SIZE);
+            assert(undefinedSpace2 >= 0);
+            leis.skipFully(undefinedSpace2);
+            size += undefinedSpace2;
+
+            bitsSrc = IOUtils.safelyAllocate(cbBitsSrc, MAX_RECORD_LENGTH);
+            leis.readFully(bitsSrc);
+            size += cbBitsSrc;
+
+            return size;
+        }
+
+        protected boolean srcEqualsDstDimension() {
+            return false;
+        }
+    }
+
+    /**
+     * The EMR_BITBLT record specifies a block transfer of pixels from a source bitmap to a destination rectangle,
+     * optionally in combination with a brush pattern, according to a specified raster operation.
+     */
+    public static class EmfBitBlt extends EmfStretchBlt {
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.bitBlt;
+        }
+
+        @Override
+        protected boolean srcEqualsDstDimension() {
+            return false;
+        }
+    }
+
+
+    /** The EMR_FRAMERGN record draws a border around the specified region using the specified brush. */
+    public static class EmfFrameRgn extends HwmfDraw.WmfFrameRegion implements HemfRecord {
+        private final Rectangle2D bounds = new Rectangle2D.Double();
+        private final List<Rectangle2D> rgnRects = new ArrayList<>();
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.frameRgn;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            long size = readRectL(leis, bounds);
+            // 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 brush EMF Object Table index.
+            brushIndex = (int)leis.readUInt();
+            // A 32-bit signed integer that specifies the width of the vertical brush stroke, in logical units.
+            width = leis.readInt();
+            // A 32-bit signed integer that specifies the height of the horizontal brush stroke, in logical units.
+            height = leis.readInt();
+            size += 4*LittleEndianConsts.INT_SIZE;
+            size += readRgnData(leis, rgnRects);
+            return size;
+        }
+
+        @Override
+        public void draw(HwmfGraphics ctx) {
+            ctx.applyObjectTableEntry(brushIndex);
+
+            Area frame = new Area();
+            for (Rectangle2D rct : rgnRects) {
+                frame.add(new Area(rct));
+            }
+            Rectangle2D frameBounds = frame.getBounds2D();
+            AffineTransform at = new AffineTransform();
+            at.translate(bounds.getX()-frameBounds.getX(), bounds.getY()-frameBounds.getY());
+            at.scale(bounds.getWidth()/frameBounds.getWidth(), bounds.getHeight()/frameBounds.getHeight());
+            frame.transform(at);
+
+            ctx.fill(frame);
+        }
+    }
+
+    /** The EMR_INVERTRGN record inverts the colors in the specified region. */
+    public static class EmfInvertRgn implements HemfRecord {
+        protected final Rectangle2D bounds = new Rectangle2D.Double();
+        protected final List<Rectangle2D> rgnRects = new ArrayList<>();
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.invertRgn;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            long size = readRectL(leis, bounds);
+            // A 32-bit unsigned integer that specifies the size of region data, in bytes.
+            long rgnDataSize = leis.readUInt();
+            size += LittleEndianConsts.INT_SIZE;
+            size += readRgnData(leis, rgnRects);
+            return size;
+        }
+    }
+
+    /**
+     * The EMR_PAINTRGN record paints the specified region by using the brush currently selected into the
+     * playback device context.
+     */
+    public static class EmfPaintRgn extends EmfInvertRgn {
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.paintRgn;
+        }
+    }
+
+    /** The EMR_FILLRGN record fills the specified region by using the specified brush. */
+    public static class EmfFillRgn extends HwmfFill.WmfFillRegion implements HemfRecord {
+        protected final Rectangle2D bounds = new Rectangle2D.Double();
+        protected final List<Rectangle2D> rgnRects = new ArrayList<>();
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.fillRgn;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            long size = readRectL(leis, bounds);
+            // A 32-bit unsigned integer that specifies the size of region data, in bytes.
+            long rgnDataSize = leis.readUInt();
+            brushIndex = (int)leis.readUInt();
+            size += 2*LittleEndianConsts.INT_SIZE;
+            size += readRgnData(leis, rgnRects);
+            return size;
+        }
+    }
+
+    public static class EmfExtSelectClipRgn implements HemfRecord {
+        protected HemfRegionMode regionMode;
+        protected final List<Rectangle2D> rgnRects = new ArrayList<>();
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.extSelectClipRgn;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            // 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());
+            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) {
+                size += readRgnData(leis, rgnRects);
+            }
+            return size;
+        }
+    }
+
+    public static class EmfAlphaBlend implements HemfRecord {
+        /** the destination bounding rectangle in device units */
+        protected final Rectangle2D bounds = new Rectangle2D.Double();
+        /** the destination rectangle */
+        protected final Rectangle2D destRect = new Rectangle2D.Double();
+        /** the source rectangle */
+        protected final Rectangle2D srcRect = new Rectangle2D.Double();
+        /**
+         * The blend operation code. The only source and destination blend operation that has been defined
+         * is 0x00, which specifies that the source bitmap MUST be combined with the destination bitmap based
+         * on the alpha transparency values of the source pixels.
+         */
+        protected byte blendOperation;
+        /** This value MUST be 0x00 and MUST be ignored. */
+        protected byte blendFlags;
+        /**
+         * An 8-bit unsigned integer that specifies alpha transparency, which determines the blend of the source
+         * and destination bitmaps. This value MUST be used on the entire source bitmap. The minimum alpha
+         * transparency value, zero, corresponds to completely transparent; the maximum value, 0xFF, corresponds
+         * to completely opaque. In effect, a value of 0xFF specifies that the per-pixel alpha values determine
+         * the blend of the source and destination bitmaps.
+         */
+        protected int srcConstantAlpha;
+        /**
+         * A byte that specifies how source and destination pixels are interpreted with respect to alpha transparency.
+         *
+         * 0x00:
+         * The pixels in the source bitmap do not specify alpha transparency.
+         * In this case, the SrcConstantAlpha value determines the blend of the source and destination bitmaps.
+         * Note that in the following equations SrcConstantAlpha is divided by 255,
+         * which produces a value in the range 0 to 1.
+         *
+         * 0x01: "AC_SRC_ALPHA"
+         * Indicates that the source bitmap is 32 bits-per-pixel and specifies an alpha transparency value
+         * for each pixel.
+         */
+        protected byte alphaFormat;
+        /** a world-space to page-space transform to apply to the source bitmap. */
+        protected final AffineTransform xFormSrc = new AffineTransform();
+        /** 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.
+         */
+        protected ColorUsage usageSrc;
+
+        protected final HwmfBitmapDib bitmap = new HwmfBitmapDib();
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.alphaBlend;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            final int startIdx = leis.getReadIndex();
+
+            long size = readRectL(leis, bounds);
+            size += readBounds2(leis, destRect);
+
+            blendOperation = leis.readByte();
+            assert (blendOperation == 0);
+            blendFlags = leis.readByte();
+            assert (blendOperation == 0);
+            srcConstantAlpha = leis.readUByte();
+            alphaFormat = leis.readByte();
+
+            // A 32-bit signed integer that specifies the logical x-coordinate of the upper-left
+            // corner of the source rectangle.
+            final int xSrc = leis.readInt();
+            // A 32-bit signed integer that specifies the logical y-coordinate of the upper-left
+            // corner of the source rectangle.
+            final int ySrc = leis.readInt();
+
+            size += 3*LittleEndianConsts.INT_SIZE;
+            size += readXForm(leis, xFormSrc);
+            size += bkColorSrc.init(leis);
+
+            usageSrc = 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.
+            final int offBmiSrc = (int)leis.readUInt();
+
+            // A 32-bit unsigned integer that specifies the size, in bytes, of the source bitmap header.
+            final int cbBmiSrc = (int)leis.readUInt();
+            // A 32-bit unsigned integer that specifies the offset, in bytes, from the
+            // start of this record to the source bitmap bits in the BitmapBuffer field.
+            final int offBitsSrc = (int)leis.readUInt();
+            // A 32-bit unsigned integer that specifies the size, in bytes, of the source bitmap bits.
+            final int cbBitsSrc = (int)leis.readUInt();
+
+            // A 32-bit signed integer that specifies the logical width of the source rectangle.
+            // This value MUST be greater than zero.
+            final int cxSrc = leis.readInt();
+            // A 32-bit signed integer that specifies the logical height of the source rectangle.
+            // This value MUST be greater than zero.
+            final int cySrc = leis.readInt();
+
+            srcRect.setRect(xSrc, ySrc, cxSrc, cySrc);
+
+            size += 7 * LittleEndianConsts.INT_SIZE;
+
+            size += readBitmap(leis, bitmap, startIdx, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc);
+
+            return size;
+        }
+    }
+
+    public static class EmfSetDiBitsToDevice implements HemfRecord {
+        protected final Rectangle2D bounds = new Rectangle2D.Double();
+        protected final Point2D dest = new Point2D.Double();
+        protected final Rectangle2D src = new Rectangle2D.Double();
+        protected ColorUsage usageSrc;
+        protected final HwmfBitmapDib bitmap = new HwmfBitmapDib();
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.setDiBitsToDevice;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            int startIdx = leis.getReadIndex();
+
+            // A WMF RectL object that defines the destination bounding rectangle in device units.
+            long size = readRectL(leis, bounds);
+            // the logical x/y-coordinate of the upper-left corner of the destination rectangle.
+            size += readPointL(leis, dest);
+            // the source rectangle
+            size += readBounds2(leis, src);
+            // 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.
+            final int offBmiSrc = (int)leis.readUInt();
+            // A 32-bit unsigned integer that specifies the size, in bytes, of the source bitmap header.
+            final int cbBmiSrc = (int)leis.readUInt();
+            // A 32-bit unsigned integer that specifies the offset, in bytes, from the
+            // start of this record to the source bitmap bits in the BitmapBuffer field.
+            final int offBitsSrc = (int)leis.readUInt();
+            // A 32-bit unsigned integer that specifies the size, in bytes, of the source bitmap bits.
+            final int cbBitsSrc = (int)leis.readUInt();
+            // 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
+            usageSrc = ColorUsage.valueOf((int)leis.readUInt());
+            // A 32-bit unsigned integer that specifies the first scan line in the array.
+            final int iStartScan = (int)leis.readUInt();
+            // A 32-bit unsigned integer that specifies the number of scan lines.
+            final int cScans = (int)leis.readUInt();
+            size += 7*LittleEndianConsts.INT_SIZE;
+
+            size += readBitmap(leis, bitmap, startIdx, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc);
+
+            return size;
+        }
+    }
+
+    static long readBitmap(final LittleEndianInputStream leis, final HwmfBitmapDib bitmap,
+            final int startIdx, final int offBmiSrc, final int cbBmiSrc, final int offBitsSrc, int cbBitsSrc)
+    throws IOException {
+        final int offCurr = leis.getReadIndex()-(startIdx-HEADER_SIZE);
+        final int undefinedSpace1 = offBmiSrc-offCurr;
+        assert(undefinedSpace1 >= 0);
+
+        final int undefinedSpace2 = offBitsSrc-offCurr-cbBmiSrc-undefinedSpace1;
+        assert(undefinedSpace2 >= 0);
+
+        leis.skipFully(undefinedSpace1);
+
+        if (cbBmiSrc == 0 || cbBitsSrc == 0) {
+            return undefinedSpace1;
+        }
+
+        final LittleEndianInputStream leisDib;
+        if (undefinedSpace2 == 0) {
+            leisDib = leis;
+        } else {
+            final ByteArrayOutputStream bos = new ByteArrayOutputStream(cbBmiSrc+cbBitsSrc);
+            final long cbBmiSrcAct = IOUtils.copy(leis, bos, cbBmiSrc);
+            assert (cbBmiSrcAct == cbBmiSrc);
+            leis.skipFully(undefinedSpace2);
+            final long cbBitsSrcAct = IOUtils.copy(leis, bos, cbBitsSrc);
+            assert (cbBitsSrcAct == cbBitsSrc);
+            leisDib = new LittleEndianInputStream(new ByteArrayInputStream(bos.toByteArray()));
+        }
+        final int dibSize = cbBmiSrc+cbBitsSrc;
+        final int dibSizeAct = bitmap.init(leisDib, dibSize);
+        assert (dibSizeAct <= dibSize);
+        return undefinedSpace1 + cbBmiSrc + undefinedSpace2 + cbBitsSrc;
+    }
+
+
+    static long readRgnData(final LittleEndianInputStream leis, final List<Rectangle2D> rgnRects) {
+        // *** RegionDataHeader ***
+        // A 32-bit unsigned integer that specifies the size of this object in bytes. This MUST be 0x00000020.
+        long rgnHdrSiez = leis.readUInt();
+        assert(rgnHdrSiez == 0x20);
+        // A 32-bit unsigned integer that specifies the region type. This SHOULD be RDH_RECTANGLES (0x00000001)
+        long rgnHdrType = leis.readUInt();
+        assert(rgnHdrType == 1);
+        // A 32-bit unsigned integer that specifies the number of rectangles in this region.
+        long rgnCntRect = leis.readUInt();
+        // A 32-bit unsigned integer that specifies the size of the buffer of rectangles in bytes.
+        long rgnCntBytes = leis.readUInt();
+        long size = 4*LittleEndianConsts.INT_SIZE;
+        // A 128-bit WMF RectL object, which specifies the bounds of the region.
+        Rectangle2D rgnBounds = new Rectangle2D.Double();
+        size += readRectL(leis, rgnBounds);
+        for (int i=0; i<rgnCntRect; i++) {
+            Rectangle2D rgnRct = new Rectangle2D.Double();
+            size += readRectL(leis, rgnRct);
+            rgnRects.add(rgnRct);
+        }
+        return size;
+    }
+
+
+    static int readBounds2(LittleEndianInputStream leis, Rectangle2D bounds) {
+        /**
+         * The 32-bit signed integers that defines the corners of the bounding rectangle.
+         */
+        int x = leis.readInt();
+        int y = leis.readInt();
+        int w = leis.readInt();
+        int h = leis.readInt();
+
+        bounds.setRect(x, y, w, h);
+
+        return 4 * LittleEndianConsts.INT_SIZE;
+    }
+
+    static int readXForm(LittleEndianInputStream leis, AffineTransform xform) {
+        // mapping <java AffineTransform> = <xform>:
+        // m00 (scaleX) = eM11 (Horizontal scaling component)
+        // m11 (scaleY) = eM22 (Vertical scaling component)
+        // m01 (shearX) = eM12 (Horizontal proportionality constant)
+        // m10 (shearY) = eM21 (Vertical proportionality constant)
+        // m02 (translateX) = eDx (The horizontal translation component, in logical units.)
+        // m12 (translateY) = eDy (The vertical translation component, in logical units.)
+
+        // A 32-bit floating-point value of the transform matrix.
+        double eM11 = leis.readFloat();
+
+        // A 32-bit floating-point value of the transform matrix.
+        double eM12 = leis.readFloat();
+
+        // A 32-bit floating-point value of the transform matrix.
+        double eM21 = leis.readFloat();
+
+        // A 32-bit floating-point value of the transform matrix.
+        double eM22 = leis.readFloat();
+
+        // A 32-bit floating-point value that contains a horizontal translation component, in logical units.
+        double eDx = leis.readFloat();
+
+        // A 32-bit floating-point value that contains a vertical translation component, in logical units.
+        double eDy = leis.readFloat();
+
+        xform.setTransform(eM11, eM21, eM12, eM22, eDx, eDy);
+
+        return 6 * LittleEndian.INT_SIZE;
+    }
+}

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

Added: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFont.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFont.java?rev=1840956&view=auto
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFont.java (added)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfFont.java Fri Sep 14 21:37:37 2018
@@ -0,0 +1,464 @@
+/* ====================================================================
+   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.hemf.record.emf;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.common.usermodel.fonts.FontCharset;
+import org.apache.poi.hwmf.record.HwmfFont;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianConsts;
+import org.apache.poi.util.LittleEndianInputStream;
+
+public class HemfFont extends HwmfFont {
+    private static final int LOGFONT_SIZE = 92;
+    private static final int LOGFONTPANOSE_SIZE = 320;
+
+    protected interface LogFontDetails {}
+
+    protected static class LogFontExDv implements LogFontDetails {
+        protected int[] designVector;
+    }
+
+    protected static class LogFontPanose implements LogFontDetails {
+        enum FamilyType {
+            PAN_ANY,
+            PAN_NO_FIT,
+            PAN_FAMILY_TEXT_DISPLAY,
+            PAN_FAMILY_SCRIPT,
+            PAN_FAMILY_DECORATIVE,
+            PAN_FAMILY_PICTORIAL
+        }
+
+        enum SerifType {
+            PAN_ANY,
+            PAN_NO_FIT,
+            PAN_SERIF_COVE,
+            PAN_SERIF_OBTUSE_COVE,
+            PAN_SERIF_SQUARE_COVE,
+            PAN_SERIF_OBTUSE_SQUARE_COVE,
+            PAN_SERIF_SQUARE,
+            PAN_SERIF_THIN,
+            PAN_SERIF_BONE,
+            PAN_SERIF_EXAGGERATED,
+            PAN_SERIF_TRIANGLE,
+            PAN_SERIF_NORMAL_SANS,
+            PAN_SERIF_OBTUSE_SANS,
+            PAN_SERIF_PERP_SANS,
+            PAN_SERIF_FLARED,
+            PAN_SERIF_ROUNDED
+        }
+
+        enum FontWeight {
+            PAN_ANY,
+            PAN_NO_FIT,
+            PAN_WEIGHT_VERY_LIGHT,
+            PAN_WEIGHT_LIGHT,
+            PAN_WEIGHT_THIN,
+            PAN_WEIGHT_BOOK,
+            PAN_WEIGHT_MEDIUM,
+            PAN_WEIGHT_DEMI,
+            PAN_WEIGHT_BOLD,
+            PAN_WEIGHT_HEAVY,
+            PAN_WEIGHT_BLACK,
+            PAN_WEIGHT_NORD
+        }
+
+        enum Proportion {
+            PAN_ANY,
+            PAN_NO_FIT,
+            PAN_PROP_OLD_STYLE,
+            PAN_PROP_MODERN,
+            PAN_PROP_EVEN_WIDTH,
+            PAN_PROP_EXPANDED,
+            PAN_PROP_CONDENSED,
+            PAN_PROP_VERY_EXPANDED,
+            PAN_PROP_VERY_CONDENSED,
+            PAN_PROP_MONOSPACED
+        }
+
+        enum Contrast {
+            PAN_ANY,
+            PAN_NO_FIT,
+            PAN_CONTRAST_NONE,
+            PAN_CONTRAST_VERY_LOW,
+            PAN_CONTRAST_LOW,
+            PAN_CONTRAST_MEDIUM_LOW,
+            PAN_CONTRAST_MEDIUM,
+            PAN_CONTRAST_MEDIUM_HIGH,
+            PAN_CONTRAST_HIGH,
+            PAN_CONTRAST_VERY_HIGH
+        }
+
+        enum StrokeVariation {
+            PAN_ANY,
+            PAN_NO_FIT,
+            PAN_STROKE_GRADUAL_DIAG,
+            PAN_STROKE_GRADUAL_TRAN,
+            PAN_STROKE_GRADUAL_VERT,
+            PAN_STROKE_GRADUAL_HORZ,
+            PAN_STROKE_RAPID_VERT,
+            PAN_STROKE_RAPID_HORZ,
+            PAN_STROKE_INSTANT_VERT
+        }
+
+        enum ArmStyle {
+            PAN_ANY,
+            PAN_NO_FIT,
+            PAN_STRAIGHT_ARMS_HORZ,
+            PAN_STRAIGHT_ARMS_WEDGE,
+            PAN_STRAIGHT_ARMS_VERT,
+            PAN_STRAIGHT_ARMS_SINGLE_SERIF,
+            PAN_STRAIGHT_ARMS_DOUBLE_SERIF,
+            PAN_BENT_ARMS_HORZ,
+            PAN_BENT_ARMS_WEDGE,
+            PAN_BENT_ARMS_VERT,
+            PAN_BENT_ARMS_SINGLE_SERIF,
+            PAN_BENT_ARMS_DOUBLE_SERIF
+        }
+
+        enum Letterform {
+            PAN_ANY,
+            PAN_NO_FIT,
+            PAN_LETT_NORMAL_CONTACT,
+            PAN_LETT_NORMAL_WEIGHTED,
+            PAN_LETT_NORMAL_BOXED,
+            PAN_LETT_NORMAL_FLATTENED,
+            PAN_LETT_NORMAL_ROUNDED,
+            PAN_LETT_NORMAL_OFF_CENTER,
+            PAN_LETT_NORMAL_SQUARE,
+            PAN_LETT_OBLIQUE_CONTACT,
+            PAN_LETT_OBLIQUE_WEIGHTED,
+            PAN_LETT_OBLIQUE_BOXED,
+            PAN_LETT_OBLIQUE_FLATTENED,
+            PAN_LETT_OBLIQUE_ROUNDED,
+            PAN_LETT_OBLIQUE_OFF_CENTER,
+            PAN_LETT_OBLIQUE_SQUARE
+        }
+
+        enum MidLine {
+            PAN_ANY,
+            PAN_NO_FIT,
+            PAN_MIDLINE_STANDARD_TRIMMED,
+            PAN_MIDLINE_STANDARD_POINTED,
+            PAN_MIDLINE_STANDARD_SERIFED,
+            PAN_MIDLINE_HIGH_TRIMMED,
+            PAN_MIDLINE_HIGH_POINTED,
+            PAN_MIDLINE_HIGH_SERIFED,
+            PAN_MIDLINE_CONSTANT_TRIMMED,
+            PAN_MIDLINE_CONSTANT_POINTED,
+            PAN_MIDLINE_CONSTANT_SERIFED,
+            PAN_MIDLINE_LOW_TRIMMED,
+            PAN_MIDLINE_LOW_POINTED,
+            PAN_MIDLINE_LOW_SERIFED
+        }
+
+        enum XHeight {
+            PAN_ANY,
+            PAN_NO_FIT,
+            PAN_XHEIGHT_CONSTANT_SMALL,
+            PAN_XHEIGHT_CONSTANT_STD,
+            PAN_XHEIGHT_CONSTANT_LARGE,
+            PAN_XHEIGHT_DUCKING_SMALL,
+            PAN_XHEIGHT_DUCKING_STD,
+            PAN_XHEIGHT_DUCKING_LARGE
+        }
+
+        protected int styleSize;
+        protected int vendorId;
+        protected int culture;
+        protected FamilyType familyType;
+        protected SerifType serifStyle;
+        protected FontWeight weight;
+        protected Proportion proportion;
+        protected Contrast contrast;
+        protected StrokeVariation strokeVariation;
+        protected ArmStyle armStyle;
+        protected Letterform letterform;
+        protected MidLine midLine;
+        protected XHeight xHeight;
+    }
+
+    protected String fullname;
+    protected String style;
+    protected String script;
+
+    protected LogFontDetails details;
+
+    @Override
+    public int init(LittleEndianInputStream leis, long recordSize) throws IOException {
+        // A 32-bit signed integer that specifies the height, in logical units, of the font's
+        // character cell or character. The character height value, also known as the em size, is the
+        // character cell height value minus the internal leading value. The font mapper SHOULD
+        // interpret the value specified in the Height field in the following manner.
+        //
+        // 0x00000000 < value:
+        // The font mapper transforms this value into device units and matches it against
+        // the cell height of the available fonts.
+        //
+        // 0x00000000
+        // The font mapper uses a default height value when it searches for a match.
+        //
+        // value < 0x00000000:
+        // The font mapper transforms this value into device units and matches its
+        // absolute value against the character height of the available fonts.
+        //
+        // For all height comparisons, the font mapper SHOULD look for the largest font that does not
+        // exceed the requested size.
+        height = leis.readInt();
+
+        // A 32-bit signed integer that specifies the average width, in logical units, of
+        // characters in the font. If the Width field value is zero, an appropriate value SHOULD be
+        // calculated from other LogFont values to find a font that has the typographer's intended
+        // aspect ratio.
+        width = leis.readInt();
+
+        // A 32-bit signed integer that specifies the angle, in tenths of degrees,
+        // between the escapement vector and the x-axis of the device. The escapement vector is
+        // parallel to the baseline of a row of text.
+        //
+        // When the graphics mode is set to GM_ADVANCED, the escapement angle of the string can
+        // be specified independently of the orientation angle of the string's characters.
+        escapement = leis.readInt();
+
+        // A 32-bit signed integer that specifies the angle, in tenths of degrees,
+        // between each character's baseline and the x-axis of the device.
+        orientation = leis.readInt();
+
+        // A 32-bit signed integer that specifies the weight of the font in the range zero through 1000.
+        // For example, 400 is normal and 700 is bold. If this value is zero, a default weight can be used.
+        weight = leis.readInt();
+
+        // An 8-bit unsigned integer that specifies an italic font if set to 0x01;
+        // otherwise, it MUST be set to 0x00.
+        italic = (leis.readUByte() == 0x01);
+
+        // An 8-bit unsigned integer that specifies an underlined font if set to 0x01;
+        // otherwise, it MUST be set to 0x00.
+        underline = (leis.readUByte() == 0x01);
+
+        // An 8-bit unsigned integer that specifies a strikeout font if set to 0x01;
+        // otherwise, it MUST be set to 0x00.
+        strikeOut = (leis.readUByte() == 0x01);
+
+        // An 8-bit unsigned integer that specifies the set of character glyphs.
+        // It MUST be a value in the WMF CharacterSet enumeration.
+        // If the character set is unknown, metafile processing SHOULD NOT attempt
+        // to translate or interpret strings that are rendered with that font.
+        // If a typeface name is specified in the Facename field, the CharSet field
+        // value MUST match the character set of that typeface.
+        charSet = FontCharset.valueOf(leis.readUByte());
+
+        // An 8-bit unsigned integer that specifies the output precision.
+        // The output precision defines how closely the font is required to match the requested height, width,
+        // character orientation, escapement, pitch, and font type.
+        // It MUST be a value from the WMF OutPrecision enumeration.
+        // Applications can use the output precision to control how the font mapper chooses a font when the
+        // operating system contains more than one font with a specified name. For example, if an operating
+        // system contains a font named Symbol in rasterized and TrueType forms, an output precision value
+        // of OUT_TT_PRECIS forces the font mapper to choose the TrueType version.
+        // A value of OUT_TT_ONLY_PRECIS forces the font mapper to choose a TrueType font, even if it is
+        // necessary to substitute a TrueType font with another name.
+        outPrecision = WmfOutPrecision.valueOf(leis.readUByte());
+
+        // An 8-bit unsigned integer that specifies the clipping precision.
+        // The clipping precision defines how to clip characters that are partially outside the clipping region.
+        // It can be one or more of the WMF ClipPrecision Flags
+        clipPrecision.init(leis);
+
+        // An 8-bit unsigned integer that specifies the output quality. The output quality defines how closely
+        // to attempt to match the logical-font attributes to those of an actual physical font.
+        // It MUST be one of the values in the WMF FontQuality enumeration
+        quality = WmfFontQuality.valueOf(leis.readUByte());
+
+        // A WMF PitchAndFamily object that specifies the pitch and family of the font.
+        // Font families describe the look of a font in a general way.
+        // They are intended for specifying a font when the specified typeface is not available.
+        pitchAndFamily = leis.readUByte();
+
+        int size = 5* LittleEndianConsts.INT_SIZE+8*LittleEndianConsts.BYTE_SIZE;
+
+        StringBuilder sb = new StringBuilder();
+
+        // A string of no more than 32 Unicode characters that specifies the typeface name of the font.
+        // If the length of this string is less than 32 characters, a terminating NULL MUST be present,
+        // after which the remainder of this field MUST be ignored.
+        int readBytes = readString(leis, sb, 32);
+        if (readBytes == -1) {
+            throw new IOException("Font facename can't be determined.");
+        }
+        facename = sb.toString();
+        size += readBytes;
+
+        if (recordSize <= LOGFONT_SIZE) {
+            return size;
+        }
+
+        // A string of 64 Unicode characters that contains the font's full name.
+        // Ifthe length of this string is less than 64 characters, a terminating
+        // NULL MUST be present, after which the remainder of this field MUST be ignored.
+        readBytes = readString(leis, sb, 64);
+        if (readBytes == -1) {
+            throw new IOException("Font fullname can't be determined.");
+        }
+        fullname = sb.toString();
+        size += readBytes;
+
+        // A string of 32 Unicode characters that defines the font's style. If the length of
+        // this string is less than 32 characters, a terminating NULL MUST be present,
+        // after which the remainder of this field MUST be ignored.
+        readBytes = readString(leis, sb, 32);
+        if (readBytes == -1) {
+            throw new IOException("Font style can't be determined.");
+        }
+        style = sb.toString();
+        size += readBytes;
+
+        if (recordSize == LOGFONTPANOSE_SIZE) {
+            // LogFontPanose Object
+
+            LogFontPanose logPan = new LogFontPanose();
+            details = logPan;
+
+            int version = leis.readInt();
+
+            // A 32-bit unsigned integer that specifies the point size at which font
+            //hinting is performed. If set to zero, font hinting is performed at the point size corresponding
+            //to the Height field in the LogFont object in the LogFont field.
+            logPan.styleSize = (int)leis.readUInt();
+
+            int match = leis.readInt();
+
+            int reserved = leis.readInt();
+
+            logPan.vendorId = leis.readInt();
+
+            logPan.culture = leis.readInt();
+
+            // An 8-bit unsigned integer that specifies the family type.
+            // The value MUST be in the FamilyType enumeration table.
+            logPan.familyType = LogFontPanose.FamilyType.values()[leis.readUByte()];
+
+            // An 8-bit unsigned integer that specifies the serif style.
+            // The value MUST be in the SerifType enumeration table.
+            logPan.serifStyle = LogFontPanose.SerifType.values()[leis.readUByte()];
+
+            // An 8-bit unsigned integer that specifies the weight of the font.
+            // The value MUST be in the Weight enumeration table.
+            logPan.weight = LogFontPanose.FontWeight.values()[leis.readUByte()];
+
+            // An 8-bit unsigned integer that specifies the proportion of the font.
+            // The value MUST be in the Proportion enumeration table.
+            logPan.proportion = LogFontPanose.Proportion.values()[leis.readUByte()];
+
+            // An 8-bit unsigned integer that specifies the proportion of the font.
+            // The value MUST be in the Proportion enumeration table.
+            logPan.contrast = LogFontPanose.Contrast.values()[leis.readUByte()];
+
+            // An 8-bit unsigned integer that specifies the stroke variation for the font.
+            // The value MUST be in the StrokeVariation enumeration table.
+            logPan.strokeVariation = LogFontPanose.StrokeVariation.values()[leis.readUByte()];
+
+            // An 8-bit unsigned integer that specifies the arm style of the font.
+            // The value MUST be in the ArmStyle enumeration table.
+            logPan.armStyle = LogFontPanose.ArmStyle.values()[leis.readUByte()];
+
+            // An 8-bit unsigned integer that specifies the letterform of the font.
+            // The value MUST be in the Letterform enumeration table.
+            logPan.letterform = LogFontPanose.Letterform.values()[leis.readUByte()];
+
+            // An 8-bit unsigned integer that specifies the midline of the font.
+            // The value MUST be in the MidLine enumeration table.
+            logPan.midLine = LogFontPanose.MidLine.values()[leis.readUByte()];
+
+            // An 8-bit unsigned integer that specifies the x height of the font.
+            // The value MUST be in the XHeight enumeration table.
+            logPan.xHeight = LogFontPanose.XHeight.values()[leis.readUByte()];
+
+            // skip 2 byte to ensure 32-bit alignment of this structure.
+            leis.skip(2);
+
+            size += 6*LittleEndianConsts.INT_SIZE+10* LittleEndianConsts.BYTE_SIZE+2;
+        } else {
+            // LogFontExDv Object
+
+            LogFontExDv logEx = new LogFontExDv();
+            details = logEx;
+
+                    // A string of 32 Unicode characters that defines the character set of the font.
+            // If the length of this string is less than 32 characters, a terminating NULL MUST be present,
+            // after which the remainder of this field MUST be ignored.
+            readBytes = readString(leis, sb, 32);
+            if (readBytes == -1) {
+                throw new IOException("Font script can't be determined.");
+            }
+            script = sb.toString();
+            size += readBytes;
+
+            // Design Vector
+
+            // A 32-bit unsigned integer that MUST be set to the value 0x08007664.
+            int signature = leis.readInt();
+            assert (signature == 0x08007664);
+
+            // A 32-bit unsigned integer that specifies the number of elements in the
+            // Values array. It MUST be in the range 0 to 16, inclusive.
+            int numAxes = leis.readInt();
+            assert (0 <= numAxes && numAxes <= 16);
+
+            // An optional array of 32-bit signed integers that specify the values of the font axes of a
+            // multiple master, OpenType font. The maximum number of values in the array is 16.
+            if (numAxes > 0) {
+                logEx.designVector = new int[numAxes];
+                for (int i=0; i<numAxes; i++) {
+                    logEx.designVector[i] = leis.readInt();
+                }
+            }
+            size += (2+numAxes)*LittleEndianConsts.INT_SIZE;
+        }
+
+
+
+
+        return size;
+    }
+
+    @Override
+    protected int readString(LittleEndianInputStream leis, StringBuilder sb, int limit) throws IOException {
+        sb.setLength(0);
+        byte buf[] = new byte[limit*2];
+        leis.readFully(buf);
+
+        int b1, b2, readBytes = 0;
+        do {
+            if (readBytes == limit*2) {
+                return -1;
+            }
+
+            b1 = buf[readBytes++];
+            b2 = buf[readBytes++];
+        } while ((b1 != 0 || b2 != 0) && b1 != -1 && b2 != -1 && readBytes <= limit*2);
+
+        sb.append(new String(buf, 0, readBytes-2, StandardCharsets.UTF_16LE));
+
+        return limit*2;
+    }
+}

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

Copied: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfHeader.java (from r1840955, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfHeader.java)
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfHeader.java?p2=poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfHeader.java&p1=poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfHeader.java&r1=1840955&r2=1840956&rev=1840956&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfHeader.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfHeader.java Fri Sep 14 21:37:37 2018
@@ -15,14 +15,20 @@
    limitations under the License.
 ==================================================================== */
 
-package org.apache.poi.hemf.record;
+package org.apache.poi.hemf.record.emf;
 
-import java.awt.Rectangle;
+import static org.apache.poi.hemf.record.emf.HemfDraw.readDimensionFloat;
+import static org.apache.poi.hemf.record.emf.HemfDraw.readDimensionInt;
+import static org.apache.poi.hemf.record.emf.HemfDraw.readRectL;
+
+import java.awt.geom.Dimension2D;
+import java.awt.geom.Rectangle2D;
 import java.io.IOException;
 
-import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.Dimension2DDouble;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianConsts;
 import org.apache.poi.util.LittleEndianInputStream;
 
 /**
@@ -35,8 +41,8 @@ public class HemfHeader implements HemfR
     private static final int MAX_RECORD_LENGTH = 1_000_000;
 
 
-    private Rectangle boundsRectangle;
-    private Rectangle frameRectangle;
+    private final Rectangle2D boundsRectangle = new Rectangle2D.Double();
+    private final Rectangle2D frameRectangle = new Rectangle2D.Double();
     private long bytes;
     private long records;
     private int handles;
@@ -48,14 +54,16 @@ public class HemfHeader implements HemfR
     private long offPixelFormat;
     private long bOpenGL;
     private boolean hasExtension2;
-    private long micrometersX;
-    private long micrometersY;
+    private final Dimension2D deviceDimension = new Dimension2DDouble();
+    private final Dimension2D milliDimension = new Dimension2DDouble();
+    private final Dimension2D microDimension = new Dimension2DDouble();
+
 
-    public Rectangle getBoundsRectangle() {
+    public Rectangle2D getBoundsRectangle() {
         return boundsRectangle;
     }
 
-    public Rectangle getFrameRectangle() {
+    public Rectangle2D getFrameRectangle() {
         return frameRectangle;
     }
 
@@ -104,11 +112,11 @@ public class HemfHeader implements HemfR
     }
 
     public long getMicrometersX() {
-        return micrometersX;
+        return (long)microDimension.getWidth();
     }
 
     public long getMicrometersY() {
-        return micrometersY;
+        return (long)microDimension.getHeight();
     }
 
     @Override
@@ -127,75 +135,61 @@ public class HemfHeader implements HemfR
                 ", offPixelFormat=" + offPixelFormat +
                 ", bOpenGL=" + bOpenGL +
                 ", hasExtension2=" + hasExtension2 +
-                ", micrometersX=" + micrometersX +
-                ", micrometersY=" + micrometersY +
+                ", micrometersX=" + getMicrometersX() +
+                ", micrometersY=" + getMicrometersY() +
                 '}';
     }
 
     @Override
-    public HemfRecordType getRecordType() {
+    public HemfRecordType getEmfRecordType() {
         return HemfRecordType.header;
     }
 
     @Override
-    public long init(LittleEndianInputStream leis, long recordId, long recordSize) throws IOException {
-        if (recordId != 1L) {
+    public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+        if (recordId != HemfRecordType.header.id) {
             throw new IOException("Not a valid EMF header. Record type:"+recordId);
         }
-        //read the record--id and size (2 bytes) have already been read
-        byte[] data = IOUtils.safelyAllocate(recordSize, MAX_RECORD_LENGTH);
-        IOUtils.readFully(leis, data);
-
-        int offset = 0;
 
         //bounds
-        int boundsLeft = LittleEndian.getInt(data, offset); offset += LittleEndian.INT_SIZE;
-        int boundsTop = LittleEndian.getInt(data, offset); offset += LittleEndian.INT_SIZE;
-        int boundsRight = LittleEndian.getInt(data, offset); offset += LittleEndian.INT_SIZE;
-        int boundsBottom = LittleEndian.getInt(data, offset); offset += LittleEndian.INT_SIZE;
-        boundsRectangle = new Rectangle(boundsLeft, boundsTop,
-                boundsRight - boundsLeft, boundsBottom - boundsTop);
-
-        int frameLeft = LittleEndian.getInt(data, offset); offset += LittleEndian.INT_SIZE;
-        int frameTop = LittleEndian.getInt(data, offset); offset += LittleEndian.INT_SIZE;
-        int frameRight = LittleEndian.getInt(data, offset); offset += LittleEndian.INT_SIZE;
-        int frameBottom = LittleEndian.getInt(data, offset); offset += LittleEndian.INT_SIZE;
-        frameRectangle = new Rectangle(frameLeft, frameTop,
-                frameRight - frameLeft, frameBottom - frameTop);
+        long size = readRectL(leis, boundsRectangle);
+        size += readRectL(leis, frameRectangle);
 
-        long recordSignature = LittleEndian.getInt(data, offset); offset += LittleEndian.INT_SIZE;
+        int recordSignature = leis.readInt();
         if (recordSignature != 0x464D4520) {
             throw new IOException("bad record signature: " + recordSignature);
         }
 
-        long version = LittleEndian.getInt(data, offset); offset += LittleEndian.INT_SIZE;
+        long version = leis.readInt();
         //According to the spec, MSOffice doesn't pay attention to this value.
         //It _should_ be 0x00010000
-        bytes = LittleEndian.getUInt(data, offset); offset += LittleEndian.INT_SIZE;
-        records = LittleEndian.getUInt(data, offset); offset += LittleEndian.INT_SIZE;
-        handles = LittleEndian.getUShort(data, offset);offset += LittleEndian.SHORT_SIZE;
-        offset += LittleEndian.SHORT_SIZE;//reserved
-        nDescription = LittleEndian.getUInt(data, offset); offset += LittleEndian.INT_SIZE;
-        offDescription = LittleEndian.getUInt(data, offset); offset += LittleEndian.INT_SIZE;
-        nPalEntries = LittleEndian.getUInt(data, offset); offset += LittleEndian.INT_SIZE;
-
-        //should be skips
-        offset += 8;//device
-        offset += 8;//millimeters
+        bytes = leis.readUInt();
+        records = leis.readUInt();
+        handles = leis.readUShort();
+        //reserved
+        leis.skipFully(LittleEndianConsts.SHORT_SIZE);
+
+        nDescription = leis.readUInt();
+        offDescription = leis.readUInt();
+        nPalEntries = leis.readUInt();
+
+        size += 8*LittleEndianConsts.INT_SIZE;
 
+        size += readDimensionInt(leis, deviceDimension);
+        size += readDimensionInt(leis, milliDimension);
 
-        if (recordSize+8 >= 100) {
+        if (size+12 <= recordSize) {
             hasExtension1 = true;
-            cbPixelFormat = LittleEndian.getUInt(data, offset); offset += LittleEndian.INT_SIZE;
-            offPixelFormat = LittleEndian.getUInt(data, offset); offset += LittleEndian.INT_SIZE;
-            bOpenGL= LittleEndian.getUInt(data, offset); offset += LittleEndian.INT_SIZE;
+            cbPixelFormat =  leis.readUInt();
+            offPixelFormat = leis.readUInt();
+            bOpenGL = leis.readUInt();
+            size += 3*LittleEndianConsts.INT_SIZE;
         }
 
-        if (recordSize+8 >= 108) {
+        if (size+8 <= recordSize) {
             hasExtension2 = true;
-            micrometersX = LittleEndian.getUInt(data, offset); offset += LittleEndian.INT_SIZE;
-            micrometersY = LittleEndian.getUInt(data, offset); offset += LittleEndian.INT_SIZE;
+            size += readDimensionInt(leis, microDimension);
         }
-        return recordSize;
+        return size;
     }
 }

Added: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java?rev=1840956&view=auto
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java (added)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfMisc.java Fri Sep 14 21:37:37 2018
@@ -0,0 +1,447 @@
+/* ====================================================================
+   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.hemf.record.emf;
+
+import static org.apache.poi.hemf.record.emf.HemfDraw.readDimensionInt;
+import static org.apache.poi.hemf.record.emf.HemfFill.readBitmap;
+import static org.apache.poi.hemf.record.emf.HemfRecordIterator.HEADER_SIZE;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hemf.draw.HemfGraphics;
+import org.apache.poi.hwmf.record.HwmfBinaryRasterOp;
+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.HwmfHatchStyle;
+import org.apache.poi.hwmf.record.HwmfMapMode;
+import org.apache.poi.hwmf.record.HwmfMisc;
+import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode;
+import org.apache.poi.hwmf.record.HwmfPalette.PaletteEntry;
+import org.apache.poi.hwmf.record.HwmfPenStyle;
+import org.apache.poi.hwmf.record.HwmfPenStyle.HwmfLineDash;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.LittleEndianConsts;
+import org.apache.poi.util.LittleEndianInputStream;
+
+public class HemfMisc {
+    private static final int MAX_RECORD_LENGTH = 10_000_000;
+
+    public static class EmfEof implements HemfRecord {
+        protected final List<PaletteEntry> palette = new ArrayList<>();
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.eof;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+
+            // A 32-bit unsigned integer that specifies the number of palette entries.
+            int nPalEntries = (int)leis.readUInt();
+            // A 32-bit unsigned integer that specifies the offset to the palette entries from the start of this record.
+            int offPalEntries = (int)leis.readUInt();
+
+            int size = 2*LittleEndianConsts.INT_SIZE;
+            int undefinedSpace1 = (int)(offPalEntries - size - HEADER_SIZE);
+            assert (undefinedSpace1 >= 0);
+            leis.skipFully(undefinedSpace1);
+            size += undefinedSpace1;
+
+            for (int i=0; i<nPalEntries; i++) {
+                PaletteEntry pe = new PaletteEntry();
+                size += pe.init(leis);
+            }
+
+            int undefinedSpace2 = (int)(recordSize - size - LittleEndianConsts.INT_SIZE);
+            assert (undefinedSpace2 >= 0);
+            leis.skipFully(undefinedSpace2);
+            size += undefinedSpace2;
+
+            // A 32-bit unsigned integer that MUST be the same as Size and MUST be the
+            // last field of the record and hence the metafile.
+            // LogPaletteEntry objects, if they exist, MUST precede this field.
+            long sizeLast = leis.readUInt();
+            size += LittleEndianConsts.INT_SIZE;
+            assert ((sizeLast-HEADER_SIZE) == recordSize && recordSize == size);
+
+            return size;
+        }
+    }
+
+    /**
+     * The EMF_SAVEDC record saves the playback device context for later retrieval.
+     */
+    public static class EmfSaveDc implements HemfRecord {
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.saveDc;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            return 0;
+        }
+
+        @Override
+        public void draw(HemfGraphics ctx) {
+            ctx.saveProperties();
+        }
+    }
+
+    /**
+     * The EMF_RESTOREDC record restores the playback device context from a previously saved device
+     * context.
+     */
+    public static class EmfRestoreDc implements HemfRecord {
+
+        /**
+         * SavedDC (4 bytes): A 32-bit signed integer that specifies the saved state to restore relative to
+         * the current state. This value MUST be negative; –1 represents the state that was most
+         * recently saved on the stack, –2 the one before that, etc.
+         */
+        private int nSavedDC;
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.restoreDc;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            nSavedDC = leis.readInt();
+            return LittleEndianConsts.INT_SIZE;
+        }
+
+        @Override
+        public void draw(HemfGraphics ctx) {
+            ctx.restoreProperties(nSavedDC);
+        }
+    }
+
+    /**
+     * The META_SETBKCOLOR record sets the background color in the playback device context to a
+     * specified color, or to the nearest physical color if the device cannot represent the specified color.
+     */
+    public static class EmfSetBkColor implements HemfRecord {
+
+        private HwmfColorRef colorRef;
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.setBkColor;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            colorRef = new HwmfColorRef();
+            return colorRef.init(leis);
+        }
+
+        @Override
+        public void draw(HemfGraphics ctx) {
+            ctx.getProperties().setBackgroundColor(colorRef);
+        }
+    }
+
+
+    /**
+     * The EMR_SETBKMODE record specifies the background mix mode of the playback device context.
+     * The background mix mode is used with text, hatched brushes, and pen styles that are not solid
+     * lines.
+     */
+    public static class EmfSetBkMode extends WmfSetBkMode implements HemfRecord {
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.setBkMode;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            /*
+             * A 32-bit unsigned integer that specifies the background mode
+             * and MUST be in the BackgroundMode (section 2.1.4) enumeration
+             */
+            bkMode = HwmfBkMode.valueOf((int)leis.readUInt());
+            return LittleEndianConsts.INT_SIZE;
+        }
+    }
+
+    /**
+     * The EMR_SETMAPPERFLAGS record specifies parameters of the process of matching logical fonts to
+     * physical fonts, which is performed by the font mapper.
+     */
+    public static class EmfSetMapperFlags extends HwmfMisc.WmfSetMapperFlags implements HemfRecord {
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.setMapperFlags;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            return super.init(leis, recordSize, (int)recordId);
+        }
+    }
+
+    /**
+     * The EMR_SETMAPMODE record specifies the mapping mode of the playback device context. The
+     * mapping mode specifies the unit of measure used to transform page space units into device space
+     * units, and also specifies the orientation of the device's x-axis and y-axis.
+     */
+    public static class EmfSetMapMode extends HwmfMisc.WmfSetMapMode implements HemfRecord {
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.setMapMode;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            // A 32-bit unsigned integer whose definition MUST be in the MapMode enumeration
+            mapMode = HwmfMapMode.valueOf((int)leis.readUInt());
+            return LittleEndianConsts.INT_SIZE;
+        }
+    }
+
+    /**
+     * The EMR_SETROP2 record defines a binary raster operation mode.
+     */
+    public static class EmfSetRop2 extends HwmfMisc.WmfSetRop2 implements HemfRecord {
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.setRop2;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            // A 32-bit unsigned integer that specifies the raster operation mode and
+            // MUST be in the WMF Binary Raster Op enumeration
+            drawMode = HwmfBinaryRasterOp.valueOf((int)leis.readUInt());
+            return LittleEndianConsts.INT_SIZE;
+        }
+    }
+
+
+    /**
+     * The EMR_SETSTRETCHBLTMODE record specifies bitmap stretch mode.
+     */
+    public static class EmfSetStretchBltMode extends HwmfMisc.WmfSetStretchBltMode implements HemfRecord {
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.setStretchBltMode;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            // A 32-bit unsigned integer that specifies the stretch mode and MAY be
+            // in the StretchMode enumeration.
+            stretchBltMode = StretchBltMode.valueOf((int)leis.readUInt());
+            return LittleEndianConsts.INT_SIZE;
+        }
+    }
+
+    /** The EMR_CREATEBRUSHINDIRECT record defines a logical brush for graphics operations. */
+    public static class EmfCreateBrushIndirect extends HwmfMisc.WmfCreateBrushIndirect implements HemfRecord {
+        /**
+         * A 32-bit unsigned integer that specifies the index of the logical brush object in the
+         * EMF Object Table. This index MUST be saved so that this object can be reused or modified.
+         */
+        private int brushIdx;
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.createBrushIndirect;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            brushIdx = (int)leis.readUInt();
+
+            brushStyle = HwmfBrushStyle.valueOf((int)leis.readUInt());
+            colorRef = new HwmfColorRef();
+            int size = colorRef.init(leis);
+            brushHatch = HwmfHatchStyle.valueOf((int)leis.readUInt());
+            return size+3*LittleEndianConsts.INT_SIZE;
+
+        }
+    }
+
+    /**
+     * The EMR_DELETEOBJECT record deletes a graphics object, which is specified by its index
+     * in the EMF Object Table
+     */
+    public static class EmfDeleteObject extends HwmfMisc.WmfDeleteObject implements HemfRecord {
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.deleteobject;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            objectIndex = (int)leis.readUInt();
+            return LittleEndianConsts.INT_SIZE;
+        }
+    }
+
+    /** The EMR_CREATEPEN record defines a logical pen for graphics operations. */
+    public static class EmfCreatePen extends HwmfMisc.WmfCreatePenIndirect implements HemfRecord {
+        /**
+         * A 32-bit unsigned integer that specifies the index of the logical palette object
+         * in the EMF Object Table. This index MUST be saved so that this object can be
+         * reused or modified.
+         */
+        protected int penIndex;
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.createPen;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            penIndex = (int)leis.readUInt();
+
+            // A 32-bit unsigned integer that specifies the PenStyle.
+            // The value MUST be defined from the PenStyle enumeration table
+            penStyle = HwmfPenStyle.valueOf((int)leis.readUInt());
+
+            int widthX = leis.readInt();
+            int widthY = leis.readInt();
+            dimension.setSize(widthX, widthY);
+
+            int size = colorRef.init(leis);
+
+            return size + 4*LittleEndianConsts.INT_SIZE;
+        }
+    }
+
+    public static class EmfExtCreatePen extends EmfCreatePen {
+        protected HwmfBrushStyle brushStyle;
+        protected HwmfHatchStyle hatchStyle;
+
+        protected int[] styleEntry;
+
+        protected final HwmfBitmapDib bitmap = new HwmfBitmapDib();
+
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.extCreatePen;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            final int startIdx = leis.getReadIndex();
+
+            penIndex = (int)leis.readUInt();
+
+            // A 32-bit unsigned integer that specifies the offset from the start of this
+            // record to the DIB header, if the record contains a DIB.
+            int offBmi = (int)leis.readUInt();
+
+            // A 32-bit unsigned integer that specifies the size of the DIB header, if the
+            // record contains a DIB.
+            int cbBmi = (int)leis.readUInt();
+
+            // A 32-bit unsigned integer that specifies the offset from the start of this
+            // record to the DIB bits, if the record contains a DIB.
+            int offBits = (int)leis.readUInt();
+
+            // A 32-bit unsigned integer that specifies the size of the DIB bits, if the record
+            // contains a DIB.
+            int cbBits = (int)leis.readUInt();
+
+            // A 32-bit unsigned integer that specifies the PenStyle.
+            // The value MUST be defined from the PenStyle enumeration table
+            penStyle = HwmfPenStyle.valueOf((int)leis.readUInt());
+
+            // A 32-bit unsigned integer that specifies the width of the line drawn by the pen.
+            // If the pen type in the PenStyle field is PS_GEOMETRIC, this value is the width in logical
+            // units; otherwise, the width is specified in device units. If the pen type in the PenStyle field is
+            // PS_COSMETIC, this value MUST be 0x00000001.
+            long width = leis.readUInt();
+            dimension.setSize(width, 0);
+
+            // A 32-bit unsigned integer that specifies a brush style for the pen from the WMF BrushStyle enumeration
+            //
+            // If the pen type in the PenStyle field is PS_GEOMETRIC, this value MUST be either BS_SOLID or BS_HATCHED.
+            // The value of this field can be BS_NULL, but only if the line style specified in PenStyle is PS_NULL.
+            // The BS_NULL style SHOULD be used to specify a brush that has no effect
+            brushStyle = HwmfBrushStyle.valueOf((int)leis.readUInt());
+
+            int size = 8 * LittleEndianConsts.INT_SIZE;
+
+            size += colorRef.init(leis);
+
+            hatchStyle = HwmfHatchStyle.valueOf(leis.readInt());
+
+            // The number of elements in the array specified in the StyleEntry
+            // field. This value SHOULD be zero if PenStyle does not specify PS_USERSTYLE.
+            final int numStyleEntries = (int)leis.readUInt();
+            size += 2*LittleEndianConsts.INT_SIZE;
+
+            assert(numStyleEntries == 0 || penStyle.getLineDash() == HwmfLineDash.USERSTYLE);
+
+            // An optional array of 32-bit unsigned integers that defines the lengths of
+            // dashes and gaps in the line drawn by this pen, when the value of PenStyle is
+            // PS_USERSTYLE line style for the pen. The array contains a number of entries specified by
+            // NumStyleEntries, but it is used as if it repeated indefinitely.
+            // The first entry in the array specifies the length of the first dash. The second entry specifies
+            // the length of the first gap. Thereafter, lengths of dashes and gaps alternate.
+            // If the pen type in the PenStyle field is PS_GEOMETRIC, the lengths are specified in logical
+            // units; otherwise, the lengths are specified in device units.
+
+            styleEntry = new int[numStyleEntries];
+
+            for (int i=0; i<numStyleEntries; i++) {
+                styleEntry[i] = (int)leis.readUInt();
+            }
+
+            size += numStyleEntries * LittleEndianConsts.INT_SIZE;
+
+            size += readBitmap(leis, bitmap, startIdx, offBmi, cbBmi, offBits, cbBits);
+
+            return size;
+        }
+    }
+
+    /**
+     * The EMR_SETMITERLIMIT record specifies the limit for the length of miter joins for the playback
+     * device context.
+     */
+    public static class EmfSetMiterLimit implements HemfRecord {
+        protected int miterLimit;
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.setMiterLimit;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            miterLimit = (int)leis.readUInt();
+            return LittleEndianConsts.INT_SIZE;
+        }
+
+        @Override
+        public void draw(HemfGraphics ctx) {
+            ctx.getProperties().setPenMiterLimit(miterLimit);
+        }
+    }
+}

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

Added: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfPalette.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfPalette.java?rev=1840956&view=auto
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfPalette.java (added)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfPalette.java Fri Sep 14 21:37:37 2018
@@ -0,0 +1,138 @@
+/* ====================================================================
+   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.hemf.record.emf;
+
+import java.io.IOException;
+
+import org.apache.poi.hwmf.record.HwmfPalette;
+import org.apache.poi.util.LittleEndianConsts;
+import org.apache.poi.util.LittleEndianInputStream;
+
+public class HemfPalette {
+    /** The EMR_SELECTPALETTE record specifies a logical palette for the playback device context. */
+    public static class EmfSelectPalette extends HwmfPalette.WmfSelectPalette implements HemfRecord {
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.selectPalette;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            /*
+             * A 32-bit unsigned integer that specifies either the index of a LogPalette object
+             * in the EMF Object Table or the value DEFAULT_PALETTE, which is the index
+             * of a stock object palette from the StockObject enumeration
+             */
+            paletteIndex = (int)leis.readUInt();
+            return LittleEndianConsts.INT_SIZE;
+        }
+    }
+
+    /** The EMR_CREATEPALETTE record defines a logical palette for graphics operations. */
+    public static class EmfCreatePalette extends HwmfPalette.WmfCreatePalette implements HemfRecord {
+
+        protected int paletteIndex;
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.createPalette;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            start = 0x0300;
+            /* A 32-bit unsigned integer that specifies the index of the logical palette object
+             * in the EMF Object Table. This index MUST be saved so that this object can be
+             * reused or modified.
+             */
+            paletteIndex = (int)leis.readUInt();
+            /* A 16-bit unsigned integer that specifies the version number of the system. This MUST be 0x0300. */
+            int version = leis.readUShort();
+            assert(version == 0x0300);
+            int size = readPaletteEntries(leis, -1);
+            return size + LittleEndianConsts.INT_SIZE + LittleEndianConsts.SHORT_SIZE;
+        }
+    }
+
+    /**
+     * The EMR_SETPALETTEENTRIES record defines RGB color values in a range of entries for an existing
+     * LogPalette object.
+     */
+    public static class EmfSetPaletteEntries extends HwmfPalette.WmfSetPaletteEntries implements HemfRecord {
+        /** specifies the palette EMF Object Table index. */
+        int paletteIndex;
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.setPaletteEntries;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            // A 32-bit unsigned integer that specifies the palette EMF Object Table index.
+            paletteIndex = (int)leis.readUInt();
+            // A 32-bit unsigned integer that specifies the index of the first entry to set.
+            start = (int)leis.readUInt();
+            // A 32-bit unsigned integer that specifies the number of entries.
+            int nbrOfEntries = (int)leis.readUInt();
+            int size = readPaletteEntries(leis, nbrOfEntries);
+            return size + 3*LittleEndianConsts.INT_SIZE;
+        }
+    }
+
+    /**
+     * The EMR_RESIZEPALETTE record increases or decreases the size of an existing LogPalette object
+     */
+    public static class EmfResizePalette extends HwmfPalette.WmfResizePalette implements HemfRecord {
+        /** specifies the palette EMF Object Table index. */
+        int paletteIndex;
+
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.resizePalette;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            // A 32-bit unsigned integer that specifies the index of the palette object in the EMF Object Table
+            paletteIndex = (int)leis.readUInt();
+
+            // A 32-bit unsigned integer that specifies the number of entries in the palette after resizing.
+            // The value MUST be less than or equal to 0x00000400 and greater than 0x00000000.
+            numberOfEntries = (int)leis.readUInt();
+
+            return 2*LittleEndianConsts.INT_SIZE;
+        }
+    }
+
+    /**
+     * This record maps palette entries from the current LogPalette object to the system_palette.
+     * This EMF record specifies no parameters.
+     */
+    public static class EmfRealizePalette extends HwmfPalette.WmfRealizePalette implements HemfRecord {
+        @Override
+        public HemfRecordType getEmfRecordType() {
+            return HemfRecordType.realizePalette;
+        }
+
+        @Override
+        public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
+            return 0;
+        }
+    }
+}

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

Copied: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecord.java (from r1840955, poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfRecord.java)
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecord.java?p2=poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecord.java&p1=poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfRecord.java&r1=1840955&r2=1840956&rev=1840956&view=diff
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/HemfRecord.java (original)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecord.java Fri Sep 14 21:37:37 2018
@@ -15,27 +15,32 @@
    limitations under the License.
 ==================================================================== */
 
-package org.apache.poi.hemf.record;
+package org.apache.poi.hemf.record.emf;
 
 
 import java.io.IOException;
 
+import org.apache.poi.hemf.draw.HemfGraphics;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.LittleEndianInputStream;
 
 @Internal
 public interface HemfRecord {
 
-    HemfRecordType getRecordType();
+    HemfRecordType getEmfRecordType();
 
     /**
      * Init record from stream
      *
      * @param leis the little endian input stream
+     * @param recordSize the size limit for this record
+     * @param recordId the id of the {@link HemfRecordType}
+     *
      * @return count of processed bytes
-     * @throws IOException
+     *
+     * @throws IOException when the inputstream is malformed
      */
-    long init(LittleEndianInputStream leis, long recordId, long recordSize) throws IOException;
-
+    long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException;
 
+    default void draw(HemfGraphics ctx) {}
 }

Added: poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordIterator.java
URL: http://svn.apache.org/viewvc/poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordIterator.java?rev=1840956&view=auto
==============================================================================
--- poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordIterator.java (added)
+++ poi/branches/hemf/src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfRecordIterator.java Fri Sep 14 21:37:37 2018
@@ -0,0 +1,82 @@
+/* ====================================================================
+   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.hemf.record.emf;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import org.apache.poi.util.LittleEndianConsts;
+import org.apache.poi.util.LittleEndianInputStream;
+import org.apache.poi.util.RecordFormatException;
+
+public class HemfRecordIterator implements Iterator<HemfRecord> {
+
+    static final int HEADER_SIZE = 2*LittleEndianConsts.INT_SIZE;
+
+    private final LittleEndianInputStream stream;
+    private HemfRecord currentRecord;
+
+    public HemfRecordIterator(LittleEndianInputStream leis) {
+        stream = leis;
+        //queue the first non-header record
+        currentRecord = _next();
+    }
+
+    @Override
+    public boolean hasNext() {
+        return currentRecord != null;
+    }
+
+    @Override
+    public HemfRecord next() {
+        HemfRecord toReturn = currentRecord;
+        currentRecord = (currentRecord instanceof HemfMisc.EmfEof) ? null : _next();
+        return toReturn;
+    }
+
+    private HemfRecord _next() {
+        if (currentRecord != null && HemfRecordType.eof == currentRecord.getEmfRecordType()) {
+            return null;
+        }
+        long recordId = stream.readUInt();
+        long recordSize = stream.readUInt();
+
+        HemfRecordType type = HemfRecordType.getById(recordId);
+        if (type == null) {
+            throw new RecordFormatException("Undefined record of type:"+recordId);
+        }
+        final HemfRecord record = type.constructor.get();
+
+        try {
+            long remBytes = recordSize-HEADER_SIZE;
+            long readBytes = record.init(stream, remBytes, recordId);
+            assert (readBytes <= remBytes);
+            stream.skipFully((int)(remBytes-readBytes));
+        } catch (IOException|RuntimeException e) {
+            throw new RecordFormatException(e);
+        }
+
+        return record;
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException("Remove not supported");
+    }
+
+}
\ No newline at end of file

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



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