Author: kiwiwings
Date: Fri Dec 28 23:43:31 2018
New Revision: 1849898

URL: http://svn.apache.org/viewvc?rev=1849898&view=rev
Log:
 #63028 - Provide font embedding for slideshows

Added:
    poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontFacet.java   
(with props)
    poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontHeader.java   
(with props)
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFontData.java   
(with props)
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFontInfo.java   
(with props)
    
poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/FontEmbeddedData.java   
(with props)
    poi/trunk/test-data/slideshow/font.fntdata   (with props)
Removed:
    poi/trunk/src/java/org/apache/poi/sl/usermodel/FontCollection.java
    poi/trunk/src/java/org/apache/poi/sl/usermodel/Resources.java
Modified:
    poi/site/src/documentation/content/xdocs/changes.xml
    poi/trunk/src/integrationtest/org/apache/poi/TestAllFiles.java
    poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java
    poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontInfo.java
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontInfo.java
    poi/trunk/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java
    poi/trunk/src/java/org/apache/poi/sl/usermodel/Slide.java
    poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShow.java
    poi/trunk/src/java/org/apache/poi/sl/usermodel/TextRun.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
    
poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/extractor/TestXSLFPowerPointExtractor.java
    
poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXMLSlideShow.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/Document.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/DocumentAtom.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/FontCollection.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/FontEntityAtom.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFontInfo.java
    
poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFontInfoPredefined.java
    
poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java
    
poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java
    
poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestHSLFSlideShow.java
    poi/trunk/src/testcases/org/apache/poi/sl/usermodel/BaseTestSlideShow.java

Modified: poi/site/src/documentation/content/xdocs/changes.xml
URL: 
http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/changes.xml?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/changes.xml (original)
+++ poi/site/src/documentation/content/xdocs/changes.xml Fri Dec 28 23:43:31 
2018
@@ -87,6 +87,7 @@
 
     <release version="4.1.0" date="2019-02-??">
       <actions>
+        <action dev="PD" type="add" fixes-bug="63028" context="SL_Common XSLF 
HSLF">Provide font embedding for slideshows</action>
         <action dev="PD" type="fix" fixes-bug="61532" context="SXSSF">Fix 
setting values/types during formula evaluation for SXSSF</action>
         <action dev="PD" type="fix" fixes-bug="62629" context="OPC">Allow to 
handle files with invalid content types for pictures</action>
         <action dev="PD" type="fix" fixes-bug="62839" context="SL_Common">Fix 
MathX.floor for negative n</action>

