Author: kiwiwings
Date: Sun Jul 23 22:45:47 2017
New Revision: 1802741

URL: http://svn.apache.org/viewvc?rev=1802741&view=rev
Log:
Bug 61331 - Font group handling / common font interface

Added:
    poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/
    poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java   
(with props)
    poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontFamily.java   
(with props)
    poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontGroup.java   
(with props)
    poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontInfo.java   
(with props)
    poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontPitch.java   
(with props)
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontInfo.java   (with props)
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java   
(with props)
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFontInfo.java
      - copied, changed from r1802740, 
poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/PPFont.java
    
poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFontInfoPredefined.java
   (with props)
Removed:
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/PPFont.java
Modified:
    poi/site/src/documentation/content/xdocs/status.xml
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawFactory.java
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontManager.java
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextFragment.java
    poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
    poi/trunk/src/java/org/apache/poi/sl/usermodel/TextRun.java
    poi/trunk/src/java/org/apache/poi/ss/usermodel/FontCharset.java
    poi/trunk/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
    poi/trunk/src/ooxml/testcases/org/apache/poi/sl/TestFonts.java
    
poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/CharFlagsTextProp.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/RecordContainer.java
    
poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java
    
poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwmf/record/HwmfFont.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/HWPFOldDocument.java
    poi/trunk/src/scratchpad/src/org/apache/poi/hwpf/model/OldFfn.java
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPFont.java
    
poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSlideMaster.java
    
poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/record/TestFontCollection.java
    
poi/trunk/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java
    poi/trunk/src/scratchpad/testcases/org/apache/poi/hwmf/TestHwmfParsing.java
    
poi/trunk/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestHWPFOldDocument.java

Modified: poi/site/src/documentation/content/xdocs/status.xml
URL: 
http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/status.xml?rev=1802741&r1=1802740&r2=1802741&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/status.xml (original)
+++ poi/site/src/documentation/content/xdocs/status.xml Sun Jul 23 22:45:47 2017
@@ -58,6 +58,7 @@
 
     <release version="3.17-beta2" date="2017-09-??">
       <actions>
+        <action dev="PD" type="add" fixes-bug="61331" module="SL Common">Font 
group handling / common font interface</action>
         <action dev="PD" type="fix" fixes-bug="61300" module="POIFS">Avoid 
infinite loop with corrupt file.</action>
         <action dev="PD" type="fix" fixes-bug="61286,61287" 
module="HSSF">Handle zero-length headerfooter and 2 byte 
WriteProtectRecord</action>
         <action dev="PD" type="fix" fixes-bug="github-43" module="SS 
Common">RoundUp and RoundDown functions round incorrectly in some 
scenarios</action>

