tag r1873550 as 4.1.2

git-svn-id: https://svn.apache.org/repos/asf/poi/tags/REL_4_1_2@1873551 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/build.xml b/build.xml
index 774a40a..e858ad7 100644
--- a/build.xml
+++ b/build.xml
@@ -1648,7 +1648,7 @@
             unless="integration.test.notRequired">
         <propertyreset name="org.apache.poi.util.POILogger" value="org.apache.poi.util.CommonsLogger"/>
         <delete dir="build" includes="test-integration.log*"/>
-        <poiunit failureproperty="integration.test.failed" heap="2048" showoutput="true" jacocodest="build/jacoco-integration.exec">
+        <poiunit failureproperty="integration.test.failed" heap="1512" showoutput="true" jacocodest="build/jacoco-integration.exec">
             <classpath refid="test.integration.classpath"/>
             <batchtest todir="${integration.reports.test}">
                 <fileset dir="${integration.src.test}">
diff --git a/src/integrationtest/org/apache/poi/stress/AbstractFileHandler.java b/src/integrationtest/org/apache/poi/stress/AbstractFileHandler.java
index 2b1114a..64179ff 100644
--- a/src/integrationtest/org/apache/poi/stress/AbstractFileHandler.java
+++ b/src/integrationtest/org/apache/poi/stress/AbstractFileHandler.java
@@ -31,9 +31,9 @@
 import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.extractor.POIOLE2TextExtractor;
 import org.apache.poi.extractor.POITextExtractor;
+import org.apache.poi.hpsf.extractor.HPSFPropertiesExtractor;
 import org.apache.poi.hssf.extractor.EventBasedExcelExtractor;
 import org.apache.poi.ooxml.extractor.ExtractorFactory;
-import org.apache.poi.hpsf.extractor.HPSFPropertiesExtractor;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
 import org.apache.poi.ss.extractor.ExcelExtractor;
 import org.apache.poi.util.IOUtils;
@@ -48,12 +48,13 @@
     static {
         // password protected files without password
     	// ... currently none ...
-        
+
         // unsupported file-types, no supported OLE2 parts
         EXPECTED_EXTRACTOR_FAILURES.add("hmef/quick-winmail.dat");
         EXPECTED_EXTRACTOR_FAILURES.add("hmef/winmail-sample1.dat");
         EXPECTED_EXTRACTOR_FAILURES.add("hmef/bug52400-winmail-simple.dat");
         EXPECTED_EXTRACTOR_FAILURES.add("hmef/bug52400-winmail-with-attachments.dat");
+        EXPECTED_EXTRACTOR_FAILURES.add("hmef/bug63955-winmail.dat");
         EXPECTED_EXTRACTOR_FAILURES.add("hpsf/Test0313rur.adm");
         EXPECTED_EXTRACTOR_FAILURES.add("poifs/Notes.ole2");
     }
@@ -70,10 +71,10 @@
         } finally {
             ExtractorFactory.setThreadPrefersEventExtractors(before);
         }