Modified: poi/trunk/src/integrationtest/org/apache/poi/TestAllFiles.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/integrationtest/org/apache/poi/TestAllFiles.java?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- poi/trunk/src/integrationtest/org/apache/poi/TestAllFiles.java (original)
+++ poi/trunk/src/integrationtest/org/apache/poi/TestAllFiles.java Fri Dec 28 
23:43:31 2018
@@ -187,11 +187,11 @@ public class TestAllFiles {
         HANDLERS.put(".tif", new NullFileHandler());
         HANDLERS.put(".tiff", new NullFileHandler());
         HANDLERS.put(".wav", new NullFileHandler());
-        HANDLERS.put(".pfx", new NullFileHandler());
         HANDLERS.put(".xml", new NullFileHandler());
         HANDLERS.put(".csv", new NullFileHandler());
         HANDLERS.put(".ods", new NullFileHandler());
         HANDLERS.put(".ttf", new NullFileHandler());
+        HANDLERS.put(".fntdata", new NullFileHandler());
         // VBA source files
         HANDLERS.put(".vba", new NullFileHandler());
         HANDLERS.put(".bas", new NullFileHandler());

Modified: 
poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java 
Fri Dec 28 23:43:31 2018
@@ -70,7 +70,7 @@ public enum FontCharset {
     /** Specifies the Russian Cyrillic character set. */
     RUSSIAN(0x000000CC, "Cp1251"),
     /** Specifies the Thai character set. */
-    THAI_(0x000000DE, "x-windows-874"),
+    THAI(0x000000DE, "x-windows-874"),
     /** Specifies a Eastern European character set. */
     EASTEUROPE(0x000000EE, "Cp1250"),
     /**

Added: poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontFacet.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontFacet.java?rev=1849898&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontFacet.java 
(added)
+++ poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontFacet.java Fri 
Dec 28 23:43:31 2018
@@ -0,0 +1,75 @@
+/* ====================================================================
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==================================================================== */
+
+package org.apache.poi.common.usermodel.fonts;
+
+import org.apache.poi.util.Beta;
+
+/**
+ * A FontFacet holds the font data for a shape of a font, i.e. a regular,
+ * italic, bold or bold-italic version of a Font.
+ */
+@SuppressWarnings("unused")
+@Beta
+public interface FontFacet {
+    /**
+     * Get the font weight.<p>
+     *
+     * The weight of the font in the range 0 through 1000.
+     * For example, 400 is normal and 700 is bold.
+     * If this value is zero, a default weight is used.
+     *
+     * @return the font weight
+     *
+     * @since POI 4.1.0
+     */
+    default int getWeight() {
+        return FontHeader.REGULAR_WEIGHT;
+    }
+
+    /**
+     * Set the font weight
+     *
+     * @param weight the font weight
+     */
+    default void setWeight(int weight) {
+        throw new UnsupportedOperationException("FontFacet is read-only.");
+    }
+
+    /**
+     * @return {@code true}, if the font is italic
+     */
+    default boolean isItalic() {
+        return false;
+    }
+
+    /**
+     * Set the font posture
+     *
+     * @param italic {@code true} for italic, {@code false} for regular
+     */
+    default void setItalic(boolean italic) {
+        throw new UnsupportedOperationException("FontFacet is read-only.");
+    }
+
+    /**
+     * @return the wrapper object holding the font data
+     */
+    default Object getFontData() {
+        return null;
+    }
+}

Propchange: 
poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontFacet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontHeader.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontHeader.java?rev=1849898&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontHeader.java 
(added)
+++ poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontHeader.java 
Fri Dec 28 23:43:31 2018
@@ -0,0 +1,227 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.common.usermodel.fonts;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.LittleEndianByteArrayInputStream;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianInputStream;
+
+
+/**
+ * The header data of an EOT font.<p>
+ *
+ * Currently only version 1 fields are read to identify a stream to be 
embedded.
+ *
+ * @see <a href="http://www.w3.org/Submission/EOT";>Embedded OpenType (EOT) 
File Format</a>
+ */
+@SuppressWarnings({"FieldCanBeLocal", "unused", "Duplicates"})
+public class FontHeader implements FontInfo {
+    /**
+     * Fonts with a font weight of 400 are regarded as regular weighted.
+     * Higher font weights (up to 1000) are bold - lower weights are thin.
+     */
+    public static final int REGULAR_WEIGHT = 400;
+
+    private int eotSize;
+    private int fontDataSize;
+    private int version;
+    private int flags;
+    private final byte[] panose = new byte[10];
+    private byte charset;
+    private byte italic;
+    private int weight;
+    private int fsType;
+    private int magic;
+    private int unicodeRange1;
+    private int unicodeRange2;
+    private int unicodeRange3;
+    private int unicodeRange4;
+    private int codePageRange1;
+    private int codePageRange2;
+    private int checkSumAdjustment;
+    private String familyName;
+    private String styleName;
+    private String versionName;
+    private String fullName;
+
+    public void init(byte[] source, int offset, int length) {
+        init(new LittleEndianByteArrayInputStream(source, offset, length));
+    }
+
+    public void init(LittleEndianInput leis) {
+        eotSize = leis.readInt();
+        fontDataSize = leis.readInt();
+        version = leis.readInt();
+        if (version != 0x00010000 && version != 0x00020001 && version != 
0x00020002) {
+            throw new RuntimeException("not a EOT font data stream");
+        }
+        flags = leis.readInt();
+        leis.readFully(panose);
+        charset = leis.readByte();
+        italic = leis.readByte();
+        weight = leis.readInt();
+        fsType = leis.readUShort();
+        magic = leis.readUShort();
+        if (magic != 0x504C) {
+            throw new RuntimeException("not a EOT font data stream");
+        }
+        unicodeRange1 = leis.readInt();
+        unicodeRange2 = leis.readInt();
+        unicodeRange3 = leis.readInt();
+        unicodeRange4 = leis.readInt();
+        codePageRange1 = leis.readInt();
+        codePageRange2 = leis.readInt();
+        checkSumAdjustment = leis.readInt();
+        int reserved1 = leis.readInt();
+        int reserved2 = leis.readInt();
+        int reserved3 = leis.readInt();
+        int reserved4 = leis.readInt();
+        familyName = readName(leis);
+        styleName = readName(leis);
+        versionName = readName(leis);
+        fullName = readName(leis);
+
+    }
+
+    public InputStream bufferInit(InputStream fontStream) throws IOException {
+        LittleEndianInputStream is = new LittleEndianInputStream(fontStream);
+        is.mark(1000);
+        init(is);
+        is.reset();
+        return is;
+    }
+
+    private String readName(LittleEndianInput leis) {
+        // padding
+        leis.readShort();
+        int nameSize = leis.readUShort();
+        byte[] nameBuf = IOUtils.safelyAllocate(nameSize, 1000);
+        leis.readFully(nameBuf);
+        // may be 0-terminated, just trim it away
+        return new String(nameBuf, 0, nameSize, 
StandardCharsets.UTF_16LE).trim();
+    }
+
+    public boolean isItalic() {
+        return italic != 0;
+    }
+
+    public int getWeight() {
+        return weight;
+    }
+
+    public boolean isBold() {
+        return getWeight() > REGULAR_WEIGHT;
+    }
+
+    public byte getCharsetByte() {
+        return charset;
+    }
+
+    public FontCharset getCharset() {
+        return FontCharset.valueOf(getCharsetByte());
+    }
+
+    public FontPitch getPitch() {
+        byte familyKind = panose[0];
+        switch (familyKind) {
+            default:
+            // Any
+            case 0:
+            // No Fit
+            case 1:
+                return FontPitch.VARIABLE;
+
+            // Latin Text
+            case 2:
+                // Latin Decorative
+            case 4:
+                byte proportion = panose[3];
+                return proportion == 9 ? FontPitch.FIXED : FontPitch.VARIABLE;
+
+            // Latin Hand Written
+            case 3:
+                // Latin Symbol
+            case 5:
+                byte spacing = panose[3];
+                return spacing == 3 ? FontPitch.FIXED : FontPitch.VARIABLE;
+        }
+
+    }
+
+    public FontFamily getFamily() {
+        switch (panose[0]) {
+            // Any
+            case 0:
+            // No Fit
+            case 1:
+                return FontFamily.FF_DONTCARE;
+            // Latin Text
+            case 2:
+                byte serifStyle = panose[1];
+                return (10 <= serifStyle && serifStyle <= 15)
+                    ? FontFamily.FF_SWISS : FontFamily.FF_ROMAN;
+            // Latin Hand Written
+            case 3:
+                return FontFamily.FF_SCRIPT;
+            // Latin Decorative
+            default:
+            case 4:
+                return FontFamily.FF_DECORATIVE;
+            // Latin Symbol
+            case 5:
+                return FontFamily.FF_MODERN;
+        }
+    }
+
+    public String getFamilyName() {
+        return familyName;
+    }
+
+    public String getStyleName() {
+        return styleName;
+    }
+
+    public String getVersionName() {
+        return versionName;
+    }
+
+    public String getFullName() {
+        return fullName;
+    }
+
+    public byte[] getPanose() {
+        return panose;
+    }
+
+    @Override
+    public String getTypeface() {
+        return getFamilyName();
+    }
+
+    public int getFlags() {
+        return flags;
+    }
+}
+
+
+

Propchange: 
poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontHeader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontInfo.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontInfo.java?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontInfo.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontInfo.java Fri 
Dec 28 23:43:31 2018
@@ -17,6 +17,11 @@ limitations under the License.
 
 package org.apache.poi.common.usermodel.fonts;
 
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.poi.util.Beta;
+
 /**
  * A FontInfo object holds information about a font configuration.
  * It is roughly an equivalent to the LOGFONT structure in Windows GDI.<p>
@@ -30,6 +35,7 @@ package org.apache.poi.common.usermodel.
  *
  * @see <a 
href="https://msdn.microsoft.com/en-us/library/dd145037.aspx";>LOGFONT 
structure</a>
  */
+@SuppressWarnings("unused")
 public interface FontInfo {
 
     /**
@@ -37,7 +43,9 @@ public interface FontInfo {
      * @return unique index number of the underlying record this Font 
represents
      *   (probably you don't care unless you're comparing which one is which)
      */
-    Integer getIndex();
+    default Integer getIndex() {
+        return null;
+    }
 
     /**
      * Sets the index within the collection of Font objects
@@ -46,7 +54,9 @@ public interface FontInfo {
      *
      * @throws UnsupportedOperationException if unsupported
      */
-    void setIndex(int index);
+    default void setIndex(int index) {
+        throw new UnsupportedOperationException("FontInfo is read-only.");
+    }
     
     
     /**
@@ -60,36 +70,48 @@ public interface FontInfo {
      * @param typeface the full name of the font, when {@code null} removes 
the font definition -
      *    removal is implementation specific
      */
-    void setTypeface(String typeface);
+    default void setTypeface(String typeface) {
+        throw new UnsupportedOperationException("FontInfo is read-only.");
+    }
 
     /**
      * @return the font charset
      */
-    FontCharset getCharset();
+    default FontCharset getCharset() {
+        return FontCharset.ANSI;
+    }
 
     /**
      * Sets the charset
      *
      * @param charset the charset
      */
-    void setCharset(FontCharset charset);
+    default void setCharset(FontCharset charset) {
+        throw new UnsupportedOperationException("FontInfo is read-only.");
+    }
 
     /**
      * @return the family class
      */
-    FontFamily getFamily();
+    default FontFamily getFamily() {
+        return FontFamily.FF_DONTCARE;
+    }
 
     /**
      * Sets the font family class
      *
      * @param family the font family class
      */
-    void setFamily(FontFamily family);
+    default void setFamily(FontFamily family) {
+        throw new UnsupportedOperationException("FontInfo is read-only.");
+    }
 
     /**
      * @return the font pitch or {@code null} if unsupported
      */
-    FontPitch getPitch();
+    default FontPitch getPitch() {
+        return null;
+    }
 
     /**
      * Set the font pitch
@@ -98,5 +120,33 @@ public interface FontInfo {
      *
      * @throws UnsupportedOperationException if unsupported
      */
-    void setPitch(FontPitch pitch);
+    default void setPitch(FontPitch pitch) {
+        throw new UnsupportedOperationException("FontInfo is read-only.");
+    }
+
+    /**
+     * @return panose info in binary form or {@code null} if unknown
+     */
+    default byte[] getPanose() {
+        return null;
+    }
+
+    /**
+     * Set the panose in binary form
+     * @param panose the panose bytes
+     */
+    default void setPanose(byte[] panose) {
+        throw new UnsupportedOperationException("FontInfo is read-only.");
+    }
+
+
+    /**
+     * If font facets are embedded in the document, return the list of 
embedded facets.
+     * The font embedding is experimental, therefore the API can change.
+     * @return the list of embedded EOT font data
+     */
+    @Beta
+    default List<? extends FontFacet> getFacets() {
+        return Collections.emptyList();
+    }
 }
\ No newline at end of file

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontInfo.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontInfo.java?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontInfo.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontInfo.java Fri Dec 28 
23:43:31 2018
@@ -19,10 +19,7 @@
 
 package org.apache.poi.sl.draw;
 
-import org.apache.poi.common.usermodel.fonts.FontCharset;
-import org.apache.poi.common.usermodel.fonts.FontFamily;
 import org.apache.poi.common.usermodel.fonts.FontInfo;
-import org.apache.poi.common.usermodel.fonts.FontPitch;
 import org.apache.poi.util.Internal;
 
 /**
@@ -38,52 +35,7 @@ import org.apache.poi.util.Internal;
     }
     
     @Override
-    public Integer getIndex() {
-        return null;
-    }
-
-    @Override
-    public void setIndex(int index) {
-        throw new UnsupportedOperationException("DrawFontManagers FontInfo 
can't be changed.");
-    }
-
-    @Override
     public String getTypeface() {
         return typeface;
     }
-
-    @Override
-    public void setTypeface(String typeface) {
-        throw new UnsupportedOperationException("DrawFontManagers FontInfo 
can't be changed.");
-    }
-
-    @Override
-    public FontCharset getCharset() {
-        return FontCharset.ANSI;
-    }
-
-    @Override
-    public void setCharset(FontCharset charset) {
-        throw new UnsupportedOperationException("DrawFontManagers FontInfo 
can't be changed.");
-    }
-
-    @Override
-    public FontFamily getFamily() {
-        return FontFamily.FF_SWISS;
-    }
-
-    @Override
-    public void setFamily(FontFamily family) {
-        throw new UnsupportedOperationException("DrawFontManagers FontInfo 
can't be changed.");
-    }
-
-    @Override
-    public FontPitch getPitch() {
-        return FontPitch.VARIABLE;
-    }
-
-    @Override
-    public void setPitch(FontPitch pitch) {
-        throw new UnsupportedOperationException("DrawFontManagers FontInfo 
can't be changed.");
-    }
 }

Modified: poi/trunk/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java 
(original)
+++ poi/trunk/src/java/org/apache/poi/sl/extractor/SlideShowExtractor.java Fri 
Dec 28 23:43:31 2018
@@ -18,10 +18,14 @@
 package org.apache.poi.sl.extractor;
 
 import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
 
 import org.apache.poi.extractor.POITextExtractor;
-import org.apache.poi.sl.usermodel.Comment;
 import org.apache.poi.sl.usermodel.MasterSheet;
 import org.apache.poi.sl.usermodel.Notes;
 import org.apache.poi.sl.usermodel.ObjectShape;
@@ -52,6 +56,10 @@ public class SlideShowExtractor<
 > extends POITextExtractor {
     private static final POILogger LOG = 
POILogFactory.getLogger(SlideShowExtractor.class);
 
+    // placeholder text for slide numbers
+    private static final String SLIDE_NUMBER_PH = "‹#›";
+
+
     private SlideShow<S,P> slideshow;
 
     private boolean slidesByDefault = true;
@@ -59,7 +67,8 @@ public class SlideShowExtractor<
     private boolean commentsByDefault;
     private boolean masterByDefault;
 
-    
+    private Predicate<Object> filter = o -> true;
+
     public SlideShowExtractor(final SlideShow<S,P> slideshow) {
         setFilesystem(slideshow);
         this.slideshow = slideshow;
@@ -115,9 +124,8 @@ public class SlideShowExtractor<
     @Override
     public String getText() {
         final StringBuilder sb = new StringBuilder();
-        
         for (final Slide<S, P> slide : slideshow.getSlides()) {
-            sb.append(getText(slide));
+            getText(slide, sb::append);
         }
 
         return sb.toString();
@@ -125,34 +133,37 @@ public class SlideShowExtractor<
 
     public String getText(final Slide<S,P> slide) {
         final StringBuilder sb = new StringBuilder();
+        getText(slide, sb::append);
+        return sb.toString();
+    }
 
+
+    private void getText(final Slide<S,P> slide, final Consumer<String> 
consumer) {
         if (slidesByDefault) {
-            printShapeText(slide, sb);
+            printShapeText(slide, consumer);
         }
 
         if (masterByDefault) {
             final MasterSheet<S,P> ms = slide.getMasterSheet();
-            printSlideMaster(ms, sb);
+            printSlideMaster(ms, consumer);
 
             // only print slide layout, if it's a different instance
             final MasterSheet<S,P> sl = slide.getSlideLayout();
             if (sl != ms) {
-                printSlideMaster(sl, sb);
+                printSlideMaster(sl, consumer);
             }
         }
 
         if (commentsByDefault) {
-            printComments(slide, sb);
+            printComments(slide, consumer);
         }
 
         if (notesByDefault) {
-            printNotes(slide, sb);
+            printNotes(slide, consumer);
         }
-
-        return sb.toString();
     }
 
-    private void printSlideMaster(final MasterSheet<S,P> master, final 
StringBuilder sb) {
+    private void printSlideMaster(final MasterSheet<S,P> master, final 
Consumer<String> consumer) {
         if (master == null) {
             return;
         }
@@ -163,163 +174,140 @@ public class SlideShowExtractor<
                 if (text == null || text.isEmpty() || "*".equals(text)) {
                     continue;
                 }
+
                 if (ts.isPlaceholder()) {
                     // don't bother about boiler plate text on master sheets
                     LOG.log(POILogger.INFO, "Ignoring boiler plate 
(placeholder) text on slide master:", text);
                     continue;
                 }
-                sb.append(text);
-                if (!text.endsWith("\n")) {
-                    sb.append("\n");
-                }
 
+                printTextParagraphs(ts.getTextParagraphs(), consumer);
             }
         }
     }
 
-    private String printHeaderReturnFooter(final Sheet<S,P> sheet, final 
StringBuilder sb) {
-        final Sheet<S, P> m = (sheet instanceof Slide) ? 
sheet.getMasterSheet() : sheet;
-        final StringBuilder footer = new StringBuilder("\n");
-        addSheetPlaceholderDatails(sheet, Placeholder.HEADER, sb);
-        addSheetPlaceholderDatails(sheet, Placeholder.FOOTER, footer);
+    private void printTextParagraphs(final List<P> paras, final 
Consumer<String> consumer) {
+        printTextParagraphs(paras, consumer, "\n");
+    }
 
-        if (masterByDefault) {
-            // write header texts and determine footer text
-            for (Shape<S, P> s : m) {
-                if (!(s instanceof TextShape)) {
-                    continue;
-                }
-                final TextShape<S, P> ts = (TextShape<S, P>) s;
-                final PlaceholderDetails pd = ts.getPlaceholderDetails();
-                if (pd == null || !pd.isVisible() || pd.getPlaceholder() == 
null) {
-                    continue;
-                }
-                switch (pd.getPlaceholder()) {
-                    case HEADER:
-                        sb.append(ts.getText());
-                        sb.append('\n');
-                        break;
-                    case SLIDE_NUMBER:
-                        if (sheet instanceof Slide) {
-                            footer.append(ts.getText().replace("‹#›", 
Integer.toString(((Slide<S, P>) sheet).getSlideNumber() + 1)));
-                            footer.append('\n');
-                        }
-                        break;
-                    case FOOTER:
-                        footer.append(ts.getText());
-                        footer.append('\n');
-                        break;
-                    case DATETIME:
-                        // currently not supported
-                    default:
-                        break;
+
+    private void printTextParagraphs(final List<P> paras, final 
Consumer<String> consumer, String trailer) {
+        printTextParagraphs(paras, consumer, trailer, 
SlideShowExtractor::replaceTextCap);
+    }
+
+    private void printTextParagraphs(final List<P> paras, final 
Consumer<String> consumer, String trailer, final Function<TextRun,String> 
converter) {
+        for (P p : paras) {
+            for (TextRun r : p) {
+                if (filter.test(r)) {
+                    consumer.accept(converter.apply(r));
                 }
             }
+            if (!trailer.isEmpty() && filter.test(trailer)) {
+                consumer.accept(trailer);
+            }
         }
-
-        return (footer.length() > 1) ? footer.toString() : "";
     }
 
-    private void addSheetPlaceholderDatails(final Sheet<S,P> sheet, final 
Placeholder placeholder, final StringBuilder sb) {
-        final PlaceholderDetails headerPD = 
sheet.getPlaceholderDetails(placeholder);
-        if (headerPD == null) {
+    private void printHeaderFooter(final Sheet<S,P> sheet, final 
Consumer<String> consumer, final Consumer<String> footerCon) {
+        final Sheet<S, P> m = (sheet instanceof Slide) ? 
sheet.getMasterSheet() : sheet;
+        addSheetPlaceholderDatails(sheet, Placeholder.HEADER, consumer);
+        addSheetPlaceholderDatails(sheet, Placeholder.FOOTER, footerCon);
+
+        if (!masterByDefault) {
             return;
         }
-        final String headerStr = headerPD.getText();
-        if (headerStr == null) {
-            return;
+
+        // write header texts and determine footer text
+        for (Shape<S, P> s : m) {
+            if (!(s instanceof TextShape)) {
+                continue;
+            }
+            final TextShape<S, P> ts = (TextShape<S, P>) s;
+            final PlaceholderDetails pd = ts.getPlaceholderDetails();
+            if (pd == null || !pd.isVisible() || pd.getPlaceholder() == null) {
+                continue;
+            }
+            switch (pd.getPlaceholder()) {
+                case HEADER:
+                    printTextParagraphs(ts.getTextParagraphs(), consumer);
+                    break;
+                case FOOTER:
+                    printTextParagraphs(ts.getTextParagraphs(), footerCon);
+                    break;
+                case SLIDE_NUMBER:
+                    printTextParagraphs(ts.getTextParagraphs(), footerCon, 
"\n", SlideShowExtractor::replaceSlideNumber);
+                    break;
+                case DATETIME:
+                    // currently not supported
+                default:
+                    break;
+            }
+        }
+    }
+
+
+    private void addSheetPlaceholderDatails(final Sheet<S,P> sheet, final 
Placeholder placeholder, final Consumer<String> consumer) {
+        final PlaceholderDetails headerPD = 
sheet.getPlaceholderDetails(placeholder);
+        final String headerStr = (headerPD != null) ? headerPD.getText() : 
null;
+        if (headerStr != null && filter.test(headerPD)) {
+            consumer.accept(headerStr);
         }
-        sb.append(headerStr);
     }
 
-    private void printShapeText(final Sheet<S,P> sheet, final StringBuilder 
sb) {
-        final String footer = printHeaderReturnFooter(sheet, sb);
-        printShapeText((ShapeContainer<S,P>)sheet, sb);
-        sb.append(footer);
+    private void printShapeText(final Sheet<S,P> sheet, final Consumer<String> 
consumer) {
+        final List<String> footer = new LinkedList<>();
+        printHeaderFooter(sheet, consumer, footer::add);
+        printShapeText((ShapeContainer<S,P>)sheet, consumer);
+        footer.forEach(consumer);
     }
 
     @SuppressWarnings("unchecked")
-    private void printShapeText(final ShapeContainer<S,P> container, final 
StringBuilder sb) {
+    private void printShapeText(final ShapeContainer<S,P> container, final 
Consumer<String> consumer) {
         for (Shape<S,P> shape : container) {
             if (shape instanceof TextShape) {
-                printShapeText((TextShape<S,P>)shape, sb);
+                
printTextParagraphs(((TextShape<S,P>)shape).getTextParagraphs(), consumer);
             } else if (shape instanceof TableShape) {
-                printShapeText((TableShape<S,P>)shape, sb);
+                printShapeText((TableShape<S,P>)shape, consumer);
             } else if (shape instanceof ShapeContainer) {
-                printShapeText((ShapeContainer<S,P>)shape, sb);
+                printShapeText((ShapeContainer<S,P>)shape, consumer);
             }
         }
     }
 
-    private void printShapeText(final TextShape<S,P> shape, final 
StringBuilder sb) {
-        final List<P> paraList = shape.getTextParagraphs();
-        if (paraList.isEmpty()) {
-            sb.append('\n');
-            return;
-        }
-        for (final P para : paraList) {
-            for (final TextRun tr : para) {
-                final String str = tr.getRawText().replace("\r", "");
-                final String newStr;
-                switch (tr.getTextCap()) {
-                    case ALL:
-                        newStr = str.toUpperCase(LocaleUtil.getUserLocale());
-                        break;
-                    case SMALL:
-                        newStr = str.toLowerCase(LocaleUtil.getUserLocale());
-                        break;
-                    default:
-                    case NONE:
-                        newStr = str;
-                        break;
-                }
-                sb.append(newStr);
-            }
-            sb.append('\n');
-        }
-    }
-
     @SuppressWarnings("Duplicates")
-    private void printShapeText(final TableShape<S,P> shape, final 
StringBuilder sb) {
+    private void printShapeText(final TableShape<S,P> shape, final 
Consumer<String> consumer) {
         final int nrows = shape.getNumberOfRows();
         final int ncols = shape.getNumberOfColumns();
-        for (int row = 0; row < nrows; row++){
+        for (int row = 0; row < nrows; row++) {
+            String trailer = "";
             for (int col = 0; col < ncols; col++){
                 TableCell<S, P> cell = shape.getCell(row, col);
                 //defensive null checks; don't know if they're necessary
-                if (cell != null){
-                    String txt = cell.getText();
-                    txt = (txt == null) ? "" : txt;
-                    sb.append(txt);
-                    if (col < ncols-1){
-                        sb.append('\t');
-                    }
+                if (cell != null) {
+                    trailer = col < ncols-1 ? "\t" : "\n";
+                    printTextParagraphs(cell.getTextParagraphs(), consumer, 
trailer);
                 }
             }
-            sb.append('\n');
+            if (!trailer.equals("\n") && filter.test("\n")) {
+                consumer.accept("\n");
+            }
         }
     }
 
-    private void printComments(final Slide<S,P> slide, final StringBuilder sb) 
{
-        for (final Comment comment : slide.getComments()) {
-            sb.append(comment.getAuthor());
-            sb.append(" - ");
-            sb.append(comment.getText());
-            sb.append("\n");
-        }
+    private void printComments(final Slide<S,P> slide, final Consumer<String> 
consumer) {
+        slide.getComments().stream().filter(filter).map(c -> c.getAuthor()+" - 
"+c.getText()).forEach(consumer);
     }
 
-    private void printNotes(final Slide<S,P> slide, final StringBuilder sb) {
+    private void printNotes(final Slide<S,P> slide, final Consumer<String> 
consumer) {
         final Notes<S, P> notes = slide.getNotes();
         if (notes == null) {
             return;
         }
 
-        final String footer = printHeaderReturnFooter(notes, sb);
-
-        printShapeText(notes, sb);
-
-        sb.append(footer);
+        List<String> footer = new LinkedList<>();
+        printHeaderFooter(notes, consumer, footer::add);
+        printShapeText(notes, consumer);
+        footer.forEach(consumer);
     }
 
     public List<? extends ObjectShape<S,P>> getOLEShapes() {
@@ -342,4 +330,83 @@ public class SlideShowExtractor<
             }
         }
     }
+
+    private static String replaceSlideNumber(TextRun tr) {
+        String raw = tr.getRawText();
+
+        if (!raw.contains(SLIDE_NUMBER_PH)) {
+            return raw;
+        }
+
+        TextParagraph tp = tr.getParagraph();
+        TextShape ps = (tp != null) ? tp.getParentShape() : null;
+        Sheet sh = (ps != null) ? ps.getSheet() : null;
+        String slideNr = (sh instanceof Slide) ? 
Integer.toString(((Slide)sh).getSlideNumber() + 1) : "";
+
+        return raw.replace(SLIDE_NUMBER_PH, slideNr);
+    }
+
+    private static String replaceTextCap(TextRun tr) {
+        final TextParagraph tp = tr.getParagraph();
+        final TextShape sh = (tp != null) ? tp.getParentShape() : null;
+        final Placeholder ph = (sh != null) ? sh.getPlaceholder() : null;
+
+        // 0xB acts like cariage return in page titles and like blank in the 
others
+        final char sep = (
+            ph == Placeholder.TITLE ||
+            ph == Placeholder.CENTERED_TITLE ||
+            ph == Placeholder.SUBTITLE
+        ) ? '\n' : ' ';
+
+        // PowerPoint seems to store files with \r as the line break
+        // The messes things up on everything but a Mac, so translate them to 
\n
+        String txt = tr.getRawText();
+        txt = txt.replace('\r', '\n');
+        txt = txt.replace((char) 0x0B, sep);
+
+        switch (tr.getTextCap()) {
+            case ALL:
+                txt = txt.toUpperCase(LocaleUtil.getUserLocale());
+            case SMALL:
+                txt = txt.toLowerCase(LocaleUtil.getUserLocale());
+        }
+
+        return txt;
+    }
+
+    /**
+     * Extract the used codepoints for font embedding / subsetting
+     * @param typeface the typeface/font family of the textruns to examine
+     * @param italic use {@code true} for italic TextRuns, {@code false} for 
non-italic ones and
+     *      {@code null} if it doesn't matter
+     * @param bold use {@code true} for bold TextRuns, {@code false} for 
non-bold ones and
+     *      {@code null} if it doesn't matter
+     * @return a bitset with the marked/used codepoints
+     */
+    public BitSet getCodepoints(String typeface, Boolean italic, Boolean bold) 
{
+        final BitSet glyphs = new BitSet();
+
+        Predicate<Object> filterOld = filter;
+        try {
+            filter = o -> filterFonts(o, typeface, italic, bold);
+            slideshow.getSlides().forEach(slide ->
+                getText(slide, s -> s.codePoints().forEach(glyphs::set))
+            );
+        } finally {
+            filter = filterOld;
+        }
+
+        return glyphs;
+    }
+
+    private static boolean filterFonts(Object o, String typeface, Boolean 
italic, Boolean bold) {
+        if (!(o instanceof TextRun)) {
+            return false;
+        }
+        TextRun tr = (TextRun)o;
+        return
+            typeface.equalsIgnoreCase(tr.getFontFamily()) &&
+            (italic == null || tr.isItalic() == italic) &&
+            (bold == null || tr.isBold() == bold);
+    }
 }

Modified: poi/trunk/src/java/org/apache/poi/sl/usermodel/Slide.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/Slide.java?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/Slide.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/Slide.java Fri Dec 28 
23:43:31 2018
@@ -19,6 +19,7 @@ package org.apache.poi.sl.usermodel;
 
 import java.util.List;
 
+@SuppressWarnings("unused")
 public interface Slide<
     S extends Shape<S,P>,
     P extends TextParagraph<S,P,? extends TextRun>
@@ -82,7 +83,7 @@ public interface Slide<
      *
      * @since POI 4.0.0
      */
-    MasterSheet getSlideLayout();
+    MasterSheet<S,P> getSlideLayout();
 
     /**
      * @return the slide name, defaults to "Slide[slideNumber]"

Modified: poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShow.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShow.java?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShow.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/SlideShow.java Fri Dec 28 
23:43:31 2018
@@ -25,6 +25,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.List;
 
+import org.apache.poi.common.usermodel.fonts.FontInfo;
 import org.apache.poi.extractor.POITextExtractor;
 import org.apache.poi.sl.usermodel.PictureData.PictureType;
 
@@ -44,8 +45,6 @@ public interface SlideShow<
      */
        List<? extends MasterSheet<S,P>> getSlideMasters();
 
-       Resources getResources();
-
     /**
      * Returns the current page size
      *
@@ -135,4 +134,30 @@ public interface SlideShow<
      * @since POI 4.0.0
      */
     Object getPersistDocument();
+
+    /**
+     * Add an EOT font to the slideshow.
+     * An EOT or MTX font is a transformed True-Type (.ttf) or Open-Type 
(.otf) font.
+     * To transform a True-Type font use the sfntly library (see "see also" 
below)<p>
+     *
+     * (Older?) Powerpoint versions handle embedded fonts by converting them 
to .ttf files
+     * and put them into the Windows fonts directory. If the user is not 
allowed to install
+     * fonts, the slideshow can't be opened. While the slideshow is opened, 
its possible
+     * to copy the extracted .ttfs from the fonts directory. When the 
slideshow is closed,
+     * they will be removed.
+     *
+     * @param fontData the EOT font as stream
+     * @return the font info object containing the new font data
+     * @throws IOException if the fontData can't be saved or if the fontData 
is no EOT font
+     *
+     * @see <a href="http://www.w3.org/Submission/EOT";>EOT specification</a>
+     * @see <a href="https://github.com/googlei18n/sfntly";>googles sfntly 
library</a>
+     * @see <a href="https://github.com/kiwiwings/poi-font-mbender";>Example on 
how to subset and embed fonts</a>
+     */
+    FontInfo addFont(InputStream fontData) throws IOException;
+
+    /**
+     * @return a list of registered fonts
+     */
+    List<? extends FontInfo> getFonts();
 }