Added: 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=1802741&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java 
(added)
+++ poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java 
Sun Jul 23 22:45:47 2017
@@ -0,0 +1,124 @@
+/* ====================================================================
+   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.nio.charset.Charset;
+import java.nio.charset.UnsupportedCharsetException;
+
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
+/**
+ * Charset represents the basic set of characters associated with a font (that 
it can display), and 
+ * corresponds to the ANSI codepage (8-bit or DBCS) of that character set used 
by a given language.
+ * 
+ * @since POI 3.17-beta2
+ */
+public enum FontCharset {
+    /** Specifies the English character set. */
+    ANSI(0x00000000, "Cp1252"),
+    /**
+     * Specifies a character set based on the current system locale;
+     * for example, when the system locale is United States English,
+     * the default character set is ANSI_CHARSET.
+     */
+    DEFAULT(0x00000001, "Cp1252"),
+    /** Specifies a character set of symbols. */
+    SYMBOL(0x00000002, ""),
+    /** Specifies the Apple Macintosh character set. */
+    MAC(0x0000004D, "MacRoman"),
+    /** Specifies the Japanese character set. */
+    SHIFTJIS(0x00000080, "Shift_JIS"),
+    /** Also spelled "Hangeul". Specifies the Hangul Korean character set. */
+    HANGUL(0x00000081, "cp949"),
+    /** Also spelled "Johap". Specifies the Johab Korean character set. */
+    JOHAB(0x00000082, "x-Johab"),
+    /** Specifies the "simplified" Chinese character set for People's Republic 
of China. */
+    GB2312(0x00000086, "GB2312"),
+    /**
+     * Specifies the "traditional" Chinese character set, used mostly in
+     * Taiwan and in the Hong Kong and Macao Special Administrative Regions.
+     */
+    CHINESEBIG5(0x00000088, "Big5"),
+    /** Specifies the Greek character set. */
+    GREEK(0x000000A1, "Cp1253"),
+    /** Specifies the Turkish character set. */
+    TURKISH(0x000000A2, "Cp1254"),
+    /** Specifies the Vietnamese character set. */
+    VIETNAMESE(0x000000A3, "Cp1258"),
+    /** Specifies the Hebrew character set. */
+    HEBREW(0x000000B1, "Cp1255"),
+    /** Specifies the Arabic character set. */
+    ARABIC(0x000000B2, "Cp1256"),
+    /** Specifies the Baltic (Northeastern European) character set. */
+    BALTIC(0x000000BA, "Cp1257"),
+    /** Specifies the Russian Cyrillic character set. */
+    RUSSIAN(0x000000CC, "Cp1251"),
+    /** Specifies the Thai character set. */
+    THAI_(0x000000DE, "x-windows-874"),
+    /** Specifies a Eastern European character set. */
+    EASTEUROPE(0x000000EE, "Cp1250"),
+    /**
+     * Specifies a mapping to one of the OEM code pages,
+     * according to the current system locale setting.
+     */
+    OEM(0x000000FF, "Cp1252");
+
+    private static FontCharset[] _table = new FontCharset[256];
+    
+    private int nativeId;
+    private Charset charset;
+
+    
+    static {
+        for (FontCharset c : values()) {
+            _table[c.getNativeId()] = c;
+        }
+    }
+    
+    FontCharset(int flag, String javaCharsetName) {
+        this.nativeId = flag;
+        if (javaCharsetName.length() > 0) {
+            try {
+                charset = Charset.forName(javaCharsetName);
+                return;
+            } catch (UnsupportedCharsetException e) {
+                POILogger logger = POILogFactory.getLogger(FontCharset.class);
+                logger.log(POILogger.WARN, "Unsupported charset: 
"+javaCharsetName);
+            }
+        }
+        charset = null;
+    }
+
+    /**
+     *
+     * @return charset for the font or <code>null</code> if there is no 
matching charset or
+     *         if the charset is a &quot;default&quot;
+     */
+    public Charset getCharset() {
+        return charset;
+    }
+    
+    public int getNativeId() {
+        return nativeId;
+    }
+
+    public static FontCharset valueOf(int value){
+        return (value < 0 || value >= _table.length) ? null :_table[value];
+    }
+}
\ No newline at end of file

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

Added: poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontFamily.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontFamily.java?rev=1802741&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontFamily.java 
(added)
+++ poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontFamily.java 
Sun Jul 23 22:45:47 2017
@@ -0,0 +1,80 @@
+/* ====================================================================
+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;
+
+/**
+ * A property of a font that describes its general appearance.
+ * 
+ * @since POI 3.17-beta2
+ */
+public enum FontFamily {
+    /**
+     * The default font is specified, which is implementation-dependent.
+     */
+    FF_DONTCARE (0x00),
+    /**
+     * Fonts with variable stroke widths, which are proportional to the actual 
widths of
+     * the glyphs, and which have serifs. "MS Serif" is an example.
+     */
+    FF_ROMAN (0x01),
+    /**
+     * Fonts with variable stroke widths, which are proportional to the actual 
widths of the
+     * glyphs, and which do not have serifs. "MS Sans Serif" is an example.
+     */
+    FF_SWISS (0x02),
+    /**
+     * Fonts with constant stroke width, with or without serifs. Fixed-width 
fonts are
+     * usually modern. "Pica", "Elite", and "Courier New" are examples.
+     */
+    FF_MODERN (0x03),
+    /**
+     * Fonts designed to look like handwriting. "Script" and "Cursive" are 
examples.
+     */
+    FF_SCRIPT (0x04),
+    /**
+     * Novelty fonts. "Old English" is an example.
+     */
+    FF_DECORATIVE (0x05);
+    
+    private int nativeId;
+    private FontFamily(int nativeId) {
+        this.nativeId = nativeId;
+    }
+    
+    public int getFlag() {
+        return nativeId;
+    }
+
+    public static FontFamily valueOf(int nativeId) {
+        for (FontFamily ff : values()) {
+            if (ff.nativeId == nativeId) {
+                return ff;
+            }
+        }
+        return null;
+    }
+    
+
+    /**
+     * Get FontFamily from combined native id
+     */
+    public static FontFamily valueOfPitchFamily(byte pitchAndFamily) {
+        return valueOf(pitchAndFamily >>> 4);
+    }
+
+}
\ No newline at end of file

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

Added: poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontGroup.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontGroup.java?rev=1802741&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontGroup.java 
(added)
+++ poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontGroup.java Sun 
Jul 23 22:45:47 2017
@@ -0,0 +1,149 @@
+/* ====================================================================
+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.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.TreeMap;
+
+/**
+ * Text runs can contain characters which will be handled (if configured) by a 
different font,
+ * because the default font (latin) doesn't contain corresponding glyphs.
+ *
+ * @since POI 3.17-beta2
+ *
+ * @see <a 
href="https://blogs.msdn.microsoft.com/officeinteroperability/2013/04/22/office-open-xml-themes-schemes-and-fonts/";>Office
 Open XML Themes, Schemes, and Fonts</a>
+ */
+public enum FontGroup {
+    /** type for latin charset (default) - also used for unicode fonts like MS 
Arial Unicode */
+    LATIN,
+    /** type for east asian charsets - usually set as fallback for the latin 
font, e.g. something like MS Gothic or MS Mincho */
+    EAST_ASIAN,
+    /** type for symbol fonts */
+    SYMBOL,
+    /** type for complex scripts - see 
https://msdn.microsoft.com/en-us/library/windows/desktop/dd317698 */
+    COMPLEX_SCRIPT
+    ;
+
+
+    public static class FontGroupRange {
+        private int len;
+        private FontGroup fontGroup;
+        public int getLength() {
+            return len;
+        }
+        public FontGroup getFontGroup( ) {
+            return fontGroup;
+        }
+    }
+
+    private static class Range {
+        int upper;
+        FontGroup fontGroup;
+        Range(int upper, FontGroup fontGroup) {
+            this.upper = upper;
+            this.fontGroup = fontGroup;
+        }
+    }
+
+    private static NavigableMap<Integer,Range> UCS_RANGES;
+
+    static {
+        UCS_RANGES = new TreeMap<Integer,Range>();
+        UCS_RANGES.put(0x0000,  new Range(0x007F, LATIN));
+        UCS_RANGES.put(0x0080,  new Range(0x00A6, LATIN));
+        UCS_RANGES.put(0x00A9,  new Range(0x00AF, LATIN));
+        UCS_RANGES.put(0x00B2,  new Range(0x00B3, LATIN));
+        UCS_RANGES.put(0x00B5,  new Range(0x00D6, LATIN));
+        UCS_RANGES.put(0x00D8,  new Range(0x00F6, LATIN));
+        UCS_RANGES.put(0x00F8,  new Range(0x058F, LATIN));
+        UCS_RANGES.put(0x0590,  new Range(0x074F, COMPLEX_SCRIPT));
+        UCS_RANGES.put(0x0780,  new Range(0x07BF, COMPLEX_SCRIPT));
+        UCS_RANGES.put(0x0900,  new Range(0x109F, COMPLEX_SCRIPT));
+        UCS_RANGES.put(0x10A0,  new Range(0x10FF, LATIN));
+        UCS_RANGES.put(0x1200,  new Range(0x137F, LATIN));
+        UCS_RANGES.put(0x13A0,  new Range(0x177F, LATIN));
+        UCS_RANGES.put(0x1D00,  new Range(0x1D7F, LATIN));
+        UCS_RANGES.put(0x1E00,  new Range(0x1FFF, LATIN));
+        UCS_RANGES.put(0x1780,  new Range(0x18AF, COMPLEX_SCRIPT));
+        UCS_RANGES.put(0x2000,  new Range(0x200B, LATIN));
+        UCS_RANGES.put(0x200C,  new Range(0x200F, COMPLEX_SCRIPT));
+        // For the quote characters in the range U+2018 - U+201E, use the East 
Asian font
+        // if the text has one of the following language identifiers:
+        // ii-CN, ja-JP, ko-KR, zh-CN,zh-HK, zh-MO, zh-SG, zh-TW
+        UCS_RANGES.put(0x2010,  new Range(0x2029, LATIN));
+        UCS_RANGES.put(0x202A,  new Range(0x202F, COMPLEX_SCRIPT));
+        UCS_RANGES.put(0x2030,  new Range(0x2046, LATIN));
+        UCS_RANGES.put(0x204A,  new Range(0x245F, LATIN));
+        UCS_RANGES.put(0x2670,  new Range(0x2671, COMPLEX_SCRIPT));
+        UCS_RANGES.put(0x27C0,  new Range(0x2BFF, LATIN));
+        UCS_RANGES.put(0x3099,  new Range(0x309A, EAST_ASIAN));
+        UCS_RANGES.put(0xD835,  new Range(0xD835, LATIN));
+        UCS_RANGES.put(0xF000,  new Range(0xF0FF, SYMBOL));
+        UCS_RANGES.put(0xFB00,  new Range(0xFB17, LATIN));
+        UCS_RANGES.put(0xFB1D,  new Range(0xFB4F, COMPLEX_SCRIPT));
+        UCS_RANGES.put(0xFE50,  new Range(0xFE6F, LATIN));
+        // All others EAST_ASIAN
+    };
+
+
+    /**
+     * Try to guess the font group based on the codepoint
+     *
+     * @param runText the text which font groups are to be analyzed
+     * @return the FontGroup
+     */
+    public static List<FontGroupRange> getFontGroupRanges(String runText) {
+        List<FontGroupRange> ttrList = new ArrayList<FontGroupRange>();
+        FontGroupRange ttrLast = null;
+        final int rlen = (runText != null) ? runText.length() : 0;
+        for(int cp, i = 0, charCount; i < rlen; i += charCount) {
+            cp = runText.codePointAt(i);
+            charCount = Character.charCount(cp);
+
+            // don't switch the font group for a few default characters 
supposedly available in all fonts
+            FontGroup tt;
+            if (ttrLast != null && " \n\r".indexOf(cp) > -1) {
+                tt = ttrLast.fontGroup;
+            } else {
+                tt = lookup(cp);
+            }
+
+            if (ttrLast == null || ttrLast.fontGroup != tt) {
+                ttrLast = new FontGroupRange();
+                ttrLast.fontGroup = tt;
+                ttrList.add(ttrLast);
+            }
+            ttrLast.len += charCount;
+        }
+        return ttrList;
+    }
+
+    public static FontGroup getFontGroupFirst(String runText) {
+        return (runText == null || runText.isEmpty()) ? LATIN : 
lookup(runText.codePointAt(0));
+    }
+
+    private static FontGroup lookup(int codepoint) {
+        // Do a lookup for a match in UCS_RANGES
+        Map.Entry<Integer,Range> entry = UCS_RANGES.floorEntry(codepoint);
+        Range range = (entry != null) ? entry.getValue() : null;
+        return (range != null && codepoint <= range.upper) ? range.fontGroup : 
EAST_ASIAN;
+    }
+}
\ No newline at end of file

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

Added: 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=1802741&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontInfo.java 
(added)
+++ poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontInfo.java Sun 
Jul 23 22:45:47 2017
@@ -0,0 +1,102 @@
+/* ====================================================================
+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;
+
+/**
+ * A FontInfo object holds information about a font configuration.
+ * It is roughly an equivalent to the LOGFONT structure in Windows GDI.<p>
+ *
+ * If an implementation doesn't provide a property, the getter will return 
{@code null} -
+ * if the value is unset, a default value will be returned.<p>
+ *
+ * Setting a unsupported property results in an {@link 
UnsupportedOperationException}.
+ *
+ * @since POI 3.17-beta2
+ *
+ * @see <a 
href="https://msdn.microsoft.com/en-us/library/dd145037.aspx";>LOGFONT 
structure</a>
+ */
+public interface FontInfo {
+
+    /**
+     * Get the index within the collection of Font objects
+     * @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();
+
+    /**
+     * Sets the index within the collection of Font objects
+     *
+     * @param index the index within the collection of Font objects
+     *
+     * @throws UnsupportedOperationException if unsupported
+     */
+    void setIndex(int index);
+    
+    
+    /**
+     * @return the full name of the font, i.e. font family + type face
+     */
+    String getTypeface();
+
+    /**
+     * Sets the font name
+     *
+     * @param typeface the full name of the font, when {@code null} removes 
the font definition -
+     *    removal is implementation specific
+     */
+    void setTypeface(String typeface);
+
+    /**
+     * @return the font charset
+     */
+    FontCharset getCharset();
+
+    /**
+     * Sets the charset
+     *
+     * @param charset the charset
+     */
+    void setCharset(FontCharset charset);
+
+    /**
+     * @return the family class
+     */
+    FontFamily getFamily();
+
+    /**
+     * Sets the font family class
+     *
+     * @param family the font family class
+     */
+    void setFamily(FontFamily family);
+
+    /**
+     * @return the font pitch or {@code null} if unsupported
+     */
+    FontPitch getPitch();
+
+    /**
+     * Set the font pitch
+     *
+     * @param pitch the font pitch
+     *
+     * @throws UnsupportedOperationException if unsupported
+     */
+    void setPitch(FontPitch pitch);
+}
\ No newline at end of file

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

Added: poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontPitch.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontPitch.java?rev=1802741&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontPitch.java 
(added)
+++ poi/trunk/src/java/org/apache/poi/common/usermodel/fonts/FontPitch.java Sun 
Jul 23 22:45:47 2017
@@ -0,0 +1,74 @@
+/* ====================================================================
+   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;
+
+/**
+ * A property of a font that describes the pitch, of the characters.
+ * 
+ * @since POI 3.17-beta2
+ */
+public enum FontPitch {
+    /**
+     * The default pitch, which is implementation-dependent.
+     */
+    DEFAULT (0x00),
+    /**
+     * A fixed pitch, which means that all the characters in the font occupy 
the same
+     * width when output in a string.
+     */
+    FIXED (0x01),
+    /**
+     * A variable pitch, which means that the characters in the font occupy 
widths
+     * that are proportional to the actual widths of the glyphs when output in 
a string. For example,
+     * the "i" and space characters usually have much smaller widths than a 
"W" or "O" character.
+     */
+    VARIABLE (0x02);
+
+    private int nativeId;
+    FontPitch(int nativeId) {
+        this.nativeId = nativeId;
+    }
+
+    public int getNativeId() {
+        return nativeId;
+    }
+
+    public static FontPitch valueOf(int flag) {
+        for (FontPitch fp : values()) {
+            if (fp.nativeId == flag) return fp;
+        }
+        return null;
+    }
+    
+    /**
+     * Combine pitch and family to native id
+     * 
+     * @see <a 
href="https://msdn.microsoft.com/en-us/library/dd145037.aspx";>LOGFONT 
structure</a>
+     */
+    public static byte getNativeId(FontPitch pitch, FontFamily family) {
+        return (byte)(pitch.getNativeId() | (family.getFlag() << 4));
+    }
+
+    /**
+     * Get FontPitch from native id
+     */
+    public static FontPitch valueOfPitchFamily(byte pitchAndFamily) {
+        return valueOf(pitchAndFamily & 0x3);
+    }
+}
+

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

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawFactory.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawFactory.java?rev=1802741&r1=1802740&r2=1802741&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawFactory.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawFactory.java Sun Jul 23 
22:45:47 2017
@@ -236,4 +236,15 @@ public class DrawFactory {
             }
         }
     }