-        
+
         /* Did fail for some documents with special XML contents...
         try {
-            OOXMLPrettyPrint.main(new String[] { file.getAbsolutePath(), 
+            OOXMLPrettyPrint.main(new String[] { file.getAbsolutePath(),
             		"/tmp/pretty-" + file.getName() });
         } catch (ZipException e) {
         	// ignore, not a Zip/OOXML file
@@ -83,7 +84,7 @@
     private void handleExtractingInternal(File file) throws Exception {
         long length = file.length();
         long modified = file.lastModified();
-        
+
         POITextExtractor extractor = null;
         String fileAndParentName = file.getParentFile().getName() + "/" + file.getName();
         try {
diff --git a/src/integrationtest/org/apache/poi/stress/HPSFFileHandler.java b/src/integrationtest/org/apache/poi/stress/HPSFFileHandler.java
index cd6b601..ba2e1bc 100644
--- a/src/integrationtest/org/apache/poi/stress/HPSFFileHandler.java
+++ b/src/integrationtest/org/apache/poi/stress/HPSFFileHandler.java
@@ -59,7 +59,8 @@
     );
 
     static final Set<String> EXCLUDES_HANDLE_FILE = unmodifiableHashSet(
-        "hpsf/Test_Humor-Generation.ppt"
+        "hpsf/Test_Humor-Generation.ppt",
+        "slideshow/missing-moveto.ppt" // POIFS properties corrupted
     );
 
 
diff --git a/src/java/org/apache/poi/sl/draw/DrawPaint.java b/src/java/org/apache/poi/sl/draw/DrawPaint.java
index d8a11a9..eb18e10 100644
--- a/src/java/org/apache/poi/sl/draw/DrawPaint.java
+++ b/src/java/org/apache/poi/sl/draw/DrawPaint.java
@@ -25,7 +25,6 @@
 import java.awt.MultipleGradientPaint.ColorSpaceType;
 import java.awt.MultipleGradientPaint.CycleMethod;
 import java.awt.Paint;
-import java.awt.Point;
 import java.awt.RadialGradientPaint;
 import java.awt.Shape;
 import java.awt.geom.AffineTransform;
@@ -33,9 +32,8 @@
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
-import java.awt.image.DataBufferInt;
-import java.awt.image.DirectColorModel;
-import java.awt.image.Raster;
+import java.awt.image.DataBuffer;
+import java.awt.image.IndexColorModel;
 import java.awt.image.WritableRaster;
 import java.io.IOException;
 import java.io.InputStream;
@@ -350,25 +348,42 @@
      * @return the original image if no duotone was found, otherwise the colorized pattern
      */
     private static BufferedImage colorizePattern(TexturePaint fill, BufferedImage pattern) {
-        List<ColorStyle> duoTone = fill.getDuoTone();
+        final List<ColorStyle> duoTone = fill.getDuoTone();
         if (duoTone == null || duoTone.size() != 2) {
             return pattern;
         }
 
         // the pattern image is actually a gray scale image, so we simply take the first color component
         // as an index into our gradient samples
-        int blendShades = 1 << pattern.getSampleModel().getSampleSize(0);
-        int[] gradSample = linearBlendedColors(duoTone, blendShades);
-        int[] redSample = pattern.getRaster().getSamples(0, 0, pattern.getWidth(), pattern.getHeight(), 0, (int[])null);
+        final int redBits = pattern.getSampleModel().getSampleSize(0);
+        final int blendBits = Math.max(Math.min(redBits, 8), 1);
+        final int blendShades = 1 << blendBits;
+        // Currently ImageIO converts 16-bit images to 8-bit internally, so it's unlikely to get a blendRatio != 1
+        final double blendRatio = blendShades / (double)(1 << Math.max(redBits,1));
+        final int[] gradSample = linearBlendedColors(duoTone, blendShades);
 
-        for (int i=0; i<redSample.length; i++) {
-            redSample[i] = gradSample[redSample[i] & 0xFF];
+        final IndexColorModel icm = new IndexColorModel(blendBits, blendShades, gradSample, 0, true, -1, DataBuffer.TYPE_BYTE);
+        final BufferedImage patIdx = new BufferedImage(pattern.getWidth(), pattern.getHeight(), BufferedImage.TYPE_BYTE_INDEXED, icm);
+
+        final WritableRaster rasterRGBA = pattern.getRaster();
+        final WritableRaster rasterIdx = patIdx.getRaster();
+
+        final int[] redSample = new int[pattern.getWidth()];
+        for (int y=0; y<pattern.getHeight(); y++) {
+            rasterRGBA.getSamples(0, y, redSample.length, 1, 0, redSample);
+            scaleShades(redSample, blendRatio);
+            rasterIdx.setSamples(0, y, redSample.length, 1, 0, redSample);
         }
 
-        DirectColorModel dcm = new DirectColorModel(32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
-        DataBufferInt dbi = new DataBufferInt(redSample, redSample.length);
-        WritableRaster raster = Raster.createPackedRaster(dbi, pattern.getWidth(), pattern.getHeight(), pattern.getWidth(), new int[]{0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000}, new Point());
-        return new BufferedImage(dcm, raster, true, null);
+        return patIdx;
+    }
+
+    private static void scaleShades(int[] samples, double ratio) {
+        if (ratio != 1) {
+            for (int x=0; x<samples.length; x++) {
+                samples[x] = (int)Math.rint(samples[x] * ratio);
+            }
+        }
     }
 
     private static int[] linearBlendedColors(List<ColorStyle> duoTone, final int blendShades) {
diff --git a/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java b/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
index 1ab4af3..c1de9c9 100644
--- a/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
+++ b/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
@@ -31,6 +31,7 @@
 import java.text.AttributedCharacterIterator.Attribute;
 import java.text.AttributedString;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
 
@@ -60,7 +61,7 @@
 
 public class DrawTextParagraph implements Drawable {
     private static final POILogger LOG = POILogFactory.getLogger(DrawTextParagraph.class);
-    
+
     /** Keys for passing hyperlinks to the graphics context */
     public static final XlinkAttribute HYPERLINK_HREF = new XlinkAttribute("href");
     public static final XlinkAttribute HYPERLINK_LABEL = new XlinkAttribute("label");
@@ -206,7 +207,7 @@
 
             line.setPosition(penX, penY);
             line.draw(graphics);
-            
+
             if(spacing > 0) {
                 // If linespacing >= 0, then linespacing is a percentage of normal line height.
                 penY += spacing*0.01* line.getHeight();
@@ -383,7 +384,14 @@
 
     @Internal
     public String getRenderableText(final TextRun tr) {
-        final String txtSpace = tr.getRawText().replace("\t", tab2space(tr)).replace('\u000b', '\n');
+        String txtSpace = tr.getRawText();
+        if (txtSpace == null) {
+            return null;
+        }
+        if (txtSpace.contains("\t")) {
+            txtSpace = txtSpace.replace("\t", tab2space(tr));
+        }
+        txtSpace = txtSpace.replace('\u000b', '\n');
         final Locale loc = LocaleUtil.getUserLocale();
 
         switch (tr.getTextCap()) {
@@ -414,19 +422,23 @@
         string.addAttribute(TextAttribute.SIZE, fs.floatValue());
 
         TextLayout l = new TextLayout(string.getIterator(), new FontRenderContext(null, true, true));
+        // some JDK versions return 0 here
         double wspace = l.getAdvance();
 
+        final int numSpaces;
         Double tabSz = paragraph.getDefaultTabSize();
-        if (tabSz == null) {
-            tabSz = wspace*4;
+        if (wspace <= 0) {
+            numSpaces = 4;
+        } else {
+            if (tabSz == null) {
+                tabSz = wspace*4;
+            }
+            numSpaces = (int)Math.min(Math.ceil(tabSz / wspace), 20);
         }
 
-        int numSpaces = (int)Math.ceil(tabSz / wspace);
-        StringBuilder buf = new StringBuilder();
-        for(int i = 0; i < numSpaces; i++) {
-            buf.append(' ');
-        }
-        return buf.toString();
+        char[] buf = new char[numSpaces];
+        Arrays.fill(buf, ' ');
+        return new String(buf);
     }
 
 
@@ -683,7 +695,7 @@
                 // fallback for unsupported glyphs
                 partBegin = partEnd;
                 partEnd = nextPart(fontMapped, runText, partBegin, rangeBegin+rangeLen, false);
-                
+
                 if (partBegin < partEnd) {
                     // handle (a) and (b)
                     attList.add(new AttributedStringData(TextAttribute.FAMILY, fontFallback.getFontName(Locale.ROOT), beginIndex+partBegin, beginIndex+partEnd));
@@ -692,11 +704,11 @@
                     }
                 }
             }
-            
+
             rangeBegin += rangeLen;
         }
     }
-    
+
     private static int nextPart(Font fontMapped, String runText, int beginPart, int endPart, boolean isDisplayed) {
         int rIdx = beginPart;
         while (rIdx < endPart) {
diff --git a/src/java/org/apache/poi/sl/draw/geom/PresetGeometries.java b/src/java/org/apache/poi/sl/draw/geom/PresetGeometries.java
index 98b2d58..6b191bd 100644
--- a/src/java/org/apache/poi/sl/draw/geom/PresetGeometries.java
+++ b/src/java/org/apache/poi/sl/draw/geom/PresetGeometries.java
@@ -38,12 +38,24 @@
 import org.apache.poi.util.XMLHelper;
 
 /**
- * 
+ *
  */
 public class PresetGeometries extends LinkedHashMap<String, CustomGeometry> {
     private final static POILogger LOG = POILogFactory.getLogger(PresetGeometries.class);
-    protected final static String BINDING_PACKAGE = "org.apache.poi.sl.draw.binding";
-    
+    private final static String BINDING_PACKAGE = "org.apache.poi.sl.draw.binding";
+
+    private static class SingletonHelper {
+        private static JAXBContext JAXB_CONTEXT;
+        static {
+            try {
+                JAXB_CONTEXT = JAXBContext.newInstance(BINDING_PACKAGE);
+            } catch (JAXBException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+
     protected static PresetGeometries _inst;
 
     protected PresetGeometries(){}
@@ -57,7 +69,7 @@
             streamReader.nextTag();
 
             // JAXB:
-            JAXBContext jaxbContext = JAXBContext.newInstance(BINDING_PACKAGE);
+            JAXBContext jaxbContext = SingletonHelper.JAXB_CONTEXT;
             Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
 
             long cntElem = 0;
@@ -76,13 +88,13 @@
             streamReader.close();
         }
     }
-    
+
     /**
      * Convert a single CustomGeometry object, i.e. from xmlbeans
      */
     public static CustomGeometry convertCustomGeometry(XMLStreamReader staxReader) {
         try {
-            JAXBContext jaxbContext = JAXBContext.newInstance(BINDING_PACKAGE);
+            JAXBContext jaxbContext = SingletonHelper.JAXB_CONTEXT;
             Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
             JAXBElement<CTCustomGeometry2D> el = unmarshaller.unmarshal(staxReader, CTCustomGeometry2D.class);
             return new CustomGeometry(el.getValue());
diff --git a/src/ooxml/java/org/apache/poi/xslf/model/ParagraphPropertyFetcher.java b/src/ooxml/java/org/apache/poi/xslf/model/ParagraphPropertyFetcher.java
index 6085b9d..1d2c342 100644
--- a/src/ooxml/java/org/apache/poi/xslf/model/ParagraphPropertyFetcher.java
+++ b/src/ooxml/java/org/apache/poi/xslf/model/ParagraphPropertyFetcher.java
@@ -19,15 +19,21 @@
 
 package org.apache.poi.xslf.model;
 
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamReader;
+
 import org.apache.poi.xslf.usermodel.XSLFShape;
-import org.apache.xmlbeans.XmlObject;
+import org.apache.xmlbeans.XmlException;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
 
-/**
- *
- * @author Yegor Kozlov
- */
 public abstract class ParagraphPropertyFetcher<T> extends PropertyFetcher<T> {
+    static final String PML_NS = "http://schemas.openxmlformats.org/presentationml/2006/main";
+    static final String DML_NS = "http://schemas.openxmlformats.org/drawingml/2006/main";
+
+    private static final QName[] TX_BODY = { new QName(PML_NS, "txBody") };
+    private static final QName[] LST_STYLE = { new QName(DML_NS, "lstStyle") };
+
     int _level;
 
     public ParagraphPropertyFetcher(int level) {
@@ -35,17 +41,20 @@
     }
 
     public boolean fetch(XSLFShape shape) {
-
-        XmlObject[] o = shape.getXmlObject().selectPath(
-                "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +
-                "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +
-                ".//p:txBody/a:lstStyle/a:lvl" + (_level + 1) + "pPr"
-        );
-        if (o.length == 1) {
-            CTTextParagraphProperties props = (CTTextParagraphProperties) o[0];
-            return fetch(props);
+        QName[] lvlProp = { new QName(DML_NS, "lvl" + (_level + 1) + "pPr") };
+        CTTextParagraphProperties props = null;
+        try {
+            props = shape.selectProperty(
+                    CTTextParagraphProperties.class, ParagraphPropertyFetcher::parse, TX_BODY, LST_STYLE, lvlProp);
+            return (props != null) && fetch(props);
+        } catch (XmlException e) {
+            return false;
         }
-        return false;
+    }
+
+    private static CTTextParagraphProperties parse(XMLStreamReader reader) throws XmlException {
+        CTTextParagraph para = CTTextParagraph.Factory.parse(reader);
+        return (para != null && para.isSetPPr()) ? para.getPPr() : null;
     }
 
     public abstract boolean fetch(CTTextParagraphProperties props);
diff --git a/src/ooxml/java/org/apache/poi/xslf/model/TextBodyPropertyFetcher.java b/src/ooxml/java/org/apache/poi/xslf/model/TextBodyPropertyFetcher.java
index 4b1d546..9bb0250 100644
--- a/src/ooxml/java/org/apache/poi/xslf/model/TextBodyPropertyFetcher.java
+++ b/src/ooxml/java/org/apache/poi/xslf/model/TextBodyPropertyFetcher.java
@@ -19,32 +19,35 @@
 
 package org.apache.poi.xslf.model;
 
+import static org.apache.poi.xslf.model.ParagraphPropertyFetcher.DML_NS;
+import static org.apache.poi.xslf.model.ParagraphPropertyFetcher.PML_NS;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamReader;
+
 import org.apache.poi.xslf.usermodel.XSLFShape;
-import org.apache.xmlbeans.XmlObject;
+import org.apache.xmlbeans.XmlException;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;
 
-/**
- * Created by IntelliJ IDEA.
- * User: yegor
- * Date: Oct 21, 2011
- * Time: 1:18:52 PM
- * To change this template use File | Settings | File Templates.
- */
 public abstract class TextBodyPropertyFetcher<T> extends PropertyFetcher<T> {
+    private static final QName[] TX_BODY = { new QName(PML_NS, "txBody") };
+    private static final QName[] BODY_PR = { new QName(DML_NS, "bodyPr") };
 
     public boolean fetch(XSLFShape shape) {
-
-        XmlObject[] o = shape.getXmlObject().selectPath(
-                "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +
-                "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +
-                ".//p:txBody/a:bodyPr"
-        );
-        if (o.length == 1) {
-            CTTextBodyProperties props = (CTTextBodyProperties) o[0];
-            return fetch(props);
+        CTTextBodyProperties props = null;
+        try {
+            props = shape.selectProperty(
+                    CTTextBodyProperties.class, TextBodyPropertyFetcher::parse, TX_BODY, BODY_PR);
+            return (props != null) && fetch(props);
+        } catch (XmlException e) {
+            return false;
         }
+    }
 
-        return false;
+    private static CTTextBodyProperties parse(XMLStreamReader reader) throws XmlException {
+        CTTextBody body = CTTextBody.Factory.parse(reader);
+        return (body != null) ? body.getBodyPr() : null;
     }
 
     public abstract boolean fetch(CTTextBodyProperties props);
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectShape.java
index 3404227..eb71e7e 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFObjectShape.java
@@ -25,10 +25,11 @@
 import java.io.OutputStream;
 
 import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamReader;
 
+import org.apache.poi.hpsf.ClassID;
 import org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart;
 import org.apache.poi.ooxml.POIXMLException;
-import org.apache.poi.hpsf.ClassID;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.openxml4j.opc.PackagePart;
@@ -42,8 +43,6 @@
 import org.apache.poi.util.Internal;
 import org.apache.xmlbeans.XmlCursor;
 import org.apache.xmlbeans.XmlException;
-import org.apache.xmlbeans.XmlObject;
-import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData;
@@ -63,6 +62,10 @@
 public class XSLFObjectShape extends XSLFGraphicFrame implements ObjectShape<XSLFShape,XSLFTextParagraph> {
 
     /* package */ static final String OLE_URI = "http://schemas.openxmlformats.org/presentationml/2006/ole";
+    private static final QName[] GRAPHIC = { new QName(DML_NS, "graphic") };
+    private static final QName[] GRAPHIC_DATA = { new QName(DML_NS, "graphicData") };
+    private static final QName[] OLE_OBJ = { new QName(PML_NS, "oleObj") };
+    private static final QName[] CT_PICTURE = { new QName(PML_NS, "pic") };
 
     private CTOleObject _oleObject;
     private XSLFPictureData _data;
@@ -70,31 +73,13 @@
     /*package*/ XSLFObjectShape(CTGraphicalObjectFrame shape, XSLFSheet sheet){
         super(shape, sheet);
 
-        CTGraphicalObjectData god = shape.getGraphic().getGraphicData();
-        XmlCursor xc = god.newCursor();
         // select oleObj potentially under AlternateContent
         // usually the mc:Choice element will be selected first
-        xc.selectPath("declare namespace p='"+PML_NS+"' .//p:oleObj");
         try {
-            if (!xc.toNextSelection()) {
-                throw new IllegalStateException("p:oleObj element was not found in\n " + god);
-            }
-
-            XmlObject xo = xc.getObject();
-            // Pesky XmlBeans bug - see Bugzilla #49934
-            // it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas
-            if (xo instanceof XmlAnyTypeImpl){
-                String errStr =
-                    "Schemas (*.xsb) for CTOleObject can't be loaded - usually this happens when OSGI " +
-                    "loading is used and the thread context classloader has no reference to " +
-                    "the xmlbeans classes - use POIXMLTypeLoader.setClassLoader() to set the loader, " +
-                    "e.g. with CTOleObject.class.getClassLoader()"
-                ;
-                throw new IllegalStateException(errStr);
-            }
-            _oleObject = (CTOleObject)xo;
-        } finally {
-            xc.dispose();
+            _oleObject = selectProperty(CTOleObject.class, null, GRAPHIC, GRAPHIC_DATA, OLE_OBJ);
+        } catch (XmlException e) {
+            // ole objects should be also inside AlternateContent tags, even with ECMA 376 edition 1
+            throw new IllegalStateException(e);
         }
     }
 
@@ -113,13 +98,13 @@
     public String getProgId() {
         return (_oleObject == null) ? null : _oleObject.getProgId();
     }
-    
+
     @Override
     public String getFullName() {
         return (_oleObject == null) ? null : _oleObject.getName();
     }
-    
-    
+
+
     /**
      * Return the data on the (internal) picture.
      * For an external linked picture, will return null
@@ -160,19 +145,19 @@
     }
 
     protected CTBlipFillProperties getBlipFill() {
-        String xquery =
-                "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' "
-              + ".//p:blipFill"
-              ;
-        XmlObject xo = selectProperty(XmlObject.class, xquery);
         try {
-            xo = CTPicture.Factory.parse(xo.getDomNode());
-        } catch (XmlException xe) {
+            CTPicture pic = selectProperty
+                (CTPicture.class, XSLFObjectShape::parse, GRAPHIC, GRAPHIC_DATA, OLE_OBJ, CT_PICTURE);
+            return (pic != null) ? pic.getBlipFill() : null;
+        } catch (XmlException e) {
             return null;
         }
-        return ((CTPicture)xo).getBlipFill();
     }
 
+    private static CTPicture parse(XMLStreamReader reader) throws XmlException {
+        CTGroupShape gs = CTGroupShape.Factory.parse(reader);
+        return (gs.sizeOfPicArray() > 0) ? gs.getPicArray(0) : null;
+    }
 
     @Override
     public OutputStream updateObjectData(final Application application, final ObjectMetaData metaData) throws IOException {
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
index 1a0c96f..1408bed 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
@@ -33,6 +33,7 @@
 
 import javax.imageio.ImageIO;
 import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamReader;
 
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.openxml4j.opc.PackageRelationship;
@@ -69,11 +70,15 @@
     implements PictureShape<XSLFShape,XSLFTextParagraph> {
     private static final POILogger LOG = POILogFactory.getLogger(XSLFPictureShape.class);
 
-    private static final String DML_NS = "http://schemas.microsoft.com/office/drawing/2010/main";
-    private static final String SVG_NS = "http://schemas.microsoft.com/office/drawing/2016/SVG/main";
+    private static final String MS_DML_NS = "http://schemas.microsoft.com/office/drawing/2010/main";
+    private static final String MS_SVG_NS = "http://schemas.microsoft.com/office/drawing/2016/SVG/main";
     private static final String BITMAP_URI = "{28A0092B-C50C-407E-A947-70E740481C1C}";
     private static final String SVG_URI = "{96DAC541-7B7A-43D3-8B79-37D633B846F1}";
 
+    private static final QName EMBED_TAG = new QName(CORE_PROPERTIES_ECMA376_NS, "embed", "rel");
+    private static final QName[] BLIP_FILL = { new QName(PML_NS, "blipFill") };
+
+
     private XSLFPictureData _data;
 
     /*package*/ XSLFPictureShape(CTPicture shape, XSLFSheet sheet) {
@@ -135,8 +140,8 @@
     public void setPlaceholder(Placeholder placeholder) {
         super.setPlaceholder(placeholder);
     }
-    
-    
+
+
     /**
      * For an external linked picture, return the last-seen
      *  path to the picture.
@@ -147,13 +152,13 @@
             // Internal picture, nothing to return
             return null;
         }
-        
+
         String rId = getBlipLink();
         if (rId == null) {
             // No link recorded, nothing we can do
             return null;
         }
-        
+
         PackagePart p = getSheet().getPackagePart();
         PackageRelationship rel = p.getRelationship(rId);
         if (rel != null) {
@@ -168,25 +173,23 @@
         if (bfp != null) {
             return bfp;
         }
-                    
-        String xquery =
-                "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main'; "
-              + "declare namespace mc='http://schemas.openxmlformats.org/markup-compatibility/2006' "
-              + ".//mc:Fallback/p:blipFill"
-              ;
-        XmlObject xo = selectProperty(XmlObject.class, xquery);
+
         try {
-            xo = CTPicture.Factory.parse(xo.getDomNode());
+            return selectProperty(CTBlipFillProperties.class, XSLFPictureShape::parse, BLIP_FILL);
         } catch (XmlException xe) {
             return null;
         }
-        return ((CTPicture)xo).getBlipFill();
     }
-    
+
+    private static CTBlipFillProperties parse(XMLStreamReader reader) throws XmlException {
+        CTPicture pic = CTPicture.Factory.parse(reader);
+        return (pic != null) ? pic.getBlipFill() : null;
+    }
+
     protected CTBlip getBlip(){
         return getBlipFill().getBlip();
     }
-    
+
     @SuppressWarnings("WeakerAccess")
     protected String getBlipLink(){
         CTBlip blip = getBlip();
@@ -232,8 +235,8 @@
             extBitmap.setUri(BITMAP_URI);
             XmlCursor cur = extBitmap.newCursor();
             cur.toEndToken();
-            cur.beginElement(new QName(DML_NS, "useLocalDpi", "a14"));
-            cur.insertNamespace("a14", DML_NS);
+            cur.beginElement(new QName(MS_DML_NS, "useLocalDpi", "a14"));
+            cur.insertNamespace("a14", MS_DML_NS);
             cur.insertAttributeWithValue("val", "0");
             cur.dispose();
         }
@@ -252,9 +255,9 @@
         svgBitmap.setUri(SVG_URI);
         XmlCursor cur = svgBitmap.newCursor();
         cur.toEndToken();
-        cur.beginElement(new QName(SVG_NS, "svgBlip", "asvg"));
-        cur.insertNamespace("asvg", SVG_NS);
-        cur.insertAttributeWithValue(new QName(CORE_PROPERTIES_ECMA376_NS, "embed", "rel"), svgRelId);
+        cur.beginElement(new QName(MS_SVG_NS, "svgBlip", "asvg"));
+        cur.insertNamespace("asvg", MS_SVG_NS);
+        cur.insertAttributeWithValue(EMBED_TAG, svgRelId);
         cur.dispose();
     }
 
@@ -277,8 +280,8 @@
         for (int i = 0; i < size; i++) {
             XmlCursor cur = extLst.getExtArray(i).newCursor();
             try {
-                if (cur.toChild(SVG_NS, "svgBlip")) {
-                    String svgRelId = cur.getAttributeText(new QName(CORE_PROPERTIES_ECMA376_NS, "embed"));
+                if (cur.toChild(MS_SVG_NS, "svgBlip")) {
+                    String svgRelId = cur.getAttributeText(EMBED_TAG);
                     return (svgRelId != null) ? (XSLFPictureData) getSheet().getRelationById(svgRelId) : null;
                 }
             } finally {
@@ -367,13 +370,13 @@
             CTOfficeArtExtensionList extLst = blip.getExtLst();
             //noinspection deprecation
             for(CTOfficeArtExtension ext : extLst.getExtArray()){
-                String xpath = "declare namespace a14='"+ DML_NS +"' $this//a14:imgProps/a14:imgLayer";
+                String xpath = "declare namespace a14='"+ MS_DML_NS +"' $this//a14:imgProps/a14:imgLayer";
                 XmlObject[] obj = ext.selectPath(xpath);
                 if(obj != null && obj.length == 1){
                     XmlCursor c = obj[0].newCursor();
-                    String id = c.getAttributeText(new QName("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "embed"));//selectPath("declare namespace r='http://schemas.openxmlformats.org/officeDocument/2006/relationships' $this//[@embed]");
+                    String id = c.getAttributeText(EMBED_TAG);
                     String newId = getSheet().importBlip(id, p.getSheet());
-                    c.setAttributeText(new QName("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "embed"), newId);
+                    c.setAttributeText(EMBED_TAG, newId);
                     c.dispose();
                 }
             }
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPlaceholderDetails.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPlaceholderDetails.java
index e5d321b..6cb179d 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPlaceholderDetails.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPlaceholderDetails.java
@@ -22,9 +22,12 @@
 import java.util.function.Consumer;
 import java.util.function.Function;
 
+import javax.xml.namespace.QName;
+
 import org.apache.poi.sl.usermodel.MasterSheet;
 import org.apache.poi.sl.usermodel.Placeholder;
 import org.apache.poi.sl.usermodel.PlaceholderDetails;
+import org.apache.xmlbeans.XmlException;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTHeaderFooter;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesMaster;
@@ -190,9 +193,24 @@
         return _ph;
     }
 
+    private static final QName[] NV_CONTAINER = {
+        new QName(PML_NS, "nvSpPr"),
+        new QName(PML_NS, "nvCxnSpPr"),
+        new QName(PML_NS, "nvGrpSpPr"),
+        new QName(PML_NS, "nvPicPr"),
+        new QName(PML_NS, "nvGraphicFramePr")
+    };
+
+    private static final QName[] NV_PROPS = {
+        new QName(PML_NS, "nvPr")
+    };
+
     private CTApplicationNonVisualDrawingProps getNvProps() {
-        final String xquery = "declare namespace p='" + PML_NS + "' .//*/p:nvPr";
-        return shape.selectProperty(CTApplicationNonVisualDrawingProps.class, xquery);
+        try {
+            return shape.selectProperty(CTApplicationNonVisualDrawingProps.class, null, NV_CONTAINER, NV_PROPS);
+        } catch (XmlException e) {
+            return null;
+        }
     }
 
     private CTHeaderFooter getHeaderFooter(final boolean create) {
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java
index 7d80fbe..efdbd7b 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java
@@ -21,7 +21,13 @@
 
 import java.awt.Graphics2D;
 import java.awt.geom.Rectangle2D;
+import java.util.Locale;
 
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamReader;
+
+import com.microsoft.schemas.compatibility.AlternateContentDocument;
+import com.microsoft.schemas.compatibility.AlternateContentDocument.AlternateContent;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.sl.draw.DrawFactory;
 import org.apache.poi.sl.draw.DrawPaint;
@@ -37,7 +43,9 @@
 import org.apache.poi.xslf.model.PropertyFetcher;
 import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties;
 import org.apache.xmlbeans.XmlCursor;
+import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlObject;
+import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientFillProperties;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupShapeProperties;
@@ -59,7 +67,36 @@
  */
 @Beta
 public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
+
+    @Internal
+    public interface ReparseFactory<T extends XmlObject> {
+        T parse(XMLStreamReader reader) throws XmlException;
+    }
+
+    static final String DML_NS = "http://schemas.openxmlformats.org/drawingml/2006/main";
     static final String PML_NS = "http://schemas.openxmlformats.org/presentationml/2006/main";
+    private static final String MC_NS = "http://schemas.openxmlformats.org/markup-compatibility/2006";
+    private static final String MAC_DML_NS = "http://schemas.microsoft.com/office/mac/drawingml/2008/main";
+
+    private static final QName ALTERNATE_CONTENT_TAG = new QName(MC_NS, "AlternateContent");
+
+    private static final QName[] NV_CONTAINER = {
+        new QName(PML_NS, "nvSpPr"),
+        new QName(PML_NS, "nvCxnSpPr"),
+        new QName(PML_NS, "nvGrpSpPr"),
+        new QName(PML_NS, "nvPicPr"),
+        new QName(PML_NS, "nvGraphicFramePr")
+    };
+
+    private static final QName[] CNV_PROPS = {
+        new QName(PML_NS, "cNvPr")
+    };
+
+    private static final String OSGI_ERROR =
+        "Schemas (*.xsb) for <CLASS> can't be loaded - usually this happens when OSGI " +
+        "loading is used and the thread context classloader has no reference to " +
+        "the xmlbeans classes - please either verify if the <XSB>.xsb is on the " +
+        "classpath or alternatively try to use the full ooxml-schemas-x.x.jar";
 
     private final XmlObject _shape;
     private final XSLFSheet _sheet;
@@ -199,11 +236,14 @@
     }
 
     protected CTNonVisualDrawingProps getCNvPr() {
-        if (_nvPr == null) {
-            String xquery = "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:cNvPr";
-            _nvPr = selectProperty(CTNonVisualDrawingProps.class, xquery);
+        try {
+            if (_nvPr == null) {
+                _nvPr = selectProperty(CTNonVisualDrawingProps.class, null, NV_CONTAINER, CNV_PROPS);
+            }
+            return _nvPr;
+        } catch (XmlException e) {
+            return null;
         }
-        return _nvPr;
     }
 
     @SuppressWarnings("WeakerAccess")
@@ -282,6 +322,160 @@
     }
 
     /**
+     * Internal code - API may change any time!
+     * <p>
+     * The {@link #selectProperty(Class, String)} xquery method has some performance penalties,
+     * which can be workaround by using {@link XmlCursor}. This method also takes into account
+     * that {@code AlternateContent} tags can occur anywhere on the given path.
+     * <p>
+     * It returns the first element found - the search order is:
+     * <ul>
+     *     <li>searching for a direct child</li>
+     *     <li>searching for a AlternateContent.Choice child</li>
+     *     <li>searching for a AlternateContent.Fallback child</li>
+     * </ul>
+     * Currently POI OOXML is based on the first edition of the ECMA 376 schema, which doesn't
+     * allow AlternateContent tags to show up everywhere. The factory flag is
+     * a workaround to process files based on a later edition. But it comes with the drawback:
+     * any change on the returned XmlObject aren't saved back to the underlying document -
+     * so it's a non updatable clone. If factory is null, a XmlException is
+     * thrown if the AlternateContent is not allowed by the surrounding element or if the
+     * extracted object is of the generic type XmlAnyTypeImpl.
+     *
+     * @param resultClass the requested result class
+     * @param factory a factory parse method reference to allow reparsing of elements
+     *                extracted from AlternateContent elements. Usually the enclosing XmlBeans type needs to be used
+     *                to parse the stream
+     * @param path the elements path, each array must contain at least 1 QName,
+     *             but can contain additional alternative tags
+     * @return the xml object at the path location, or null if not found
+     *
+     * @throws XmlException If factory is null, a XmlException is
+     *      thrown if the AlternateContent is not allowed by the surrounding element or if the
+     *      extracted object is of the generic type XmlAnyTypeImpl.
+     *
+     * @since POI 4.1.2
+     */
+    @SuppressWarnings("unchecked")
+    @Internal
+    public <T extends XmlObject> T selectProperty(Class<T> resultClass, ReparseFactory<T> factory, QName[]... path)
+    throws XmlException {
+        XmlObject xo = getXmlObject();
+        XmlCursor cur = xo.newCursor();
+        XmlCursor innerCur = null;
+        try {
+            innerCur = selectProperty(cur, path, 0, factory != null, false);
+            if (innerCur == null) {
+                return null;
+            }
+
+            // Pesky XmlBeans bug - see Bugzilla #49934
+            // it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas
+            xo = innerCur.getObject();
+            if (xo instanceof XmlAnyTypeImpl) {
+                String errorTxt = OSGI_ERROR
+                    .replace("<CLASS>", resultClass.getSimpleName())
+                    .replace("<XSB>", resultClass.getSimpleName().toLowerCase(Locale.ROOT)+"*");
+                if (factory == null) {
+                    throw new XmlException(errorTxt);
+                } else {
+                    xo = factory.parse(innerCur.newXMLStreamReader());
+                }
+            }
+
+            return (T)xo;
+        } finally {
+            cur.dispose();
+            if (innerCur != null) {
+                innerCur.dispose();
+            }
+        }
+    }
+
+    private XmlCursor selectProperty(final XmlCursor cur, final QName[][] path, final int offset, final boolean reparseAlternate, final boolean isAlternate)
+    throws XmlException {
+        // first try the direct children
+        for (QName qn : path[offset]) {
+            if (cur.toChild(qn)) {
+                if (offset == path.length-1) {
+                    return cur;
+                }
+                cur.push();
+                XmlCursor innerCur = selectProperty(cur, path, offset+1, reparseAlternate, false);
+                if (innerCur != null) {
+                    return innerCur;
+                }
+                cur.pop();
+            }
+        }
+        // if we were called inside an alternate content handling don't look for alternates again
+        if (isAlternate || !cur.toChild(ALTERNATE_CONTENT_TAG)) {
+            return null;
+        }
+
+        // otherwise check first the choice then the fallback content
+        XmlObject xo = cur.getObject();
+        AlternateContent alterCont;
+        if (xo instanceof AlternateContent) {
+            alterCont = (AlternateContent)xo;
+        } else {
+            // Pesky XmlBeans bug - see Bugzilla #49934
+            // it never happens when using the full ooxml-schemas jar but may happen with the abridged poi-ooxml-schemas
+            if (!reparseAlternate) {
+                throw new XmlException(OSGI_ERROR
+                    .replace("<CLASS>", "AlternateContent")
+                    .replace("<XSB>", "alternatecontentelement")
+                );
+            }
+            try {
+                AlternateContentDocument acd = AlternateContentDocument.Factory.parse(cur.newXMLStreamReader());
+                alterCont = acd.getAlternateContent();
+            } catch (XmlException e) {
+                throw new XmlException("unable to parse AlternateContent element", e);
+            }
+        }
+
+        final int choices = alterCont.sizeOfChoiceArray();
+        for (int i=0; i<choices; i++) {
+            // TODO: check [Requires] attribute of [Choice] element, if we can handle the content
+            AlternateContent.Choice choice = alterCont.getChoiceArray(i);
+            XmlCursor cCur = choice.newCursor();
+            XmlCursor innerCur = null;
+            try {
+                String requiresNS = cCur.namespaceForPrefix(choice.getRequires());
+                if (MAC_DML_NS.equalsIgnoreCase(requiresNS)) {
+                    // Mac DML usually contains PDFs ...
+                    continue;
+                }
+                innerCur = selectProperty(cCur, path, offset, reparseAlternate, true);
+                if (innerCur != null) {
+                    return innerCur;
+                }
+            } finally {
+                if (innerCur != cCur) {
+                    cCur.dispose();
+                }
+            }
+        }
+
+        if (!alterCont.isSetFallback()) {
+            return null;
+        }
+
+        XmlCursor fCur = alterCont.getFallback().newCursor();
+        XmlCursor innerCur = null;
+        try {
+            innerCur = selectProperty(fCur, path, offset, reparseAlternate, true);
+            return innerCur;
+        } finally {
+            if (innerCur != fCur) {
+                fCur.dispose();
+            }
+        }
+    }
+
+
+    /**
      * Walk up the inheritance tree and fetch shape properties.<p>
      *
      * The following order of inheritance is assumed:<p>
diff --git a/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java b/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java
index a9a9e16..d83de63 100644
--- a/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java
+++ b/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java
@@ -17,7 +17,14 @@
 package org.apache.poi.xslf;
 
 import static org.apache.poi.POITestCase.assertContains;
-import static org.junit.Assert.*;
+import static org.apache.poi.xslf.XSLFTestDataSamples.openSampleDocument;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.awt.Color;
 import java.awt.Dimension;
@@ -66,6 +73,7 @@
 import org.apache.poi.xslf.usermodel.XSLFGroupShape;
 import org.apache.poi.xslf.usermodel.XSLFHyperlink;
 import org.apache.poi.xslf.usermodel.XSLFNotes;
+import org.apache.poi.xslf.usermodel.XSLFObjectShape;
 import org.apache.poi.xslf.usermodel.XSLFPictureData;
 import org.apache.poi.xslf.usermodel.XSLFPictureShape;
 import org.apache.poi.xslf.usermodel.XSLFRelation;
@@ -89,7 +97,7 @@
 
     @Test
     public void bug62929() throws Exception {
-        try(XMLSlideShow ss1 = XSLFTestDataSamples.openSampleDocument("missing-blip-fill.pptx")) {
+        try(XMLSlideShow ss1 = openSampleDocument("missing-blip-fill.pptx")) {
             assertEquals(1, ss1.getSlides().size());
 
             XSLFSlide slide = ss1.getSlides().get(0);
@@ -108,7 +116,7 @@
 
     @Test
     public void bug62736() throws Exception {
-        XMLSlideShow ss1 = XSLFTestDataSamples.openSampleDocument("bug62736.pptx");
+        XMLSlideShow ss1 = openSampleDocument("bug62736.pptx");
 
         assertEquals(1, ss1.getSlides().size());
 
@@ -332,7 +340,7 @@
 
     @Test
     public void bug51187() throws Exception {
-       XMLSlideShow ss1 = XSLFTestDataSamples.openSampleDocument("51187.pptx");
+       XMLSlideShow ss1 = openSampleDocument("51187.pptx");
 
        assertEquals(1, ss1.getSlides().size());
 
@@ -373,7 +381,7 @@
      */
     @Test
     public void tika705() throws Exception {
-       XMLSlideShow ss = XSLFTestDataSamples.openSampleDocument("with_japanese.pptx");
+       XMLSlideShow ss = openSampleDocument("with_japanese.pptx");
 
        // Should have one slide
        assertEquals(1, ss.getSlides().size());
@@ -423,7 +431,7 @@
      */
     @Test
     public void bug54916() throws IOException {
-        try (XMLSlideShow ss = XSLFTestDataSamples.openSampleDocument("OverlappingRelations.pptx")) {
+        try (XMLSlideShow ss = openSampleDocument("OverlappingRelations.pptx")) {
             XSLFSlide slide;
 
             // Should find 4 slides
@@ -452,7 +460,7 @@
      */
     @Test
     public void bug56812() throws Exception {
-        XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("56812.pptx");
+        XMLSlideShow ppt = openSampleDocument("56812.pptx");
 
         int internalPictures = 0;
         int externalPictures = 0;
@@ -485,7 +493,7 @@
     @Test
     @Ignore("Similar to TestFontRendering it doesn't make sense to compare images because of tiny rendering differences in windows/unix")
     public void bug54542() throws Exception {
-        XMLSlideShow ss = XSLFTestDataSamples.openSampleDocument("54542_cropped_bitmap.pptx");
+        XMLSlideShow ss = openSampleDocument("54542_cropped_bitmap.pptx");
 
         Dimension pgsize = ss.getPageSize();
 
@@ -676,7 +684,7 @@
 
     @Test
     public void bug58205() throws IOException {
-        XMLSlideShow ss = XSLFTestDataSamples.openSampleDocument("themes.pptx");
+        XMLSlideShow ss = openSampleDocument("themes.pptx");
 
         int i = 1;
         for (XSLFSlideMaster sm : ss.getSlideMasters()) {
@@ -688,14 +696,14 @@
 
     @Test
     public void bug55791a() throws IOException {
-        XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("45541_Footer.pptx");
+        XMLSlideShow ppt = openSampleDocument("45541_Footer.pptx");
         removeAndCreateSlide(ppt);
         ppt.close();
     }
 
     @Test
     public void bug55791b() throws IOException {
-        XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("SampleShow.pptx");
+        XMLSlideShow ppt = openSampleDocument("SampleShow.pptx");
         removeAndCreateSlide(ppt);
         ppt.close();
     }
@@ -708,7 +716,7 @@
 
     @Test
     public void blibFillAlternateContent() throws IOException {
-        XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("2411-Performance_Up.pptx");
+        XMLSlideShow ppt = openSampleDocument("2411-Performance_Up.pptx");
         XSLFPictureShape ps = (XSLFPictureShape)ppt.getSlides().get(4).getShapes().get(0);
         assertNotNull(ps.getPictureData());
         ppt.close();
@@ -781,7 +789,7 @@
 
     @Test
     public void bug55714() throws IOException {
-        XMLSlideShow srcPptx = XSLFTestDataSamples.openSampleDocument("pptx2svg.pptx");
+        XMLSlideShow srcPptx = openSampleDocument("pptx2svg.pptx");
         XMLSlideShow newPptx = new XMLSlideShow();
         XSLFSlide srcSlide = srcPptx.getSlides().get(0);
         XSLFSlide newSlide = newPptx.createSlide();
@@ -807,7 +815,7 @@
 
     @Test
     public void bug59273() throws IOException {
-        XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("bug59273.potx");
+        XMLSlideShow ppt = openSampleDocument("bug59273.potx");
         ppt.getPackage().replaceContentType(
             XSLFRelation.PRESENTATIONML_TEMPLATE.getContentType(),
             XSLFRelation.MAIN.getContentType()
@@ -851,7 +859,7 @@
 
     @Test
     public void bug60715() throws IOException {
-        XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("bug60715.pptx");
+        XMLSlideShow ppt = openSampleDocument("bug60715.pptx");
         ppt.createSlide();
         ppt.close();
     }
@@ -887,7 +895,7 @@
 
     @Test
     public void test60810() throws IOException {
-        XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("60810.pptx");
+        XMLSlideShow ppt = openSampleDocument("60810.pptx");
         for(XSLFSlide slide : ppt.getSlides()) {
             XSLFNotes notesSlide = ppt.getNotesSlide(slide);
             assertNotNull(notesSlide);
@@ -898,7 +906,7 @@
 
     @Test
     public void test60042() throws IOException {
-        XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("60042.pptx");
+        XMLSlideShow ppt = openSampleDocument("60042.pptx");
         ppt.removeSlide(0);
         ppt.createSlide();
         ppt.close();
@@ -906,7 +914,7 @@
 
     @Test
     public void test61515() throws IOException {
-        XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("61515.pptx");
+        XMLSlideShow ppt = openSampleDocument("61515.pptx");
         ppt.removeSlide(0);
         assertEquals(1, ppt.createSlide().getRelations().size());
         try {
@@ -923,7 +931,7 @@
 
     @Test
     public void testAptia() throws IOException {
-        try (XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("aptia.pptx");
+        try (XMLSlideShow ppt = openSampleDocument("aptia.pptx");
              XMLSlideShow saved = XSLFTestDataSamples.writeOutAndReadBack(ppt)) {
             assertEquals(ppt.getSlides().size(), saved.getSlides().size());
         }
@@ -932,7 +940,7 @@
     @Ignore
     @Test
     public void testDivinoRevelado() throws IOException {
-        try (XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("Divino_Revelado.pptx");
+        try (XMLSlideShow ppt = openSampleDocument("Divino_Revelado.pptx");
              XMLSlideShow saved = XSLFTestDataSamples.writeOutAndReadBack(ppt)){
             assertEquals(ppt.getSlides().size(), saved.getSlides().size());
         }
@@ -968,7 +976,7 @@
 
     @Test
     public void bug63200() throws Exception {
-        try (XMLSlideShow ss1 = XSLFTestDataSamples.openSampleDocument("63200.pptx")) {
+        try (XMLSlideShow ss1 = openSampleDocument("63200.pptx")) {
             assertEquals(1, ss1.getSlides().size());
 
             XSLFSlide slide = ss1.getSlides().get(0);
@@ -982,4 +990,25 @@
             assertNull(arrow.getFillColor());
         }
     }
+
+    @Test
+    public void alternateContent() throws Exception {
+        try (XMLSlideShow ppt = openSampleDocument("alterman_security.pptx")) {
+            XSLFSlideMaster slide = ppt.getSlideMasters().get(0);
+            XSLFObjectShape os = (XSLFObjectShape)slide.getShapes().get(0);
+            // ctOleObject is nested in AlternateContent in this file
+            // if there are casting errors, we would fail early and wouldn't reach this point anyway
+            assertNotNull(os.getCTOleObject());
+            // accessing the picture data of the AlternateContent fallback part
+            XSLFPictureData picData = os.getPictureData();
+            assertNotNull(picData);
+        }
+
+        try (XMLSlideShow ppt = openSampleDocument("2411-Performance_Up.pptx")) {
+            XSLFSlide slide = ppt.getSlides().get(4);
+            XSLFPictureShape ps = (XSLFPictureShape)slide.getShapes().get(0);
+            assertEquals("image4.png", ps.getPictureData().getFileName());
+            assertEquals("Picture 5", ps.getShapeName());
+        }
+    }
 }
diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
index 10757fb..bf6f565 100644
--- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
+++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
@@ -47,7 +47,7 @@
     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," +
-        "customGeo.pptx, customGeo.ppt, wrench.emf, santa.wmf";
+        "customGeo.pptx, customGeo.ppt, wrench.emf, santa.wmf, missing-moveto.ppt";
 
     @BeforeClass
     public static void checkHslf() {
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java
index 3b57ccb..206bb16 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java
@@ -17,6 +17,9 @@
 
 package org.apache.poi.hslf.usermodel;
 
+import static org.apache.poi.hslf.usermodel.HSLFFreeformShape.ShapePath.CURVES_CLOSED;
+import static org.apache.poi.hslf.usermodel.HSLFFreeformShape.ShapePath.LINES_CLOSED;
+
 import java.awt.geom.Arc2D;
 import java.awt.geom.Path2D;
 import java.awt.geom.Point2D;
@@ -69,22 +72,10 @@
     static final byte[] SEGMENTINFO_CLOSE    = new byte[]{0x01, (byte)0x60};
     static final byte[] SEGMENTINFO_END      = new byte[]{0x00, (byte)0x80};
 
+    private static final ObjectFactory OF = new ObjectFactory();
     private static final BitField PATH_INFO = BitFieldFactory.getInstance(0xE000);
     private static final BitField ESCAPE_INFO = BitFieldFactory.getInstance(0x1F00);
 
-    private static final EscherPropertyTypes[] ADJUST_VALUES = {
-        EscherPropertyTypes.GEOMETRY__ADJUSTVALUE,
-        EscherPropertyTypes.GEOMETRY__ADJUST2VALUE,
-        EscherPropertyTypes.GEOMETRY__ADJUST3VALUE,
-        EscherPropertyTypes.GEOMETRY__ADJUST4VALUE,
-        EscherPropertyTypes.GEOMETRY__ADJUST5VALUE,
-        EscherPropertyTypes.GEOMETRY__ADJUST6VALUE,
-        EscherPropertyTypes.GEOMETRY__ADJUST7VALUE,
-        EscherPropertyTypes.GEOMETRY__ADJUST8VALUE,
-        EscherPropertyTypes.GEOMETRY__ADJUST9VALUE,
-        EscherPropertyTypes.GEOMETRY__ADJUST10VALUE
-    };
-
     enum PathInfo {
         lineTo(0),curveTo(1),moveTo(2),close(3),end(4),escape(5),clientEscape(6);
         private final int flag;
@@ -220,12 +211,11 @@
     }
 
     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 CTCustomGeometry2D cusGeo = OF.createCTCustomGeometry2D();
+        cusGeo.setAvLst(OF.createCTGeomGuideList());
+        cusGeo.setGdLst(OF.createCTGeomGuideList());
+        cusGeo.setAhLst(OF.createCTAdjustHandleList());
+        cusGeo.setCxnLst(OF.createCTConnectionSiteList());
 
         final AbstractEscherOptRecord opt = getEscherOptRecord();
 
@@ -249,8 +239,8 @@
         final int[] xyPoints = new int[2];
         boolean isClosed = false;
 
-        final CTPath2DList pathLst = of.createCTPath2DList();
-        final CTPath2D pathCT = of.createCTPath2D();
+        final CTPath2DList pathLst = OF.createCTPath2DList();
+        final CTPath2D pathCT = OF.createCTPath2D();
         final List<Object> moveLst = pathCT.getCloseOrMoveToOrLnTo();
         pathLst.getPath().add(pathCT);
         cusGeo.setPathLst(pathLst);
@@ -262,46 +252,23 @@
                 continue;
             }
             switch (pi) {
-                case escape: {
+                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]);
-                    }
+                    handleMoveTo(vertIter, xyPoints, moveLst, path2D);
                     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]);
-                    }
+                    handleLineTo(vertIter, xyPoints, moveLst, path2D);
                     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]);
-                        }
-                    }
+                case curveTo:
+                    handleCurveTo(vertIter, xyPoints, moveLst, path2D);
                     break;
-                }
                 case close:
-                    moveLst.add(of.createCTPath2DClose());
-                    path2D.closePath();
+                    if (path2D.getCurrentPoint() != null) {
+                        moveLst.add(OF.createCTPath2DClose());
+                        path2D.closePath();
+                    }
                     isClosed = true;
                     break;
                 default:
@@ -309,28 +276,11 @@
             }
         }
 
-        EscherSimpleProperty shapePath = getEscherProperty(opt, EscherPropertyTypes.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();
+        if (!isClosed) {
+            handleClosedShape(opt, moveLst, path2D);
         }
 
-        EscherSimpleProperty geoLeft = getEscherProperty(opt, EscherPropertyTypes.GEOMETRY__LEFT);
-        EscherSimpleProperty geoRight = getEscherProperty(opt, EscherPropertyTypes.GEOMETRY__RIGHT);
-        EscherSimpleProperty geoTop = getEscherProperty(opt, EscherPropertyTypes.GEOMETRY__TOP);
-        EscherSimpleProperty geoBottom = getEscherProperty(opt, EscherPropertyTypes.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();
-        }
+        final Rectangle2D bounds = getBounds(opt, path2D);
 
         pathCT.setW((int)Math.rint(bounds.getWidth()));
         pathCT.setH((int)Math.rint(bounds.getHeight()));
@@ -338,8 +288,94 @@
         return new CustomGeometry(cusGeo);
     }
 
-    private void handleEscapeInfo(CTPath2D pathCT, Path2D path2D, byte[] segElem, Iterator<byte[]> vertIter) {
-        final ObjectFactory of = new ObjectFactory();
+    private static Rectangle2D getBounds(AbstractEscherOptRecord opt, Path2D path2D) {
+        EscherSimpleProperty geoLeft = getEscherProperty(opt, EscherPropertyTypes.GEOMETRY__LEFT);
+        EscherSimpleProperty geoRight = getEscherProperty(opt, EscherPropertyTypes.GEOMETRY__RIGHT);
+        EscherSimpleProperty geoTop = getEscherProperty(opt, EscherPropertyTypes.GEOMETRY__TOP);
+        EscherSimpleProperty geoBottom = getEscherProperty(opt, EscherPropertyTypes.GEOMETRY__BOTTOM);
+
+        if (geoLeft != null && geoRight != null && geoTop != null && geoBottom != null) {
+            final Rectangle2D bounds = new Rectangle2D.Double();
+            bounds.setFrameFromDiagonal(
+                    new Point2D.Double(geoLeft.getPropertyValue(), geoTop.getPropertyValue()),
+                    new Point2D.Double(geoRight.getPropertyValue(), geoBottom.getPropertyValue())
+            );
+            return bounds;
+        } else {
+            return path2D.getBounds2D();
+        }
+    }
+
+    private static void handleClosedShape(AbstractEscherOptRecord opt, List<Object> moveLst, Path2D path2D) {
+        EscherSimpleProperty shapePath = getEscherProperty(opt, EscherPropertyTypes.GEOMETRY__SHAPEPATH);
+        HSLFFreeformShape.ShapePath sp = HSLFFreeformShape.ShapePath.valueOf(shapePath == null ? 1 : shapePath.getPropertyValue());
+        if (sp == LINES_CLOSED || sp == CURVES_CLOSED) {
+            moveLst.add(OF.createCTPath2DClose());
+            path2D.closePath();
+        }
+    }
+
+    private static void handleMoveTo(Iterator<byte[]> vertIter, int[] xyPoints, List<Object> moveLst, Path2D path2D) {
+        if (!vertIter.hasNext()) {
+            return;
+        }
+        final CTPath2DMoveTo m = OF.createCTPath2DMoveTo();
+        m.setPt(fillPoint(vertIter.next(), xyPoints));
+        moveLst.add(m);
+        path2D.moveTo(xyPoints[0], xyPoints[1]);
+    }
+
+    private static void handleLineTo(Iterator<byte[]> vertIter, int[] xyPoints, List<Object> moveLst, Path2D path2D) {
+        if (!vertIter.hasNext()) {
+            return;
+        }
+        handleMoveTo0(moveLst, path2D);
+
+        final CTPath2DLineTo m = OF.createCTPath2DLineTo();
+        m.setPt(fillPoint(vertIter.next(), xyPoints));
+        moveLst.add(m);
+        path2D.lineTo(xyPoints[0], xyPoints[1]);
+    }
+
+    private static void handleCurveTo(Iterator<byte[]> vertIter, int[] xyPoints, List<Object> moveLst, Path2D path2D) {
+        if (!vertIter.hasNext()) {
+            return;
+        }
+        handleMoveTo0(moveLst, path2D);
+
+        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]);
+            }
+        }
+    }
+
+    /**
+     * Sometimes the path2D is not initialized - this initializes it with the 0,0 position
+     */
+    private static void handleMoveTo0(List<Object> moveLst, Path2D path2D) {
+        if (path2D.getCurrentPoint() == null) {
+            final CTPath2DMoveTo m = OF.createCTPath2DMoveTo();
+
+            CTAdjPoint2D pt = OF.createCTAdjPoint2D();
+            pt.setX("0");
+            pt.setY("0");
+            m.setPt(pt);
+            moveLst.add(m);
+            path2D.moveTo(0, 0);
+        }
+    }
+
+    private static void handleEscapeInfo(CTPath2D pathCT, Path2D path2D, byte[] segElem, Iterator<byte[]> vertIter) {
         HSLFFreeformShape.EscapeInfo ei = getEscapeInfo(segElem);
         if (ei == null) {
             return;
@@ -376,7 +412,7 @@
                 path2D.append(arc2D, true);
 
 
-                CTPath2DArcTo arcTo = of.createCTPath2DArcTo();
+                CTPath2DArcTo arcTo = OF.createCTPath2DArcTo();
                 arcTo.setHR(d2s(bounds.getHeight()/2.0));
                 arcTo.setWR(d2s(bounds.getWidth()/2.0));
 
@@ -451,7 +487,7 @@
     }
 
 
-    private CTAdjPoint2D fillPoint(byte[] xyMaster, int[] xyPoints) {
+    private static 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;
@@ -477,7 +513,7 @@
     }
 
     private static CTAdjPoint2D toPoint(int[] xyPoints) {
-        CTAdjPoint2D pt = new CTAdjPoint2D();
+        CTAdjPoint2D pt = OF.createCTAdjPoint2D();
         pt.setX(Integer.toString(xyPoints[0]));
         pt.setY(Integer.toString(xyPoints[1]));
         return pt;
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
index dd7afa4..097342f 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
@@ -62,7 +62,7 @@
 
     public final static double DEFAULT_LINE_WIDTH = 0.75;
 
-    private static final EscherPropertyTypes[] ADJUST_VALUES = {
+    protected static final EscherPropertyTypes[] ADJUST_VALUES = {
             EscherPropertyTypes.GEOMETRY__ADJUSTVALUE,
             EscherPropertyTypes.GEOMETRY__ADJUST2VALUE,
             EscherPropertyTypes.GEOMETRY__ADJUST3VALUE,
@@ -79,7 +79,7 @@
      * Hyperlink
      */
     protected HSLFHyperlink _hyperlink;
-    
+
     /**
      * Create a SimpleShape object and initialize it from the supplied Record container.
      *
@@ -563,8 +563,8 @@
     public HSLFShapePlaceholderDetails getPlaceholderDetails() {
         return new HSLFShapePlaceholderDetails(this);
     }
-    
-    
+
+
     @Override
     public Placeholder getPlaceholder() {
         return getPlaceholderDetails().getPlaceholder();
@@ -604,7 +604,7 @@
     public HSLFHyperlink getHyperlink(){
         return _hyperlink;
     }
-    
+
     @Override
     public HSLFHyperlink createHyperlink() {
         if (_hyperlink == null) {
@@ -612,7 +612,7 @@
         }
         return _hyperlink;
     }
-    
+
     /**
      * Sets the hyperlink - used when the document is parsed
      *
@@ -621,7 +621,7 @@
     protected void setHyperlink(HSLFHyperlink link) {
         _hyperlink = link;
     }
-    
+
     @Override
     public boolean isPlaceholder() {
         // currently we only identify TextShapes as placeholders
diff --git a/test-data/slideshow/missing-moveto.ppt b/test-data/slideshow/missing-moveto.ppt
new file mode 100644
index 0000000..1d8c241
--- /dev/null
+++ b/test-data/slideshow/missing-moveto.ppt
Binary files differ