Modified: poi/trunk/src/java/org/apache/poi/sl/usermodel/TextRun.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/usermodel/TextRun.java?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/usermodel/TextRun.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/usermodel/TextRun.java Fri Dec 28 
23:43:31 2018
@@ -27,6 +27,7 @@ import org.apache.poi.util.Internal;
 /**
  * Some text.
  */
+@SuppressWarnings("unused")
 public interface TextRun {
     /**
      * Type of text capitals
@@ -243,4 +244,11 @@ public interface TextRun {
      */
     @Internal
     FieldType getFieldType();
+
+    /**
+     * @return the paragraph which contains this TextRun
+     *
+     * @since POI 4.1.0
+     */
+    TextParagraph<?,?,?> getParagraph();
 }

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java 
(original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java 
Fri Dec 28 23:43:31 2018
@@ -30,19 +30,20 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.OptionalLong;
 import java.util.regex.Pattern;
+import java.util.stream.Stream;
 
 import org.apache.poi.ooxml.POIXMLDocument;
 import org.apache.poi.ooxml.POIXMLDocumentPart;
 import org.apache.poi.ooxml.POIXMLException;
 import org.apache.poi.ooxml.extractor.POIXMLPropertiesTextExtractor;
 import org.apache.poi.ooxml.util.PackageHelper;
-import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.sl.usermodel.MasterSheet;
 import org.apache.poi.sl.usermodel.PictureData.PictureType;
-import org.apache.poi.sl.usermodel.Resources;
 import org.apache.poi.sl.usermodel.SlideShow;
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.IOUtils;
@@ -60,7 +61,6 @@ import org.openxmlformats.schemas.presen
 import org.openxmlformats.schemas.presentationml.x2006.main.CTPresentation;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdList;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdListEntry;
-import 
org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterIdListEntry;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideSize;
 import 
org.openxmlformats.schemas.presentationml.x2006.main.PresentationDocument;
 
@@ -70,6 +70,7 @@ import org.openxmlformats.schemas.presen
  * they are reading or writing a slideshow. It is also the
  * top level object for creating new slides/etc.
  */
+@SuppressWarnings("WeakerAccess")
 @Beta
 public class XMLSlideShow extends POIXMLDocument
         implements SlideShow<XSLFShape, XSLFTextParagraph> {
@@ -78,10 +79,10 @@ public class XMLSlideShow extends POIXML
     private static final int MAX_RECORD_LENGTH = 1_000_000;
 
     private CTPresentation _presentation;
-    private List<XSLFSlide> _slides;
-    private List<XSLFSlideMaster> _masters;
-    private List<XSLFPictureData> _pictures;
-    private List<XSLFChart> _charts;
+    private final List<XSLFSlide> _slides = new ArrayList<>();
+    private final List<XSLFSlideMaster> _masters = new ArrayList<>();
+    private final List<XSLFPictureData> _pictures = new ArrayList<>();
+    private final List<XSLFChart> _charts = new ArrayList<>();
     private XSLFTableStyles _tableStyles;
     private XSLFNotesMaster _notesMaster;
     private XSLFCommentAuthors _commentAuthors;
@@ -153,27 +154,26 @@ public class XMLSlideShow extends POIXML
                 }
             }
 