+    
+    /**
+     * Return a FontManager, either registered beforehand or a default 
implementation
+     *
+     * @param graphics the graphics context holding potentially a font manager
+     * @return the font manager
+     */
+    public DrawFontManager getFontManager(Graphics2D graphics) {
+        DrawFontManager fontHandler = 
(DrawFontManager)graphics.getRenderingHint(Drawable.FONT_HANDLER);
+        return (fontHandler != null) ? fontHandler : new 
DrawFontManagerDefault();
+    }
 }
\ No newline at end of file

Added: 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=1802741&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontInfo.java (added)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontInfo.java Sun Jul 23 
22:45:47 2017
@@ -0,0 +1,89 @@
+/*
+ *  ====================================================================
+ *    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.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;
+
+/**
+ * Convenience class to handle FontInfo mappings
+ */
+@Internal
+/* package */ class DrawFontInfo implements FontInfo {
+
+    private final String typeface;
+    
+    DrawFontInfo(String typeface) {
+        this.typeface = typeface;
+    }
+    
+    @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.");
+    }
+}

Propchange: poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontManager.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontManager.java?rev=1802741&r1=1802740&r2=1802741&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontManager.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontManager.java Sun Jul 23 
22:45:47 2017
@@ -19,6 +19,12 @@
 
 package org.apache.poi.sl.draw;
 
+import java.awt.Font;
+import java.awt.Graphics2D;
+
+import org.apache.poi.common.usermodel.fonts.FontInfo;
+import org.apache.poi.util.StringUtil;
+
 /**
  * Manages fonts when rendering slides.
  *
@@ -29,28 +35,50 @@ public interface DrawFontManager {
     /**
      * select a font to be used to paint text
      *
-     * @param typeface the font family as defined in the .pptx file.
-     * This can be unknown or missing in the graphic environment.
-     * @param pitchFamily a pitch-and-family,
-     * see {@link org.apache.poi.hwmf.record.HwmfFont#getFamily()} and
-     * {@link org.apache.poi.hwmf.record.HwmfFont#getPitch()}
-     * for how to calculate those (ancient) values
+     * @param graphics the graphics context to request additional rendering 
hints
+     * @param fontInfo the font info object corresponding to the text run font
      *
      * @return the font to be used to paint text
      */
-    String getRendererableFont(String typeface, int pitchFamily);
+    FontInfo getMappedFont(Graphics2D graphics, FontInfo fontInfo);
 
     /**
      * In case the original font doesn't contain a glyph, use the
      * returned fallback font as an alternative
      *
-     * @param typeface the font family as defined in the .pptx file.
-     * @param pitchFamily a pitch-and-family,
-     * see {@link org.apache.poi.hwmf.record.HwmfFont#getFamily()} and
-     * {@link org.apache.poi.hwmf.record.HwmfFont#getPitch()}
-     * for how to calculate those (ancient) values
+     * @param graphics the graphics context to request additional rendering 
hints
+     * @param fontInfo the font info object corresponding to the text run font
      * 
      * @return the font to be used as a fallback for the original typeface
      */
-    String getFallbackFont(String typeface, int pitchFamily);
+    FontInfo getFallbackFont(Graphics2D graphics, FontInfo fontInfo);
+
+    /**
+     * Map text charset depending on font family.<p>
+     * 
+     * Currently this only maps for wingdings font (into unicode private use 
area)
+     *
+     * @param graphics the graphics context to request additional rendering 
hints
+     * @param fontInfo the font info object corresponding to the text run font
+     * @param text the raw text
+     * 
+     * @return String with mapped codepoints
+     *
+     * @see <a href="http://stackoverflow.com/questions/8692095";>Drawing 
exotic fonts in a java applet</a>
+     * @see StringUtil#mapMsCodepointString(String)
+     */
+    String mapFontCharset(Graphics2D graphics, FontInfo fontInfo, String text);
+
+    /**
+     * Create an AWT font object with the given attributes
+     *
+     * @param graphics the graphics context to request additional rendering 
hints
+     * @param fontInfo the font info object corresponding to the text run font
+     * @param size the font size in points
+     * @param bold {@code true} if the font is bold
+     * @param italic {@code true} if the font is italic
+     * 
+     * @return the AWT font object
+     */
+    Font createAWTFont(Graphics2D graphics, FontInfo fontInfo, double size, 
boolean bold, boolean italic);
 }

Added: poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java?rev=1802741&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java 
(added)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java Sun 
Jul 23 22:45:47 2017
@@ -0,0 +1,101 @@
+/*
+ *  ====================================================================
+ *    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.sl.draw;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.util.Map;
+
+import org.apache.poi.common.usermodel.fonts.FontInfo;
+import org.apache.poi.sl.draw.Drawable.DrawableHint;
+
+/**
+ * Manages fonts when rendering slides.
+ *
+ * Use this class to handle unknown / missing fonts or to substitute fonts
+ */
+public class DrawFontManagerDefault implements DrawFontManager {
+
+    @Override
+    public FontInfo getMappedFont(Graphics2D graphics, FontInfo fontInfo) {
+        return getFontWithFallback(graphics, Drawable.FONT_MAP, fontInfo);
+    }
+
+    @Override
+    public FontInfo getFallbackFont(Graphics2D graphics, FontInfo fontInfo) {
+        FontInfo fi = getFontWithFallback(graphics, Drawable.FONT_FALLBACK, 
fontInfo);
+        if (fi == null) {
+            fi = new DrawFontInfo(Font.SANS_SERIF);
+        }
+        return fi;
+    }
+
+    public String mapFontCharset(Graphics2D graphics, FontInfo fontInfo, 
String text) {
+        // TODO: find a real charset mapping solution instead of hard coding 
for Wingdings
+        String attStr = text;
+        if (fontInfo != null && 
"Wingdings".equalsIgnoreCase(fontInfo.getTypeface())) {
+            // wingdings doesn't contain high-surrogates, so chars are ok
+            boolean changed = false;
+            char chrs[] = attStr.toCharArray();
+            for (int i=0; i<chrs.length; i++) {
+                // only change valid chars
+                if ((0x20 <= chrs[i] && chrs[i] <= 0x7f) ||
+                    (0xa0 <= chrs[i] && chrs[i] <= 0xff)) {
+                    chrs[i] |= 0xf000;
+                    changed = true;
+                }
+            }
+
+            if (changed) {
+                attStr = new String(chrs);
+            }
+        }
+        return attStr;
+    }
+
+    @Override
+    public Font createAWTFont(Graphics2D graphics, FontInfo fontInfo, double 
fontSize, boolean bold, boolean italic) {
+        int style = (bold ? Font.BOLD : 0) | (italic ? Font.ITALIC : 0);
+        Font font = new Font(fontInfo.getTypeface(), style, 12);
+        if (Font.DIALOG.equals(font.getFamily())) {
+            // SansSerif is a better choice than Dialog
+            font = new Font(Font.SANS_SERIF, style, 12);
+        }
+        return font.deriveFont((float)fontSize);
+    }
+
+    private FontInfo getFontWithFallback(Graphics2D graphics, DrawableHint 
hint, FontInfo fontInfo) {
+        @SuppressWarnings("unchecked")
+        Map<String,String> fontMap = 
(Map<String,String>)graphics.getRenderingHint(hint);
+        if (fontMap == null) {
+            return fontInfo;
+        }
+        
+        String f = (fontInfo != null) ? fontInfo.getTypeface() : null;
+        String mappedTypeface = null;
+        if (fontMap.containsKey(f)) {
+            mappedTypeface = fontMap.get(f);
+        } else if (fontMap.containsKey("*")) {
+            mappedTypeface = fontMap.get("*");
+        }
+
+        return (mappedTypeface != null) ? new DrawFontInfo(mappedTypeface) : 
fontInfo;
+    }
+}

