aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/poi
diff options
context:
space:
mode:
authorAndreas Beeker <kiwiwings@apache.org>2017-07-23 22:45:47 +0000
committerAndreas Beeker <kiwiwings@apache.org>2017-07-23 22:45:47 +0000
commitb8242721fb34f1e87a8c81b66d1d668b5bb39688 (patch)
tree0180d5a25875a802fe6819c63e462a3fc5ff31d4 /src/java/org/apache/poi
parent7b8e1c9150815af16490c582a24f0123b8ad41a8 (diff)
downloadpoi-b8242721fb34f1e87a8c81b66d1d668b5bb39688.tar.gz
poi-b8242721fb34f1e87a8c81b66d1d668b5bb39688.zip
Bug 61331 - Font group handling / common font interface
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1802741 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/poi')
-rw-r--r--src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java124
-rw-r--r--src/java/org/apache/poi/common/usermodel/fonts/FontFamily.java80
-rw-r--r--src/java/org/apache/poi/common/usermodel/fonts/FontGroup.java149
-rw-r--r--src/java/org/apache/poi/common/usermodel/fonts/FontInfo.java102
-rw-r--r--src/java/org/apache/poi/common/usermodel/fonts/FontPitch.java74
-rw-r--r--src/java/org/apache/poi/sl/draw/DrawFactory.java11
-rw-r--r--src/java/org/apache/poi/sl/draw/DrawFontInfo.java89
-rw-r--r--src/java/org/apache/poi/sl/draw/DrawFontManager.java54
-rw-r--r--src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java101
-rw-r--r--src/java/org/apache/poi/sl/draw/DrawTextFragment.java11
-rw-r--r--src/java/org/apache/poi/sl/draw/DrawTextParagraph.java256
-rw-r--r--src/java/org/apache/poi/sl/usermodel/TextRun.java58
-rw-r--r--src/java/org/apache/poi/ss/usermodel/FontCharset.java5
13 files changed, 948 insertions, 166 deletions
diff --git a/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java b/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java
new file mode 100644
index 0000000000..aeeca9284c
--- /dev/null
+++ b/src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java
@@ -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
diff --git a/src/java/org/apache/poi/common/usermodel/fonts/FontFamily.java b/src/java/org/apache/poi/common/usermodel/fonts/FontFamily.java
new file mode 100644
index 0000000000..8faa788f58
--- /dev/null
+++ b/src/java/org/apache/poi/common/usermodel/fonts/FontFamily.java
@@ -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
diff --git a/src/java/org/apache/poi/common/usermodel/fonts/FontGroup.java b/src/java/org/apache/poi/common/usermodel/fonts/FontGroup.java
new file mode 100644
index 0000000000..b1c294588e
--- /dev/null
+++ b/src/java/org/apache/poi/common/usermodel/fonts/FontGroup.java
@@ -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
diff --git a/src/java/org/apache/poi/common/usermodel/fonts/FontInfo.java b/src/java/org/apache/poi/common/usermodel/fonts/FontInfo.java
new file mode 100644
index 0000000000..ecb5a69687
--- /dev/null
+++ b/src/java/org/apache/poi/common/usermodel/fonts/FontInfo.java
@@ -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
diff --git a/src/java/org/apache/poi/common/usermodel/fonts/FontPitch.java b/src/java/org/apache/poi/common/usermodel/fonts/FontPitch.java
new file mode 100644
index 0000000000..78c6533944
--- /dev/null
+++ b/src/java/org/apache/poi/common/usermodel/fonts/FontPitch.java
@@ -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);
+ }
+}
+
diff --git a/src/java/org/apache/poi/sl/draw/DrawFactory.java b/src/java/org/apache/poi/sl/draw/DrawFactory.java
index 53b2bcba78..376a8daab8 100644
--- a/src/java/org/apache/poi/sl/draw/DrawFactory.java
+++ b/src/java/org/apache/poi/sl/draw/DrawFactory.java
@@ -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
diff --git a/src/java/org/apache/poi/sl/draw/DrawFontInfo.java b/src/java/org/apache/poi/sl/draw/DrawFontInfo.java
new file mode 100644
index 0000000000..dc7afb4e24
--- /dev/null
+++ b/src/java/org/apache/poi/sl/draw/DrawFontInfo.java
@@ -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.");
+ }
+}
diff --git a/src/java/org/apache/poi/sl/draw/DrawFontManager.java b/src/java/org/apache/poi/sl/draw/DrawFontManager.java
index 5b74f8400c..0c16dd994a 100644
--- a/src/java/org/apache/poi/sl/draw/DrawFontManager.java
+++ b/src/java/org/apache/poi/sl/draw/DrawFontManager.java
@@ -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);
}
diff --git a/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java b/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java
new file mode 100644
index 0000000000..c439fc926f
--- /dev/null
+++ b/src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java
@@ -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;
+ }
+}
diff --git a/src/java/org/apache/poi/sl/draw/DrawTextFragment.java b/src/java/org/apache/poi/sl/draw/DrawTextFragment.java
index 0eceb93643..898ac51bd4 100644
--- a/src/java/org/apache/poi/sl/draw/DrawTextFragment.java
+++ b/src/java/org/apache/poi/sl/draw/DrawTextFragment.java
@@ -70,7 +70,7 @@ public class DrawTextFragment implements Drawable {
* @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 Drawable {
* @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;
}
/**
diff --git a/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java b/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
index 10d4edfd62..7f708d1249 100644
--- a/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
+++ b/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java
@@ -32,8 +32,11 @@ import java.text.AttributedCharacterIterator.Attribute;
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.TextRun.FieldType;
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 implements Drawable {
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 implements Drawable {
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 implements Drawable {
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 implements Drawable {
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 implements Drawable {
}
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 implements Drawable {
}
// 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 implements Drawable {
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 implements Drawable {
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;
}
- if (changed) {
- attStr = new String(chrs);
+ Font fontMapped = dfm.createAWTFont(graphics, fiMapped, 10, run.isBold(), run.isItalic());
+ Font fontFallback = dfm.createAWTFont(graphics, fiFallback, 10, run.isBold(), run.isItalic());
+
+ // 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());
}
}
diff --git a/src/java/org/apache/poi/sl/usermodel/TextRun.java b/src/java/org/apache/poi/sl/usermodel/TextRun.java
index 32b9c9933d..394166071c 100644
--- a/src/java/org/apache/poi/sl/usermodel/TextRun.java
+++ b/src/java/org/apache/poi/sl/usermodel/TextRun.java
@@ -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();
diff --git a/src/java/org/apache/poi/ss/usermodel/FontCharset.java b/src/java/org/apache/poi/ss/usermodel/FontCharset.java
index 90e4038b31..64953675f7 100644
--- a/src/java/org/apache/poi/ss/usermodel/FontCharset.java
+++ b/src/java/org/apache/poi/ss/usermodel/FontCharset.java
@@ -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),