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 2016/02/24 23:43:52 UTC

svn commit: r1732236 [1/2] - in /poi/trunk/src: integrationtest/org/apache/poi/stress/ java/org/apache/poi/ddf/ java/org/apache/poi/sl/draw/ java/org/apache/poi/sl/draw/geom/ java/org/apache/poi/sl/usermodel/ ooxml/java/org/apache/poi/xslf/usermodel/ o...

Author: kiwiwings
Date: Wed Feb 24 22:43:51 2016
New Revision: 1732236

URL: http://svn.apache.org/viewvc?rev=1732236&view=rev
Log:
Regression fixes for H/XSLF and HWMF
see http://apache-poi.1045710.n5.nabble.com/3-14-beta-2-3-14-final-tt5721829.html

Added:
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBinaryRasterOp.java
Modified:
    poi/trunk/src/integrationtest/org/apache/poi/stress/SlideShowHandler.java
    poi/trunk/src/java/org/apache/poi/ddf/EscherArrayProperty.java
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawBackground.java
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawFactory.java
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawPaint.java
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawPictureShape.java
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawShape.java
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawSimpleShape.java
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextShape.java
    poi/trunk/src/java/org/apache/poi/sl/draw/PathGradientPaint.java
    poi/trunk/src/java/org/apache/poi/sl/draw/SLGraphics.java
    poi/trunk/src/java/org/apache/poi/sl/draw/geom/ArcToCommand.java
    poi/trunk/src/java/org/apache/poi/sl/draw/geom/ClosePathCommand.java
    poi/trunk/src/java/org/apache/poi/sl/draw/geom/CurveToCommand.java
    poi/trunk/src/java/org/apache/poi/sl/draw/geom/LineToCommand.java
    poi/trunk/src/java/org/apache/poi/sl/draw/geom/MoveToCommand.java
    poi/trunk/src/java/org/apache/poi/sl/draw/geom/Path.java
    poi/trunk/src/java/org/apache/poi/sl/draw/geom/PathCommand.java
    poi/trunk/src/java/org/apache/poi/sl/draw/geom/QuadToCommand.java
    poi/trunk/src/java/org/apache/poi/sl/usermodel/FreeformShape.java
    poi/trunk/src/java/org/apache/poi/sl/usermodel/PlaceableShape.java
    poi/trunk/src/java/org/apache/poi/sl/usermodel/Shape.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFHyperlink.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java
    poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
    poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFFreeformShape.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/InteractiveInfo.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/Record.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFHyperlink.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureShape.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfDrawProperties.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfDraw.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfEscape.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFill.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMapMode.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfMisc.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfPalette.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfTernaryRasterOp.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfWindowing.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestPicture.java
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java
    poi/trunk/src/testcases/org/apache/poi/sl/draw/geom/TestPresetGeometries.java

Modified: poi/trunk/src/integrationtest/org/apache/poi/stress/SlideShowHandler.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/integrationtest/org/apache/poi/stress/SlideShowHandler.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/integrationtest/org/apache/poi/stress/SlideShowHandler.java (original)
+++ poi/trunk/src/integrationtest/org/apache/poi/stress/SlideShowHandler.java Wed Feb 24 22:43:51 2016
@@ -26,10 +26,8 @@ import java.awt.image.BufferedImage;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
 
-import org.apache.poi.sl.draw.Drawable;
+import org.apache.poi.sl.draw.DrawFactory;
 import org.apache.poi.sl.usermodel.PictureData;
 import org.apache.poi.sl.usermodel.Shape;
 import org.apache.poi.sl.usermodel.ShapeContainer;
@@ -39,7 +37,6 @@ import org.apache.poi.sl.usermodel.Slide
 import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.poi.sl.usermodel.TextRun;
 import org.apache.poi.sl.usermodel.TextShape;
-import org.apache.poi.util.JvmBugs;
 
 public abstract class SlideShowHandler extends POIFSFileHandler {
     public void handleSlideShow(SlideShow<?,?> ss) throws IOException {
@@ -55,10 +52,12 @@ public abstract class SlideShowHandler e
 
         // read in the writen file
         SlideShow<?,?> read = SlideShowFactory.create(new ByteArrayInputStream(out.toByteArray()));
-        assertNotNull(read);
-        
-        readContent(read);
-        
+        try {
+            assertNotNull(read);
+            readContent(read);
+        } finally {
+            read.close();
+        }
     }
 
     private ByteArrayOutputStream writeToArray(SlideShow<?,?> ss) throws IOException {
@@ -109,7 +108,7 @@ public abstract class SlideShowHandler e
         for (Slide<?,?> s : ss.getSlides()) {
             BufferedImage img = new BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_ARGB);
             Graphics2D graphics = img.createGraphics();
-            fixFonts(graphics);
+            DrawFactory.getInstance(graphics).fixFonts(graphics);
 
             // default rendering options
             graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
@@ -124,15 +123,4 @@ public abstract class SlideShowHandler e
             img.flush();
         }
     }
-
-    @SuppressWarnings("unchecked")
-    private static void fixFonts(Graphics2D graphics) {
-        if (!JvmBugs.hasLineBreakMeasurerBug()) return;
-        Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_MAP);
-        if (fontMap == null) fontMap = new HashMap<String,String>();
-        fontMap.put("Calibri", "Lucida Sans");
-        fontMap.put("Cambria", "Lucida Bright");
-        graphics.setRenderingHint(Drawable.FONT_MAP, fontMap);        
-    }
-
 }
\ No newline at end of file

Modified: poi/trunk/src/java/org/apache/poi/ddf/EscherArrayProperty.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ddf/EscherArrayProperty.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ddf/EscherArrayProperty.java (original)
+++ poi/trunk/src/java/org/apache/poi/ddf/EscherArrayProperty.java Wed Feb 24 22:43:51 2016
@@ -43,7 +43,7 @@ public final class EscherArrayProperty e
     private boolean sizeIncludesHeaderSize = true;
 
     /**
-     * When reading a property from data stream remeber if the complex part is empty and set this flag.
+     * When reading a property from data stream remember if the complex part is empty and set this flag.
      */
     private boolean emptyComplexPart = false;
 
