]> source.dussan.org Git - poi.git/commitdiff
#62953 - Rendering of FreeformShapes with formula fails
authorAndreas Beeker <kiwiwings@apache.org>
Sun, 9 Dec 2018 01:06:15 +0000 (01:06 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sun, 9 Dec 2018 01:06:15 +0000 (01:06 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1848492 13f79535-47bb-0310-9956-ffa450edef68

21 files changed:
src/java/org/apache/poi/ddf/EscherProperties.java
src/java/org/apache/poi/sl/draw/DrawFreeformShape.java
src/java/org/apache/poi/sl/draw/DrawSimpleShape.java
src/java/org/apache/poi/sl/draw/geom/Context.java
src/java/org/apache/poi/sl/usermodel/FreeformShape.java
src/java/org/apache/poi/util/Units.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java
src/scratchpad/testcases/org/apache/poi/hslf/model/TestBackground.java [deleted file]
src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java
src/scratchpad/testcases/org/apache/poi/hslf/usermodel/AllHSLFUserModelTests.java
src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBackground.java [new file with mode: 0644]
test-data/slideshow/customGeo.ppt [new file with mode: 0644]
test-data/slideshow/customGeo.pptx [new file with mode: 0644]

index acff6241c2ee4100a03d9f6310005757c38464a3..482bce95c5e896f2ed5b40b0cda45ace31b7fdcd 100644 (file)
@@ -26,6 +26,7 @@ import java.util.Map;
  *
  * @author Glen Stampoultzis (glens at apache.org)
  */
+@SuppressWarnings("WeakerAccess")
 public final class EscherProperties {
 
        // Property constants
@@ -117,6 +118,15 @@ public final class EscherProperties {
        public static final short GEOMETRY__ADJUST8VALUE = 334;
        public static final short GEOMETRY__ADJUST9VALUE = 335;
        public static final short GEOMETRY__ADJUST10VALUE = 336;
+       public static final short GEOMETRY__PCONNECTIONSITES = 337;
+       public static final short GEOMETRY__PCONNECTIONSITESDIR = 338;
+       public static final short GEOMETRY__XLIMO = 339;
+       public static final short GEOMETRY__YLIMO = 340;
+       public static final short GEOMETRY__PADJUSTHANDLES = 341;
+       public static final short GEOMETRY__PGUIDES = 342;
+       public static final short GEOMETRY__PINSCRIBE = 343;
+       public static final short GEOMETRY__CXK = 344;
+       public static final short GEOMETRY__PFRAGMENTS = 345;
        public static final short GEOMETRY__SHADOWok = 378;
        public static final short GEOMETRY__3DOK = 379;
        public static final short GEOMETRY__LINEOK = 380;
@@ -333,6 +343,9 @@ public final class EscherProperties {
 
        private static final Map<Short, EscherPropertyMetaData> properties = initProps();
 
+       private EscherProperties() {
+       }
+
        private static Map<Short, EscherPropertyMetaData> initProps() {
                Map<Short, EscherPropertyMetaData> m = new HashMap<>();
                addProp(m, TRANSFORM__ROTATION, "transform.rotation");
@@ -423,6 +436,15 @@ public final class EscherProperties {
                addProp(m, GEOMETRY__ADJUST8VALUE, "geometry.adjust8value");
                addProp(m, GEOMETRY__ADJUST9VALUE, "geometry.adjust9value");
                addProp(m, GEOMETRY__ADJUST10VALUE, "geometry.adjust10value");
+               addProp(m, GEOMETRY__PCONNECTIONSITES, "geometry.pConnectionSites");
+               addProp(m, GEOMETRY__PCONNECTIONSITESDIR, "geometry.pConnectionSitesDir");
+               addProp(m, GEOMETRY__XLIMO, "geometry.xLimo");
+               addProp(m, GEOMETRY__YLIMO, "geometry.yLimo");
+               addProp(m, GEOMETRY__PADJUSTHANDLES, "geometry.pAdjustHandles");
+               addProp(m, GEOMETRY__PGUIDES, "geometry.pGuides");
+               addProp(m, GEOMETRY__PINSCRIBE, "geometry.pInscribe");
+               addProp(m, GEOMETRY__CXK, "geometry.cxk");
+               addProp(m, GEOMETRY__PFRAGMENTS, "geometry.pFragments");
                addProp(m, GEOMETRY__SHADOWok, "geometry.shadowOK");
                addProp(m, GEOMETRY__3DOK, "geometry.3dok");
                addProp(m, GEOMETRY__LINEOK, "geometry.lineok");
@@ -641,20 +663,20 @@ public final class EscherProperties {
        }
 
        private static void addProp(Map<Short, EscherPropertyMetaData> m, int s, String propName) {
-               m.put(Short.valueOf((short) s), new EscherPropertyMetaData(propName));
+               m.put((short) s, new EscherPropertyMetaData(propName));
        }
 
        private static void addProp(Map<Short, EscherPropertyMetaData> m, int s, String propName, byte type) {
-               m.put(Short.valueOf((short) s), new EscherPropertyMetaData(propName, type));
+               m.put((short) s, new EscherPropertyMetaData(propName, type));
        }
 
        public static String getPropertyName(short propertyId) {
-               EscherPropertyMetaData o = properties.get(Short.valueOf(propertyId));
+               EscherPropertyMetaData o = properties.get(propertyId);
                return o == null ? "unknown" : o.getDescription();
        }
 
        public static byte getPropertyType(short propertyId) {
-               EscherPropertyMetaData escherPropertyMetaData = properties.get(Short.valueOf(propertyId));
+               EscherPropertyMetaData escherPropertyMetaData = properties.get(propertyId);
                return escherPropertyMetaData == null ? 0 : escherPropertyMetaData.getType();
        }
 }
index 6eb60dfb52e24e55f6bbf49040655ab4fef84869..be18f037ab3b6ae0ad6292c81f8a716193c3f518 100644 (file)
 
 package org.apache.poi.sl.draw;
 
-import java.awt.Graphics2D;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Path2D;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.poi.sl.draw.geom.Outline;
-import org.apache.poi.sl.draw.geom.Path;
-import org.apache.poi.sl.usermodel.*;
+import org.apache.poi.sl.usermodel.FreeformShape;
 
+@SuppressWarnings("WeakerAccess")
 public class DrawFreeformShape extends DrawAutoShape {
     public DrawFreeformShape(FreeformShape<?,?> shape) {
         super(shape);
     }
-
-    protected Collection<Outline> computeOutlines(Graphics2D graphics) {
-        List<Outline> lst = new ArrayList<>();
-        FreeformShape<?,?> fsh = (FreeformShape<?, ?>) getShape();
-        Path2D sh = fsh.getPath();
-
-        AffineTransform tx = (AffineTransform)graphics.getRenderingHint(Drawable.GROUP_TRANSFORM);
-        if (tx == null) {
-            tx = new AffineTransform();
-        }
-
-        java.awt.Shape canvasShape = tx.createTransformedShape(sh);
-
-        FillStyle fs = fsh.getFillStyle();
-        StrokeStyle ss = fsh.getStrokeStyle();
-        Path path = new Path(fs != null, ss != null);
-        lst.add(new Outline(canvasShape, path));
-        return lst;
-    }
-
-    @Override
-    protected TextShape<?,? extends TextParagraph<?,?,? extends TextRun>> getShape() {
-        return (TextShape<?,? extends TextParagraph<?,?,? extends TextRun>>)shape;
-    }
 }
index 7ed1d35da2c9ab42647793cd765feb2069169754..35c3aa1207f9ab427116b47587fdf00d8e9c4aec 100644 (file)
@@ -410,14 +410,20 @@ public class DrawSimpleShape extends DrawShape {
         }
         for (Path p : geom) {
 
-            double w = p.getW(), h = p.getH(), scaleX = Units.toPoints(1), scaleY = scaleX;
+            double w = p.getW(), h = p.getH(), scaleX, scaleY;
             if (w == -1) {
                 w = Units.toEMU(anchor.getWidth());
+                scaleX = Units.toPoints(1);
+            } else if (anchor.getWidth() == 0) {
+                scaleX = 1;
             } else {
                 scaleX = anchor.getWidth() / w;
             }
             if (h == -1) {
                 h = Units.toEMU(anchor.getHeight());
+                scaleY = Units.toPoints(1);
+            } else if (anchor.getHeight() == 0) {
+                scaleY = 1;
             } else {
                 scaleY = anchor.getHeight() / h;
             }
index 31847ceeff03f1b8063d5dc3da8aed0482b03589..3ed84b3d184dcc923773fb72ec25b3d0b95084ab 100644 (file)
@@ -22,11 +22,18 @@ package org.apache.poi.sl.draw.geom;
 import java.awt.geom.Rectangle2D;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.regex.Pattern;
 
 public class Context {
-    final Map<String, Double> _ctx = new HashMap<>();
-    final IAdjustableShape _props;
-    final Rectangle2D _anchor;
+    private static final Pattern DOUBLE_PATTERN = Pattern.compile(
+        "[\\x00-\\x20]*[+-]?(NaN|Infinity|((((\\p{Digit}+)(\\.)?((\\p{Digit}+)?)" +
+        "([eE][+-]?(\\p{Digit}+))?)|(\\.(\\p{Digit}+)([eE][+-]?(\\p{Digit}+))?)|" +
+        "(((0[xX](\\p{XDigit}+)(\\.)?)|(0[xX](\\p{XDigit}+)?(\\.)(\\p{XDigit}+)))" +
+        "[pP][+-]?(\\p{Digit}+)))[fFdD]?))[\\x00-\\x20]*");
+
+    private final Map<String, Double> _ctx = new HashMap<>();
+    private final IAdjustableShape _props;
+    private final Rectangle2D _anchor;
     
     public Context(CustomGeometry geom, Rectangle2D anchor, IAdjustableShape props){
         _props = props;
@@ -39,23 +46,22 @@ public class Context {
         }
     }
 
-    public Rectangle2D getShapeAnchor(){
+    Rectangle2D getShapeAnchor(){
         return _anchor;
     }
 
-    public Guide getAdjustValue(String name){
+    Guide getAdjustValue(String name){
         // ignore HSLF props for now ... the results with default value are usually better - see #59004
         return (_props.getClass().getName().contains("hslf")) ? null : _props.getAdjustValue(name);
     }
 
     public double getValue(String key){
-        if(key.matches("(\\+|-)?\\d+")){
+        if(DOUBLE_PATTERN.matcher(key).matches()){
             return Double.parseDouble(key);
         }
 
-        Double val = _ctx.get(key);
         // BuiltInGuide throws IllegalArgumentException if key is not defined
-        return (val != null) ? val : evaluate(BuiltInGuide.valueOf("_"+key));
+        return _ctx.containsKey(key) ? _ctx.get(key) : evaluate(BuiltInGuide.valueOf("_"+key));
     }
 
     public double evaluate(Formula fmla){
index 2a1580a7da4b1ccd2acbcff070291fe765cdbd98..42ae10ae9a1fc01541f8fdb907e541c9a0835529 100644 (file)
@@ -24,16 +24,15 @@ public interface FreeformShape<
     P extends TextParagraph<S,P,? extends TextRun>
 > extends AutoShape<S,P> {
     /**
-     * Gets the shape path.
-     * <p>
-     *     The path is translated in the shape's coordinate system, i.e.
-     *     freeform.getPath().getBounds2D() equals to freeform.getAnchor()
-     *     (small discrepancies are possible due to rounding errors)
-     * </p>
+     * Gets the shape path.<p>
+     *
+     * The path is translated in the shape's coordinate system, i.e.
+     * freeform.getPath2D().getBounds2D() equals to freeform.getAnchor()
+     * (small discrepancies are possible due to rounding errors)
      *
      * @return the path
      */
-    Path2D.Double getPath();
+    Path2D getPath();
 
     /**
      * Set the shape path
@@ -41,5 +40,5 @@ public interface FreeformShape<
      * @param path  shape outline
      * @return the number of points written
      */
-    int setPath(Path2D.Double path);
+    int setPath(Path2D path);
 }
index da0a877cf4a63578cd948efb328996fde8e61e58..709e3f10cc517c9cd29666bad825a68ba12a44a2 100644 (file)
@@ -127,7 +127,7 @@ public class Units {
         points /= MASTER_DPI;
         return points;
     }
-    
+
     public static int pointsToMaster(double points) {
         points *= MASTER_DPI;
         points /= POINT_DPI;
index 54acd2b7bacc757497f6278c0a5b8625d57929b0..8c41fe1b93ff8de0f409bbf07ccf63f3c9aa0849 100644 (file)
@@ -24,6 +24,12 @@ import java.awt.geom.Path2D;
 import java.awt.geom.PathIterator;
 import java.awt.geom.Rectangle2D;
 
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.poi.ooxml.POIXMLTypeLoader;
+import org.apache.poi.sl.draw.geom.CustomGeometry;
+import org.apache.poi.sl.draw.geom.PresetGeometries;
 import org.apache.poi.sl.usermodel.FreeformShape;
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.POILogFactory;
@@ -31,6 +37,7 @@ import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlObject;
+import org.apache.xmlbeans.XmlOptions;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTAdjPoint2D;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTCustomGeometry2D;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomRect;
@@ -61,7 +68,7 @@ public class XSLFFreeformShape extends XSLFAutoShape
     }
 
     @Override
-    public int setPath(final Path2D.Double path) {
+    public int setPath(final Path2D path) {
         final CTPath2D ctPath = CTPath2D.Factory.newInstance();
 
         final Rectangle2D bounds = path.getBounds2D();
@@ -117,6 +124,30 @@ public class XSLFFreeformShape extends XSLFAutoShape
         return numPoints;
     }
 
+    /**
+     * @return definition of the shape geometry
+     */
+    @Override
+    public CustomGeometry getGeometry() {
+        final XmlObject xo = getShapeProperties();
+        if (!(xo instanceof CTShapeProperties)) {
+            return null;
+        }
+
+        XmlOptions xop = new XmlOptions(POIXMLTypeLoader.DEFAULT_XML_OPTIONS);
+        xop.setSaveOuter();
+
+        XMLStreamReader staxReader = ((CTShapeProperties)xo).getCustGeom().newXMLStreamReader(xop);
+        CustomGeometry custGeo = PresetGeometries.convertCustomGeometry(staxReader);
+        try {
+            staxReader.close();
+        } catch (XMLStreamException e) {
+            LOG.log(POILogger.WARN,
+                    "An error occurred while closing a Custom Geometry XML Stream Reader: " + e.getMessage());
+        }
+
+        return custGeo;
+    }
 
     @Override
     public Path2D.Double getPath() {
index 4e54712a778bd861adf6c8882c4b88086b82a1f3..89f312327bda8724366c76160c27462847bccd13 100644 (file)
@@ -716,7 +716,6 @@ public abstract class XSLFSimpleShape extends XSLFShape
     }
 
     /**
-     *
      * @return definition of the shape geometry
      */
     @Override
index 199a9f6286eab8d4b0f30c7dd68cf46b0b94741a..9a206a48caf2886047523353dfb2c5a1807e77da 100644 (file)
@@ -47,7 +47,9 @@ public class TestPPTX2PNG {
     private static final POIDataSamples samples = POIDataSamples.getSlideShowInstance();
     private static final File basedir = null;
     private static final String files =
-        "53446.ppt, alterman_security.ppt, alterman_security.pptx, KEY02.pptx, themes.pptx, backgrounds.pptx, layouts.pptx, sample.pptx, shapes.pptx, 54880_chinese.ppt, keyframes.pptx";
+        "53446.ppt, alterman_security.ppt, alterman_security.pptx, KEY02.pptx, themes.pptx, " +
+        "backgrounds.pptx, layouts.pptx, sample.pptx, shapes.pptx, 54880_chinese.ppt, keyframes.pptx," +
+        "customGeo.pptx, customGeo.ppt";
 
         
     
index 910c8a0adc192e3310daf457a77667b5b7fe4e5a..3a3fa7afb36771e0afcec44f43f2607f7d85c62e 100644 (file)
 
 package org.apache.poi.hslf.usermodel;
 
+import java.awt.geom.Arc2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.poi.ddf.AbstractEscherOptRecord;
+import org.apache.poi.ddf.EscherArrayProperty;
 import org.apache.poi.ddf.EscherContainerRecord;
 import org.apache.poi.ddf.EscherProperties;
-import org.apache.poi.sl.usermodel.*;
+import org.apache.poi.ddf.EscherProperty;
+import org.apache.poi.ddf.EscherSimpleProperty;
+import org.apache.poi.sl.draw.binding.CTAdjPoint2D;
+import org.apache.poi.sl.draw.binding.CTCustomGeometry2D;
+import org.apache.poi.sl.draw.binding.CTPath2D;
+import org.apache.poi.sl.draw.binding.CTPath2DArcTo;
+import org.apache.poi.sl.draw.binding.CTPath2DCubicBezierTo;
+import org.apache.poi.sl.draw.binding.CTPath2DLineTo;
+import org.apache.poi.sl.draw.binding.CTPath2DList;
+import org.apache.poi.sl.draw.binding.CTPath2DMoveTo;
+import org.apache.poi.sl.draw.binding.ObjectFactory;
+import org.apache.poi.sl.draw.geom.CustomGeometry;
+import org.apache.poi.sl.usermodel.AutoShape;
+import org.apache.poi.sl.usermodel.ShapeContainer;
+import org.apache.poi.sl.usermodel.ShapeType;
+import org.apache.poi.sl.usermodel.VerticalAlignment;
 import org.apache.poi.ss.usermodel.ShapeTypes;
+import org.apache.poi.util.BitField;
+import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
 
 /**
- * Represents an AutoShape.
- * <p>
+ * Represents an AutoShape.<p>
+ *
  * AutoShapes are drawing objects with a particular shape that may be customized through smart resizing and adjustments.
  * See {@link ShapeTypes}
- * </p>
- *
- *  @author Yegor Kozlov
  */
 public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,HSLFTextParagraph> {
+    private static final POILogger LOG = POILogFactory.getLogger(HSLFAutoShape.class);
+
+    static final byte[] SEGMENTINFO_MOVETO   = new byte[]{0x00, 0x40};
+    static final byte[] SEGMENTINFO_LINETO   = new byte[]{0x00, (byte)0xAC};
+    static final byte[] SEGMENTINFO_ESCAPE   = new byte[]{0x01, 0x00};
+    static final byte[] SEGMENTINFO_ESCAPE2  = new byte[]{0x01, 0x20};
+    static final byte[] SEGMENTINFO_CUBICTO  = new byte[]{0x00, (byte)0xAD};
+    // OpenOffice inserts 0xB3 instead of 0xAD.
+    // protected static final byte[] SEGMENTINFO_CUBICTO2 = new byte[]{0x00, (byte)0xB3};
+    static final byte[] SEGMENTINFO_CLOSE    = new byte[]{0x01, (byte)0x60};
+    static final byte[] SEGMENTINFO_END      = new byte[]{0x00, (byte)0x80};
+
+    private static final BitField PATH_INFO = BitFieldFactory.getInstance(0xE000);
+    private static final BitField ESCAPE_INFO = BitFieldFactory.getInstance(0x1F00);
+
+    enum PathInfo {
+        lineTo(0),curveTo(1),moveTo(2),close(3),end(4),escape(5),clientEscape(6);
+        private final int flag;
+        PathInfo(int flag) {
+            this.flag = flag;
+        }
+        public int getFlag() {
+            return flag;
+        }
+        static PathInfo valueOf(int flag) {
+            for (PathInfo v : values()) {
+                if (v.flag == flag) {
+                    return v;
+                }
+            }
+            return null;
+        }
+    }
+
+    enum EscapeInfo {
+        EXTENSION(0x0000),
+        ANGLE_ELLIPSE_TO(0x0001),
+        ANGLE_ELLIPSE(0x0002),
+        ARC_TO(0x0003),
+        ARC(0x0004),
+        CLOCKWISE_ARC_TO(0x0005),
+        CLOCKWISE_ARC(0x0006),
+        ELLIPTICAL_QUADRANT_X(0x0007),
+        ELLIPTICAL_QUADRANT_Y(0x0008),
+        QUADRATIC_BEZIER(0x0009),
+        NO_FILL(0X000A),
+        NO_LINE(0X000B),
+        AUTO_LINE(0X000C),
+        AUTO_CURVE(0X000D),
+        CORNER_LINE(0X000E),
+        CORNER_CURVE(0X000F),
+        SMOOTH_LINE(0X0010),
+        SMOOTH_CURVE(0X0011),
+        SYMMETRIC_LINE(0X0012),
+        SYMMETRIC_CURVE(0X0013),
+        FREEFORM(0X0014),
+        FILL_COLOR(0X0015),
+        LINE_COLOR(0X0016);
+
+        private final int flag;
+        EscapeInfo(int flag) {
+            this.flag = flag;
+        }
+        public int getFlag() {
+            return flag;
+        }
+        static EscapeInfo valueOf(int flag) {
+            for (EscapeInfo v : values()) {
+                if (v.flag == flag) {
+                    return v;
+                }
+            }
+            return null;
+        }
+    }
 
     protected HSLFAutoShape(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
         super(escherRecord, parent);
@@ -72,13 +173,11 @@ public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,
     }
 
     /**
-     * Gets adjust value which controls smart resizing of the auto-shape.
+     * Gets adjust value which controls smart resizing of the auto-shape.<p>
      *
-     * <p>
      * The adjustment values are given in shape coordinates:
      * the origin is at the top-left, positive-x is to the right, positive-y is down.
      * The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant).
-     * </p>
      *
      * @param idx the adjust index in the [0, 9] range
      * @return the adjustment value
@@ -90,13 +189,11 @@ public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,
     }
 
     /**
-     * Sets adjust value which controls smart resizing of the auto-shape.
+     * Sets adjust value which controls smart resizing of the auto-shape.<p>
      *
-     * <p>
      * The adjustment values are given in shape coordinates:
      * the origin is at the top-left, positive-x is to the right, positive-y is down.
      * The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant).
-     * </p>
      *
      * @param idx the adjust index in the [0, 9] range
      * @param val the adjustment value
@@ -106,4 +203,278 @@ public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,
 
         setEscherProperty((short)(EscherProperties.GEOMETRY__ADJUSTVALUE + idx), val);
     }
+
+    @Override
+    public CustomGeometry getGeometry() {
+        return getGeometry(new Path2D.Double());
+    }
+
+    CustomGeometry getGeometry(Path2D path2D) {
+        final ObjectFactory of = new ObjectFactory();
+        final CTCustomGeometry2D cusGeo = of.createCTCustomGeometry2D();
+        cusGeo.setAvLst(of.createCTGeomGuideList());
+        cusGeo.setGdLst(of.createCTGeomGuideList());
+        cusGeo.setAhLst(of.createCTAdjustHandleList());
+        cusGeo.setCxnLst(of.createCTConnectionSiteList());
+
+        final AbstractEscherOptRecord opt = getEscherOptRecord();
+
+        EscherArrayProperty verticesProp = getShapeProp(opt, EscherProperties.GEOMETRY__VERTICES);
+        EscherArrayProperty segmentsProp = getShapeProp(opt, EscherProperties.GEOMETRY__SEGMENTINFO);
+
+        // return empty path if either GEOMETRY__VERTICES or GEOMETRY__SEGMENTINFO is missing, see Bugzilla 54188
+
+        //sanity check
+        if(verticesProp == null) {
+            LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__VERTICES ");
+            return super.getGeometry();
+        }
+        if(segmentsProp == null) {
+            LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__SEGMENTINFO ");
+            return super.getGeometry();
+        }
+
+        final Iterator<byte[]> vertIter = verticesProp.iterator();
+        final Iterator<byte[]> segIter = segmentsProp.iterator();
+        final int[] xyPoints = new int[2];
+        boolean isClosed = false;
+
+        final CTPath2DList pathLst = of.createCTPath2DList();
+        final CTPath2D pathCT = of.createCTPath2D();
+        final List<Object> moveLst = pathCT.getCloseOrMoveToOrLnTo();
+        pathLst.getPath().add(pathCT);
+        cusGeo.setPathLst(pathLst);
+
+        while (segIter.hasNext()) {
+            byte[] segElem = segIter.next();
+            HSLFFreeformShape.PathInfo pi = getPathInfo(segElem);
+            if (pi == null) {
+                continue;
+            }
+            switch (pi) {
+                case escape: {
+                    handleEscapeInfo(pathCT, path2D, segElem, vertIter);
+                    break;
+                }
+                case moveTo:
+                    if (vertIter.hasNext()) {
+                        final CTPath2DMoveTo m = of.createCTPath2DMoveTo();
+                        m.setPt(fillPoint(vertIter.next(), xyPoints));
+                        moveLst.add(m);
+                        path2D.moveTo(xyPoints[0], xyPoints[1]);
+                    }
+                    break;
+                case lineTo:
+                    if (vertIter.hasNext()) {
+                        final CTPath2DLineTo m = of.createCTPath2DLineTo();
+                        m.setPt(fillPoint(vertIter.next(), xyPoints));
+                        moveLst.add(m);
+                        path2D.lineTo(xyPoints[0], xyPoints[1]);
+                    }
+                    break;
+                case curveTo: {
+                    final CTPath2DCubicBezierTo m = of.createCTPath2DCubicBezierTo();
+                    List<CTAdjPoint2D> mLst = m.getPt();
+
+                    int[] pts = new int[6];
+
+                    for (int i=0; vertIter.hasNext() && i<3; i++) {
+                        mLst.add(fillPoint(vertIter.next(), xyPoints));
+                        pts[i*2] = xyPoints[0];
+                        pts[i*2+1] = xyPoints[1];
+                        if (i == 2) {
+                            moveLst.add(m);
+                            path2D.curveTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
+                        }
+                    }
+                    break;
+                }
+                case close:
+                    moveLst.add(of.createCTPath2DClose());
+                    path2D.closePath();
+                    isClosed = true;
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        EscherSimpleProperty shapePath = getShapeProp(opt, EscherProperties.GEOMETRY__SHAPEPATH);
+        HSLFFreeformShape.ShapePath sp = HSLFFreeformShape.ShapePath.valueOf(shapePath == null ? 1 : shapePath.getPropertyValue());
+        if ((sp == HSLFFreeformShape.ShapePath.LINES_CLOSED || sp == HSLFFreeformShape.ShapePath.CURVES_CLOSED) && !isClosed) {
+            moveLst.add(of.createCTPath2DClose());
+            path2D.closePath();
+        }
+
+        EscherSimpleProperty geoLeft = getShapeProp(opt, EscherProperties.GEOMETRY__LEFT);
+        EscherSimpleProperty geoRight = getShapeProp(opt, EscherProperties.GEOMETRY__RIGHT);
+        EscherSimpleProperty geoTop = getShapeProp(opt, EscherProperties.GEOMETRY__TOP);
+        EscherSimpleProperty geoBottom = getShapeProp(opt, EscherProperties.GEOMETRY__BOTTOM);
+
+        final Rectangle2D bounds;
+        if (geoLeft != null && geoRight != null && geoTop != null && geoBottom != null) {
+            bounds = new Rectangle2D.Double();
+            bounds.setFrameFromDiagonal(
+                new Point2D.Double(geoLeft.getPropertyValue(), geoTop.getPropertyValue()),
+                new Point2D.Double(geoRight.getPropertyValue(), geoBottom.getPropertyValue())
+            );
+        } else {
+            bounds = path2D.getBounds2D();
+        }
+
+        pathCT.setW((int)Math.rint(bounds.getWidth()));
+        pathCT.setH((int)Math.rint(bounds.getHeight()));
+
+        return new CustomGeometry(cusGeo);
+    }
+
+    private void handleEscapeInfo(CTPath2D pathCT, Path2D path2D, byte[] segElem, Iterator<byte[]> vertIter) {
+        final ObjectFactory of = new ObjectFactory();
+        HSLFFreeformShape.EscapeInfo ei = getEscapeInfo(segElem);
+        switch (ei) {
+            case EXTENSION:
+                break;
+            case ANGLE_ELLIPSE_TO:
+                break;
+            case ANGLE_ELLIPSE:
+                break;
+            case ARC_TO: {
+                // The first two POINT values specify the bounding rectangle of the ellipse.
+                // The second two POINT values specify the radial vectors for the ellipse.
+                // The radial vectors are cast from the center of the bounding rectangle.
+                // The path starts at the POINT where the first radial vector intersects the
+                // bounding rectangle and goes to the POINT where the second radial vector
+                // intersects the bounding rectangle. The drawing direction is always counterclockwise.
+                // If the path has already been started, a line is drawn from the last POINT to
+                // the starting POINT of the arc; otherwise, a new path is started.
+                // The number of arc segments drawn equals the number of segments divided by four.
+
+                int[] r1 = new int[2], r2 = new int[2], start = new int[2], end = new int[2];
+                fillPoint(vertIter.next(), r1);
+                fillPoint(vertIter.next(), r2);
+                fillPoint(vertIter.next(), start);
+                fillPoint(vertIter.next(), end);
+
+                Arc2D arc2D = new Arc2D.Double();
+                Rectangle2D.Double bounds = new Rectangle2D.Double();
+                bounds.setFrameFromDiagonal(xy2p(r1), xy2p(r2));
+                arc2D.setFrame(bounds);
+                arc2D.setAngles(xy2p(start), xy2p(end));
+                path2D.append(arc2D, true);
+
+
+                CTPath2DArcTo arcTo = of.createCTPath2DArcTo();
+                arcTo.setHR(d2s(bounds.getHeight()/2.0));
+                arcTo.setWR(d2s(bounds.getWidth()/2.0));
+
+                arcTo.setStAng(d2s(-arc2D.getAngleStart()*60000.));
+                arcTo.setSwAng(d2s(-arc2D.getAngleExtent()*60000.));
+
+                pathCT.getCloseOrMoveToOrLnTo().add(arcTo);
+
+                break;
+            }
+            case ARC:
+                break;
+            case CLOCKWISE_ARC_TO:
+                break;
+            case CLOCKWISE_ARC:
+                break;
+            case ELLIPTICAL_QUADRANT_X:
+                break;
+            case ELLIPTICAL_QUADRANT_Y:
+                break;
+            case QUADRATIC_BEZIER:
+                break;
+            case NO_FILL:
+                break;
+            case NO_LINE:
+                break;
+            case AUTO_LINE:
+                break;
+            case AUTO_CURVE:
+                break;
+            case CORNER_LINE:
+                break;
+            case CORNER_CURVE:
+                break;
+            case SMOOTH_LINE:
+                break;
+            case SMOOTH_CURVE:
+                break;
+            case SYMMETRIC_LINE:
+                break;
+            case SYMMETRIC_CURVE:
+                break;
+            case FREEFORM:
+                break;
+            case FILL_COLOR:
+                break;
+            case LINE_COLOR:
+                break;
+            default:
+                break;
+        }
+    }
+
+    private static String d2s(double d) {
+        return Integer.toString((int)Math.rint(d));
+    }
+
+    private static Point2D xy2p(int[] xyPoints) {
+        return new Point2D.Double(xyPoints[0],xyPoints[1]);
+    }
+
+    private static HSLFFreeformShape.PathInfo getPathInfo(byte[] elem) {
+        int elemUS = LittleEndian.getUShort(elem, 0);
+        int pathInfo = PATH_INFO.getValue(elemUS);
+        return HSLFFreeformShape.PathInfo.valueOf(pathInfo);
+    }
+
+    private static HSLFFreeformShape.EscapeInfo getEscapeInfo(byte[] elem) {
+        int elemUS = LittleEndian.getUShort(elem, 0);
+        int escInfo = ESCAPE_INFO.getValue(elemUS);
+        return HSLFFreeformShape.EscapeInfo.valueOf(escInfo);
+    }
+
+
+    private static <T extends EscherProperty> T getShapeProp(AbstractEscherOptRecord opt, int propId) {
+        T prop = getEscherProperty(opt, (short)(propId + 0x4000));
+        if (prop == null) {
+            prop = getEscherProperty(opt, propId);
+        }
+        return prop;
+    }
+
+    private CTAdjPoint2D fillPoint(byte[] xyMaster, int[] xyPoints) {
+        if (xyMaster == null || xyPoints == null) {
+            LOG.log(POILogger.WARN, "Master bytes or points not set - ignore point");
+            return null;
+        }
+        if ((xyMaster.length != 4 && xyMaster.length != 8) || xyPoints.length != 2) {
+            LOG.log(POILogger.WARN, "Invalid number of master bytes for a single point - ignore point");
+            return null;
+        }
+
+        int x, y;
+        if (xyMaster.length == 4) {
+            x = LittleEndian.getShort(xyMaster, 0);
+            y = LittleEndian.getShort(xyMaster, 2);
+        } else {
+            x = LittleEndian.getInt(xyMaster, 0);
+            y = LittleEndian.getInt(xyMaster, 4);
+        }
+
+        xyPoints[0] = x;
+        xyPoints[1] = y;
+
+        return toPoint(xyPoints);
+    }
+
+    private static CTAdjPoint2D toPoint(int[] xyPoints) {
+        CTAdjPoint2D pt = new CTAdjPoint2D();
+        pt.setX(Integer.toString(xyPoints[0]));
+        pt.setY(Integer.toString(xyPoints[1]));
+        return pt;
+    }
 }
index ee0a2d07316a9ee2ef7b09056ae13752b6376c23..63885af3f3777c4392b579364f01244e8d9df6c7 100644 (file)
@@ -49,60 +49,61 @@ import org.apache.poi.util.Units;
 /**
  * Represents functionality provided by the 'Fill Effects' dialog in PowerPoint.
  */
+@SuppressWarnings("WeakerAccess")
 public final class HSLFFill {
     private static final POILogger LOG = POILogFactory.getLogger(HSLFFill.class);
 
     /**
      *  Fill with a solid color
      */
-    public static final int FILL_SOLID = 0;
+    static final int FILL_SOLID = 0;
 
     /**
      *  Fill with a pattern (bitmap)
      */
-    public static final int FILL_PATTERN = 1;
+    static final int FILL_PATTERN = 1;
 
     /**
      *  A texture (pattern with its own color map)
      */
-    public static final int FILL_TEXTURE = 2;
+    static final int FILL_TEXTURE = 2;
 
     /**
      *  Center a picture in the shape
      */
-    public static final int FILL_PICTURE = 3;
+    static final int FILL_PICTURE = 3;
 
     /**
      *  Shade from start to end points
      */
-    public static final int FILL_SHADE = 4;
+    static final int FILL_SHADE = 4;
 
     /**
      *  Shade from bounding rectangle to end point
      */
-    public static final int FILL_SHADE_CENTER = 5;
+    static final int FILL_SHADE_CENTER = 5;
 
     /**
      *  Shade from shape outline to end point
      */
-    public static final int FILL_SHADE_SHAPE = 6;
+    static final int FILL_SHADE_SHAPE = 6;
 
     /**
      *  Similar to FILL_SHADE, but the fill angle
      *  is additionally scaled by the aspect ratio of
      *  the shape. If shape is square, it is the same as FILL_SHADE
      */
-    public static final int FILL_SHADE_SCALE = 7;
+    static final int FILL_SHADE_SCALE = 7;
 
     /**
      *  shade to title
      */
-    public static final int FILL_SHADE_TITLE = 8;
+    static final int FILL_SHADE_TITLE = 8;
 
     /**
      *  Use the background fill color/pattern
      */
-    public static final int FILL_BACKGROUND = 9;
+    static final int FILL_BACKGROUND = 9;
 
     /**
      * A bit that specifies whether the RecolorFillAsPicture bit is set.
@@ -214,7 +215,7 @@ public final class HSLFFill {
     private HSLFShape shape;
 
     /**
-     * Construct a <code>Fill</code> object for a shape.
+     * Construct a {@code Fill} object for a shape.
      * Fill information will be read from shape's escher properties.
      *
      * @param shape the shape this background applies to
@@ -279,7 +280,7 @@ public final class HSLFFill {
             
             @Override
             public ColorStyle[] getGradientColors() {
-                ColorStyle cs[];
+                ColorStyle[] cs;
                 if (colorCnt == 0) {
                     cs = new ColorStyle[2];
                     cs[0] = wrapColor(getBackgroundColor());
@@ -288,7 +289,7 @@ public final class HSLFFill {
                     cs = new ColorStyle[colorCnt];
                     int idx = 0;
                     // TODO: handle palette colors and alpha(?) value 
-                    for (byte data[] : ep) {
+                    for (byte[] data : ep) {
                         EscherColorRef ecr = new EscherColorRef(data, 0, 4);
                         cs[idx++] = wrapColor(shape.getColor(ecr));
                     }
@@ -302,13 +303,13 @@ public final class HSLFFill {
             
             @Override
             public float[] getGradientFractions() {
-                float frc[];
+                float[] frc;
                 if (colorCnt == 0) {
                     frc = new float[]{0, 1};
                 } else {
                     frc = new float[colorCnt];
                     int idx = 0;
-                    for (byte data[] : ep) {
+                    for (byte[] data : ep) {
                         double pos = Units.fixedPointToDouble(LittleEndian.getInt(data, 4));
                         frc[idx++] = (float)pos;
                     }
@@ -354,7 +355,7 @@ public final class HSLFFill {
 
     /**
      * Returns fill type.
-     * Must be one of the <code>FILL_*</code> constants defined in this class.
+     * Must be one of the {@code FILL_*} constants defined in this class.
      *
      * @return type of fill
      */
@@ -364,9 +365,7 @@ public final class HSLFFill {
         return prop == null ? FILL_SOLID : prop.getPropertyValue();
     }
 
-    /**
-     */
-    protected void afterInsert(HSLFSheet sh){
+    void afterInsert(HSLFSheet sh){
         AbstractEscherOptRecord opt = shape.getEscherOptRecord();
         EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
         if(p != null) {
@@ -379,7 +378,7 @@ public final class HSLFFill {
     }
 
     @SuppressWarnings("resource")
-    protected EscherBSERecord getEscherBSERecord(int idx){
+    EscherBSERecord getEscherBSERecord(int idx){
         HSLFSheet sheet = shape.getSheet();
         if(sheet == null) {
             LOG.log(POILogger.DEBUG, "Fill has not yet been assigned to a sheet");
@@ -399,7 +398,7 @@ public final class HSLFFill {
 
     /**
      * Sets fill type.
-     * Must be one of the <code>FILL_*</code> constants defined in this class.
+     * Must be one of the {@code FILL_*} constants defined in this class.
      *
      * @param type type of the fill
      */
@@ -415,10 +414,10 @@ public final class HSLFFill {
         AbstractEscherOptRecord opt = shape.getEscherOptRecord();
         EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
         int propVal = (p == null) ? 0 : p.getPropertyValue();
-        
+
         return (FILL_USE_FILLED.isSet(propVal) && !FILL_FILLED.isSet(propVal))
             ? null
-            : shape.getColor(EscherProperties.FILL__FILLCOLOR, EscherProperties.FILL__FILLOPACITY, -1);
+            : shape.getColor(EscherProperties.FILL__FILLCOLOR, EscherProperties.FILL__FILLOPACITY);
     }
 
     /**
@@ -462,7 +461,7 @@ public final class HSLFFill {
 
         return (FILL_USE_FILLED.isSet(propVal) && !FILL_FILLED.isSet(propVal))
             ? null
-            : shape.getColor(EscherProperties.FILL__FILLBACKCOLOR, EscherProperties.FILL__FILLOPACITY, -1);
+            : shape.getColor(EscherProperties.FILL__FILLBACKCOLOR, EscherProperties.FILL__FILLOPACITY);
     }
 
     /**
@@ -480,7 +479,7 @@ public final class HSLFFill {
     }
 
     /**
-     * <code>PictureData</code> object used in a texture, pattern of picture fill.
+     * {@code PictureData} object used in a texture, pattern of picture fill.
      */
     @SuppressWarnings("resource")
     public HSLFPictureData getPictureData(){
index 0b2d322b6319fa0b8f2d0248bdd08081fa72aad0..10eeb7b19c2f1ebca7b8a886a82e48390199f841 100644 (file)
@@ -23,20 +23,16 @@ import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 
 import org.apache.poi.ddf.AbstractEscherOptRecord;
 import org.apache.poi.ddf.EscherArrayProperty;
 import org.apache.poi.ddf.EscherContainerRecord;
 import org.apache.poi.ddf.EscherProperties;
-import org.apache.poi.ddf.EscherProperty;
 import org.apache.poi.ddf.EscherSimpleProperty;
 import org.apache.poi.sl.usermodel.FreeformShape;
 import org.apache.poi.sl.usermodel.ShapeContainer;
 import org.apache.poi.sl.usermodel.ShapeType;
-import org.apache.poi.util.BitField;
-import org.apache.poi.util.BitFieldFactory;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
@@ -53,79 +49,6 @@ import org.apache.poi.util.Units;
 public final class HSLFFreeformShape extends HSLFAutoShape implements FreeformShape<HSLFShape,HSLFTextParagraph> {
     private static final POILogger LOG = POILogFactory.getLogger(HSLFFreeformShape.class);
 
-    private static final byte[] SEGMENTINFO_MOVETO   = new byte[]{0x00, 0x40};
-    private static final byte[] SEGMENTINFO_LINETO   = new byte[]{0x00, (byte)0xAC};
-    private static final byte[] SEGMENTINFO_ESCAPE   = new byte[]{0x01, 0x00};
-    private static final byte[] SEGMENTINFO_ESCAPE2  = new byte[]{0x01, 0x20};
-    private static final byte[] SEGMENTINFO_CUBICTO  = new byte[]{0x00, (byte)0xAD};
-    // OpenOffice inserts 0xB3 instead of 0xAD.
-    // private static final byte[] SEGMENTINFO_CUBICTO2 = new byte[]{0x00, (byte)0xB3};
-    private static final byte[] SEGMENTINFO_CLOSE    = new byte[]{0x01, (byte)0x60};
-    private static final byte[] SEGMENTINFO_END      = new byte[]{0x00, (byte)0x80};
-
-    private static final BitField PATH_INFO = BitFieldFactory.getInstance(0xE000);
-    // private static final BitField ESCAPE_INFO = BitFieldFactory.getInstance(0x1F00);
-
-    enum PathInfo {
-        lineTo(0),curveTo(1),moveTo(2),close(3),end(4),escape(5),clientEscape(6);
-        private final int flag;
-        PathInfo(int flag) {
-            this.flag = flag;
-        }
-        public int getFlag() {
-            return flag;
-        }
-        static PathInfo valueOf(int flag) {
-            for (PathInfo v : values()) {
-                if (v.flag == flag) {
-                    return v;
-                }
-            }
-            return null;
-        }
-    }
-
-    enum EscapeInfo {
-        EXTENSION(0x0000),
-        ANGLE_ELLIPSE_TO(0x0001),
-        ANGLE_ELLIPSE(0x0002),
-        ARC_TO(0x0003),
-        ARC(0x0004),
-        CLOCKWISE_ARC_TO(0x0005),
-        CLOCKWISE_ARC(0x0006),
-        ELLIPTICAL_QUADRANT_X(0x0007),
-        ELLIPTICAL_QUADRANT_Y(0x0008),
-        QUADRATIC_BEZIER(0x0009),
-        NO_FILL(0X000A),
-        NO_LINE(0X000B),
-        AUTO_LINE(0X000C),
-        AUTO_CURVE(0X000D),
-        CORNER_LINE(0X000E),
-        CORNER_CURVE(0X000F),
-        SMOOTH_LINE(0X0010),
-        SMOOTH_CURVE(0X0011),
-        SYMMETRIC_LINE(0X0012),
-        SYMMETRIC_CURVE(0X0013),
-        FREEFORM(0X0014),
-        FILL_COLOR(0X0015),
-        LINE_COLOR(0X0016);
-
-        private final int flag;
-        EscapeInfo(int flag) {
-            this.flag = flag;
-        }
-        public int getFlag() {
-            return flag;
-        }
-        static EscapeInfo valueOf(int flag) {
-            for (EscapeInfo v : values()) {
-                if (v.flag == flag) {
-                    return v;
-                }
-            }
-            return null;
-        }
-    }
 
     enum ShapePath {
         LINES(0),
@@ -182,9 +105,9 @@ public final class HSLFFreeformShape extends HSLFAutoShape implements FreeformSh
     }
 
     @Override
-    public int setPath(Path2D.Double path) {
+    public int setPath(Path2D path) {
         Rectangle2D bounds = path.getBounds2D();
-        PathIterator it = path.getPathIterator(new AffineTransform());
+        PathIterator it = path.getPathIterator(null);
 
         List<byte[]> segInfo = new ArrayList<>();
         List<Point2D.Double> pntInfo = new ArrayList<>();
@@ -275,187 +198,24 @@ public final class HSLFFreeformShape extends HSLFAutoShape implements FreeformSh
     }
 
     @Override
-    public Path2D.Double getPath(){
-        AbstractEscherOptRecord opt = getEscherOptRecord();
-
-        EscherArrayProperty verticesProp = getShapeProp(opt, EscherProperties.GEOMETRY__VERTICES);
-        EscherArrayProperty segmentsProp = getShapeProp(opt, EscherProperties.GEOMETRY__SEGMENTINFO);
-
-        // return empty path if either GEOMETRY__VERTICES or GEOMETRY__SEGMENTINFO is missing, see Bugzilla 54188
-        Path2D.Double path = new Path2D.Double();
+    public Path2D getPath(){
+        Path2D path2D = new Path2D.Double();
+        getGeometry(path2D);
 
-        //sanity check
-        if(verticesProp == null) {
-            LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__VERTICES ");
-            return path;
-        }
-        if(segmentsProp == null) {
-            LOG.log(POILogger.WARN, "Freeform is missing GEOMETRY__SEGMENTINFO ");
-            return path;
-        }
-
-        Iterator<byte[]> vertIter = verticesProp.iterator();
-        Iterator<byte[]> segIter = segmentsProp.iterator();
-        double xyPoints[] = new double[2];
-        
-        while (vertIter.hasNext() && segIter.hasNext()) {
-            byte[] segElem = segIter.next();
-            PathInfo pi = getPathInfo(segElem);
-            if (pi != null) {
-                switch (pi) {
-                    case escape: {
-                        // handleEscapeInfo(path, segElem, vertIter);
-                        break;
-                    }
-                    case moveTo: {
-                        fillPoint(vertIter.next(), xyPoints);
-                        double x = xyPoints[0];
-                        double y = xyPoints[1];
-                        path.moveTo(x, y);
-                        break;
-                    }
-                    case curveTo: {
-                        fillPoint(vertIter.next(), xyPoints);
-                        double x1 = xyPoints[0];
-                        double y1 = xyPoints[1];
-                        fillPoint(vertIter.next(), xyPoints);
-                        double x2 = xyPoints[0];
-                        double y2 = xyPoints[1];
-                        fillPoint(vertIter.next(), xyPoints);
-                        double x3 = xyPoints[0];
-                        double y3 = xyPoints[1];
-                        path.curveTo(x1, y1, x2, y2, x3, y3);
-                        break;
-                    }
-                    case lineTo:
-                        if (vertIter.hasNext()) {
-                            fillPoint(vertIter.next(), xyPoints);
-                            double x = xyPoints[0];
-                            double y = xyPoints[1];
-                            path.lineTo(x, y);
-                        }
-                        break;
-                    case close:
-                        path.closePath();
-                        break;
-                    default:
-                        break;
-                }
-            }
-        }
-
-        EscherSimpleProperty shapePath = getShapeProp(opt, EscherProperties.GEOMETRY__SHAPEPATH);
-        ShapePath sp = ShapePath.valueOf(shapePath == null ? 1 : shapePath.getPropertyValue());
-        if (sp == ShapePath.LINES_CLOSED || sp == ShapePath.CURVES_CLOSED) {
-            path.closePath();
-        }
-        
+        Rectangle2D bounds = path2D.getBounds2D();
         Rectangle2D anchor = getAnchor();
-        Rectangle2D bounds = path.getBounds2D();
         AffineTransform at = new AffineTransform();
         at.translate(anchor.getX(), anchor.getY());
         at.scale(
                 anchor.getWidth()/bounds.getWidth(),
                 anchor.getHeight()/bounds.getHeight()
         );
-        return new Path2D.Double(at.createTransformedShape(path));
-    }
-    
-    private void fillPoint(byte xyMaster[], double xyPoints[]) {
-        if (xyMaster == null || xyPoints == null) {
-            LOG.log(POILogger.WARN, "Master bytes or points not set - ignore point");
-            return;
-        }
-        if ((xyMaster.length != 4 && xyMaster.length != 8) || xyPoints.length != 2) {
-            LOG.log(POILogger.WARN, "Invalid number of master bytes for a single point - ignore point");
-            return;
-        }
-        
-        int x, y;
-        if (xyMaster.length == 4) {
-            x = LittleEndian.getShort(xyMaster, 0);
-            y = LittleEndian.getShort(xyMaster, 2);
-        } else {
-            x = LittleEndian.getInt(xyMaster, 0);
-            y = LittleEndian.getInt(xyMaster, 4);
-        }
-        
-        xyPoints[0] = Units.masterToPoints(x);
-        xyPoints[1] = Units.masterToPoints(y);
-    }
-    
-    private static <T extends EscherProperty> T getShapeProp(AbstractEscherOptRecord opt, int propId) {
-        T prop = getEscherProperty(opt, (short)(propId + 0x4000));
-        if (prop == null) {
-            prop = getEscherProperty(opt, propId);
-        }
-        return prop;
-    }
-    
-//    private void handleEscapeInfo(Path2D path, byte segElem[], Iterator<byte[]> vertIter) {
-//        EscapeInfo ei = getEscapeInfo(segElem);
-//        switch (ei) {
-//            case EXTENSION:
-//                break;
-//            case ANGLE_ELLIPSE_TO:
-//                break;
-//            case ANGLE_ELLIPSE:
-//                break;
-//            case ARC_TO:
-//                break;
-//            case ARC:
-//                break;
-//            case CLOCKWISE_ARC_TO:
-//                break;
-//            case CLOCKWISE_ARC:
-//                break;
-//            case ELLIPTICAL_QUADRANT_X:
-//                break;
-//            case ELLIPTICAL_QUADRANT_Y:
-//                break;
-//            case QUADRATIC_BEZIER:
-//                break;
-//            case NO_FILL:
-//                break;
-//            case NO_LINE:
-//                break;
-//            case AUTO_LINE:
-//                break;
-//            case AUTO_CURVE:
-//                break;
-//            case CORNER_LINE:
-//                break;
-//            case CORNER_CURVE:
-//                break;
-//            case SMOOTH_LINE:
-//                break;
-//            case SMOOTH_CURVE:
-//                break;
-//            case SYMMETRIC_LINE:
-//                break;
-//            case SYMMETRIC_CURVE:
-//                break;
-//            case FREEFORM:
-//                break;
-//            case FILL_COLOR:
-//                break;
-//            case LINE_COLOR:
-//                break;
-//            default:
-//                break;
-//        }
-//    }
-    
 
-    private static PathInfo getPathInfo(byte elem[]) {
-        int elemUS = LittleEndian.getUShort(elem, 0);
-        int pathInfo = PATH_INFO.getValue(elemUS);
-        return PathInfo.valueOf(pathInfo);
+        path2D.transform(at);
+
+
+        return path2D;
     }
-    
-//    private static EscapeInfo getEscapeInfo(byte elem[]) {
-//        int elemUS = LittleEndian.getUShort(elem, 0);
-//        int escInfo = ESCAPE_INFO.getValue(elemUS);
-//        return EscapeInfo.valueOf(escInfo);
-//    }
+
+
 }
index 085d617eb85fe6108468cd8ccba052724884e2df..f1f2c224060164fb8c1052b2eadba56f6d393673 100644 (file)
@@ -358,17 +358,18 @@ public abstract class HSLFShape implements Shape<HSLFShape,HSLFTextParagraph> {
         _sheet = sheet;
     }
 
-    Color getColor(short colorProperty, short opacityProperty, int defaultColor){
-        AbstractEscherOptRecord opt = getEscherOptRecord();
-        EscherSimpleProperty p = getEscherProperty(opt, colorProperty);
-        if(p == null && defaultColor == -1) return null;
-
-        int val = (p == null) ? defaultColor : p.getPropertyValue();
-
-        EscherColorRef ecr = new EscherColorRef(val);
-        Color col = getColor(ecr);
-        if (col == null) {
-            return null;
+    Color getColor(short colorProperty, short opacityProperty){
+        final AbstractEscherOptRecord opt = getEscherOptRecord();
+        final EscherSimpleProperty colProp = getEscherProperty(opt, colorProperty);
+        final Color col;
+        if (colProp == null) {
+            col = Color.WHITE;
+        } else {
+            EscherColorRef ecr = new EscherColorRef(colProp.getPropertyValue());
+            col = getColor(ecr);
+            if (col == null) {
+                return null;
+            }
         }
 
         double alpha = getAlpha(opacityProperty);
index f9cf74c2632ff0c6f128823e7a2616b8abc41fe6..acabc68715ca10d9a00c54e65285675eb42e3451 100644 (file)
@@ -164,7 +164,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
             return null;
         }
 
-        Color clr = getColor(EscherProperties.LINESTYLE__COLOR, EscherProperties.LINESTYLE__OPACITY, -1);
+        Color clr = getColor(EscherProperties.LINESTYLE__COLOR, EscherProperties.LINESTYLE__OPACITY);
         return clr == null ? null : clr;
     }
 
@@ -179,7 +179,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
             return null;
         }
 
-        Color clr = getColor(EscherProperties.LINESTYLE__BACKCOLOR, EscherProperties.LINESTYLE__OPACITY, -1);
+        Color clr = getColor(EscherProperties.LINESTYLE__BACKCOLOR, EscherProperties.LINESTYLE__OPACITY);
         return clr == null ? null : clr;
     }
 
@@ -385,7 +385,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
      * @return color of the line. If color is not set returns <code>java.awt.Color.black</code>
      */
     public Color getShadowColor(){
-        Color clr = getColor(EscherProperties.SHADOWSTYLE__COLOR, EscherProperties.SHADOWSTYLE__OPACITY, -1);
+        Color clr = getColor(EscherProperties.SHADOWSTYLE__COLOR, EscherProperties.SHADOWSTYLE__OPACITY);
         return clr == null ? Color.black : clr;
     }
 
index 14301af2ba448c93e2db28b0d2f1b08f58d1df6d..26b30ea53ca65062936dd15524252136d3b16a5d 100644 (file)
@@ -25,7 +25,6 @@ import org.junit.runners.Suite;
  */
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-    TestBackground.class,
     TestFreeform.class,
     TestHeadersFooters.class,
     TestHyperlink.class,
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestBackground.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestBackground.java
deleted file mode 100644 (file)
index faf61fb..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/* ====================================================================
-   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.hslf.model;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.awt.Color;
-import java.io.IOException;
-import java.util.List;
-
-import org.apache.poi.POIDataSamples;
-import org.apache.poi.ddf.AbstractEscherOptRecord;
-import org.apache.poi.ddf.EscherBSERecord;
-import org.apache.poi.ddf.EscherContainerRecord;
-import org.apache.poi.ddf.EscherProperties;
-import org.apache.poi.ddf.EscherRecord;
-import org.apache.poi.ddf.EscherSimpleProperty;
-import org.apache.poi.hslf.HSLFTestDataSamples;
-import org.apache.poi.hslf.record.Document;
-import org.apache.poi.hslf.usermodel.HSLFAutoShape;
-import org.apache.poi.hslf.usermodel.HSLFFill;
-import org.apache.poi.hslf.usermodel.HSLFPictureData;
-import org.apache.poi.hslf.usermodel.HSLFShape;
-import org.apache.poi.hslf.usermodel.HSLFSheet;
-import org.apache.poi.hslf.usermodel.HSLFSlide;
-import org.apache.poi.hslf.usermodel.HSLFSlideShow;
-import org.apache.poi.sl.usermodel.PictureData.PictureType;
-import org.apache.poi.sl.usermodel.ShapeType;
-import org.junit.Test;
-
-
-/**
- * Test <code>Fill</code> object.
- *
- * @author Yegor Kozlov
- */
-public final class TestBackground {
-    private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
-
-    /**
-     * Default background for slide, shape and slide master.
-     */
-    @Test
-    public void defaults() throws IOException {
-        HSLFSlideShow ppt = new HSLFSlideShow();
-
-        assertEquals(HSLFFill.FILL_SOLID, ppt.getSlideMasters().get(0).getBackground().getFill().getFillType());
-
-        HSLFSlide slide = ppt.createSlide();
-        assertTrue(slide.getFollowMasterBackground());
-        assertEquals(HSLFFill.FILL_SOLID, slide.getBackground().getFill().getFillType());
-
-        HSLFShape shape = new HSLFAutoShape(ShapeType.RECT);
-        assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
-        ppt.close();
-    }
-
-    /**
-     * Read fill information from an reference ppt file
-     */
-    @Test
-    public void readBackground() throws IOException {
-        HSLFSlideShow ppt = HSLFTestDataSamples.getSlideShow("backgrounds.ppt");
-        HSLFFill fill;
-        HSLFShape shape;
-
-        List<HSLFSlide> slide = ppt.getSlides();
-
-        fill = slide.get(0).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_PICTURE, fill.getFillType());
-        shape = slide.get(0).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
-
-        fill = slide.get(1).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_PATTERN, fill.getFillType());
-        shape = slide.get(1).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_BACKGROUND, shape.getFill().getFillType());
-
-        fill = slide.get(2).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_TEXTURE, fill.getFillType());
-        shape = slide.get(2).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_PICTURE, shape.getFill().getFillType());
-
-        fill = slide.get(3).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_SHADE_CENTER, fill.getFillType());
-        shape = slide.get(3).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_SHADE, shape.getFill().getFillType());
-        ppt.close();
-    }
-
-    /**
-     * Create a ppt with various fill effects
-     */
-    @Test
-    public void backgroundPicture() throws IOException {
-        HSLFSlideShow ppt1 = new HSLFSlideShow();
-        HSLFSlide slide;
-        HSLFFill fill;
-        HSLFShape shape;
-        HSLFPictureData data;
-
-        //slide 1
-        slide = ppt1.createSlide();
-        slide.setFollowMasterBackground(false);
-        fill = slide.getBackground().getFill();
-        data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
-        fill.setFillType(HSLFFill.FILL_PICTURE);
-        fill.setPictureData(data);
-
-        shape = new HSLFAutoShape(ShapeType.RECT);
-        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
-        fill = shape.getFill();
-        fill.setFillType(HSLFFill.FILL_SOLID);
-        slide.addShape(shape);
-
-        //slide 2
-        slide = ppt1.createSlide();
-        slide.setFollowMasterBackground(false);
-        fill = slide.getBackground().getFill();
-        data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
-        fill.setFillType(HSLFFill.FILL_PATTERN);
-        fill.setPictureData(data);
-        fill.setBackgroundColor(Color.green);
-        fill.setForegroundColor(Color.red);
-
-        shape = new HSLFAutoShape(ShapeType.RECT);
-        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
-        fill = shape.getFill();
-        fill.setFillType(HSLFFill.FILL_BACKGROUND);
-        slide.addShape(shape);
-
-        //slide 3
-        slide = ppt1.createSlide();
-        slide.setFollowMasterBackground(false);
-        fill = slide.getBackground().getFill();
-        data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
-        fill.setFillType(HSLFFill.FILL_TEXTURE);
-        fill.setPictureData(data);
-
-        shape = new HSLFAutoShape(ShapeType.RECT);
-        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
-        fill = shape.getFill();
-        fill.setFillType(HSLFFill.FILL_PICTURE);
-        data = ppt1.addPicture(_slTests.readFile("clock.jpg"), PictureType.JPEG);
-        fill.setPictureData(data);
-        slide.addShape(shape);
-
-        // slide 4
-        slide = ppt1.createSlide();
-        slide.setFollowMasterBackground(false);
-        fill = slide.getBackground().getFill();
-        fill.setFillType(HSLFFill.FILL_SHADE_CENTER);
-        fill.setBackgroundColor(Color.white);
-        fill.setForegroundColor(Color.darkGray);
-
-        shape = new HSLFAutoShape(ShapeType.RECT);
-        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
-        fill = shape.getFill();
-        fill.setFillType(HSLFFill.FILL_SHADE);
-        fill.setBackgroundColor(Color.red);
-        fill.setForegroundColor(Color.green);
-        slide.addShape(shape);
-
-        //serialize and read again
-        HSLFSlideShow ppt2 = HSLFTestDataSamples.writeOutAndReadBack(ppt1);
-        List<HSLFSlide> slides = ppt2.getSlides();
-
-        fill = slides.get(0).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_PICTURE, fill.getFillType());
-        assertEquals(3, getFillPictureRefCount(slides.get(0).getBackground(), fill));
-        shape = slides.get(0).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
-
-        fill = slides.get(1).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_PATTERN, fill.getFillType());
-        shape = slides.get(1).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_BACKGROUND, shape.getFill().getFillType());
-
-        fill = slides.get(2).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_TEXTURE, fill.getFillType());
-        assertEquals(3, getFillPictureRefCount(slides.get(2).getBackground(), fill));
-        shape = slides.get(2).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_PICTURE, shape.getFill().getFillType());
-        assertEquals(1, getFillPictureRefCount(shape, fill));
-
-        fill = slides.get(3).getBackground().getFill();
-        assertEquals(HSLFFill.FILL_SHADE_CENTER, fill.getFillType());
-        shape = slides.get(3).getShapes().get(0);
-        assertEquals(HSLFFill.FILL_SHADE, shape.getFill().getFillType());
-        ppt2.close();
-        ppt1.close();
-    }
-
-    private int getFillPictureRefCount(HSLFShape shape, HSLFFill fill) {
-        AbstractEscherOptRecord opt = shape.getEscherOptRecord();
-        EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
-        if(p != null) {
-            int idx = p.getPropertyValue();
-
-            HSLFSheet sheet = shape.getSheet();
-            HSLFSlideShow ppt = sheet.getSlideShow();
-            Document doc = ppt.getDocumentRecord();
-            EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
-            EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
-            List<EscherRecord> lst = bstore.getChildRecords();
-            return ((EscherBSERecord)lst.get(idx-1)).getRef();
-        }
-        return 0;
-    }
-
-}
index 91d23664d828c80ab72c61dbdc25d4ebef48e662..1e3c52ddeeefab94ca61c7ed54e0888397960763 100644 (file)
@@ -87,7 +87,7 @@ public final class TestFreeform {
     public void test54188() {
 
         HSLFFreeformShape p = new HSLFFreeformShape();
-        Path2D.Double path = p.getPath();
+        Path2D path = p.getPath();
         Path2D.Double emptyPath = new Path2D.Double();
         assertEquals(emptyPath.getBounds2D(), path.getBounds2D());
     }
index 0354d9b46cc75131a90873d5d6b7e216e4b166d5..cf8dc7658d1115132c966b9aa2a932120fc30cd8 100644 (file)
@@ -26,6 +26,7 @@ import org.junit.runners.Suite;
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
     TestAddingSlides.class,
+    TestBackground.class,
     TestBugs.class,
     TestCounts.class,
     TestMostRecentRecords.class,
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBackground.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBackground.java
new file mode 100644 (file)
index 0000000..2732d16
--- /dev/null
@@ -0,0 +1,227 @@
+/* ====================================================================
+   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.hslf.usermodel;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.ddf.AbstractEscherOptRecord;
+import org.apache.poi.ddf.EscherBSERecord;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherProperties;
+import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherSimpleProperty;
+import org.apache.poi.hslf.HSLFTestDataSamples;
+import org.apache.poi.hslf.record.Document;
+import org.apache.poi.hslf.usermodel.HSLFAutoShape;
+import org.apache.poi.hslf.usermodel.HSLFFill;
+import org.apache.poi.hslf.usermodel.HSLFPictureData;
+import org.apache.poi.hslf.usermodel.HSLFShape;
+import org.apache.poi.hslf.usermodel.HSLFSheet;
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.sl.usermodel.PictureData.PictureType;
+import org.apache.poi.sl.usermodel.ShapeType;
+import org.junit.Test;
+
+
+/**
+ * Test <code>Fill</code> object.
+ *
+ * @author Yegor Kozlov
+ */
+public final class TestBackground {
+    private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
+
+    /**
+     * Default background for slide, shape and slide master.
+     */
+    @Test
+    public void defaults() throws IOException {
+        HSLFSlideShow ppt = new HSLFSlideShow();
+
+        assertEquals(HSLFFill.FILL_SOLID, ppt.getSlideMasters().get(0).getBackground().getFill().getFillType());
+
+        HSLFSlide slide = ppt.createSlide();
+        assertTrue(slide.getFollowMasterBackground());
+        assertEquals(HSLFFill.FILL_SOLID, slide.getBackground().getFill().getFillType());
+
+        HSLFShape shape = new HSLFAutoShape(ShapeType.RECT);
+        assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
+        ppt.close();
+    }
+
+    /**
+     * Read fill information from an reference ppt file
+     */
+    @Test
+    public void readBackground() throws IOException {
+        HSLFSlideShow ppt = HSLFTestDataSamples.getSlideShow("backgrounds.ppt");
+        HSLFFill fill;
+        HSLFShape shape;
+
+        List<HSLFSlide> slide = ppt.getSlides();
+
+        fill = slide.get(0).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_PICTURE, fill.getFillType());
+        shape = slide.get(0).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
+
+        fill = slide.get(1).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_PATTERN, fill.getFillType());
+        shape = slide.get(1).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_BACKGROUND, shape.getFill().getFillType());
+
+        fill = slide.get(2).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_TEXTURE, fill.getFillType());
+        shape = slide.get(2).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_PICTURE, shape.getFill().getFillType());
+
+        fill = slide.get(3).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_SHADE_CENTER, fill.getFillType());
+        shape = slide.get(3).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_SHADE, shape.getFill().getFillType());
+        ppt.close();
+    }
+
+    /**
+     * Create a ppt with various fill effects
+     */
+    @Test
+    public void backgroundPicture() throws IOException {
+        HSLFSlideShow ppt1 = new HSLFSlideShow();
+        HSLFSlide slide;
+        HSLFFill fill;
+        HSLFShape shape;
+        HSLFPictureData data;
+
+        //slide 1
+        slide = ppt1.createSlide();
+        slide.setFollowMasterBackground(false);
+        fill = slide.getBackground().getFill();
+        data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
+        fill.setFillType(HSLFFill.FILL_PICTURE);
+        fill.setPictureData(data);
+
+        shape = new HSLFAutoShape(ShapeType.RECT);
+        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
+        fill = shape.getFill();
+        fill.setFillType(HSLFFill.FILL_SOLID);
+        slide.addShape(shape);
+
+        //slide 2
+        slide = ppt1.createSlide();
+        slide.setFollowMasterBackground(false);
+        fill = slide.getBackground().getFill();
+        data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
+        fill.setFillType(HSLFFill.FILL_PATTERN);
+        fill.setPictureData(data);
+        fill.setBackgroundColor(Color.green);
+        fill.setForegroundColor(Color.red);
+
+        shape = new HSLFAutoShape(ShapeType.RECT);
+        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
+        fill = shape.getFill();
+        fill.setFillType(HSLFFill.FILL_BACKGROUND);
+        slide.addShape(shape);
+
+        //slide 3
+        slide = ppt1.createSlide();
+        slide.setFollowMasterBackground(false);
+        fill = slide.getBackground().getFill();
+        data = ppt1.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG);
+        fill.setFillType(HSLFFill.FILL_TEXTURE);
+        fill.setPictureData(data);
+
+        shape = new HSLFAutoShape(ShapeType.RECT);
+        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
+        fill = shape.getFill();
+        fill.setFillType(HSLFFill.FILL_PICTURE);
+        data = ppt1.addPicture(_slTests.readFile("clock.jpg"), PictureType.JPEG);
+        fill.setPictureData(data);
+        slide.addShape(shape);
+
+        // slide 4
+        slide = ppt1.createSlide();
+        slide.setFollowMasterBackground(false);
+        fill = slide.getBackground().getFill();
+        fill.setFillType(HSLFFill.FILL_SHADE_CENTER);
+        fill.setBackgroundColor(Color.white);
+        fill.setForegroundColor(Color.darkGray);
+
+        shape = new HSLFAutoShape(ShapeType.RECT);
+        shape.setAnchor(new java.awt.Rectangle(100, 100, 200, 200));
+        fill = shape.getFill();
+        fill.setFillType(HSLFFill.FILL_SHADE);
+        fill.setBackgroundColor(Color.red);
+        fill.setForegroundColor(Color.green);
+        slide.addShape(shape);
+
+        //serialize and read again
+        HSLFSlideShow ppt2 = HSLFTestDataSamples.writeOutAndReadBack(ppt1);
+        List<HSLFSlide> slides = ppt2.getSlides();
+
+        fill = slides.get(0).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_PICTURE, fill.getFillType());
+        assertEquals(3, getFillPictureRefCount(slides.get(0).getBackground(), fill));
+        shape = slides.get(0).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType());
+
+        fill = slides.get(1).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_PATTERN, fill.getFillType());
+        shape = slides.get(1).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_BACKGROUND, shape.getFill().getFillType());
+
+        fill = slides.get(2).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_TEXTURE, fill.getFillType());
+        assertEquals(3, getFillPictureRefCount(slides.get(2).getBackground(), fill));
+        shape = slides.get(2).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_PICTURE, shape.getFill().getFillType());
+        assertEquals(1, getFillPictureRefCount(shape, fill));
+
+        fill = slides.get(3).getBackground().getFill();
+        assertEquals(HSLFFill.FILL_SHADE_CENTER, fill.getFillType());
+        shape = slides.get(3).getShapes().get(0);
+        assertEquals(HSLFFill.FILL_SHADE, shape.getFill().getFillType());
+        ppt2.close();
+        ppt1.close();
+    }
+
+    private int getFillPictureRefCount(HSLFShape shape, HSLFFill fill) {
+        AbstractEscherOptRecord opt = shape.getEscherOptRecord();
+        EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
+        if(p != null) {
+            int idx = p.getPropertyValue();
+
+            HSLFSheet sheet = shape.getSheet();
+            HSLFSlideShow ppt = sheet.getSlideShow();
+            Document doc = ppt.getDocumentRecord();
+            EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
+            EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
+            List<EscherRecord> lst = bstore.getChildRecords();
+            return ((EscherBSERecord)lst.get(idx-1)).getRef();
+        }
+        return 0;
+    }
+
+}
diff --git a/test-data/slideshow/customGeo.ppt b/test-data/slideshow/customGeo.ppt
new file mode 100644 (file)
index 0000000..fdb80ed
Binary files /dev/null and b/test-data/slideshow/customGeo.ppt differ
diff --git a/test-data/slideshow/customGeo.pptx b/test-data/slideshow/customGeo.pptx
new file mode 100644 (file)
index 0000000..c30e331
Binary files /dev/null and b/test-data/slideshow/customGeo.pptx differ