-            _charts = new ArrayList<>(chartMap.size());
-            for (XSLFChart chart : chartMap.values()) {
-                _charts.add(chart);
-            }
+            _charts.clear();
+            _charts.addAll(chartMap.values());
 
-            _masters = new ArrayList<>(masterMap.size());
-            for (CTSlideMasterIdListEntry masterId : 
_presentation.getSldMasterIdLst().getSldMasterIdList()) {
-                XSLFSlideMaster master = masterMap.get(masterId.getId2());
-                _masters.add(master);
+            _masters.clear();
+            if (_presentation.isSetSldMasterIdLst()) {
+                _presentation.getSldMasterIdLst().getSldMasterIdList().forEach(
+                   id -> _masters.add(masterMap.get(id.getId2()))
+                );
             }
 
-            _slides = new ArrayList<>(shIdMap.size());
+            _slides.clear();
             if (_presentation.isSetSldIdLst()) {
-                for (CTSlideIdListEntry slId : 
_presentation.getSldIdLst().getSldIdList()) {
-                    XSLFSlide sh = shIdMap.get(slId.getId2());
+                _presentation.getSldIdLst().getSldIdList().forEach(id -> {
+                    XSLFSlide sh = shIdMap.get(id.getId2());
                     if (sh == null) {
-                        LOG.log(POILogger.WARN, "Slide with r:id " + 
slId.getId() + " was defined, but didn't exist in package, skipping");
-                        continue;
+                        LOG.log(POILogger.WARN, "Slide with r:id " + 
id.getId() + " was defined, but didn't exist in package, skipping");
+                    } else {
+                        _slides.add(sh);
                     }
-                    _slides.add(sh);
-                }
+                });
             }
         } catch (XmlException e) {
             throw new POIXMLException(e);
@@ -192,7 +192,7 @@ public class XMLSlideShow extends POIXML
      * Get the document's embedded files.
      */
     @Override
-    public List<PackagePart> getAllEmbeddedParts() throws OpenXML4JException {
+    public List<PackagePart> getAllEmbeddedParts() {
         return Collections.unmodifiableList(
                 
getPackage().getPartsByName(Pattern.compile("/ppt/embeddings/.*?"))
         );
@@ -200,14 +200,12 @@ public class XMLSlideShow extends POIXML
 
     @Override
     public List<XSLFPictureData> getPictureData() {
-        if (_pictures == null) {
-            List<PackagePart> mediaParts = 
getPackage().getPartsByName(Pattern.compile("/ppt/media/.*?"));
-            _pictures = new ArrayList<>(mediaParts.size());
-            for (PackagePart part : mediaParts) {
+        if (_pictures.isEmpty()) {
+            
getPackage().getPartsByName(Pattern.compile("/ppt/media/.*?")).forEach(part -> {
                 XSLFPictureData pd = new XSLFPictureData(part);
                 pd.setIndex(_pictures.size());
                 _pictures.add(pd);
-            }
+            });
         }
         return Collections.unmodifiableList(_pictures);
     }
@@ -219,20 +217,16 @@ public class XMLSlideShow extends POIXML
      * @return created slide
      */
     public XSLFSlide createSlide(XSLFSlideLayout layout) {
-        int slideNumber = 256, cnt = 1;
-        CTSlideIdList slideList;
-        XSLFRelation relationType = XSLFRelation.SLIDE;
-        if (!_presentation.isSetSldIdLst()) {
-            slideList = _presentation.addNewSldIdLst();
-        } else {
-            slideList = _presentation.getSldIdLst();
-            for (CTSlideIdListEntry slideId : slideList.getSldIdArray()) {
-                slideNumber = (int) Math.max(slideId.getId() + 1, slideNumber);
-                cnt++;
-            }
+        CTSlideIdList slideList = _presentation.isSetSldIdLst()
+            ? _presentation.getSldIdLst() : _presentation.addNewSldIdLst();
 
-            cnt = findNextAvailableFileNameIndex(relationType, cnt);
-        }
+        @SuppressWarnings("deprecation")
+        OptionalLong maxId = Stream.of(slideList.getSldIdArray())
+            .mapToLong(CTSlideIdListEntry::getId).max();
+
+        final XSLFRelation relationType = XSLFRelation.SLIDE;
+        final int slideNumber = (int)(Math.max(maxId.orElse(0),255)+1);
+        final int cnt = findNextAvailableFileNameIndex(relationType);
 
         RelationPart rp = createRelationship
                 (relationType, XSLFFactory.getInstance(), cnt, false);
@@ -250,33 +244,14 @@ public class XMLSlideShow extends POIXML
         return slide;
     }
 
-    private int findNextAvailableFileNameIndex(XSLFRelation relationType, int 
idx) {
+    private int findNextAvailableFileNameIndex(XSLFRelation relationType) {
         // Bug 55791: We also need to check that the resulting file name is 
not already taken
         // this can happen when removing/adding slides, notes or charts
-        while (true) {
-            String fileName = relationType.getFileName(idx);
-            boolean found = false;
-            for (POIXMLDocumentPart relation : getRelations()) {
-                if (relation.getPackagePart() != null &&
-                        
fileName.equals(relation.getPackagePart().getPartName().getName())) {
-                    // name is taken => try next one
-                    found = true;
-                    break;
-                }
-            }
-
-            if (!found &&
-                    
getPackage().getPartsByName(Pattern.compile(Pattern.quote(fileName))).size() > 
0) {
-                // name is taken => try next one
-                found = true;
-            }
-
-            if (!found) {
-                break;
-            }
-            idx++;
+        try {
+            return 
getPackage().getUnusedPartIndex(relationType.getDefaultFileName());
+        } catch (InvalidFormatException e) {
+            throw new RuntimeException(e);
         }
-        return idx;
     }
 
     /**
@@ -313,8 +288,8 @@ public class XMLSlideShow extends POIXML
      * @since POI 4.1.0
      */
     public XSLFChart createChart() {
-        int chartIdx = findNextAvailableFileNameIndex(XSLFRelation.CHART, 
_charts.size() + 1);
-        XSLFChart chart = (XSLFChart) createRelationship(XSLFRelation.CHART, 
XSLFFactory.getInstance(), chartIdx, true).getDocumentPart();
+        int chartIdx = findNextAvailableFileNameIndex(XSLFRelation.CHART);
+        XSLFChart chart = createRelationship(XSLFRelation.CHART, 
XSLFFactory.getInstance(), chartIdx, true).getDocumentPart();
         chart.setChartIndex(chartIdx);
         _charts.add(chart);
         return chart;
@@ -341,10 +316,8 @@ public class XMLSlideShow extends POIXML
             createNotesMaster();
         }
 
-        int slideIndex = XSLFRelation.SLIDE.getFileNameIndex(slide);
-
         XSLFRelation relationType = XSLFRelation.NOTES;
-        slideIndex = findNextAvailableFileNameIndex(relationType, slideIndex);
+        int slideIndex = findNextAvailableFileNameIndex(relationType);
 
         // add notes slide to presentation
         XSLFNotes notesSlide = (XSLFNotes) createRelationship
@@ -453,6 +426,7 @@ public class XMLSlideShow extends POIXML
 
         // fix ordering in the low-level xml
         CTSlideIdList sldIdLst = _presentation.getSldIdLst();
+        @SuppressWarnings("deprecation")
         CTSlideIdListEntry[] entries = sldIdLst.getSldIdArray();
         CTSlideIdListEntry oldEntry = entries[oldIndex];
         if (oldIndex < newIndex) {
@@ -517,14 +491,21 @@ public class XMLSlideShow extends POIXML
             return img;
         }
 
-        int imageNumber = _pictures.size();
+
         XSLFRelation relType = XSLFPictureData.getRelationForType(format);
         if (relType == null) {
             throw new IllegalArgumentException("Picture type " + format + " is 
not supported.");
         }
 
-        img = createRelationship(relType, XSLFFactory.getInstance(), 
imageNumber + 1, true).getDocumentPart();
-        img.setIndex(imageNumber);
+        int imageNumber;
+        try {
+            imageNumber = 
getPackage().getUnusedPartIndex("/ppt/media/image#\\..+");
+        } catch (InvalidFormatException e) {
+            imageNumber = _pictures.size() + 1;
+        }
+
+        img = createRelationship(relType, XSLFFactory.getInstance(), 
imageNumber, true).getDocumentPart();
+        img.setIndex(_pictures.size());
         _pictures.add(img);
 
         try (OutputStream out = img.getPackagePart().getOutputStream()) {
@@ -624,6 +605,7 @@ public class XMLSlideShow extends POIXML
         return null;
     }
 
+    @SuppressWarnings("RedundantThrows")
     @Override
     public MasterSheet<XSLFShape, XSLFTextParagraph> createMasterSheet() 
throws IOException {
         // TODO: implement!
@@ -631,12 +613,6 @@ public class XMLSlideShow extends POIXML
     }
 
     @Override
-    public Resources getResources() {
-        // TODO: implement!
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
     public POIXMLPropertiesTextExtractor getMetadataTextExtractor() {
         return new POIXMLPropertiesTextExtractor(this);
     }
@@ -645,4 +621,14 @@ public class XMLSlideShow extends POIXML
     public Object getPersistDocument() {
         return this;
     }
+
+    @Override
+    public XSLFFontInfo addFont(InputStream fontStream) throws IOException {
+        return XSLFFontInfo.addFontToSlideShow(this, fontStream);
+    }
+
+    @Override
+    public List<XSLFFontInfo> getFonts() {
+        return XSLFFontInfo.getFonts(this);
+    }
 }

Added: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFontData.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFontData.java?rev=1849898&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFontData.java 
(added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFontData.java 
Fri Dec 28 23:43:31 2018
@@ -0,0 +1,84 @@
+/*
+ *  ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one or more
+ *    contributor license agreements.  See the NOTICE file distributed with
+ *    this work for additional information regarding copyright ownership.
+ *    The ASF licenses this file to You under the Apache License, Version 2.0
+ *    (the "License"); you may not use this file except in compliance with
+ *    the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.xslf.usermodel;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.util.Beta;
+
+/**
+ * A container for fontdata files, i.e. MTX fonts derived from
+ * true (TTF) or open (OTF) type fonts.
+ *
+ * @since POI 4.1.0
+ */
+@Beta
+public class XSLFFontData extends POIXMLDocumentPart {
+    /**
+     * Create a new XSLFFontData node
+     */
+    @SuppressWarnings("unused")
+    protected XSLFFontData() {
+        super();
+    }
+
+    /**
+     * Construct XSLFFontData from a package part
+     *
+     * @param part the package part holding the ole data
+     */
+    @SuppressWarnings("unused")
+    public XSLFFontData(final PackagePart part) {
+        super(part);
+    }
+
+    public InputStream getInputStream() throws IOException {
+        return getPackagePart().getInputStream();
+    }
+
+    public OutputStream getOutputStream() {
+        final PackagePart pp = getPackagePart();
+        pp.clear();
+        return pp.getOutputStream();
+    }
+
+    /**
+     * XSLFFontData objects store the actual content in the part directly 
without keeping a
+     * copy like all others therefore we need to handle them differently.
+     */
+    @Override
+    protected void prepareForCommit() {
+        // do not clear the part here
+    }
+
+
+    public void setData(final byte[] data) throws IOException {
+        try (final OutputStream os = getPackagePart().getOutputStream()) {
+            os.write(data);
+        }
+    }
+
+
+
+}

Propchange: 
poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFontData.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFontInfo.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFontInfo.java?rev=1849898&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFontInfo.java 
(added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFontInfo.java 
Fri Dec 28 23:43:31 2018
@@ -0,0 +1,285 @@
+/*
+ *  ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one or more
+ *    contributor license agreements.  See the NOTICE file distributed with
+ *    this work for additional information regarding copyright ownership.
+ *    The ASF licenses this file to You under the Apache License, Version 2.0
+ *    (the "License"); you may not use this file except in compliance with
+ *    the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ * ====================================================================
+ */
+
+package org.apache.poi.xslf.usermodel;
+
+import java.awt.Font;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.poi.common.usermodel.fonts.FontCharset;
+import org.apache.poi.common.usermodel.fonts.FontFacet;
+import org.apache.poi.common.usermodel.fonts.FontFamily;
+import org.apache.poi.common.usermodel.fonts.FontHeader;
+import org.apache.poi.common.usermodel.fonts.FontInfo;
+import org.apache.poi.common.usermodel.fonts.FontPitch;
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.util.IOUtils;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;
+import 
org.openxmlformats.schemas.presentationml.x2006.main.CTEmbeddedFontDataId;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTEmbeddedFontList;
+import 
org.openxmlformats.schemas.presentationml.x2006.main.CTEmbeddedFontListEntry;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPresentation;
+
+@SuppressWarnings("WeakerAccess")
+public class XSLFFontInfo implements FontInfo {
+    final XMLSlideShow ppt;
+    final String typeface;
+    final CTEmbeddedFontListEntry fontListEntry;
+
+    public XSLFFontInfo(XMLSlideShow ppt, String typeface) {
+        this.ppt = ppt;
+        this.typeface = typeface;
+
+        final CTPresentation pres = ppt.getCTPresentation();
+        CTEmbeddedFontList fontList = pres.isSetEmbeddedFontLst()
+            ? pres.getEmbeddedFontLst() : pres.addNewEmbeddedFontLst();
+
+        for (CTEmbeddedFontListEntry fe : fontList.getEmbeddedFontArray()) {
+            if (typeface.equalsIgnoreCase(fe.getFont().getTypeface())) {
+                fontListEntry = fe;
+                return;
+            }
+        }
+
+        fontListEntry = fontList.addNewEmbeddedFont();
+        fontListEntry.addNewFont().setTypeface(typeface);
+    }
+
+    public XSLFFontInfo(XMLSlideShow ppt, CTEmbeddedFontListEntry 
fontListEntry) {
+        this.ppt = ppt;
+        this.typeface = fontListEntry.getFont().getTypeface();
+        this.fontListEntry = fontListEntry;
+    }
+
+    @Override
+    public String getTypeface() {
+        return getFont().getTypeface();
+    }
+
+    @Override
+    public void setTypeface(String typeface) {
+        getFont().setTypeface(typeface);
+    }
+
+    @Override
+    public FontCharset getCharset() {
+        return FontCharset.valueOf(getFont().getCharset());
+    }
+
+    @Override
+    public void setCharset(FontCharset charset) {
+        getFont().setCharset((byte)charset.getNativeId());
+    }
+
+    @Override
+    public FontFamily getFamily() {
+        return FontFamily.valueOfPitchFamily(getFont().getPitchFamily());
+    }
+
+    @Override
+    public void setFamily(FontFamily family) {
+        byte pitchAndFamily = getFont().getPitchFamily();
+        FontPitch pitch = FontPitch.valueOfPitchFamily(pitchAndFamily);
+        getFont().setPitchFamily(FontPitch.getNativeId(pitch, family));
+    }
+
+    @Override
+    public FontPitch getPitch() {
+        return FontPitch.valueOfPitchFamily(getFont().getPitchFamily());
+    }
+
+    @Override
+    public void setPitch(FontPitch pitch) {
+        byte pitchAndFamily = getFont().getPitchFamily();
+        FontFamily family = FontFamily.valueOfPitchFamily(pitchAndFamily);
+        getFont().setPitchFamily(FontPitch.getNativeId(pitch, family));
+    }
+
+    @Override
+    public byte[] getPanose() {
+        return getFont().getPanose();
+    }
+
+    @Override
+    public List<FontFacet> getFacets() {
+        List<FontFacet> facetList = new ArrayList<>();
+        if (fontListEntry.isSetRegular()) {
+            facetList.add(new XSLFFontFacet((fontListEntry.getRegular())));
+        }
+        if (fontListEntry.isSetItalic()) {
+            facetList.add(new XSLFFontFacet((fontListEntry.getItalic())));
+        }
+        if (fontListEntry.isSetBold()) {
+            facetList.add(new XSLFFontFacet((fontListEntry.getBold())));
+        }
+        if (fontListEntry.isSetBoldItalic()) {
+            facetList.add(new XSLFFontFacet((fontListEntry.getBoldItalic())));
+        }
+        return facetList;
+    }
+
+    public FontFacet addFacet(InputStream fontData) throws IOException {
+        FontHeader header = new FontHeader();
+        InputStream is = header.bufferInit(fontData);
+
+        final CTPresentation pres = ppt.getCTPresentation();
+        pres.setEmbedTrueTypeFonts(true);
+        pres.setSaveSubsetFonts(true);
+
+        final CTEmbeddedFontDataId dataId;
+        final int style =
+                (header.getWeight() > 400 ? Font.BOLD : Font.PLAIN) |
+                        (header.isItalic() ? Font.ITALIC : Font.PLAIN);
+        switch (style) {
+            case Font.PLAIN:
+                dataId = fontListEntry.isSetRegular()
+                    ? fontListEntry.getRegular() : 
fontListEntry.addNewRegular();
+                break;
+            case Font.BOLD:
+                dataId = fontListEntry.isSetBold()
+                    ? fontListEntry.getBold() : fontListEntry.addNewBold();
+                break;
+            case Font.ITALIC:
+                dataId = fontListEntry.isSetItalic()
+                    ? fontListEntry.getItalic() : fontListEntry.addNewItalic();
+                break;
+            default:
+                dataId = fontListEntry.isSetBoldItalic()
+                    ? fontListEntry.getBoldItalic() : 
fontListEntry.addNewBoldItalic();
+                break;
+        }
+
+        XSLFFontFacet facet = new XSLFFontFacet(dataId);
+        facet.setFontData(is);
+        return facet;
+    }
+
+    private final class XSLFFontFacet implements FontFacet {
+        private final CTEmbeddedFontDataId fontEntry;
+        private final FontHeader header = new FontHeader();
+
+        private XSLFFontFacet(CTEmbeddedFontDataId fontEntry) {
+            this.fontEntry = fontEntry;
+        }
+
+        @Override
+        public int getWeight() {
+            init();
+            return header.getWeight();
+        }
+
+        @Override
+        public boolean isItalic() {
+            init();
+            return header.isItalic();
+        }
+
+        @Override
+        public XSLFFontData getFontData() {
+            return 
ppt.getRelationPartById(fontEntry.getId()).getDocumentPart();
+        }
+
+        void setFontData(InputStream is) throws IOException {
+            final XSLFRelation fntRel = XSLFRelation.FONT;
+            final String relId = fontEntry.getId();
+            final XSLFFontData fntData;
+            if (relId == null || relId.isEmpty()) {
+                final int fntDataIdx;
+                try {
+                    fntDataIdx = 
ppt.getPackage().getUnusedPartIndex(fntRel.getDefaultFileName());
+                } catch (InvalidFormatException e) {
+                    throw new RuntimeException(e);
+                }
+
+                POIXMLDocumentPart.RelationPart rp = 
ppt.createRelationship(fntRel, XSLFFactory.getInstance(), fntDataIdx, false);
+                fntData = rp.getDocumentPart();
+                fontEntry.setId(rp.getRelationship().getId());
+            } else {
+                fntData = (XSLFFontData)ppt.getRelationById(relId);
+            }
+
+            assert (fntData != null);
+            try (OutputStream os = fntData.getOutputStream()) {
+                IOUtils.copy(is, os);
+            }
+        }
+
+        private void init() {
+            if (header.getFamilyName() == null) {
+                try (InputStream is = getFontData().getInputStream()) {
+                    byte[] buf = IOUtils.toByteArray(is, 1000);
+                    header.init(buf, 0, buf.length);
+                } catch (IOException e) {
+                    // TODO: better exception class
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+
+
+    private CTTextFont getFont() {
+        return fontListEntry.getFont();
+    }
+
+
+
+    /**
+     * Adds or updates a (MTX-) font
+     * @param ppt the slideshow which will contain the font
+     * @param fontStream the (MTX) font data as stream
+     * @return a font data object
+     * @throws IOException if the font data can't be stored
+     *
+     * @since POI 4.1.0
+     */
+    public static XSLFFontInfo addFontToSlideShow(XMLSlideShow ppt, 
InputStream fontStream)
+    throws IOException {
+        FontHeader header = new FontHeader();
+        InputStream is = header.bufferInit(fontStream);
+
+        XSLFFontInfo fontInfo = new XSLFFontInfo(ppt, header.getFamilyName());
+        fontInfo.addFacet(is);
+        return fontInfo;
+    }
+
+    /**
+     * Return all registered fonts
+     * @param ppt the slideshow containing the fonts
+     * @return the list of registered fonts
+     */
+    public static List<XSLFFontInfo> getFonts(XMLSlideShow ppt) {
+        final CTPresentation pres = ppt.getCTPresentation();
+
+        //noinspection deprecation
+        return pres.isSetEmbeddedFontLst()
+            ? Stream.of(pres.getEmbeddedFontLst().getEmbeddedFontArray())
+                .map(fe -> new XSLFFontInfo(ppt, 
fe)).collect(Collectors.toList())
+            : Collections.emptyList();
+    }
+
+}

Propchange: 
poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFontInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java 
(original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java 
Fri Dec 28 23:43:31 2018
@@ -260,6 +260,13 @@ public final class XSLFRelation extends
             XSLFObjectData.class
     );
 
+    public static final XSLFRelation FONT = new XSLFRelation(
+            "application/x-fontdata",
+            
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/font";,
+            "/ppt/fonts/font#.fntdata",
+            XSLFFontData.class
+    );
+
 
     private XSLFRelation(String type, String rel, String defaultName, Class<? 
extends POIXMLDocumentPart> cls) {
         super(type, rel, defaultName, cls);

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=1849898&r1=1849897&r2=1849898&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 Fri 
Dec 28 23:43:31 2018
@@ -28,6 +28,7 @@ import org.apache.poi.openxml4j.opc.Pack
 import org.apache.poi.sl.draw.DrawPaint;
 import org.apache.poi.sl.usermodel.PaintStyle;
 import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
+import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.poi.sl.usermodel.TextRun;
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.POILogFactory;
@@ -629,16 +630,6 @@ public class XSLFTextRun implements Text
         }
 
         @Override
-        public Integer getIndex() {
-            return null;
-        }
-
-        @Override
-        public void setIndex(int index) {
-            throw new UnsupportedOperationException("setIndex not supported by 
XSLFFontInfo.");
-        }
-
-        @Override
         public String getTypeface() {
             CTTextFont tf = getXmlObject(false);
             return (tf != null && tf.isSetTypeface()) ? tf.getTypeface() : 
null;
@@ -829,4 +820,9 @@ public class XSLFTextRun implements Text
             return font;
         }
     }
+
+    @Override
+    public XSLFTextParagraph getParagraph() {
+        return _p;
+    }
 }

Modified: 
poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/extractor/TestXSLFPowerPointExtractor.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/extractor/TestXSLFPowerPointExtractor.java?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- 
poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/extractor/TestXSLFPowerPointExtractor.java
 (original)
+++ 
poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/extractor/TestXSLFPowerPointExtractor.java
 Fri Dec 28 23:43:31 2018
@@ -59,7 +59,7 @@ public class TestXSLFPowerPointExtractor
 
             // Check Basics
             assertStartsWith(text, "Lorem ipsum dolor sit amet\n");
-            assertContains(text, "amet\n\n");
+            assertContains(text, "amet\n");
 
             // Our placeholder master text
             // This shouldn't show up in the output
@@ -96,7 +96,7 @@ public class TestXSLFPowerPointExtractor
             extractor.setSlidesByDefault(false);
             extractor.setNotesByDefault(true);
             text = extractor.getText();
-            assertEquals("\n\n1\n\n\n2\n", text);
+            assertEquals("\n1\n\n2\n", text);
 
             // Both
             extractor.setSlidesByDefault(true);
@@ -105,14 +105,14 @@ public class TestXSLFPowerPointExtractor
             String bothText =
                 "Lorem ipsum dolor sit amet\n" +
                 "Nunc at risus vel erat tempus posuere. Aenean non ante.\n" +
-                "\n\n\n1\n" +
+                "\n\n1\n" +
                 "Lorem ipsum dolor sit amet\n" +
                 "Lorem\n" +
                 "ipsum\n" +
                 "dolor\n" +
                 "sit\n" +
                 "amet\n" +
-                "\n\n\n2\n";
+                "\n\n2\n";
             assertEquals(bothText, text);
 
             // With Slides and Master Text
@@ -141,21 +141,21 @@ public class TestXSLFPowerPointExtractor
             String snmText =
                 "Lorem ipsum dolor sit amet\n" +
                 "Nunc at risus vel erat tempus posuere. Aenean non ante.\n" +
-                "\n\n\n1\n" +
+                "\n\n1\n" +
                 "Lorem ipsum dolor sit amet\n" +
                 "Lorem\n" +
                 "ipsum\n" +
                 "dolor\n" +
                 "sit\n" +
                 "amet\n" +
-                "\n\n\n2\n";
+                "\n\n2\n";
             assertEquals(snmText, text);
 
             // Via set defaults
             extractor.setSlidesByDefault(false);
             extractor.setNotesByDefault(true);
             text = extractor.getText();
-            assertEquals("\n\n1\n\n\n2\n", text);
+            assertEquals("\n1\n\n2\n", text);
         }
        }
 

Modified: 
poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXMLSlideShow.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXMLSlideShow.java?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- 
poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXMLSlideShow.java
 (original)
+++ 
poi/trunk/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXMLSlideShow.java
 Fri Dec 28 23:43:31 2018
@@ -38,7 +38,7 @@ import org.openxmlformats.schemas.presen
 import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdListEntry;
 import 
org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterIdListEntry;
 
-public class TestXMLSlideShow extends BaseTestSlideShow {
+public class TestXMLSlideShow extends 
BaseTestSlideShow<XSLFShape,XSLFTextParagraph> {
    private OPCPackage pack;
    
    @Override
@@ -81,6 +81,7 @@ public class TestXMLSlideShow extends Ba
       xml.close();
    }
 
+   @SuppressWarnings("deprecation")
    @Test
    public void testSlideBasics() throws IOException {
       XMLSlideShow xml = new XMLSlideShow(pack);
@@ -136,7 +137,7 @@ public class TestXMLSlideShow extends Ba
       assertEquals(0, 
xml.getProperties().getExtendedProperties().getUnderlyingProperties().getCharacters());
       assertEquals(0, 
xml.getProperties().getExtendedProperties().getUnderlyingProperties().getLines());
 
-      assertEquals(null, xml.getProperties().getCoreProperties().getTitle());
+      assertNull(xml.getProperties().getCoreProperties().getTitle());
       
assertFalse(xml.getProperties().getCoreProperties().getUnderlyingProperties().getSubjectProperty().isPresent());
       
       xml.close();
@@ -146,8 +147,8 @@ public class TestXMLSlideShow extends Ba
    public void testComments() throws Exception {
       // Default sample file has none
       XMLSlideShow xml = new XMLSlideShow(pack);
-      
-      assertEquals(null, xml.getCommentAuthors());
+
+      assertNull(xml.getCommentAuthors());
       
       for (XSLFSlide slide : xml.getSlides()) {
          assertTrue(slide.getComments().isEmpty());
@@ -186,19 +187,16 @@ public class TestXMLSlideShow extends Ba
       xml.close();
    }
    
-   public SlideShow<?, ?> reopen(SlideShow<?, ?> show) {
-       return reopen((XMLSlideShow)show);
-   }
-
-   private static XMLSlideShow reopen(XMLSlideShow show) {
-       try {
-           BufAccessBAOS bos = new BufAccessBAOS();
-           show.write(bos);
-           return new XMLSlideShow(new ByteArrayInputStream(bos.getBuf()));
-       } catch (IOException e) {
-           fail(e.getMessage());
-           return null;
-       }
+   @Override
+   public XMLSlideShow reopen(SlideShow<XSLFShape,XSLFTextParagraph> show) {
+      try {
+         BufAccessBAOS bos = new BufAccessBAOS();
+         show.write(bos);
+         return new XMLSlideShow(new ByteArrayInputStream(bos.getBuf()));
+      } catch (IOException e) {
+         fail(e.getMessage());
+         return null;
+      }
    }
 
    private static class BufAccessBAOS extends ByteArrayOutputStream {

Modified: poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/Document.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/Document.java?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/Document.java 
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/Document.java Fri 
Dec 28 23:43:31 2018
@@ -87,11 +87,11 @@ public final class Document extends Posi
         *  Master Slides
         */
        public SlideListWithText getMasterSlideListWithText() {
-        for (int i = 0; i < slwts.length; i++) {
-            if(slwts[i].getInstance() == SlideListWithText.MASTER) {
-                return slwts[i];
-            }
-        }
+               for (SlideListWithText slwt : slwts) {
+                       if (slwt.getInstance() == SlideListWithText.MASTER) {
+                               return slwt;
+                       }
+               }
         return null;
     }
 
@@ -100,11 +100,11 @@ public final class Document extends Posi
         *  Slides, or null if there isn't one
         */
        public SlideListWithText getSlideSlideListWithText() {
-        for (int i = 0; i < slwts.length; i++) {
-            if(slwts[i].getInstance() == SlideListWithText.SLIDES) {
-                return slwts[i];
-            }
-        }
+               for (SlideListWithText slwt : slwts) {
+                       if (slwt.getInstance() == SlideListWithText.SLIDES) {
+                               return slwt;
+                       }
+               }
                return null;
     }
        /**
@@ -112,11 +112,11 @@ public final class Document extends Posi
         *  notes, or null if there isn't one
         */
        public SlideListWithText getNotesSlideListWithText() {
-        for (int i = 0; i < slwts.length; i++) {
-            if(slwts[i].getInstance() == SlideListWithText.NOTES) {
-                return slwts[i];
-            }
-        }
+               for (SlideListWithText slwt : slwts) {
+                       if (slwt.getInstance() == SlideListWithText.NOTES) {
+                               return slwt;
+                       }
+               }
                return null;
     }
 
@@ -124,7 +124,7 @@ public final class Document extends Posi
        /**
         * Set things up, and find our more interesting children
         */
-       protected Document(byte[] source, int start, int len) {
+       /* package */ Document(byte[] source, int start, int len) {
                // Grab the header
                _header = new byte[8];
                System.arraycopy(source,start,_header,0,8);
@@ -186,7 +186,7 @@ public final class Document extends Posi
                // The new SlideListWithText should go in
                //  just before the EndDocumentRecord
                Record endDoc = _children[_children.length - 1];
-               if(endDoc.getRecordType() == 
RecordTypes.RoundTripCustomTableStyles12Atom.typeID) {
+               if(endDoc.getRecordType() == 
RecordTypes.RoundTripCustomTableStyles12.typeID) {
                    // last record can optionally be a 
RoundTripCustomTableStyles12Atom
                    endDoc = _children[_children.length - 2];
                }
@@ -213,7 +213,7 @@ public final class Document extends Posi
                 removeChild(slwt);
             }
         }
-        slwts = lst.toArray(new SlideListWithText[lst.size()]);
+        slwts = lst.toArray(new SlideListWithText[0]);
     }
 
        /**

Modified: 
poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/DocumentAtom.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/DocumentAtom.java?rev=1849898&r1=1849897&r2=1849898&view=diff
==============================================================================
--- poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/DocumentAtom.java 
(original)
+++ poi/trunk/src/scratchpad/src/org/apache/poi/hslf/record/DocumentAtom.java 
Fri Dec 28 23:43:31 2018
@@ -17,25 +17,25 @@
 
 package org.apache.poi.hslf.record;
 
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.LittleEndian;
 import java.io.IOException;
 import java.io.OutputStream;
 
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.LittleEndianByteArrayInputStream;
+
 /**
  * A Document Atom (type 1001). Holds misc information on the PowerPoint
  * document, lots of them size and scale related.
- *
- * @author Nick Burch
  */
 
+@SuppressWarnings({"WeakerAccess", "unused"})
 public final class DocumentAtom extends RecordAtom
 {
        //arbitrarily selected; may need to increase
        private static final int MAX_RECORD_LENGTH = 1_000_000;
 
-       private byte[] _header;
-       private static long _type = 1001l;
+       private final byte[] _header = new byte[8];
+       private static long _type = RecordTypes.DocumentAtom.typeID;
 
        private long slideSizeX; // PointAtom, assume 1st 4 bytes = X
        private long slideSizeY; // PointAtom, assume 2nd 4 bytes = Y
@@ -87,6 +87,11 @@ public final class DocumentAtom extends
                return saveWithFonts != 0;
        }
 
+       /** Set the font embedding state */
+       public void setSaveWithFonts(boolean saveWithFonts) {
+               this.saveWithFonts = (byte)(saveWithFonts ? 1 : 0);
+       }
+
        /** Have the placeholders on the title slide been omitted? */
        public boolean getOmitTitlePlace() {
                return omitTitlePlace != 0;
@@ -108,41 +113,41 @@ public final class DocumentAtom extends
        /**
         * For the Document Atom
         */
-       protected DocumentAtom(byte[] source, int start, int len) {
-               // Sanity Checking
-               if(len < 48) { len = 48; }
+       /* package */ DocumentAtom(byte[] source, int start, int len) {
+               final int maxLen = Math.max(len, 48);
+               LittleEndianByteArrayInputStream leis =
+                       new LittleEndianByteArrayInputStream(source, start, 
maxLen);
 
                // Get the header
-               _header = new byte[8];
-               System.arraycopy(source,start,_header,0,8);
+               leis.readFully(_header);
 
                // Get the sizes and zoom ratios
-               slideSizeX = LittleEndian.getInt(source,start+0+8);
-               slideSizeY = LittleEndian.getInt(source,start+4+8);
-               notesSizeX = LittleEndian.getInt(source,start+8+8);
-               notesSizeY = LittleEndian.getInt(source,start+12+8);
-               serverZoomFrom = LittleEndian.getInt(source,start+16+8);
-               serverZoomTo   = LittleEndian.getInt(source,start+20+8);
+               slideSizeX = leis.readInt();
+               slideSizeY = leis.readInt();
+               notesSizeX = leis.readInt();
+               notesSizeY = leis.readInt();
+               serverZoomFrom = leis.readInt();
+               serverZoomTo = leis.readInt();
 
                // Get the master persists
-               notesMasterPersist = LittleEndian.getInt(source,start+24+8);
-               handoutMasterPersist = LittleEndian.getInt(source,start+28+8);
+               notesMasterPersist = leis.readInt();
+               handoutMasterPersist = leis.readInt();
 
                // Get the ID of the first slide
-               firstSlideNum = LittleEndian.getShort(source,start+32+8);
+               firstSlideNum = leis.readShort();
 
                // Get the slide size type
-               slideSizeType = LittleEndian.getShort(source,start+34+8);
+               slideSizeType = leis.readShort();
 
                // Get the booleans as bytes
-               saveWithFonts = source[start+36+8];
-               omitTitlePlace = source[start+37+8];
-               rightToLeft = source[start+38+8];
-               showComments = source[start+39+8];
+               saveWithFonts = leis.readByte();
+               omitTitlePlace = leis.readByte();
+               rightToLeft = leis.readByte();
+               showComments = leis.readByte();
 
                // If there's any other bits of data, keep them about
-               reserved = IOUtils.safelyAllocate(len-40-8, MAX_RECORD_LENGTH);
-               System.arraycopy(source,start+48,reserved,0,reserved.length);
+               reserved = IOUtils.safelyAllocate(maxLen-48, MAX_RECORD_LENGTH);
+               leis.readFully(reserved);
        }
 
        /**



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to