@@ -65,10 +65,7 @@ public final class EscherArrayProperty e
     }
 
     public int getNumberOfElementsInArray() {
-        if (emptyComplexPart){
-            return 0;
-        }
-        return LittleEndian.getUShort(_complexData, 0);
+        return (emptyComplexPart) ? 0 : LittleEndian.getUShort(_complexData, 0);
     }
 
     public void setNumberOfElementsInArray(int numberOfElements) {
@@ -82,7 +79,7 @@ public final class EscherArrayProperty e
     }
 
     public int getNumberOfElementsInMemory() {
-        return LittleEndian.getUShort(_complexData, 2);
+        return (emptyComplexPart) ? 0 : LittleEndian.getUShort(_complexData, 2);
     }
 
     public void setNumberOfElementsInMemory(int numberOfElements) {
@@ -96,7 +93,7 @@ public final class EscherArrayProperty e
     }
 
     public short getSizeOfElements() {
-        return LittleEndian.getShort( _complexData, 4 );
+        return (emptyComplexPart) ? 0 : LittleEndian.getShort( _complexData, 4 );
     }
 
     public void setSizeOfElements(int sizeOfElements) {

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawBackground.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawBackground.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawBackground.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawBackground.java Wed Feb 24 22:43:51 2016
@@ -25,6 +25,7 @@ import java.awt.geom.Rectangle2D;
 import org.apache.poi.sl.usermodel.Background;
 import org.apache.poi.sl.usermodel.PlaceableShape;
 import org.apache.poi.sl.usermodel.ShapeContainer;
+import org.apache.poi.sl.usermodel.Sheet;
 
 
 public class DrawBackground extends DrawShape {
@@ -47,6 +48,7 @@ public class DrawBackground extends Draw
             public void setFlipVertical(boolean flip) {}
             public boolean getFlipHorizontal() { return false; }
             public boolean getFlipVertical() { return false; }
+            public Sheet<?,?> getSheet() { return shape.getSheet(); }
         };
         
         DrawFactory drawFact = DrawFactory.getInstance(graphics);
@@ -55,6 +57,7 @@ public class DrawBackground extends Draw
         Rectangle2D anchor2 = getAnchor(graphics, anchor);
         
         if(fill != null) {
+            graphics.setRenderingHint(Drawable.GRADIENT_SHAPE, anchor);
             graphics.setPaint(fill);
             graphics.fill(anchor2);
         }

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawFactory.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawFactory.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawFactory.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawFactory.java Wed Feb 24 22:43:51 2016
@@ -17,11 +17,11 @@
 
 package org.apache.poi.sl.draw;
 
-import static org.apache.poi.sl.draw.Drawable.DRAW_FACTORY;
-
 import java.awt.Graphics2D;
 import java.awt.font.TextLayout;
 import java.text.AttributedString;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.poi.sl.usermodel.Background;
 import org.apache.poi.sl.usermodel.ConnectorShape;
@@ -38,6 +38,7 @@ import org.apache.poi.sl.usermodel.Table
 import org.apache.poi.sl.usermodel.TextBox;
 import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.poi.sl.usermodel.TextShape;
+import org.apache.poi.util.JvmBugs;
 
 public class DrawFactory {
     protected static final ThreadLocal<DrawFactory> defaultFactory = new ThreadLocal<DrawFactory>();
@@ -58,7 +59,7 @@ public class DrawFactory {
         DrawFactory factory = null;
         boolean isHint = false;
         if (graphics != null) {
-            factory = (DrawFactory)graphics.getRenderingHint(DRAW_FACTORY);
+            factory = (DrawFactory)graphics.getRenderingHint(Drawable.DRAW_FACTORY);
             isHint = (factory != null);
         }
         // secondly try the thread local default
@@ -70,7 +71,7 @@ public class DrawFactory {
             factory = new DrawFactory();
         }
         if (graphics != null && !isHint) {
-            graphics.setRenderingHint(DRAW_FACTORY, factory);
+            graphics.setRenderingHint(Drawable.DRAW_FACTORY, factory);
         }
         return factory;
     }
@@ -166,4 +167,29 @@ public class DrawFactory {
     public DrawPaint getPaint(PlaceableShape<?,?> shape) {
         return new DrawPaint(shape);
     }
-}
+
+
+    /**
+     * Replace font families for Windows JVM 6, which contains a font rendering error.
+     * This is likely to be removed, when POI upgrades to JDK 7
+     *
+     * @param graphics the graphics context which will contain the font mapping
+     */
+    public void fixFonts(Graphics2D graphics) {
+        if (!JvmBugs.hasLineBreakMeasurerBug()) return;
+        @SuppressWarnings("unchecked")
+        Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_MAP);
+        if (fontMap == null) {
+            fontMap = new HashMap<String,String>();
+            graphics.setRenderingHint(Drawable.FONT_MAP, fontMap);
+        }
+        
+        String fonts[][] = { { "Calibri", "Lucida Sans" }, { "Cambria", "Lucida Bright" } };
+
+        for (String f[] : fonts) {
+            if (!fontMap.containsKey(f[0])) {
+                fontMap.put(f[0], f[1]);
+            }
+        }
+    }
+}
\ No newline at end of file

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawPaint.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawPaint.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawPaint.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawPaint.java Wed Feb 24 22:43:51 2016
@@ -134,8 +134,11 @@ public class DrawPaint {
         ImageRenderer renderer = DrawPictureShape.getImageRenderer(graphics, fill.getContentType());
 
         try {
-            renderer.loadImage(is, fill.getContentType());
-            is.close();
+            try {
+                renderer.loadImage(is, fill.getContentType());
+            } finally {
+                is.close();
+            }
         } catch (IOException e) {
             LOG.log(POILogger.ERROR, "Can't load image data - using transparent color", e);
             return null;
@@ -274,15 +277,35 @@ public class DrawPaint {
 
         Point2D p2 = new Point2D.Double(anchor.getX() + anchor.getWidth(), anchor.getY() + anchor.getHeight() / 2);
         p2 = at.transform(p2, null);
-
+        
         snapToAnchor(p1, anchor);
         snapToAnchor(p2, anchor);
 
+        if (p1.equals(p2)) {
+            // gradient paint on the same point throws an exception ... and doesn't make sense
+            return null;
+        }
+
         float[] fractions = fill.getGradientFractions();
         Color[] colors = new Color[fractions.length];
         
         int i = 0;
         for (ColorStyle fc : fill.getGradientColors()) {
+            if (fc == null) {
+                // get color of background
+                fc = new ColorStyle() {
+                    public int getTint() { return -1; }
+                    public int getShade() { return -1; }
+                    public int getSatOff() { return -1; }
+                    public int getSatMod() { return -1; }
+                    public int getLumOff() { return -1; }
+                    public int getLumMod() { return -1; }
+                    public int getHueOff() { return -1; }
+                    public int getHueMod() { return -1; }
+                    public Color getColor() { return Color.white; }
+                    public int getAlpha() { return 0; }
+                };
+            }
             colors[i++] = applyColorTransform(fc);
         }
 

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawPictureShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawPictureShape.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawPictureShape.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawPictureShape.java Wed Feb 24 22:43:51 2016
@@ -52,8 +52,7 @@ public class DrawPictureShape extends Dr
             renderer.loadImage(data.getData(), data.getContentType());
             renderer.drawImage(graphics, anchor, insets);
         } catch (IOException e) {
-            // TODO: draw specific runtime exception?
-            throw new RuntimeException(e);
+            LOG.log(POILogger.ERROR, "image can't be loaded/rendered.", e);
         }
     }    
 

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawShape.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawShape.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawShape.java Wed Feb 24 22:43:51 2016
@@ -90,17 +90,23 @@ public class DrawShape implements Drawab
 
                 Rectangle2D anchor2 = txs.createTransformedShape(ps.getAnchor()).getBounds2D();
 
-                scaleX = anchor.getWidth() == 0. ? 1.0 : anchor.getWidth() / anchor2.getWidth();
-                scaleY = anchor.getHeight() == 0. ? 1.0 : anchor.getHeight() / anchor2.getHeight();
+                scaleX = safeScale(anchor.getWidth(), anchor2.getWidth());
+                scaleY = safeScale(anchor.getHeight(), anchor2.getHeight());
             } else {
                 quadrant = 0;
             }
 
             // transformation is applied reversed ...
             graphics.translate(centerX, centerY);
-            graphics.rotate(Math.toRadians(rotation-quadrant*90.));
+            double rot = Math.toRadians(rotation-quadrant*90.);
+            if (rot != 0) {
+                graphics.rotate(rot);
+            }
             graphics.scale(scaleX, scaleY);
-            graphics.rotate(Math.toRadians(quadrant*90));
+            rot = Math.toRadians(quadrant*90);
+            if (rot != 0) {
+                graphics.rotate(rot);
+            }
             graphics.translate(-centerX, -centerY);
         }
 
@@ -119,6 +125,12 @@ public class DrawShape implements Drawab
         }
     }
 
+    private static double safeScale(double dim1, double dim2) {
+        if (dim1 == 0.) {
+            return 1;
+        }
+        return (dim2 == 0.) ? 1 : dim1/dim2;
+    }
 
     public void draw(Graphics2D graphics) {
     }

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawSimpleShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawSimpleShape.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawSimpleShape.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawSimpleShape.java Wed Feb 24 22:43:51 2016
@@ -23,7 +23,7 @@ import java.awt.Graphics2D;
 import java.awt.Paint;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
 import java.awt.geom.Rectangle2D;
 import java.io.IOException;
 import java.io.InputStream;
@@ -179,20 +179,20 @@ public class DrawSimpleShape extends Dra
             case STEALTH:
             case ARROW:
                 p = new Path(false, true);
-                GeneralPath arrow = new GeneralPath();
-                arrow.moveTo((float) (-lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));
+                Path2D.Double arrow = new Path2D.Double();
+                arrow.moveTo((-lineWidth * scaleX), (-lineWidth * scaleY / 2));
                 arrow.lineTo(0, 0);
-                arrow.lineTo((float) (-lineWidth * scaleX), (float) (lineWidth * scaleY / 2));
+                arrow.lineTo((-lineWidth * scaleX), (lineWidth * scaleY / 2));
                 tailShape = arrow;
                 at.translate(x2, y2);
                 at.rotate(alpha);
                 break;
             case TRIANGLE:
                 p = new Path();
-                GeneralPath triangle = new GeneralPath();
-                triangle.moveTo((float) (-lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));
+                Path2D.Double triangle = new Path2D.Double();
+                triangle.moveTo((-lineWidth * scaleX), (-lineWidth * scaleY / 2));
                 triangle.lineTo(0, 0);
-                triangle.lineTo((float) (-lineWidth * scaleX), (float) (lineWidth * scaleY / 2));
+                triangle.lineTo((-lineWidth * scaleX), (lineWidth * scaleY / 2));
                 triangle.closePath();
                 tailShape = triangle;
                 at.translate(x2, y2);