Propchange: 
poi/trunk/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextFragment.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextFragment.java?rev=1802741&r1=1802740&r2=1802741&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextFragment.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextFragment.java Sun Jul 23 
22:45:47 2017
@@ -70,7 +70,7 @@ public class DrawTextFragment implements
      * @return full height of this text run which is sum of ascent, descent 
and leading
      */
     public float getHeight(){ 
-        double h = Math.ceil(layout.getAscent()) + 
Math.ceil(layout.getDescent()) + getLeading();
+        double h = layout.getAscent() + layout.getDescent() + getLeading();
         return (float)h;
     }
 
@@ -78,9 +78,14 @@ public class DrawTextFragment implements
      * @return the leading height before/after a text line
      */
     public float getLeading() {
-        // fix invalid leadings (leading == 0) by fallback to descent
+        // fix invalid leadings (leading == 0)
         double l = layout.getLeading();
-        return (float)(l == 0 ? layout.getDescent() : l);
+        if (l == 0) {
+            // see https://stackoverflow.com/questions/925147
+            // we use a 115% value instead of the 120% proposed one, as this 
seems to be closer to LO/OO
+            l = (layout.getAscent()+layout.getDescent())*0.15;
+        }
+        return (float)l;
     }
     
     /**

Modified: poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java?rev=1802741&r1=1802740&r2=1802741&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java (original)
+++ poi/trunk/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java Sun Jul 23 
22:45:47 2017
@@ -32,8 +32,11 @@ import java.text.AttributedCharacterIter
 import java.text.AttributedString;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
+import java.util.Locale;
 
+import org.apache.poi.common.usermodel.fonts.FontGroup;
+import org.apache.poi.common.usermodel.fonts.FontGroup.FontGroupRange;
+import org.apache.poi.common.usermodel.fonts.FontInfo;
 import org.apache.poi.sl.usermodel.AutoNumberingScheme;
 import org.apache.poi.sl.usermodel.Hyperlink;
 import org.apache.poi.sl.usermodel.Insets2D;
@@ -50,11 +53,14 @@ import org.apache.poi.sl.usermodel.TextR
 import org.apache.poi.sl.usermodel.TextRun.TextCap;
 import org.apache.poi.sl.usermodel.TextShape;
 import org.apache.poi.sl.usermodel.TextShape.TextDirection;
-import org.apache.poi.util.StringUtil;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
 import org.apache.poi.util.Units;
 
 
 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");
@@ -200,7 +206,7 @@ public class DrawTextParagraph implement
 
             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();
@@ -325,12 +331,6 @@ public class DrawTextParagraph implement
             return null;
         }
 
-        String buFont = bulletStyle.getBulletFont();
-        if (buFont == null) {
-            buFont = paragraph.getDefaultFontFamily();
-        }
-        assert(buFont != null);
-
         PlaceableShape<?,?> ps = getParagraphShape();
         PaintStyle fgPaintStyle = bulletStyle.getBulletFontColor();
         Paint fgPaint;
@@ -351,10 +351,21 @@ public class DrawTextParagraph implement
             fontSize = (float)-buSz;
         }
 
+        String buFontStr = bulletStyle.getBulletFont();
+        if (buFontStr == null) {
+            buFontStr = paragraph.getDefaultFontFamily();
+        }
+        assert(buFontStr != null);
+        FontInfo buFont = new DrawFontInfo(buFontStr);
+
+
+        DrawFontManager dfm = 
DrawFactory.getInstance(graphics).getFontManager(graphics);
+        // TODO: check font group defaulting to Symbol
+        buFont = dfm.getMappedFont(graphics, buFont);
 
-        AttributedString str = new 
AttributedString(mapFontCharset(buCharacter,buFont));
+        AttributedString str = new 
AttributedString(dfm.mapFontCharset(graphics,buFont,buCharacter));
         str.addAttribute(TextAttribute.FOREGROUND, fgPaint);
-        str.addAttribute(TextAttribute.FAMILY, buFont);
+        str.addAttribute(TextAttribute.FAMILY, buFont.getTypeface());
         str.addAttribute(TextAttribute.SIZE, fontSize);
 
         TextLayout layout = new TextLayout(str.getIterator(), 
graphics.getFontRenderContext());
@@ -365,7 +376,7 @@ public class DrawTextParagraph implement
     protected String getRenderableText(Graphics2D graphics, TextRun tr) {
         if (tr.getFieldType() == FieldType.SLIDE_NUMBER) {
             Slide<?,?> slide = 
(Slide<?,?>)graphics.getRenderingHint(Drawable.CURRENT_SLIDE);
-            return (slide == null) ? "" : 
Integer.toString(slide.getSlideNumber()); 
+            return (slide == null) ? "" : 
Integer.toString(slide.getSlideNumber());
         }
         StringBuilder buf = new StringBuilder();
         TextCap cap = tr.getTextCap();
@@ -557,11 +568,8 @@ public class DrawTextParagraph implement
         }
 
         PlaceableShape<?,?> ps = getParagraphShape();
-        DrawFontManager fontHandler = 
(DrawFontManager)graphics.getRenderingHint(Drawable.FONT_HANDLER);
-        @SuppressWarnings("unchecked")
-        Map<String,String> fontMap = 
(Map<String,String>)graphics.getRenderingHint(Drawable.FONT_MAP);
-        @SuppressWarnings("unchecked")
-        Map<String,String> fallbackMap = 
(Map<String,String>)graphics.getRenderingHint(Drawable.FONT_FALLBACK);
+        DrawFontManager dfm = 
DrawFactory.getInstance(graphics).getFontManager(graphics);
+        assert(dfm != null);
 
         for (TextRun run : paragraph){
             String runText = getRenderableText(graphics, run);
@@ -571,36 +579,12 @@ public class DrawTextParagraph implement
             }
 
             // user can pass an custom object to convert fonts
-            String mappedFont = run.getFontFamily();
-            String fallbackFont = Font.SANS_SERIF;
 
-            if (mappedFont == null) {
-                mappedFont = paragraph.getDefaultFontFamily();
-            }
-            if (mappedFont == null) {
-                mappedFont = Font.SANS_SERIF;
-            }            
-            if (fontHandler != null) {
-                String font = fontHandler.getRendererableFont(mappedFont, 
run.getPitchAndFamily());
-                if (font != null) {
-                    mappedFont = font;
-                }
-                font = fontHandler.getFallbackFont(mappedFont, 
run.getPitchAndFamily());
-                if (font != null) {
-                    fallbackFont = font;
-                }
-            } else {
-                mappedFont = getFontWithFallback(fontMap, mappedFont);
-                fallbackFont = getFontWithFallback(fallbackMap, mappedFont);
-            }
-            
-            runText = mapFontCharset(runText,mappedFont);
+            runText = dfm.mapFontCharset(graphics, run.getFontInfo(null), 
runText);
             int beginIndex = text.length();
             text.append(runText);
             int endIndex = text.length();
 
-            attList.add(new AttributedStringData(TextAttribute.FAMILY, 
mappedFont, beginIndex, endIndex));
-
             PaintStyle fgPaintStyle = run.getFontColor();
             Paint fgPaint = new DrawPaint(ps).getPaint(graphics, fgPaintStyle);
             attList.add(new AttributedStringData(TextAttribute.FOREGROUND, 
fgPaint, beginIndex, endIndex));
@@ -630,39 +614,14 @@ public class DrawTextParagraph implement
             if(run.isSuperscript()) {
                 attList.add(new 
AttributedStringData(TextAttribute.SUPERSCRIPT, 
TextAttribute.SUPERSCRIPT_SUPER, beginIndex, endIndex));
             }
-            
+
             Hyperlink<?,?> hl = run.getHyperlink();
             if (hl != null) {
                 attList.add(new AttributedStringData(HYPERLINK_HREF, 
hl.getAddress(), beginIndex, endIndex));
                 attList.add(new AttributedStringData(HYPERLINK_LABEL, 
hl.getLabel(), beginIndex, endIndex));
             }
-            
-            int style = (run.isBold() ? Font.BOLD : 0) | (run.isItalic() ? 
Font.ITALIC : 0);
-            Font f = new Font(mappedFont, style, (int)Math.rint(fontSz));
-            
-            // check for unsupported characters and add a fallback font for 
these
-            char textChr[] = runText.toCharArray();
-            int nextEnd = canDisplayUpTo(f, textChr, 0, textChr.length);
-            int last = nextEnd;
-            boolean isNextValid = (nextEnd == 0);
-            while ( nextEnd != -1 && nextEnd <= textChr.length ) {
-                if (isNextValid) {
-                    nextEnd = canDisplayUpTo(f, textChr, nextEnd, 
textChr.length);
-                    isNextValid = false;
-                } else {
-                    if (nextEnd >= textChr.length || 
f.canDisplay(Character.codePointAt(textChr, nextEnd, textChr.length)) ) {
-                        attList.add(new 
AttributedStringData(TextAttribute.FAMILY, fallbackFont, beginIndex+last, 
beginIndex+Math.min(nextEnd,textChr.length)));
-                        if (nextEnd >= textChr.length) {
-                            break;
-                        }
-                        last = nextEnd;
-                        isNextValid = true;
-                    } else {
-                        boolean isHS = 
Character.isHighSurrogate(textChr[nextEnd]);
-                        nextEnd+=(isHS?2:1);
-                    }
-                }
-            } 
+
+            processGlyphs(graphics, dfm, attList, beginIndex, run, runText);
         }
 
         // ensure that the paragraph contains at least one character
@@ -681,94 +640,97 @@ public class DrawTextParagraph implement
         return string;
     }
 
-    private String getFontWithFallback(Map<String, String> fontMap, String 
mappedFont) {
-        if (fontMap != null) {
-            if (fontMap.containsKey(mappedFont)) {
-                mappedFont = fontMap.get(mappedFont);
-            } else if (fontMap.containsKey("*")) {
-                mappedFont = fontMap.get("*");
-            }
-        }
-        return mappedFont;
-    }
-
     /**
-     * @return {@code true} if the HSLF implementation is used
-     */
-    protected boolean isHSLF() {
-        return DrawShape.isHSLF(paragraph.getParentShape());
-    }
-
-    /**
-     * Map text charset depending on font family.
-     * Currently this only maps for wingdings font (into unicode private use 
area)
+     * Processing the glyphs is done in two steps.
+     * <li>determine the font group - a text run can have different font 
groups. Depending on the chars,
+     * the correct font group needs to be used
      *
-     * @param text the raw text
-     * @param fontFamily the font family
-     * @return AttributedString with mapped codepoints
+     * @param graphics
+     * @param dfm
+     * @param attList
+     * @param beginIndex
+     * @param run
+     * @param runText
      *
-     * @see <a href="http://stackoverflow.com/questions/8692095";>Drawing 
exotic fonts in a java applet</a>
-     * @see StringUtil#mapMsCodepointString(String)
+     * @see <a 
href="https://blogs.msdn.microsoft.com/officeinteroperability/2013/04/22/office-open-xml-themes-schemes-and-fonts/";>Office
 Open XML Themes, Schemes, and Fonts</a>
      */