@@ -252,20 +252,20 @@ public class DrawSimpleShape extends Dra
             case STEALTH:
             case ARROW:
                 p = new Path(false, true);
-                GeneralPath arrow = new GeneralPath();
-                arrow.moveTo((float) (lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));
+                Path2D.Double arrow = new Path2D.Double();
+                arrow.moveTo((lineWidth * scaleX), (-lineWidth * scaleY / 2));
                 arrow.lineTo(0, 0);
-                arrow.lineTo((float) (lineWidth * scaleX), (float) (lineWidth * scaleY / 2));
+                arrow.lineTo((lineWidth * scaleX), (lineWidth * scaleY / 2));
                 headShape = arrow;
                 at.translate(x1, y1);
                 at.rotate(alpha);
                 break;
             case TRIANGLE:
                 p = new Path();
-                GeneralPath triangle = new GeneralPath();
-                triangle.moveTo((float) (lineWidth * scaleX), (float) (-lineWidth * scaleY / 2));
+                Path2D.Double triangle = new Path2D.Double();
+                triangle.moveTo((lineWidth * scaleX), (-lineWidth * scaleY / 2));
                 triangle.lineTo(0, 0);
-                triangle.lineTo((float) (lineWidth * scaleX), (float) (lineWidth * scaleY / 2));
+                triangle.lineTo((lineWidth * scaleX), (lineWidth * scaleY / 2));
                 triangle.closePath();
                 headShape = triangle;
                 at.translate(x1, y1);

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java Wed Feb 24 22:43:51 2016
@@ -38,6 +38,7 @@ import org.apache.poi.sl.usermodel.Inset
 import org.apache.poi.sl.usermodel.PaintStyle;
 import org.apache.poi.sl.usermodel.PlaceableShape;
 import org.apache.poi.sl.usermodel.ShapeContainer;
+import org.apache.poi.sl.usermodel.Sheet;
 import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.poi.sl.usermodel.TextParagraph.BulletStyle;
 import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
@@ -465,6 +466,7 @@ public class DrawTextParagraph implement
             public void setFlipVertical(boolean flip) {}
             public boolean getFlipHorizontal() { return false; }
             public boolean getFlipVertical() { return false; }
+            public Sheet<?,?> getSheet() { return paragraph.getParentShape().getSheet(); }
         };
         return ps;
     }
@@ -530,7 +532,7 @@ public class DrawTextParagraph implement
                 attList.add(new AttributedStringData(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER, beginIndex, endIndex));
             }
             
-            Hyperlink hl = run.getHyperlink();
+            Hyperlink<?,?> hl = run.getHyperlink();
             if (hl != null) {
                 attList.add(new AttributedStringData(HYPERLINK_HREF, hl.getAddress(), beginIndex, endIndex));
                 attList.add(new AttributedStringData(HYPERLINK_LABEL, hl.getLabel(), beginIndex, endIndex));

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextShape.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextShape.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextShape.java Wed Feb 24 22:43:51 2016
@@ -21,11 +21,15 @@ import java.awt.Graphics2D;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
-import java.util.*;
+import java.util.Iterator;
 
-import org.apache.poi.sl.usermodel.*;
+import org.apache.poi.sl.usermodel.Insets2D;
+import org.apache.poi.sl.usermodel.PlaceableShape;
+import org.apache.poi.sl.usermodel.ShapeContainer;
+import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.poi.sl.usermodel.TextParagraph.BulletStyle;
-import org.apache.poi.util.JvmBugs;
+import org.apache.poi.sl.usermodel.TextRun;
+import org.apache.poi.sl.usermodel.TextShape;
 
 public class DrawTextShape extends DrawSimpleShape {
 
@@ -35,7 +39,7 @@ public class DrawTextShape extends DrawS
 
     @Override
     public void drawContent(Graphics2D graphics) {
-        fixFonts(graphics);
+        DrawFactory.getInstance(graphics).fixFonts(graphics);
         
         TextShape<?,?> s = getShape();
         
@@ -71,7 +75,7 @@ public class DrawTextShape extends DrawS
         }
         
         Double textRot = s.getTextRotation();
-        if (textRot != null) {
+        if (textRot != null && textRot != 0) {
             graphics.translate(anchor.getCenterX(), anchor.getCenterY());
             graphics.rotate(Math.toRadians(textRot));
             graphics.translate(-anchor.getCenterX(), -anchor.getCenterY());
@@ -110,8 +114,9 @@ public class DrawTextShape extends DrawS
 
         double y0 = y;
         //noinspection RedundantCast
-        Iterator<? extends TextParagraph<?,?,? extends TextRun>> paragraphs = (Iterator<? extends TextParagraph<?, ?, ? extends TextRun>>) getShape().iterator();
-
+        Iterator<? extends TextParagraph<?,?,? extends TextRun>> paragraphs =
+            (Iterator<? extends TextParagraph<?,?,? extends TextRun>>) getShape().iterator();
+        
         boolean isFirstLine = true;
         for (int autoNbrIdx=0; paragraphs.hasNext(); autoNbrIdx++){
             TextParagraph<?,?,? extends TextRun> p = paragraphs.next();
@@ -170,23 +175,10 @@ public class DrawTextShape extends DrawS
         // dry-run in a 1x1 image and return the vertical advance
         BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
         Graphics2D graphics = img.createGraphics();
-        fixFonts(graphics);
+        DrawFactory.getInstance(graphics).fixFonts(graphics);
         return drawParagraphs(graphics, 0, 0);
     }
     
-    @SuppressWarnings("unchecked")
-    private static void fixFonts(Graphics2D graphics) {
-        if (!JvmBugs.hasLineBreakMeasurerBug()) return;
-        Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_MAP);
-        if (fontMap == null) {
-            fontMap = new HashMap<String,String>();
-            graphics.setRenderingHint(Drawable.FONT_MAP, fontMap);
-        }
-        
-        if (!fontMap.containsKey("Calibri")) fontMap.put("Calibri", "Lucida Sans");
-        if (!fontMap.containsKey("Cambria")) fontMap.put("Cambria", "Lucida Bright");
-    }
-
     @Override
     protected TextShape<?,?> getShape() {
         return (TextShape<?,?>)shape;

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/PathGradientPaint.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/PathGradientPaint.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/PathGradientPaint.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/PathGradientPaint.java Wed Feb 24 22:43:51 2016
@@ -87,7 +87,7 @@ class PathGradientPaint implements Paint
         ) {
             shape = (Shape)hints.get(Drawable.GRADIENT_SHAPE);
             if (shape == null) {
-                throw new IllegalPathStateException("PathGradientPaint needs a shape to be set via the rendering hint PathGradientPaint.GRADIANT_SHAPE.");
+                throw new IllegalPathStateException("PathGradientPaint needs a shape to be set via the rendering hint Drawable.GRADIANT_SHAPE.");
             }
 
             this.deviceBounds = deviceBounds;
@@ -137,14 +137,14 @@ class PathGradientPaint implements Paint
             return childRaster;
         }
 
-        protected int getGradientSteps(Shape shape) {
-            Rectangle rect = shape.getBounds();
+        protected int getGradientSteps(Shape gradientShape) {
+            Rectangle rect = gradientShape.getBounds();
             int lower = 1;
             int upper = (int)(Math.max(rect.getWidth(),rect.getHeight())/2.0);
             while (lower < upper-1) {
                 int mid = lower + (upper - lower) / 2;
                 BasicStroke bs = new BasicStroke(mid, capStyle, joinStyle);
-                Area area = new Area(bs.createStrokedShape(shape));
+                Area area = new Area(bs.createStrokedShape(gradientShape));
                 if (area.isSingular()) {
                     upper = mid;
                 } else {

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/SLGraphics.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/SLGraphics.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/SLGraphics.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/SLGraphics.java Wed Feb 24 22:43:51 2016
@@ -42,6 +42,7 @@ import java.awt.geom.Arc2D;
 import java.awt.geom.Ellipse2D;
 import java.awt.geom.GeneralPath;
 import java.awt.geom.Line2D;
+import java.awt.geom.Path2D;
 import java.awt.geom.RoundRectangle2D;
 import java.awt.image.BufferedImage;
 import java.awt.image.BufferedImageOp;
@@ -243,7 +244,7 @@ public final class SLGraphics extends Gr
      * @see #setComposite
      */
     public void draw(Shape shape){
-        GeneralPath path = new GeneralPath(_transform.createTransformedShape(shape));
+        Path2D.Double path = new Path2D.Double(_transform.createTransformedShape(shape));
         FreeformShape<?,?> p = _group.createFreeform();
         p.setPath(path);
         p.setFillColor(null);
@@ -339,7 +340,7 @@ public final class SLGraphics extends Gr
      * @see #setClip
      */
     public void fill(Shape shape){
-        GeneralPath path = new GeneralPath(_transform.createTransformedShape(shape));
+        Path2D.Double path = new Path2D.Double(_transform.createTransformedShape(shape));
         FreeformShape<?,?> p = _group.createFreeform();
         p.setPath(path);
         applyPaint(p);
@@ -450,7 +451,7 @@ public final class SLGraphics extends Gr
      */
     public void drawRoundRect(int x, int y, int width, int height,
                               int arcWidth, int arcHeight){
-        RoundRectangle2D rect = new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight);
+        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight);
         draw(rect);
      }
 
@@ -481,7 +482,7 @@ public final class SLGraphics extends Gr
      * @see         java.awt.Graphics#drawOval
      */
     public void fillOval(int x, int y, int width, int height){
-        Ellipse2D oval = new Ellipse2D.Float(x, y, width, height);
+        Ellipse2D oval = new Ellipse2D.Double(x, y, width, height);
         fill(oval);
     }
 
@@ -504,7 +505,7 @@ public final class SLGraphics extends Gr
     public void fillRoundRect(int x, int y, int width, int height,
                               int arcWidth, int arcHeight){
 
-        RoundRectangle2D rect = new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight);
+        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight);
         fill(rect);
     }
 
@@ -544,9 +545,8 @@ public final class SLGraphics extends Gr
      *                    relative to the start angle.
      * @see         java.awt.Graphics#drawArc
      */
-    public void fillArc(int x, int y, int width, int height,
-                        int startAngle, int arcAngle){
-        Arc2D arc = new Arc2D.Float(x, y, width, height, startAngle, arcAngle, Arc2D.PIE);
+    public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle){
+        Arc2D arc = new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.PIE);
         fill(arc);
     }
 
@@ -587,9 +587,8 @@ public final class SLGraphics extends Gr
      *                    relative to the start angle.
      * @see         java.awt.Graphics#fillArc
      */
-    public void drawArc(int x, int y, int width, int height,
-                        int startAngle, int arcAngle) {
-        Arc2D arc = new Arc2D.Float(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN);
+    public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
+        Arc2D arc = new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN);
         draw(arc);
     }
 
@@ -636,7 +635,7 @@ public final class SLGraphics extends Gr
      * @see         java.awt.Graphics#fillOval
      */
     public void drawOval(int x, int y, int width, int height){
-        Ellipse2D oval = new Ellipse2D.Float(x, y, width, height);
+        Ellipse2D oval = new Ellipse2D.Double(x, y, width, height);
         draw(oval);
     }
 
@@ -932,7 +931,7 @@ public final class SLGraphics extends Gr
      * @param   y2  the second point's <i>y</i> coordinate.
      */
     public void drawLine(int x1, int y1, int x2, int y2){
-        Line2D line = new Line2D.Float(x1, y1, x2, y2);
+        Line2D line = new Line2D.Double(x1, y1, x2, y2);
         draw(line);
     }
 

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/geom/ArcToCommand.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/geom/ArcToCommand.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/geom/ArcToCommand.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/geom/ArcToCommand.java Wed Feb 24 22:43:51 2016
@@ -19,12 +19,12 @@
 
 package org.apache.poi.sl.draw.geom;
 
-import org.apache.poi.sl.draw.binding.CTPath2DArcTo;
-
 import java.awt.geom.Arc2D;
-import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
 import java.awt.geom.Point2D;
 
+import org.apache.poi.sl.draw.binding.CTPath2DArcTo;
+
 /**
  * ArcTo command within a shape path in DrawingML:
  *
@@ -48,7 +48,7 @@ public class ArcToCommand implements Pat
         swAng = arc.getSwAng().toString();
     }
 
-    public void execute(GeneralPath path, Context ctx){
+    public void execute(Path2D.Double path, Context ctx){
         double rx = ctx.getValue(wr);
         double ry = ctx.getValue(hr);
         double start = ctx.getValue(stAng) / 60000;

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/geom/ClosePathCommand.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/geom/ClosePathCommand.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/geom/ClosePathCommand.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/geom/ClosePathCommand.java Wed Feb 24 22:43:51 2016
@@ -19,7 +19,7 @@
 
 package org.apache.poi.sl.draw.geom;
 
-import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
 
 /**
  * Date: 10/25/11
@@ -31,7 +31,7 @@ public class ClosePathCommand implements
     ClosePathCommand(){
     }
 
-    public void execute(GeneralPath path, Context ctx){
+    public void execute(Path2D.Double path, Context ctx){
         path.closePath();
     }
 }

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/geom/CurveToCommand.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/geom/CurveToCommand.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/geom/CurveToCommand.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/geom/CurveToCommand.java Wed Feb 24 22:43:51 2016
@@ -19,9 +19,9 @@
 
 package org.apache.poi.sl.draw.geom;
 
-import org.apache.poi.sl.draw.binding.CTAdjPoint2D;
+import java.awt.geom.Path2D;
 
-import java.awt.geom.GeneralPath;
+import org.apache.poi.sl.draw.binding.CTAdjPoint2D;
 
 /**
  * Date: 10/25/11
@@ -40,13 +40,13 @@ public class CurveToCommand implements P
         arg6 = pt3.getY().toString();
     }
 
-    public void execute(GeneralPath path, Context ctx){
+    public void execute(Path2D.Double path, Context ctx){
         double x1 = ctx.getValue(arg1);
         double y1 = ctx.getValue(arg2);
         double x2 = ctx.getValue(arg3);
         double y2 = ctx.getValue(arg4);
         double x3 = ctx.getValue(arg5);
         double y3 = ctx.getValue(arg6);
-        path.curveTo((float)x1, (float)y1, (float)x2, (float)y2, (float)x3, (float)y3);
+        path.curveTo(x1, y1, x2, y2, x3, y3);
     }
 }

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/geom/LineToCommand.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/geom/LineToCommand.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/geom/LineToCommand.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/geom/LineToCommand.java Wed Feb 24 22:43:51 2016
@@ -19,9 +19,9 @@
 
 package org.apache.poi.sl.draw.geom;
 
-import org.apache.poi.sl.draw.binding.CTAdjPoint2D;
+import java.awt.geom.Path2D;
 
-import java.awt.geom.GeneralPath;
+import org.apache.poi.sl.draw.binding.CTAdjPoint2D;
 
 /**
  * Date: 10/25/11
@@ -41,9 +41,9 @@ public class LineToCommand implements Pa
         arg2 = s2;
     }
 
-    public void execute(GeneralPath path, Context ctx){
+    public void execute(Path2D.Double path, Context ctx){
         double x = ctx.getValue(arg1);
         double y = ctx.getValue(arg2);
-        path.lineTo((float)x, (float)y);
+        path.lineTo(x, y);
     }
 }

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/geom/MoveToCommand.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/geom/MoveToCommand.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/geom/MoveToCommand.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/geom/MoveToCommand.java Wed Feb 24 22:43:51 2016
@@ -19,9 +19,9 @@
 
 package org.apache.poi.sl.draw.geom;
 
-import org.apache.poi.sl.draw.binding.CTAdjPoint2D;
+import java.awt.geom.Path2D;
 
-import java.awt.geom.GeneralPath;
+import org.apache.poi.sl.draw.binding.CTAdjPoint2D;
 
 /**
  * Date: 10/25/11
@@ -41,9 +41,9 @@ public class MoveToCommand implements Pa
         arg2 = s2;
     }
 
-    public void execute(GeneralPath path, Context ctx){
+    public void execute(Path2D.Double path, Context ctx){
         double x = ctx.getValue(arg1);
         double y = ctx.getValue(arg2);
-        path.moveTo((float)x, (float)y);
+        path.moveTo(x, y);
     }
 }

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/geom/Path.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/geom/Path.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/geom/Path.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/geom/Path.java Wed Feb 24 22:43:51 2016
@@ -19,11 +19,19 @@
 
 package org.apache.poi.sl.draw.geom;
 
-import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.poi.sl.draw.binding.*;
+import org.apache.poi.sl.draw.binding.CTAdjPoint2D;
+import org.apache.poi.sl.draw.binding.CTPath2D;
+import org.apache.poi.sl.draw.binding.CTPath2DArcTo;
+import org.apache.poi.sl.draw.binding.CTPath2DClose;
+import org.apache.poi.sl.draw.binding.CTPath2DCubicBezierTo;
+import org.apache.poi.sl.draw.binding.CTPath2DLineTo;
+import org.apache.poi.sl.draw.binding.CTPath2DMoveTo;
+import org.apache.poi.sl.draw.binding.CTPath2DQuadBezierTo;
+import org.apache.poi.sl.draw.binding.STPathFillMode;
 
 /**
  * Specifies a creation path consisting of a series of moves, lines and curves
@@ -90,10 +98,10 @@ public class Path {
     }
 
     /**
-     * Convert the internal represenation to java.awt.GeneralPath
+     * Convert the internal represenation to java.awt.geom.Path2D
      */
-    public GeneralPath getPath(Context ctx) {
-        GeneralPath path = new GeneralPath();
+    public Path2D.Double getPath(Context ctx) {
+        Path2D.Double path = new Path2D.Double();
         for(PathCommand cmd : commands)
             cmd.execute(path, ctx);
         return path;

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/geom/PathCommand.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/geom/PathCommand.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/geom/PathCommand.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/geom/PathCommand.java Wed Feb 24 22:43:51 2016
@@ -19,7 +19,7 @@
 
 package org.apache.poi.sl.draw.geom;
 
-import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
 
 /**
  * A path command in DrawingML. One of:
@@ -41,5 +41,5 @@ public interface PathCommand {
      * @param path  the path to append the result to
      * @param ctx   the context to lookup variables
      */
-    void execute(GeneralPath path, Context ctx);
+    void execute(Path2D.Double path, Context ctx);
 }

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/geom/QuadToCommand.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/geom/QuadToCommand.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/geom/QuadToCommand.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/geom/QuadToCommand.java Wed Feb 24 22:43:51 2016
@@ -19,9 +19,9 @@
 
 package org.apache.poi.sl.draw.geom;
 
-import org.apache.poi.sl.draw.binding.CTAdjPoint2D;
+import java.awt.geom.Path2D;
 
-import java.awt.geom.GeneralPath;
+import org.apache.poi.sl.draw.binding.CTAdjPoint2D;
 
 /**
  * Date: 10/25/11
@@ -38,11 +38,11 @@ public class QuadToCommand implements Pa
         arg4 = pt2.getY().toString();
     }
 
-    public void execute(GeneralPath path, Context ctx){
+    public void execute(Path2D.Double path, Context ctx){
         double x1 = ctx.getValue(arg1);
         double y1 = ctx.getValue(arg2);
         double x2 = ctx.getValue(arg3);
         double y2 = ctx.getValue(arg4);
-        path.quadTo((float)x1, (float)y1, (float)x2, (float)y2);
+        path.quadTo(x1, y1, x2, y2);
     }
 }

Modified: poi/trunk/src/java/org/apache/poi/sl/usermodel/FreeformShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/FreeformShape.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/FreeformShape.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/FreeformShape.java Wed Feb 24 22:43:51 2016
@@ -17,7 +17,7 @@
 
 package org.apache.poi.sl.usermodel;
 
-import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
 
 public interface FreeformShape<
     S extends Shape<S,P>,
@@ -33,7 +33,7 @@ public interface FreeformShape<
      *
      * @return the path
      */
-    GeneralPath getPath();
+    Path2D.Double getPath();
 
     /**
      * Set the shape path
@@ -41,5 +41,5 @@ public interface FreeformShape<
      * @param path  shape outline
      * @return the number of points written
      */
-    int setPath(GeneralPath path);
+    int setPath(Path2D.Double path);
 }

Modified: poi/trunk/src/java/org/apache/poi/sl/usermodel/PlaceableShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/PlaceableShape.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/PlaceableShape.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/PlaceableShape.java Wed Feb 24 22:43:51 2016
@@ -26,6 +26,11 @@ public interface PlaceableShape<
     ShapeContainer<S,P> getParent();
     
     /**
+     * @return the sheet this shape belongs to
+     */
+    Sheet<S,P> getSheet();
+    
+    /**
      * @return the position of this shape within the drawing canvas.
      *         The coordinates are expressed in points
      */

Modified: poi/trunk/src/java/org/apache/poi/sl/usermodel/Shape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/Shape.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/Shape.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/Shape.java Wed Feb 24 22:43:51 2016
@@ -25,8 +25,7 @@ public interface Shape<
 > {
 	ShapeContainer<S,P> getParent();
 	
-    /**
-    *
+   /**
     * @return the sheet this shape belongs to
     */
    Sheet<S,P> getSheet();

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java Wed Feb 24 22:43:51 2016
@@ -20,7 +20,7 @@
 package org.apache.poi.xslf.usermodel;
 
 import java.awt.geom.AffineTransform;
-import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
 import java.awt.geom.PathIterator;
 import java.awt.geom.Rectangle2D;
 
@@ -57,7 +57,7 @@ public class XSLFFreeformShape extends X
     }
 
     @Override
-    public int setPath(GeneralPath path) {
+    public int setPath(Path2D.Double path) {
         CTPath2D ctPath = CTPath2D.Factory.newInstance();
 
         Rectangle2D bounds = path.getBounds2D();
@@ -119,8 +119,8 @@ public class XSLFFreeformShape extends X
     }
 
     @Override
-    public GeneralPath getPath() {
-        GeneralPath path = new GeneralPath();
+    public Path2D.Double getPath() {
+        Path2D.Double path = new Path2D.Double();
         Rectangle2D bounds = getAnchor();
 
         CTCustomGeometry2D geom = getSpPr().getCustGeom();
@@ -168,7 +168,7 @@ public class XSLFFreeformShape extends X
         // The returned path should fit in the bounding rectangle
         AffineTransform at = new AffineTransform();
         at.translate(bounds.getX(), bounds.getY());
-        return new GeneralPath(at.createTransformedShape(path));
+        return new Path2D.Double(at.createTransformedShape(path));
     }
     /**
      * @param shapeId 1-based shapeId

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFHyperlink.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFHyperlink.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFHyperlink.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFHyperlink.java Wed Feb 24 22:43:51 2016
@@ -48,11 +48,11 @@ public class XSLFHyperlink implements Hy
 
     @Override
     public String getAddress() {
-        if (!_link.isSetId()) {
+        String id = _link.getId();
+        if (id == null || "".equals(id)) {
             return _link.getAction();
         }
 
-        String id = _link.getId();
         URI targetURI = _sheet.getPackagePart().getRelationship(id).getTargetURI();
         
         return targetURI.toASCIIString();

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java Wed Feb 24 22:43:51 2016
@@ -455,8 +455,15 @@ public class XSLFTextRun implements Text
 
     @Override
     public XSLFHyperlink getHyperlink(){
-        if(!_r.getRPr().isSetHlinkClick()) return null;
-        return new XSLFHyperlink(_r.getRPr().getHlinkClick(), _p.getParentShape().getSheet());
+        CTTextCharacterProperties rPr = _r.getRPr();
+        if (rPr == null) { 
+            return null;
+        }
+        CTHyperlink hl = rPr.getHlinkClick();
+        if (hl == null) {
+            return null;
+        }
+        return new XSLFHyperlink(hl, _p.getParentShape().getSheet());
     }
 
     private boolean fetchCharacterProperty(CharacterPropertyFetcher<?> fetcher){

Modified: poi/trunk/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java Wed Feb 24 22:43:51 2016
@@ -24,18 +24,17 @@ import java.awt.Graphics2D;
 import java.awt.RenderingHints;
 import java.awt.image.BufferedImage;
 import java.io.File;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
 
 import javax.imageio.ImageIO;
 
-import org.apache.poi.sl.draw.Drawable;
+import org.apache.poi.sl.draw.DrawFactory;
 import org.apache.poi.sl.usermodel.Slide;
 import org.apache.poi.sl.usermodel.SlideShow;
 import org.apache.poi.sl.usermodel.SlideShowFactory;
-import org.apache.poi.util.JvmBugs;
 
 /**
  * An utility to convert slides of a .pptx slide show to a PNG image
@@ -65,7 +64,7 @@ public class PPTX2PNG {
             return;
         }
 
-        int slidenum = -1;
+        String slidenumStr = "-1";
         float scale = 1;
         File file = null;
         String format = "png";
@@ -77,7 +76,7 @@ public class PPTX2PNG {
                 if ("-scale".equals(args[i])) {
                     scale = Float.parseFloat(args[++i]);
                 } else if ("-slide".equals(args[i])) {
-                    slidenum = Integer.parseInt(args[++i]);
+                    slidenumStr = args[++i];
                 } else if ("-format".equals(args[i])) {
                     format = args[++i];
                 } else if ("-outdir".equals(args[i])) {
@@ -120,9 +119,11 @@ public class PPTX2PNG {
         SlideShow<?,?> ss = SlideShowFactory.create(file, null, true);
         List<? extends Slide<?,?>> slides = ss.getSlides();
 
+        Set<Integer> slidenum = slideIndexes(slides.size(), slidenumStr);
         
-        if (slidenum < -1 || slidenum == 0 || slidenum > slides.size()) {
+        if (slidenum.isEmpty()) {
             usage("slidenum must be either -1 (for all) or within range: [1.."+slides.size()+"] for "+file);
+            ss.close();
             return;
         }
         
@@ -130,39 +131,36 @@ public class PPTX2PNG {
         int width = (int) (pgsize.width * scale);
         int height = (int) (pgsize.height * scale);
 
-        int slideNo=1;
-        for(Slide<?,?> slide : slides) {
-            if (slidenum == -1 || slideNo == slidenum) {
-                String title = slide.getTitle();
-                if (!quiet) {
-                    System.out.println("Rendering slide " + slideNo + (title == null ? "" : ": " + title));
-                }
+        for(Integer slideNo : slidenum) {
+            Slide<?,?> slide = slides.get(slideNo);
+            String title = slide.getTitle();
+            if (!quiet) {
+                System.out.println("Rendering slide " + slideNo + (title == null ? "" : ": " + title));
+            }
 
-                BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-                Graphics2D graphics = img.createGraphics();
-                fixFonts(graphics);
-            
-                // default rendering options
-                graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-                graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
-                graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
-                graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
-
-                graphics.scale(scale, scale);
-
-                // draw stuff
-                slide.draw(graphics);
-
-                // save the result
-                if (!"null".equals(format)) {
-                    String outname = file.getName().replaceFirst(".pptx?", "");
-                    outname = String.format(Locale.ROOT, "%1$s-%2$04d.%3$s", outname, slideNo, format);
-                    File outfile = new File(outdir, outname);
-                    ImageIO.write(img, format, outfile);
-                }
-            }                
-            slideNo++;
-        }
+            BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+            Graphics2D graphics = img.createGraphics();
+            DrawFactory.getInstance(graphics).fixFonts(graphics);
+        
+            // default rendering options
+            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+            graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+            graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+            graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+
+            graphics.scale(scale, scale);
+
+            // draw stuff
+            slide.draw(graphics);
+
+            // save the result
+            if (!"null".equals(format)) {
+                String outname = file.getName().replaceFirst(".pptx?", "");
+                outname = String.format(Locale.ROOT, "%1$s-%2$04d.%3$s", outname, slideNo, format);
+                File outfile = new File(outdir, outname);
+                ImageIO.write(img, format, outfile);
+            }
+        }                
         
         if (!quiet) {
             System.out.println("Done");
@@ -170,14 +168,43 @@ public class PPTX2PNG {
         
         ss.close();
     }
-
-    @SuppressWarnings("unchecked")
-    private static void fixFonts(Graphics2D graphics) {
-        if (!JvmBugs.hasLineBreakMeasurerBug()) return;
-        Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_MAP);
-        if (fontMap == null) fontMap = new HashMap<String,String>();
-        fontMap.put("Calibri", "Lucida Sans");
-        fontMap.put("Cambria", "Lucida Bright");
-        graphics.setRenderingHint(Drawable.FONT_MAP, fontMap);        
+    
+    private static Set<Integer> slideIndexes(final int slideCount, String range) {
+        Set<Integer> slideIdx = new TreeSet<Integer>();
+        if ("-1".equals(range)) {
+            for (int i=0; i<slideCount; i++) {
+                slideIdx.add(i);
+            }
+        } else {
+            for (String subrange : range.split(",")) {
+                String idx[] = subrange.split("-");
+                switch (idx.length) {
+                default:
+                case 0: break;
+                case 1: {
+                    int subidx = Integer.parseInt(idx[0]);
+                    if (subrange.contains("-")) {
+                        int startIdx = subrange.startsWith("-") ? 0 : subidx;
+                        int endIdx = subrange.endsWith("-") ? slideCount : Math.min(subidx,slideCount);
+                        for (int i=Math.max(startIdx,1); i<endIdx; i++) {
+                            slideIdx.add(i-1);
+                        }
+                    } else {
+                        slideIdx.add(Math.max(subidx,1)-1);
+                    }
+                    break;
+                }
+                case 2: {
+                    int startIdx = Math.min(Integer.parseInt(idx[0]), slideCount);
+                    int endIdx = Math.min(Integer.parseInt(idx[1]), slideCount);
+                    for (int i=Math.max(startIdx,1); i<endIdx; i++) {
+                        slideIdx.add(i-1);
+                    }
+                    break;
+                }
+                }
+            }
+        }
+        return slideIdx;
     }
 }

Modified: poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java (original)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java Wed Feb 24 22:43:51 2016
@@ -36,17 +36,28 @@ public class TestPPTX2PNG {
     public void render() throws Exception {
         POIDataSamples samples = POIDataSamples.getSlideShowInstance();
 
-        String[] testFiles = {"alterman_security.ppt","alterman_security.pptx","KEY02.pptx","themes.pptx","backgrounds.pptx","layouts.pptx", "sample.pptx", "shapes.pptx",};
-//        String[] testFiles = {"41246-2.ppt","45543.ppt","53446.ppt","ParagraphStylesShorterThanCharStyles.ppt"};
+//        File testFilesX[] = new File("tmp_ppt").listFiles(new FileFilter() {
+//            public boolean accept(File pathname) {
+//                return pathname.getName().toLowerCase().contains("ppt");
+//            }
+//        });
+//        String testFiles[] = new String[testFilesX.length];
+//        for (int i=0; i<testFilesX.length; i++) {
+//            testFiles[i] = testFilesX[i].getPath();
+//        }
+        
+
+        String[] testFiles = {"53446.ppt", "alterman_security.ppt","alterman_security.pptx","KEY02.pptx","themes.pptx","backgrounds.pptx","layouts.pptx", "sample.pptx", "shapes.pptx",};
         String[] args = {
             "-format", "null", // png,gif,jpg or null for test
             "-slide", "-1", // -1 for all
             "-outdir", new File("build/tmp/").getCanonicalPath(),
-            "-quite",
+            "-quiet",
             "dummyfile"
         };
         for(String sampleFile : testFiles){
             args[args.length-1] = samples.getFile(sampleFile).getCanonicalPath();
+//            args[args.length-1] = new File(sampleFile).getCanonicalPath();
             try {
                 PPTX2PNG.main(args);
             } catch (IllegalStateException e) {

Modified: poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFFreeformShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFFreeformShape.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFFreeformShape.java (original)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFFreeformShape.java Wed Feb 24 22:43:51 2016
@@ -19,8 +19,9 @@ package org.apache.poi.xslf.usermodel;
 import static org.junit.Assert.assertEquals;
 
 import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
 import java.awt.geom.Rectangle2D;
+import java.io.IOException;
 
 import org.junit.Test;
 
@@ -30,16 +31,16 @@ import org.junit.Test;
 public class TestXSLFFreeformShape {
 
     @Test
-    public void testSetPath() {
+    public void testSetPath() throws IOException {
         XMLSlideShow ppt = new XMLSlideShow();
         XSLFSlide slide = ppt.createSlide();
         XSLFFreeformShape shape1 = slide.createFreeform();
         // comples path consisting of a rectangle and an ellipse inside it
-        GeneralPath path1 = new GeneralPath(new Rectangle2D.Double(150, 150, 300, 300));
+        Path2D.Double path1 = new Path2D.Double(new Rectangle2D.Double(150, 150, 300, 300));
         path1.append(new Ellipse2D.Double(200, 200, 100, 50), false);
         shape1.setPath(path1);
 
-        GeneralPath path2 = shape1.getPath();
+        Path2D.Double path2 = shape1.getPath();
 
         // YK: how to compare the original path1 and the value returned by XSLFFreeformShape.getPath() ?
         // one way is to create another XSLFFreeformShape from path2 and compare the resulting xml
@@ -49,5 +50,7 @@ public class TestXSLFFreeformShape {
         shape2.setPath(path2);
 
         assertEquals(shape1.getSpPr().getCustGeom().toString(), shape2.getSpPr().getCustGeom().toString());
+        
+        ppt.close();
     }
 }
\ No newline at end of file

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java Wed Feb 24 22:43:51 2016
@@ -42,6 +42,7 @@ import java.awt.geom.Arc2D;
 import java.awt.geom.Ellipse2D;
 import java.awt.geom.GeneralPath;
 import java.awt.geom.Line2D;
+import java.awt.geom.Path2D;
 import java.awt.geom.RoundRectangle2D;
 import java.awt.image.BufferedImage;
 import java.awt.image.BufferedImageOp;
@@ -244,7 +245,7 @@ public final class PPGraphics2D extends
      * @see #setComposite
      */
     public void draw(Shape shape){
-        GeneralPath path = new GeneralPath(_transform.createTransformedShape(shape));
+        Path2D.Double path = new Path2D.Double(_transform.createTransformedShape(shape));
         HSLFFreeformShape p = new HSLFFreeformShape(_group);
         p.setPath(path);
         p.getFill().setForegroundColor(null);
@@ -346,7 +347,7 @@ public final class PPGraphics2D extends
      * @see #setClip
      */
     public void fill(Shape shape){
-        GeneralPath path = new GeneralPath(_transform.createTransformedShape(shape));
+        Path2D.Double path = new Path2D.Double(_transform.createTransformedShape(shape));
         HSLFFreeformShape p = new HSLFFreeformShape(_group);
         p.setPath(path);
         applyPaint(p);

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/InteractiveInfo.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/InteractiveInfo.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/InteractiveInfo.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/InteractiveInfo.java Wed Feb 24 22:43:51 2016
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.io.OutputStream;
 
 import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogger;
 
 /**
  * This class represents the metadata of a link in a slide/notes/etc.
@@ -59,11 +60,12 @@ public class InteractiveInfo extends Rec
 	 */	
 	private void findInterestingChildren() {
 		// First child should be the InteractiveInfoAtom
-		if(_children[0] instanceof InteractiveInfoAtom) {
-			infoAtom = (InteractiveInfoAtom)_children[0];
-		} else {
-			throw new IllegalStateException("First child record wasn't a InteractiveInfoAtom, was of type " + _children[0].getRecordType());
-		}
+	    if (_children == null || _children.length == 0 || !(_children[0] instanceof InteractiveInfoAtom)) {
+	        logger.log(POILogger.WARN, "First child record wasn't a InteractiveInfoAtom - leaving this atom in an invalid state...");
+	        return;
+	    }
+
+	    infoAtom = (InteractiveInfoAtom)_children[0];
 	}
 	
 	/**

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/Record.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/Record.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/Record.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/Record.java Wed Feb 24 22:43:51 2016
@@ -168,7 +168,7 @@ public abstract class Record
 		try {
 			c = RecordTypes.forTypeID((short)type).handlingClass;
 			if(c == null) {
-				// How odd. RecordTypes normally subsitutes in
+				// How odd. RecordTypes normally substitutes in
 				//  a default handler class if it has heard of the record
 				//  type but there's no support for it. Explicitly request
 				//  that now

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java Wed Feb 24 22:43:51 2016
@@ -23,23 +23,28 @@ import java.io.InputStream;
 import java.util.List;
 
 import org.apache.poi.ddf.AbstractEscherOptRecord;
+import org.apache.poi.ddf.EscherArrayProperty;
 import org.apache.poi.ddf.EscherBSERecord;
+import org.apache.poi.ddf.EscherColorRef;
 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.record.Document;
 import org.apache.poi.sl.draw.DrawPaint;
+import org.apache.poi.sl.usermodel.ColorStyle;
 import org.apache.poi.sl.usermodel.FillStyle;
 import org.apache.poi.sl.usermodel.PaintStyle;
+import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint;
+import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint.GradientType;
 import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;
+import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
+import org.apache.poi.util.Units;
 
 /**
  * Represents functionality provided by the 'Fill Effects' dialog in PowerPoint.
- *
- * @author Yegor Kozlov
  */
 public final class HSLFFill {
     // For logging
@@ -118,36 +123,110 @@ public final class HSLFFill {
     public FillStyle getFillStyle() {
         return new FillStyle() {
             public PaintStyle getPaint() {
-                switch (getFillType()) {
+                final int fillType = getFillType();
+                // TODO: fix gradient types, this mismatches with the MS-ODRAW definition ...
+                // need to handle (not only) the type (radial,rectangular,linear),
+                // the direction, e.g. top right, and bounds (e.g. for rectangular boxes)
+                switch (fillType) {
                     case FILL_SOLID:
                         return DrawPaint.createSolidPaint(getForegroundColor());
-                    case FILL_PICTURE: {
-                        final HSLFPictureData pd = getPictureData();
-                        if (pd == null) break;
-                        
-                        return new TexturePaint() {
-                            public InputStream getImageData() {
-                                return new ByteArrayInputStream(pd.getData());
-                            }
-
-                            public String getContentType() {
-                                return pd.getContentType();
-                            }
-
-                            public int getAlpha() {
-                                return (int)(shape.getAlpha(EscherProperties.FILL__FILLOPACITY)*100000.0);
-                            }
-                        };
-                    }
+                    case FILL_SHADE_SHAPE:
+                        return getGradientPaint(GradientType.shape);
+                    case FILL_SHADE_CENTER:
+                    case FILL_SHADE_TITLE:
+                        return getGradientPaint(GradientType.circular);
+                    case FILL_SHADE:
+                    case FILL_SHADE_SCALE:
+                        return getGradientPaint(GradientType.linear);
+                    case FILL_PICTURE:
+                        return getTexturePaint();
                     default:
-                        logger.log(POILogger.WARN, "unsuported fill type: " + getFillType());
-                        break;
+                        logger.log(POILogger.WARN, "unsuported fill type: " + fillType);
+                        return null;
                 }
-                return null;
             }
         };
     }
     
+    
+
+    private GradientPaint getGradientPaint(final GradientType gradientType) {
+        final AbstractEscherOptRecord opt = shape.getEscherOptRecord();
+        final EscherArrayProperty ep = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__SHADECOLORS);
+        final int colorCnt = (ep == null) ? 0 : ep.getNumberOfElementsInArray();
+
+        return new GradientPaint() {
+            public double getGradientAngle() {
+                // A value of type FixedPoint, as specified in [MS-OSHARED] section 2.2.1.6,
+                // that specifies the angle of the gradient fill. Zero degrees represents a vertical vector from
+                // bottom to top. The default value for this property is 0x00000000.
+                int rot = shape.getEscherProperty(EscherProperties.FILL__ANGLE);
+                return 90-Units.fixedPointToDouble(rot);
+            }
+            public ColorStyle[] getGradientColors() {
+                ColorStyle cs[];
+                if (colorCnt == 0) {
+                    cs = new ColorStyle[2];
+                    cs[0] = wrapColor(getBackgroundColor());
+                    cs[1] = wrapColor(getForegroundColor());
+                } else {
+                    cs = new ColorStyle[colorCnt];
+                    int idx = 0;
+                    // TODO: handle palette colors and alpha(?) value 
+                    for (byte data[] : ep) {
+                        EscherColorRef ecr = new EscherColorRef(data, 0, 4);
+                        cs[idx++] = wrapColor(shape.getColor(ecr));
+                    }
+                }
+                return cs;
+            }
+            private ColorStyle wrapColor(Color col) {
+                return (col == null) ? null : DrawPaint.createSolidPaint(col).getSolidColor();
+            }
+            public float[] getGradientFractions() {
+                float frc[];
+                if (colorCnt == 0) {
+                    frc = new float[]{0, 1};
+                } else {
+                    frc = new float[colorCnt];
+                    int idx = 0;
+                    for (byte data[] : ep) {
+                        double pos = Units.fixedPointToDouble(LittleEndian.getInt(data, 4));
+                        frc[idx++] = (float)pos;
+                    }
+                }
+                return frc;
+            }
+            public boolean isRotatedWithShape() {
+                return false;
+            }
+            public GradientType getGradientType() {
+                return gradientType;
+            }
+        };
+    }
+    
+    private TexturePaint getTexturePaint() {
+        final HSLFPictureData pd = getPictureData();
+        if (pd == null) {
+            return null;
+        }
+
+        return new TexturePaint() {
+            public InputStream getImageData() {
+                return new ByteArrayInputStream(pd.getData());
+            }
+
+            public String getContentType() {
+                return pd.getContentType();
+            }
+
+            public int getAlpha() {
+                return (int)(shape.getAlpha(EscherProperties.FILL__FILLOPACITY)*100000.0);
+            }
+        };
+    }
+
     /**
      * Returns fill type.
      * Must be one of the <code>FILL_*</code> constants defined in this class.
@@ -172,6 +251,7 @@ public final class HSLFFill {
         }
     }
 
+    @SuppressWarnings("resource")
     protected EscherBSERecord getEscherBSERecord(int idx){
         HSLFSheet sheet = shape.getSheet();
         if(sheet == null) {
@@ -258,6 +338,7 @@ public final class HSLFFill {
     /**
      * <code>PictureData</code> object used in a texture, pattern of picture fill.
      */
+    @SuppressWarnings("resource")
     public HSLFPictureData getPictureData(){
         AbstractEscherOptRecord opt = shape.getEscherOptRecord();
         EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java?rev=1732236&r1=1732235&r2=1732236&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java (original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java Wed Feb 24 22:43:51 2016
@@ -18,22 +18,25 @@
 package org.apache.poi.hslf.usermodel;
 
 import java.awt.geom.AffineTransform;
-import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
 import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.util.ArrayList;
-import java.util.Arrays;
+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.POILogger;
 import org.apache.poi.util.Units;
@@ -57,6 +60,85 @@ public final class HSLFFreeformShape ext
     public static final byte[] SEGMENTINFO_CLOSE    = new byte[]{0x01, (byte)0x60};
     public static final byte[] SEGMENTINFO_END      = new byte[]{0x00, (byte)0x80};
 
+    private static BitField PATH_INFO = BitFieldFactory.getInstance(0xE000);
+    private static BitField ESCAPE_INFO = BitFieldFactory.getInstance(0x1F00);
+
+    enum PathInfo {
+        lineTo(0),curveTo(1),moveTo(2),close(3),end(4),escape(5),clientEscape(6);
+        int flag;
+        PathInfo(int flag) {
+            this.flag = 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);
+
+        int flag;
+        EscapeInfo(int flag) {
+            this.flag = flag;
+        }
+        static EscapeInfo valueOf(int flag) {
+            for (EscapeInfo v : values()) {
+                if (v.flag == flag) {
+                    return v;
+                }
+            }
+            return null;
+        }
+    }
+
+    enum ShapePath {
+        LINES(0),
+        LINES_CLOSED(1),
+        CURVES(2),
+        CURVES_CLOSED(3),
+        COMPLEX(4);
+
+        int flag;
+        ShapePath(int flag) {
+            this.flag = flag;
+        }
+        static ShapePath valueOf(int flag) {
+            for (ShapePath v : values()) {
+                if (v.flag == flag) {
+                    return v;
+                }
+            }
+            return null;
+        }
+    }
+    
     /**
      * Create a Freeform object and initialize it from the supplied Record container.
      *
@@ -88,7 +170,7 @@ public final class HSLFFreeformShape ext
     }
 
     @Override
-    public int setPath(GeneralPath path) {
+    public int setPath(Path2D.Double path) {
         Rectangle2D bounds = path.getBounds2D();
         PathIterator it = path.getPathIterator(new AffineTransform());
 
@@ -174,23 +256,19 @@ public final class HSLFFreeformShape ext
         opt.sortProperties();
 
         setAnchor(bounds);
-        
+
         return numPoints;
     }
 
     @Override
-    public GeneralPath getPath(){
+    public Path2D.Double getPath(){
         AbstractEscherOptRecord opt = getEscherOptRecord();
-        opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 0x4));
-
-        EscherArrayProperty verticesProp = getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__VERTICES + 0x4000));
-        if(verticesProp == null) verticesProp = getEscherProperty(opt, EscherProperties.GEOMETRY__VERTICES);
 
-        EscherArrayProperty segmentsProp = getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__SEGMENTINFO + 0x4000));
-        if(segmentsProp == null) segmentsProp = getEscherProperty(opt, EscherProperties.GEOMETRY__SEGMENTINFO);
+        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
-        GeneralPath path = new GeneralPath();
+        Path2D.Double path = new Path2D.Double();
 
         //sanity check
         if(verticesProp == null) {
@@ -202,46 +280,60 @@ public final class HSLFFreeformShape ext
             return path;
         }
 
-        int numPoints = verticesProp.getNumberOfElementsInArray();
-        int numSegments = segmentsProp.getNumberOfElementsInArray();
-        for (int i = 0, j = 0; i < numSegments && j < numPoints; i++) {
-            byte[] elem = segmentsProp.getElement(i);
-            if(Arrays.equals(elem, SEGMENTINFO_MOVETO)){
-                byte[] p = verticesProp.getElement(j++);
-                short x = LittleEndian.getShort(p, 0);
-                short y = LittleEndian.getShort(p, 2);
-                path.moveTo(Units.masterToPoints(x), Units.masterToPoints(y));
-            } else if (Arrays.equals(elem, SEGMENTINFO_CUBICTO) || Arrays.equals(elem, SEGMENTINFO_CUBICTO2)){
-                i++;
-                byte[] p1 = verticesProp.getElement(j++);
-                short x1 = LittleEndian.getShort(p1, 0);
-                short y1 = LittleEndian.getShort(p1, 2);
-                byte[] p2 = verticesProp.getElement(j++);
-                short x2 = LittleEndian.getShort(p2, 0);
-                short y2 = LittleEndian.getShort(p2, 2);
-                byte[] p3 = verticesProp.getElement(j++);
-                short x3 = LittleEndian.getShort(p3, 0);
-                short y3 = LittleEndian.getShort(p3, 2);
-                path.curveTo(
-                    Units.masterToPoints(x1), Units.masterToPoints(y1),
-                    Units.masterToPoints(x2), Units.masterToPoints(y2),
-                    Units.masterToPoints(x3), Units.masterToPoints(y3));
-
-            } else if (Arrays.equals(elem, SEGMENTINFO_LINETO)){
-                i++;
-                byte[] pnext = segmentsProp.getElement(i);
-                if(Arrays.equals(pnext, SEGMENTINFO_ESCAPE)){
-                    if(j + 1 < numPoints){
-                        byte[] p = verticesProp.getElement(j++);
-                        short x = LittleEndian.getShort(p, 0);
-                        short y = LittleEndian.getShort(p, 2);
-                        path.lineTo(Units.masterToPoints(x), Units.masterToPoints(y));
+        Iterator<byte[]> vertIter = verticesProp.iterator();
+        Iterator<byte[]> segIter = segmentsProp.iterator();
+        
+        byte segPushBack[] = null;
+        while (vertIter.hasNext() && segIter.hasNext()) {
+            byte[] segElem = (segPushBack != null) ? segPushBack : segIter.next();
+            segPushBack = null;
+            PathInfo pi = getPathInfo(segElem);
+            switch (pi) {
+                case escape: {
+                    handleEscapeInfo(path, segElem, vertIter);
+                    break;
+                }
+                case moveTo: {
+                    byte[] p = vertIter.next();
+                    double x = Units.masterToPoints(LittleEndian.getShort(p, 0));
+                    double y = Units.masterToPoints(LittleEndian.getShort(p, 2));
+                    path.moveTo(x,y);
+                    break;
+                }
+                case curveTo: {
+                    byte[] p1 = vertIter.next();
+                    double x1 = Units.masterToPoints(LittleEndian.getShort(p1, 0));
+                    double y1 = Units.masterToPoints(LittleEndian.getShort(p1, 2));
+                    byte[] p2 = vertIter.next();
+                    double x2 = Units.masterToPoints(LittleEndian.getShort(p2, 0));
+                    double y2 = Units.masterToPoints(LittleEndian.getShort(p2, 2));
+                    byte[] p3 = vertIter.next();
+                    double x3 = Units.masterToPoints(LittleEndian.getShort(p3, 0));
+                    double y3 = Units.masterToPoints(LittleEndian.getShort(p3, 2));
+                    path.curveTo(x1,y1,x2,y2,x3,y3);
+                    break;
+                }
+                case lineTo:
+                    if (vertIter.hasNext()) {
+                        byte[] p = vertIter.next();
+                        double x = Units.masterToPoints(LittleEndian.getShort(p, 0));
+                        double y = Units.masterToPoints(LittleEndian.getShort(p, 2));
+                        path.lineTo(x,y);
                     }
-                } else if (Arrays.equals(pnext, SEGMENTINFO_CLOSE)){
+                    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 anchor = getAnchor();
         Rectangle2D bounds = path.getBounds2D();
@@ -251,6 +343,81 @@ public final class HSLFFreeformShape ext
                 anchor.getWidth()/bounds.getWidth(),
                 anchor.getHeight()/bounds.getHeight()
         );
-        return new GeneralPath(at.createTransformedShape(path));
+        return new Path2D.Double(at.createTransformedShape(path));
+    }
+    
+    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);
+    }
+    
+    private static EscapeInfo getEscapeInfo(byte elem[]) {
+        int elemUS = LittleEndian.getUShort(elem, 0);
+        int escInfo = ESCAPE_INFO.getValue(elemUS);
+        return EscapeInfo.valueOf(escInfo);
     }
 }




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