-    protected String mapFontCharset(String text, String fontFamily) {
-        // TODO: find a real charset mapping solution instead of hard coding 
for Wingdings
-        String attStr = text;
-        if ("Wingdings".equalsIgnoreCase(fontFamily)) {
-            // wingdings doesn't contain high-surrogates, so chars are ok
-            boolean changed = false;
-            char chrs[] = attStr.toCharArray();
-            for (int i=0; i<chrs.length; i++) {
-                // only change valid chars
-                if ((0x20 <= chrs[i] && chrs[i] <= 0x7f) ||
-                    (0xa0 <= chrs[i] && chrs[i] <= 0xff)) {
-                    chrs[i] |= 0xf000;
-                    changed = true;
-                }
+    private void processGlyphs(Graphics2D graphics, DrawFontManager dfm, 
List<AttributedStringData> attList, final int beginIndex, TextRun run, String 
runText) {
+        // determine font group ranges of the textrun to focus the fallback 
handling only on that font group
+        List<FontGroupRange> ttrList = FontGroup.getFontGroupRanges(runText);
+        int rangeBegin = 0;
+        for (FontGroupRange ttr : ttrList) {
+            FontInfo fiRun = run.getFontInfo(ttr.getFontGroup());
+            if (fiRun == null) {
+                // if the font group specific font wasn't defined, fallback to 
LATIN
+                fiRun = run.getFontInfo(FontGroup.LATIN);
+            }
+            FontInfo fiMapped = dfm.getMappedFont(graphics, fiRun);
+            FontInfo fiFallback = dfm.getFallbackFont(graphics, fiRun);
+            assert(fiFallback != null);
+            if (fiMapped == null) {
+                fiMapped = dfm.getMappedFont(graphics, new 
DrawFontInfo(paragraph.getDefaultFontFamily()));
             }
+            if (fiMapped == null) {
+                fiMapped = fiFallback;
+            }
+
+            Font fontMapped = dfm.createAWTFont(graphics, fiMapped, 10, 
run.isBold(), run.isItalic());
+            Font fontFallback = dfm.createAWTFont(graphics, fiFallback, 10, 
run.isBold(), run.isItalic());
 
-            if (changed) {
-                attStr = new String(chrs);
+            // check for unsupported characters and add a fallback font for 
these
+            final int rangeLen = ttr.getLength();
+            int partEnd = rangeBegin;
+            while (partEnd<rangeBegin+rangeLen) {
+                // start with the assumption that the font is able to display 
the chars
+                int partBegin = partEnd;
+                partEnd = nextPart(fontMapped, runText, partBegin, 
rangeBegin+rangeLen, true);
+
+                // Now we have 3 cases:
+                // (a) the first part couldn't be displayed,
+                // (b) only part of the text run could be displayed
+                // (c) or all chars can be displayed (default)
+
+                if (partBegin < partEnd) {
+                    // handle (b) and (c)
+                    attList.add(new AttributedStringData(TextAttribute.FAMILY, 
fontMapped.getFontName(Locale.ROOT), beginIndex+partBegin, beginIndex+partEnd));
+                    if (LOG.check(POILogger.DEBUG)) {
+                        LOG.log(POILogger.DEBUG, "mapped: 
",fontMapped.getFontName(Locale.ROOT)," ",(beginIndex+partBegin)," 
",(beginIndex+partEnd)," - ",runText.substring(beginIndex+partBegin, 
beginIndex+partEnd));
+                    }
+                }
+
+                // 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));
+                    if (LOG.check(POILogger.DEBUG)) {
+                        LOG.log(POILogger.DEBUG, "fallback: 
",fontFallback.getFontName(Locale.ROOT)," ",(beginIndex+partBegin)," 
",(beginIndex+partEnd)," - ",runText.substring(beginIndex+partBegin, 
beginIndex+partEnd));
+                    }
+                }
             }
+            
+            rangeBegin += rangeLen;
         }
-        return attStr;
     }
     
-    /**
-     * Indicates whether or not this {@code Font} can display the characters 
in the specified {@code text}
-     * starting at {@code start} and ending at {@code limit}.<p>
-     * 
-     * This is a workaround for the Java 6 implementation of {@link 
Font#canDisplayUpTo(char[], int, int)}
-     *
-     * @param font the font to inspect
-     * @param text the specified array of {@code char} values
-     * @param start the specified starting offset (in
-     *              {@code char}s) into the specified array of
-     *              {@code char} values
-     * @param limit the specified ending offset (in
-     *              {@code char}s) into the specified array of
-     *              {@code char} values
-     * @return an offset into {@code text} that points
-     *          to the first character in {@code text} that this
-     *          {@code Font} cannot display; or {@code -1} if
-     *          this {@code Font} can display all characters in
-     *          {@code text}.
-     * 
-     * @see <a 
href="https://bugs.openjdk.java.net/browse/JDK-6623219";>Font.canDisplayUpTo 
does not work with supplementary characters</a>
-     */
-    protected static int canDisplayUpTo(Font font, char[] text, int start, int 
limit) {
-        for (int i = start; i < limit; i++) {
-            char c = text[i];
-            if (font.canDisplay(c)) {
-                continue;
-            }
-            if (!Character.isHighSurrogate(c)) {
-                return i;
-            }
-            if (!font.canDisplay(Character.codePointAt(text, i, limit))) {
-                return i;
+    private static int nextPart(Font fontMapped, String runText, int 
beginPart, int endPart, boolean isDisplayed) {
+        int rIdx = beginPart;
+        while (rIdx < endPart) {
+            int codepoint = runText.codePointAt(rIdx);
+            if (fontMapped.canDisplay(codepoint) != isDisplayed) {
+                break;
             }
-            i++;
+            rIdx += Character.charCount(codepoint);
         }
-        return -1;
+        return rIdx;
+    }
+
+    /**
+     * @return {@code true} if the HSLF implementation is used
+     */
+    protected boolean isHSLF() {
+        return DrawShape.isHSLF(paragraph.getParentShape());
     }
 }

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=1802741&r1=1802740&r2=1802741&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 Sun Jul 23 
22:45:47 2017
@@ -19,6 +19,8 @@ package org.apache.poi.sl.usermodel;
 
 import java.awt.Color;
 
+import org.apache.poi.common.usermodel.fonts.FontGroup;
+import org.apache.poi.common.usermodel.fonts.FontInfo;
 import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
 import org.apache.poi.util.Internal;
 
@@ -26,12 +28,18 @@ import org.apache.poi.util.Internal;
  * Some text.
  */
 public interface TextRun {
+    /**
+     * Type of text capitals
+     */
     enum TextCap {
         NONE,
         SMALL,
         ALL
     }
     
+    /**
+     * Type of placeholder fields
+     */
     enum FieldType {
         SLIDE_NUMBER, DATE_TIME
     }
@@ -87,19 +95,65 @@ public interface TextRun {
     void setFontSize(Double fontSize);
 
     /**
+     * Get the font family - convenience method for {@link 
#getFontInfo(FontGroup)} 
+     * 
      * @return  font family or null if not set
      */
     String getFontFamily();
 
     /**
-     * Specifies the typeface, or name of the font that is to be used for this 
text run.
+     * Get the font family - convenience method for {@link 
#getFontInfo(FontGroup)}
+     * 
+     * @param fontGroup the font group, i.e. the range of glpyhs to be covered.
+     *    if {@code null}, the font group matching the first character will be 
returned 
+     * 
+     * @return  font family or null if not set
+     */
+    String getFontFamily(FontGroup fontGroup);
+
+    /**
+     * Specifies the typeface, or name of the font that is to be used for this 
text run -
+     * convenience method for calling {@link #setFontInfo(FontInfo, 
FontGroup)} with just a font name
      *
      * @param typeface  the font to apply to this text run.
-     * The value of <code>null</code> unsets the Typeface attrubute from the 
underlying xml.
+     *      The value of {@code null} removes the run specific font setting, 
so the default setting is activated again.
      */
     void setFontFamily(String typeface);
 
     /**
+     * Specifies the typeface, or name of the font that is to be used for this 
text run -
+     * convenience method for calling {@link #setFontInfo(FontInfo, 
FontGroup)} with just a font name
+     *
+     * @param typeface  the font to apply to this text run.
+     *      The value of {@code null} removes the run specific font setting, 
so the default setting is activated again.
+     * @param fontGroup the font group, i.e. the range of glpyhs to be covered.
+     *    if {@code null}, the font group matching the first character will be 
returned 
+     */
+    void setFontFamily(String typeface, FontGroup fontGroup);
+
+    /**
+     * Get the font info for the given font group
+     * 
+     * @param fontGroup the font group, i.e. the range of glpyhs to be covered.
+     *    if {@code null}, the font group matching the first character will be 
returned 
+     * @return  font info or {@code null} if not set
+     * 
+     * @since POI 3.17-beta2
+     */
+    FontInfo getFontInfo(FontGroup fontGroup);
+
+    /**
+     * Specifies the font to be used for this text run.
+     *
+     * @param fontInfo the font to apply to this text run.
+     *      The value of {@code null} removes the run specific font setting, 
so the default setting is activated again.
+     * @param fontGroup the font group, i.e. the range of glpyhs to be 
covered. defaults to latin, if {@code null}.
+     * 
+     * @since POI 3.17-beta2
+     */
+    void setFontInfo(FontInfo fontInfo, FontGroup fontGroup);
+    
+    /**
      * @return true, if text is bold
      */
     boolean isBold();

Modified: poi/trunk/src/java/org/apache/poi/ss/usermodel/FontCharset.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/usermodel/FontCharset.java?rev=1802741&r1=1802740&r2=1802741&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/usermodel/FontCharset.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/usermodel/FontCharset.java Sun Jul 23 
22:45:47 2017
@@ -17,13 +17,16 @@
 
 package org.apache.poi.ss.usermodel;
 
+import org.apache.poi.util.Removal;
 
 /**
  * Charset represents the basic set of characters associated with a font (that 
it can display), and 
  * corresponds to the ANSI codepage (8-bit or DBCS) of that character set used 
by a given language. 
  * 
- * @author Gisella Bronzetti
+ * @deprecated enum will be replaced by common version 
org.apache.poi.common.usermodel.FontCharset
  */
+@Removal(version="4.0")
+@Deprecated
 public enum FontCharset {
 
      ANSI(0),

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=1802741&r1=1802740&r2=1802741&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 Sun 
Jul 23 22:45:47 2017
@@ -18,6 +18,11 @@ package org.apache.poi.xslf.usermodel;
 
 import java.awt.Color;
 
+import org.apache.poi.common.usermodel.fonts.FontCharset;
+import org.apache.poi.common.usermodel.fonts.FontFamily;
+import org.apache.poi.common.usermodel.fonts.FontGroup;
+import org.apache.poi.common.usermodel.fonts.FontInfo;
+import org.apache.poi.common.usermodel.fonts.FontPitch;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.sl.draw.DrawPaint;
@@ -28,6 +33,8 @@ import org.apache.poi.util.Beta;
 import org.apache.poi.xslf.model.CharacterPropertyFetcher;
 import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties;
 import org.apache.xmlbeans.XmlObject;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTFontCollection;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTFontScheme;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
@@ -85,8 +92,8 @@ public class XSLFTextRun implements Text
         } else if (_r instanceof CTTextLineBreak) {
             return "\n";
         }
-        
-        
+
+
         String txt = ((CTRegularTextRun)_r).getT();
         TextCap cap = getTextCap();
         StringBuffer buf = new StringBuffer();
@@ -139,7 +146,7 @@ public class XSLFTextRun implements Text
     public void setFontColor(Color color) {
         setFontColor(DrawPaint.createSolidPaint(color));
     }
-    
+
     @Override
     public void setFontColor(PaintStyle color) {
         if (!(color instanceof SolidPaint)) {
@@ -147,10 +154,10 @@ public class XSLFTextRun implements Text
         }
         SolidPaint sp = (SolidPaint)color;
         Color c = DrawPaint.applyColorTransform(sp.getSolidColor());
-        
+
         CTTextCharacterProperties rPr = getRPr(true);
         CTSolidColorFillProperties fill = rPr.isSetSolidFill() ? 
rPr.getSolidFill() : rPr.addNewSolidFill();
-        
+
         XSLFColor col = new XSLFColor(fill, 
getParentParagraph().getParentShape().getSheet().getTheme(), 
fill.getSchemeClr());
         col.setColor(c);
     }
@@ -164,7 +171,7 @@ public class XSLFTextRun implements Text
                 if (props == null) {
                     return false;
                 }
-                
+
                 XSLFShape shape = _p.getParentShape();
                 CTShapeStyle style = shape.getSpStyle();
                 CTSchemeColor phClr = null;
@@ -177,12 +184,12 @@ public class XSLFTextRun implements Text
                 PackagePart pp = sheet.getPackagePart();
                 XSLFTheme theme = sheet.getTheme();
                 PaintStyle ps = XSLFShape.selectPaint(fp, phClr, pp, theme, 
hasPlaceholder);
-                
+
                 if (ps != null)  {
                     setValue(ps);
                     return true;
                 }
-                
+
                 return false;
             }
         };
@@ -270,88 +277,51 @@ public class XSLFTextRun implements Text
     }
 
     @Override
-    public void setFontFamily(String typeface){
-        setFontFamily(typeface, (byte)-1, (byte)-1, false);
+    public void setFontFamily(String typeface) {
+        FontGroup fg = FontGroup.getFontGroupFirst(getRawText());
+        new XSLFFontInfo(fg).setTypeface(typeface);
     }
 
-    public void setFontFamily(String typeface, byte charset, byte 
pictAndFamily, boolean isSymbol){
-        CTTextCharacterProperties rPr = getRPr(true);
+    @Override
+    public void setFontFamily(String typeface, FontGroup fontGroup) {
+        new XSLFFontInfo(fontGroup).setTypeface(typeface);
+    }
 
-        if(typeface == null){
-            if(rPr.isSetLatin()) {
-                rPr.unsetLatin();
-            }
-            if(rPr.isSetCs()) {
-                rPr.unsetCs();
-            }
-            if(rPr.isSetSym()) {
-                rPr.unsetSym();
-            }
-        } else {
-            if(isSymbol){
-                CTTextFont font = rPr.isSetSym() ? rPr.getSym() : 
rPr.addNewSym();
-                font.setTypeface(typeface);
-            } else {
-                CTTextFont latin = rPr.isSetLatin() ? rPr.getLatin() : 
rPr.addNewLatin();
-                latin.setTypeface(typeface);
-                if(charset != -1) {
-                    latin.setCharset(charset);
-                }
-                if(pictAndFamily != -1) {
-                    latin.setPitchFamily(pictAndFamily);
-                }
-            }
-        }
+    @Override
+    public void setFontInfo(FontInfo fontInfo, FontGroup fontGroup) {
+        new XSLFFontInfo(fontGroup).copyFrom(fontInfo);
     }
 
     @Override
-    public String getFontFamily(){
-        final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();
+    public String getFontFamily() {
+        FontGroup fg = FontGroup.getFontGroupFirst(getRawText());
+        return new XSLFFontInfo(fg).getTypeface();
+    }
 
-        CharacterPropertyFetcher<String> visitor = new 
CharacterPropertyFetcher<String>(_p.getIndentLevel()){
-            @Override
-            public boolean fetch(CTTextCharacterProperties props){
-                if (props != null) {
-                    CTTextFont font = props.getLatin();
-                    if (font != null) {
-                        String typeface = font.getTypeface();
-                        if("+mj-lt".equals(typeface)) {
-                            typeface = theme.getMajorFont();
-                        } else if ("+mn-lt".equals(typeface)){
-                            typeface = theme.getMinorFont();
-                        }
-                        setValue(typeface);
-                        return true;
-                    }
-                }
-                return false;
-            }
-        };
-        fetchCharacterProperty(visitor);
+    @Override
+    public String getFontFamily(FontGroup fontGroup) {
+        return new XSLFFontInfo(fontGroup).getTypeface();
+    }
 
-        return  visitor.getValue();
+    @Override
+    public FontInfo getFontInfo(FontGroup fontGroup) {
+        XSLFFontInfo fontInfo = new XSLFFontInfo(fontGroup);
+        return (fontInfo.getTypeface() != null) ? fontInfo : null;
     }
 
     @Override
     public byte getPitchAndFamily(){
-        // final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();
-
-        CharacterPropertyFetcher<Byte> visitor = new 
CharacterPropertyFetcher<Byte>(_p.getIndentLevel()){
-            @Override
-            public boolean fetch(CTTextCharacterProperties props){
-                if (props != null) {
-                    CTTextFont font = props.getLatin();
-                    if (font != null) {
-                        setValue(font.getPitchFamily());
-                        return true;
-                    }
-                }
-                return false;
-            }
-        };
-        fetchCharacterProperty(visitor);
-
-        return  visitor.getValue() == null ? 0 : visitor.getValue();
+        FontGroup fg = FontGroup.getFontGroupFirst(getRawText());
+        XSLFFontInfo fontInfo = new XSLFFontInfo(fg);
+        FontPitch pitch = fontInfo.getPitch();
+        if (pitch == null) {
+            pitch = FontPitch.VARIABLE;
+        }
+        FontFamily family = fontInfo.getFamily();
+        if (family == null) {
+            family = FontFamily.FF_SWISS;
+        }
+        return FontPitch.getNativeId(pitch, family);
     }
 
     @Override
@@ -574,7 +544,7 @@ public class XSLFTextRun implements Text
     @Override
     public XSLFHyperlink getHyperlink(){
         CTTextCharacterProperties rPr = getRPr(false);
-        if (rPr == null) { 
+        if (rPr == null) {
             return null;
         }
         CTHyperlink hl = rPr.getHlinkClick();
@@ -592,11 +562,11 @@ public class XSLFTextRun implements Text
         if (rPr != null && fetcher.fetch(rPr)) {
             return true;
         }
-        
+
         if (shape.fetchShapeProperty(fetcher)) {
             return true;
         }
-        
+
         CTPlaceholder ph = shape.getCTPlaceholder();
         if (ph == null){
             // if it is a plain text box then take defaults from 
presentation.xml
@@ -654,8 +624,8 @@ public class XSLFTextRun implements Text
             setStrikethrough(strike);
         }
     }
-    
-    
+
+
     @Override
     public FieldType getFieldType() {
         if (_r instanceof CTTextField) {
@@ -666,4 +636,224 @@ public class XSLFTextRun implements Text
         }
         return null;
     }
+
+
+    private class XSLFFontInfo implements FontInfo {
+        private final FontGroup fontGroup;
+
+        private XSLFFontInfo(FontGroup fontGroup) {
+            this.fontGroup = (fontGroup != null) ? fontGroup : 
FontGroup.getFontGroupFirst(getRawText());
+        }
+
+        public void copyFrom(FontInfo fontInfo) {
+            CTTextFont tf = getXmlObject(true);
+            setTypeface(fontInfo.getTypeface());
+            setCharset(fontInfo.getCharset());
+            FontPitch pitch = fontInfo.getPitch();
+            FontFamily family = fontInfo.getFamily();
+            if (pitch == null && family == null) {
+                if (tf.isSetPitchFamily()) {
+                    tf.unsetPitchFamily();
+                }
+            } else {
+                setPitch(pitch);
+                setFamily(family);
+            }
+        }
+
+        @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;
+        }
+
+        @Override
+        public void setTypeface(String typeface) {
+            if (typeface != null) {
+                getXmlObject(true).setTypeface(typeface);
+                return;
+            }
+            
+            CTTextCharacterProperties props = getRPr(false);
+            if (props == null) {
+                return;
+            }
+            FontGroup fg = FontGroup.getFontGroupFirst(getRawText());
+            switch (fg) {
+            default:
+            case LATIN:
+                if (props.isSetLatin()) {
+                    props.unsetLatin();
+                }
+                break;
+            case EAST_ASIAN:
+                if (props.isSetEa()) {
+                    props.unsetEa();
+                }
+                break;
+            case COMPLEX_SCRIPT:
+                if (props.isSetCs()) {
+                    props.unsetCs();
+                }
+                break;
+            case SYMBOL:
+                if (props.isSetSym()) {
+                    props.unsetSym();
+                }
+                break;
+            }
+        }
+
+        @Override
+        public FontCharset getCharset() {
+            CTTextFont tf = getXmlObject(false);
+            return (tf != null && tf.isSetCharset()) ? 
FontCharset.valueOf(tf.getCharset()&0xFF) : null;
+        }
+
+        @Override
+        public void setCharset(FontCharset charset) {
+            CTTextFont tf = getXmlObject(true);
+            if (charset != null) {
+                tf.setCharset((byte)charset.getNativeId());
+            } else {
+                if (tf.isSetCharset()) {
+                    tf.unsetCharset();
+                }
+            }
+        }
+
+        @Override
+        public FontFamily getFamily() {
+            CTTextFont tf = getXmlObject(false);
+            return (tf != null && tf.isSetPitchFamily()) ? 
FontFamily.valueOfPitchFamily(tf.getPitchFamily()) : null;
+        }
+
+        @Override
+        public void setFamily(FontFamily family) {
+            CTTextFont tf = getXmlObject(true);
+            if (family == null && !tf.isSetPitchFamily()) {
+                return;
+            }
+            FontPitch pitch = (tf.isSetPitchFamily())
+                ? FontPitch.valueOfPitchFamily(tf.getPitchFamily())
+                : FontPitch.VARIABLE;
+            byte pitchFamily = FontPitch.getNativeId(pitch, family != null ? 
family : FontFamily.FF_SWISS);
+            tf.setPitchFamily(pitchFamily);
+        }
+
+        @Override
+        public FontPitch getPitch() {
+            CTTextFont tf = getXmlObject(false);
+            return (tf != null && tf.isSetPitchFamily()) ? 
FontPitch.valueOfPitchFamily(tf.getPitchFamily()) : null;
+        }
+
+        @Override
+        public void setPitch(FontPitch pitch) {
+            CTTextFont tf = getXmlObject(true);
+            if (pitch == null && !tf.isSetPitchFamily()) {
+                return;
+            }
+            FontFamily family = (tf.isSetPitchFamily())
+                ? FontFamily.valueOfPitchFamily(tf.getPitchFamily())
+                : FontFamily.FF_SWISS;
+            byte pitchFamily = FontPitch.getNativeId(pitch != null ? pitch : 
FontPitch.VARIABLE, family);
+            tf.setPitchFamily(pitchFamily);
+        }
+
+        private CTTextFont getXmlObject(boolean create) {
+            if (create) {
+                return getCTTextFont(getRPr(true), true);
+            }
+
+            CharacterPropertyFetcher<CTTextFont> visitor = new 
CharacterPropertyFetcher<CTTextFont>(_p.getIndentLevel()){
+                @Override
+                public boolean fetch(CTTextCharacterProperties props){
+                    CTTextFont font = getCTTextFont(props, false);
+                    if (font == null) {
+                        return false;
+                    }
+                    setValue(font);
+                    return true;
+                }
+            };
+            fetchCharacterProperty(visitor);
+
+            return  visitor.getValue();
+        }
+
+        private CTTextFont getCTTextFont(CTTextCharacterProperties props, 
boolean create) {
+            if (props == null) {
+                return null;
+            }
+
+            CTTextFont font;
+            switch (fontGroup) {
+            default:
+            case LATIN:
+                font = props.getLatin();
+                if (font == null && create) {
+                    font = props.addNewLatin();
+                }
+                break;
+            case EAST_ASIAN:
+                font = props.getEa();
+                if (font == null && create) {
+                    font = props.addNewEa();
+                }
+                break;
+            case COMPLEX_SCRIPT:
+                font = props.getCs();
+                if (font == null && create) {
+                    font = props.addNewCs();
+                }
+                break;
+            case SYMBOL:
+                font = props.getSym();
+                if (font == null && create) {
+                    font = props.addNewSym();
+                }
+                break;
+            }
+
+            if (font == null) {
+                return null;
+            }
+
+            String typeface = font.isSetTypeface() ? font.getTypeface() : "";
+            if (typeface.startsWith("+mj-") || typeface.startsWith("+mn-")) {
+                //  "+mj-lt".equals(typeface) || "+mn-lt".equals(typeface)
+                final XSLFTheme theme = 
_p.getParentShape().getSheet().getTheme();
+                CTFontScheme fontTheme = 
theme.getXmlObject().getThemeElements().getFontScheme();
+                CTFontCollection coll = typeface.startsWith("+mj-")
+                    ? fontTheme.getMajorFont() : fontTheme.getMinorFont();
+                // TODO: handle LCID codes
+                // see 
https://blogs.msdn.microsoft.com/officeinteroperability/2013/04/22/office-open-xml-themes-schemes-and-fonts/
+                String fgStr = typeface.substring(4);
+                if ("ea".equals(fgStr)) {
+                    font = coll.getEa();
+                } else if ("cs".equals(fgStr)) {
+                    font = coll.getCs();
+                } else {
+                    font = coll.getLatin();
+                }
+                // SYMBOL is missing
+                
+                if (font != null || !font.isSetTypeface() || 
"".equals(font.getTypeface())) {
+                    font = coll.getLatin();
+                }
+            }
+
+            return font;
+        }
+    }
 }

Modified: poi/trunk/src/ooxml/testcases/org/apache/poi/sl/TestFonts.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/ooxml/testcases/org/apache/poi/sl/TestFonts.java?rev=1802741&r1=1802740&r2=1802741&view=diff
==============================================================================
--- poi/trunk/src/ooxml/testcases/org/apache/poi/sl/TestFonts.java (original)
+++ poi/trunk/src/ooxml/testcases/org/apache/poi/sl/TestFonts.java Sun Jul 23 
22:45:47 2017
@@ -37,6 +37,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.poi.POIDataSamples;
+import org.apache.poi.common.usermodel.fonts.FontGroup;
 import org.apache.poi.hslf.usermodel.HSLFSlideShow;
 import org.apache.poi.sl.draw.DrawFactory;
 import org.apache.poi.sl.draw.Drawable;
@@ -47,10 +48,8 @@ import org.apache.poi.sl.usermodel.TextB
 import org.apache.poi.sl.usermodel.TextParagraph;
 import org.apache.poi.sl.usermodel.TextRun;
 import org.apache.poi.xslf.usermodel.XMLSlideShow;
-import org.apache.poi.xslf.usermodel.XSLFTextRun;
 import org.junit.BeforeClass;
 import org.junit.Test;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
 
 
 /**
@@ -71,14 +70,14 @@ public class TestFonts {
         
"\u9451\u3092\u4E00\u7DD2\u306B\u898B\u3066\u305F\u306E\u601D\u3044\u51FA\u3059\u301C\u3068\u3044";
 
     private static final String INIT_FONTS[] = { "mona.ttf" };
-    
+
     // currently linux and mac return quite different values
     private static final int[] expected_sizes = { 311, 312, 313,
             362, // Windows 10, 13.3" 1080p high-dpi
             398, 399,
             406  // Ubuntu Trusty, 15", 1680x1050
     };
-    
+
     @BeforeClass
     public static void initGE() throws FontFormatException, IOException {
         GraphicsEnvironment ge = 
GraphicsEnvironment.getLocalGraphicsEnvironment();
@@ -87,83 +86,65 @@ public class TestFonts {
             ge.registerFont(font);
         }
     }
-    
+
     @Test
     public void resizeToFitTextHSLF() throws IOException {
         assumeFalse(xslfOnly());
         SlideShow<?,?> ppt = new HSLFSlideShow();
-        TextBox<?,?> tb = resizeToFitText(ppt);
-        Rectangle2D anc = tb.getAnchor();
-        // ignore font metrics differences on windows / linux (... hopefully 
...)
-        boolean found = Arrays.binarySearch(expected_sizes, 
(int)anc.getHeight()) > -1;
-        assertTrue("Did not find height " + anc.getHeight() + " in expected 
sizes: " + Arrays.toString(expected_sizes),
-                found);
-//        setFont(tb, "Mona");
-//        FileOutputStream fos = new FileOutputStream("bla-hslf.ppt");
-//        ppt.write(fos);
-//        fos.close();
+        resizeToFitText(ppt);
         ppt.close();
     }
 
     @Test
     public void resizeToFitTextXSLF() throws IOException {
         SlideShow<?,?> ppt = new XMLSlideShow();
-        TextBox<?,?> tb = resizeToFitText(ppt);
-        Rectangle2D anc = tb.getAnchor();
-        // ignore font metrics differences on windows / linux (... hopefully 
...)
-        boolean found = Arrays.binarySearch(expected_sizes, 
(int)anc.getHeight()) > -1;
-        assertTrue("Did not find height " + anc.getHeight() + " in expected 
sizes: " + Arrays.toString(expected_sizes),
-                found);
-//        setFont(tb, "Mona");
-//        FileOutputStream fos = new FileOutputStream("bla-xslf.ppt");
-//        ppt.write(fos);
-//        fos.close();
+        resizeToFitText(ppt);
         ppt.close();
     }
 
-    private TextBox<?,?> resizeToFitText(SlideShow<?,?> slideshow) throws 
IOException {
+    private void resizeToFitText(SlideShow<?,?> slideshow) throws IOException {
         Slide<?,?> sld = slideshow.createSlide();
         TextBox<?,?> tb = sld.createTextBox();
         tb.setAnchor(new Rectangle(50, 50, 200, 50));
         tb.setStrokeStyle(Color.black, LineDash.SOLID, 3);
         tb.setText(JPTEXT);
-        
-        setFont(tb, "NoSuchFont");
+
+        setFont(tb, "NoSuchFont", FontGroup.LATIN);
 
         Dimension pgsize = slideshow.getPageSize();
         int width = (int)pgsize.getWidth();
         int height = (int)pgsize.getHeight();
-        
+
         BufferedImage img = new BufferedImage(width, height, 
BufferedImage.TYPE_INT_ARGB);
         Graphics2D graphics = img.createGraphics();
 
         Map<String,String> fallbackMap = new HashMap<String,String>();
         fallbackMap.put("NoSuchFont", "Mona");
+        // in XSLF the fonts default to the theme fonts (Calibri), if the font 
group is not overridden
+        // see XSLFTextRun.XSLFTextInfo.getCTTextFont
+        fallbackMap.put("Calibri", "Mona");
         graphics.setRenderingHint(Drawable.FONT_FALLBACK, fallbackMap);
         graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, 
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
-        
+
         DrawFactory.getInstance(graphics).fixFonts(graphics);
-        
+
         tb.resizeToFitText(graphics);
         graphics.dispose();
-        
-        return tb;
+
+        Rectangle2D anc = tb.getAnchor();
+        // ignore font metrics differences on windows / linux (... hopefully 
...)
+        int tbHeight = (int)anc.getHeight();
+        boolean found = Arrays.binarySearch(expected_sizes, tbHeight) > -1;
+        assertTrue(tbHeight+" wasn't within the expected sizes: 
"+Arrays.toString(expected_sizes), found);
     }
-    
-    private void setFont(TextBox<?,?> tb, String fontFamily) {
+
+    private void setFont(TextBox<?,?> tb, String fontFamily, FontGroup 
fontGroup) {
         // TODO: set east asian font family - MS Office uses "MS Mincho" or 
"MS Gothic" as a fallback
         // see https://stackoverflow.com/questions/26063828 for good 
explanation about the font metrics
         // differences on different environments
         for (TextParagraph<?,?,?> p : tb.getTextParagraphs()) {
             for (TextRun r : p.getTextRuns()) {
-                r.setFontFamily(fontFamily);
-                if (r instanceof XSLFTextRun) {
-                    // TODO: provide API for HSLF
-                    XSLFTextRun xr = (XSLFTextRun)r;
-                    CTRegularTextRun tr = (CTRegularTextRun)xr.getXmlObject();
-                    tr.getRPr().addNewEa().setTypeface(fontFamily);
-     
-                }
+                r.setFontFamily(fontFamily, fontGroup);
             }
         }
     }

Modified: 
poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/CharFlagsTextProp.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/CharFlagsTextProp.java?rev=1802741&r1=1802740&r2=1802741&view=diff
==============================================================================
--- 
poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/CharFlagsTextProp.java
 (original)
+++ 
poi/trunk/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/CharFlagsTextProp.java
 Sun Jul 23 22:45:47 2017
@@ -43,7 +43,7 @@ public class CharFlagsTextProp extends B
                        "fehint",               // 0x0020  A bit that specifies 
whether characters originated from double-byte input.
                        "unused2",              // 0x0040  Undefined and MUST 
be ignored.
                        "kumi",                 // 0x0080  A bit that specifies 
whether Kumimoji are used for vertical text.
-                       "strikethrough",        // 0x0100  Undefined and MUST 
be ignored.
+                       "strikethrough",        // 0x0100  aka "unused3" - 
sometimes contains the strikethrough flag 
                        "emboss",               // 0x0200  A bit that specifies 
whether the characters are embossed.
             "pp9rt_1",              // 0x0400  An unsigned integer that 
specifies the run grouping of additional text properties in StyleTextProp9Atom 
record.
             "pp9rt_2",              // 0x0800



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

Reply via email to