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
This commit is contained in:
parent
8a95a71a48
commit
2325cdb9e6
124
src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java
Normal file
124
src/java/org/apache/poi/common/usermodel/fonts/FontCharset.java
Normal file
@ -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 "default"
|
||||
*/
|
||||
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];
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
149
src/java/org/apache/poi/common/usermodel/fonts/FontGroup.java
Normal file
149
src/java/org/apache/poi/common/usermodel/fonts/FontGroup.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
102
src/java/org/apache/poi/common/usermodel/fonts/FontInfo.java
Normal file
102
src/java/org/apache/poi/common/usermodel/fonts/FontInfo.java
Normal file
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
89
src/java/org/apache/poi/sl/draw/DrawFontInfo.java
Normal file
89
src/java/org/apache/poi/sl/draw/DrawFontInfo.java
Normal file
@ -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.");
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
101
src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java
Normal file
101
src/java/org/apache/poi/sl/draw/DrawFontManagerDefault.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
||||
AttributedString str = new AttributedString(mapFontCharset(buCharacter,buFont));
|
||||
|
||||
DrawFontManager dfm = DrawFactory.getInstance(graphics).getFontManager(graphics);
|
||||
// TODO: check font group defaulting to Symbol
|
||||
buFont = dfm.getMappedFont(graphics, 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,15 +640,91 @@ 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("*");
|
||||
/**
|
||||
* 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 graphics
|
||||
* @param dfm
|
||||
* @param attList
|
||||
* @param beginIndex
|
||||
* @param run
|
||||
* @param runText
|
||||
*
|
||||
* @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>
|
||||
*/
|
||||
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());
|
||||
|
||||
// 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 mappedFont;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
rIdx += Character.charCount(codepoint);
|
||||
}
|
||||
return rIdx;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -698,77 +733,4 @@ public class DrawTextParagraph implements Drawable {
|
||||
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)
|
||||
*
|
||||
* @param text the raw text
|
||||
* @param fontFamily the font family
|
||||
* @return AttributedString with mapped codepoints
|
||||
*
|
||||
* @see <a href="http://stackoverflow.com/questions/8692095">Drawing exotic fonts in a java applet</a>
|
||||
* @see StringUtil#mapMsCodepointString(String)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
attStr = new String(chrs);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -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,18 +95,64 @@ 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
|
||||
*/
|
||||
|
@ -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),
|
||||
|
@ -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 TextRun {
|
||||
} 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 TextRun {
|
||||
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 TextRun {
|
||||
}
|
||||
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 TextRun {
|
||||
if (props == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
XSLFShape shape = _p.getParentShape();
|
||||
CTShapeStyle style = shape.getSpStyle();
|
||||
CTSchemeColor phClr = null;
|
||||
@ -177,12 +184,12 @@ public class XSLFTextRun implements TextRun {
|
||||
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 TextRun {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFontFamily(String typeface){
|
||||
setFontFamily(typeface, (byte)-1, (byte)-1, false);
|
||||
}
|
||||
|
||||
public void setFontFamily(String typeface, byte charset, byte pictAndFamily, boolean isSymbol){
|
||||
CTTextCharacterProperties rPr = getRPr(true);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void setFontFamily(String typeface) {
|
||||
FontGroup fg = FontGroup.getFontGroupFirst(getRawText());
|
||||
new XSLFFontInfo(fg).setTypeface(typeface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFontFamily(){
|
||||
final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();
|
||||
public void setFontFamily(String typeface, FontGroup fontGroup) {
|
||||
new XSLFFontInfo(fontGroup).setTypeface(typeface);
|
||||
}
|
||||
|
||||
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 void setFontInfo(FontInfo fontInfo, FontGroup fontGroup) {
|
||||
new XSLFFontInfo(fontGroup).copyFrom(fontInfo);
|
||||
}
|
||||
|
||||
return visitor.getValue();
|
||||
@Override
|
||||
public String getFontFamily() {
|
||||
FontGroup fg = FontGroup.getFontGroupFirst(getRawText());
|
||||
return new XSLFFontInfo(fg).getTypeface();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFontFamily(FontGroup fontGroup) {
|
||||
return new XSLFFontInfo(fontGroup).getTypeface();
|
||||
}
|
||||
|
||||
@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 TextRun {
|
||||
@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 TextRun {
|
||||
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 TextRun {
|
||||
setStrikethrough(strike);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public FieldType getFieldType() {
|
||||
if (_r instanceof CTTextField) {
|
||||
@ -666,4 +636,224 @@ public class XSLFTextRun implements TextRun {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.TextBox;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,243 +0,0 @@
|
||||
/* ====================================================================
|
||||
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.hslf.model;
|
||||
|
||||
import org.apache.poi.hslf.record.FontEntityAtom;
|
||||
|
||||
/**
|
||||
* Represents a Font used in a presenation.
|
||||
* <p>
|
||||
* In PowerPoint Font is a shared resource and can be shared among text object in the presentation.
|
||||
* </p>
|
||||
* Some commonly used fonts are predefined in static constants.
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public final class PPFont {
|
||||
/**
|
||||
* ANSI character set
|
||||
*/
|
||||
public final static byte ANSI_CHARSET = 0;
|
||||
|
||||
/**
|
||||
* Default character set.
|
||||
*/
|
||||
public final static byte DEFAULT_CHARSET = 1;
|
||||
|
||||
/**
|
||||
* Symbol character set
|
||||
*/
|
||||
public final static byte SYMBOL_CHARSET = 2;
|
||||
|
||||
|
||||
/**
|
||||
* Constants for the pitch and family of the font.
|
||||
* The two low-order bits specify the pitch of the font and can be one of the following values
|
||||
*/
|
||||
public final static byte DEFAULT_PITCH = 0;
|
||||
public final static byte FIXED_PITCH = 1;
|
||||
public final static byte VARIABLE_PITCH = 2;
|
||||
|
||||
/**
|
||||
* Don't care or don't know.
|
||||
*/
|
||||
public final static byte FF_DONTCARE = 0;
|
||||
/**
|
||||
* Fonts with variable stroke width (proportional) and with serifs. Times New Roman is an example.
|
||||
*/
|
||||
public final static byte FF_ROMAN = 16;
|
||||
/**
|
||||
* Fonts with variable stroke width (proportional) and without serifs. Arial is an example.
|
||||
*/
|
||||
public final static byte FF_SWISS = 32;
|
||||
/**
|
||||
* Fonts designed to look like handwriting. Script and Cursive are examples.
|
||||
*/
|
||||
public final static byte FF_SCRIPT = 64;
|
||||
/**
|
||||
* Fonts with constant stroke width (monospace), with or without serifs.
|
||||
* Monospace fonts are usually modern. CourierNew is an example
|
||||
*/
|
||||
public final static byte FF_MODERN = 48;
|
||||
/**
|
||||
* Novelty fonts. Old English is an example
|
||||
*/
|
||||
public final static byte FF_DECORATIVE = 80;
|
||||
|
||||
|
||||
private int charset;
|
||||
private int type;
|
||||
private int flags;
|
||||
private int pitch;
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Creates a new instance of PPFont
|
||||
*/
|
||||
public PPFont(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of PPFont and initialize it from the supplied font atom
|
||||
*/
|
||||
public PPFont(FontEntityAtom fontAtom){
|
||||
name = fontAtom.getFontName();
|
||||
charset = fontAtom.getCharSet();
|
||||
type = fontAtom.getFontType();
|
||||
flags = fontAtom.getFontFlags();
|
||||
pitch = fontAtom.getPitchAndFamily();
|
||||
}
|
||||
|
||||
/**
|
||||
* set the name for the font (i.e. Arial)
|
||||
*
|
||||
* @param val String representing the name of the font to use
|
||||
*/
|
||||
public void setFontName(String val){
|
||||
name = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the name for the font (i.e. Arial)
|
||||
*
|
||||
* @return String representing the name of the font to use
|
||||
*/
|
||||
public String getFontName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the character set
|
||||
*
|
||||
* @param val - characterset
|
||||
*/
|
||||
public void setCharSet(int val){
|
||||
charset = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the character set
|
||||
*
|
||||
* @return charset - characterset
|
||||
*/
|
||||
public int getCharSet(){
|
||||
return charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the font flags
|
||||
* Bit 1: If set, font is subsetted
|
||||
*
|
||||
* @param val - the font flags
|
||||
*/
|
||||
public void setFontFlags(int val){
|
||||
flags = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the character set
|
||||
* Bit 1: If set, font is subsetted
|
||||
*
|
||||
* @return the font flags
|
||||
*/
|
||||
public int getFontFlags(){
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the font type
|
||||
* <p>
|
||||
* Bit 1: Raster Font
|
||||
* Bit 2: Device Font
|
||||
* Bit 3: TrueType Font
|
||||
* </p>
|
||||
*
|
||||
* @param val - the font type
|
||||
*/
|
||||
public void setFontType(int val){
|
||||
type = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the font type
|
||||
* <p>
|
||||
* Bit 1: Raster Font
|
||||
* Bit 2: Device Font
|
||||
* Bit 3: TrueType Font
|
||||
* </p>
|
||||
*
|
||||
* @return the font type
|
||||
*/
|
||||
public int getFontType(){
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* set lfPitchAndFamily
|
||||
*
|
||||
*
|
||||
* @param val - Corresponds to the lfPitchAndFamily field of the Win32 API LOGFONT structure
|
||||
*/
|
||||
public void setPitchAndFamily(int val){
|
||||
pitch = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* get lfPitchAndFamily
|
||||
*
|
||||
* @return corresponds to the lfPitchAndFamily field of the Win32 API LOGFONT structure
|
||||
*/
|
||||
public int getPitchAndFamily(){
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public static final PPFont ARIAL;
|
||||
public static final PPFont TIMES_NEW_ROMAN ;
|
||||
public static final PPFont COURIER_NEW;
|
||||
public static final PPFont WINGDINGS;
|
||||
static {
|
||||
ARIAL = new PPFont();
|
||||
ARIAL.setFontName("Arial");
|
||||
ARIAL.setCharSet(ANSI_CHARSET);
|
||||
ARIAL.setFontType(4);
|
||||
ARIAL.setFontFlags(0);
|
||||
ARIAL.setPitchAndFamily(VARIABLE_PITCH | FF_SWISS);
|
||||
|
||||
TIMES_NEW_ROMAN = new PPFont();
|
||||
TIMES_NEW_ROMAN.setFontName("Times New Roman");
|
||||
TIMES_NEW_ROMAN.setCharSet(ANSI_CHARSET);
|
||||
TIMES_NEW_ROMAN.setFontType(4);
|
||||
TIMES_NEW_ROMAN.setFontFlags(0);
|
||||
TIMES_NEW_ROMAN.setPitchAndFamily(VARIABLE_PITCH | FF_ROMAN);
|
||||
|
||||
COURIER_NEW = new PPFont();
|
||||
COURIER_NEW.setFontName("Courier New");
|
||||
COURIER_NEW.setCharSet(ANSI_CHARSET);
|
||||
COURIER_NEW.setFontType(4);
|
||||
COURIER_NEW.setFontFlags(0);
|
||||
COURIER_NEW.setPitchAndFamily(FIXED_PITCH | FF_MODERN);
|
||||
|
||||
WINGDINGS = new PPFont();
|
||||
WINGDINGS.setFontName("Wingdings");
|
||||
WINGDINGS.setCharSet(SYMBOL_CHARSET);
|
||||
WINGDINGS.setFontType(4);
|
||||
WINGDINGS.setFontFlags(0);
|
||||
WINGDINGS.setPitchAndFamily(VARIABLE_PITCH | FF_DONTCARE);
|
||||
}
|
||||
}
|
@ -43,7 +43,7 @@ public class CharFlagsTextProp extends BitMaskTextProp {
|
||||
"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
|
||||
|
@ -17,38 +17,37 @@
|
||||
|
||||
package org.apache.poi.hslf.record;
|
||||
|
||||
import org.apache.poi.hslf.model.PPFont;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.poi.common.usermodel.fonts.FontInfo;
|
||||
import org.apache.poi.hslf.usermodel.HSLFFontInfo;
|
||||
import org.apache.poi.hslf.usermodel.HSLFFontInfoPredefined;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* <code>FontCollection</code> ia a container that holds information
|
||||
* {@code FontCollection} ia a container that holds information
|
||||
* about all the fonts in the presentation.
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
|
||||
public final class FontCollection extends RecordContainer {
|
||||
private List<String> fonts;
|
||||
private final Map<String,HSLFFontInfo> fonts = new LinkedHashMap<String,HSLFFontInfo>();
|
||||
private byte[] _header;
|
||||
|
||||
protected FontCollection(byte[] source, int start, int len) {
|
||||
// Grab the header
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
_children = Record.findChildRecords(source,start+8,len-8);
|
||||
|
||||
// Save font names into <code>List</code>
|
||||
fonts = new ArrayList<String>();
|
||||
for (int i = 0; i < _children.length; i++){
|
||||
if(_children[i] instanceof FontEntityAtom) {
|
||||
FontEntityAtom atom = (FontEntityAtom)_children[i];
|
||||
fonts.add(atom.getFontName());
|
||||
for (Record r : _children){
|
||||
if(r instanceof FontEntityAtom) {
|
||||
HSLFFontInfo fi = new HSLFFontInfo((FontEntityAtom)r);
|
||||
fonts.put(fi.getTypeface(), fi);
|
||||
} else {
|
||||
logger.log(POILogger.WARN, "Warning: FontCollection child wasn't a FontEntityAtom, was " + _children[i]);
|
||||
logger.log(POILogger.WARN, "Warning: FontCollection child wasn't a FontEntityAtom, was " + r.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -56,7 +55,8 @@ public final class FontCollection extends RecordContainer {
|
||||
/**
|
||||
* Return the type, which is 2005
|
||||
*/
|
||||
public long getRecordType() {
|
||||
@Override
|
||||
public long getRecordType() {
|
||||
return RecordTypes.FontCollection.typeID;
|
||||
}
|
||||
|
||||
@ -64,66 +64,72 @@ public final class FontCollection extends RecordContainer {
|
||||
* Write the contents of the record back, so it can be written
|
||||
* to disk
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
@Override
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
writeOut(_header[0],_header[1],getRecordType(),_children,out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add font with the specified name to the font collection.
|
||||
* If the font is already present return its index.
|
||||
* @param name of the font
|
||||
* @return zero based index of the font in the collection
|
||||
* Add font with the given FontInfo configuration to the font collection.
|
||||
* The returned FontInfo contains the HSLF specific details and the collection
|
||||
* uniquely contains fonts based on their typeface, i.e. calling the method with FontInfo
|
||||
* objects having the same name results in the same HSLFFontInfo reference.
|
||||
*
|
||||
* @param fontInfo the FontInfo configuration, can be a instance of {@link HSLFFontInfo},
|
||||
* {@link HSLFFontInfoPredefined} or a custom implementation
|
||||
* @return the register HSLFFontInfo object
|
||||
*/
|
||||
public int addFont(String name) {
|
||||
int idx = getFontIndex(name);
|
||||
if (idx != -1) return idx;
|
||||
public HSLFFontInfo addFont(FontInfo fontInfo) {
|
||||
HSLFFontInfo fi = getFontInfo(fontInfo.getTypeface());
|
||||
if (fi != null) {
|
||||
return fi;
|
||||
}
|
||||
|
||||
return addFont(name, 0, 0, 4, PPFont.FF_SWISS | PPFont.VARIABLE_PITCH);
|
||||
}
|
||||
|
||||
public int addFont(String name, int charset, int flags, int type, int pitch) {
|
||||
FontEntityAtom fnt = new FontEntityAtom();
|
||||
fnt.setFontIndex(fonts.size() << 4);
|
||||
fnt.setFontName(name);
|
||||
fnt.setCharSet(charset);
|
||||
fnt.setFontFlags(flags);
|
||||
fnt.setFontType(type);
|
||||
fnt.setPitchAndFamily(pitch);
|
||||
fonts.add(name);
|
||||
fi = new HSLFFontInfo(fontInfo);
|
||||
fi.setIndex(fonts.size());
|
||||
fonts.put(fi.getTypeface(), fi);
|
||||
|
||||
FontEntityAtom fnt = fi.createRecord();
|
||||
|
||||
// Append new child to the end
|
||||
appendChildRecord(fnt);
|
||||
appendChildRecord(fnt);
|
||||
|
||||
return fonts.size()-1; //the added font is the last in the list
|
||||
// the added font is the last in the list
|
||||
return fi;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lookup a FontInfo object by its typeface
|
||||
*
|
||||
* @param typeface the full font name
|
||||
*
|
||||
* @return the HSLFFontInfo for the given name or {@code null} if not found
|
||||
*/
|
||||
public HSLFFontInfo getFontInfo(String typeface) {
|
||||
return fonts.get(typeface);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return zero based index of the font in the collection or -1 if not found
|
||||
* Lookup a FontInfo object by its internal font index
|
||||
*
|
||||
* @param index the internal font index
|
||||
*
|
||||
* @return the HSLFFontInfo for the given index or {@code null} if not found
|
||||
*/
|
||||
public int getFontIndex(String name) {
|
||||
for (int i = 0; i < fonts.size(); i++) {
|
||||
if(fonts.get(i).equals(name)){
|
||||
//if the font is already present return its index
|
||||
return i;
|
||||
public HSLFFontInfo getFontInfo(int index) {
|
||||
for (HSLFFontInfo fi : fonts.values()) {
|
||||
if (fi.getIndex() == index) {
|
||||
return fi;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the number of registered fonts
|
||||
*/
|
||||
public int getNumberOfFonts() {
|
||||
return fonts.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the font at the given ID, or null if there is
|
||||
* no font at that ID.
|
||||
* @param id
|
||||
*/
|
||||
public String getFontWithId(int id) {
|
||||
if(id >= fonts.size()) {
|
||||
// No font with that id
|
||||
return null;
|
||||
}
|
||||
return fonts.get(id);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package org.apache.poi.hslf.record;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
@ -97,20 +98,18 @@ public final class FontEntityAtom extends RecordAtom {
|
||||
* Will be converted to null-terminated if not already
|
||||
* @param name of the font
|
||||
*/
|
||||
public void setFontName(String name){
|
||||
// Add a null termination if required
|
||||
if(! name.endsWith("\u0000")) {
|
||||
name += '\u0000';
|
||||
}
|
||||
public void setFontName(String name) {
|
||||
// Ensure it's not now too long
|
||||
int nameLen = name.length() + (name.endsWith("\u0000") ? 0 : 1);
|
||||
if (nameLen > 32) {
|
||||
throw new HSLFException("The length of the font name, including null termination, must not exceed 32 characters");
|
||||
}
|
||||
|
||||
// Ensure it's not now too long
|
||||
if(name.length() > 32) {
|
||||
throw new HSLFException("The length of the font name, including null termination, must not exceed 32 characters");
|
||||
}
|
||||
|
||||
// Everything's happy, so save the name
|
||||
// Everything's happy, so save the name
|
||||
byte[] bytes = StringUtil.getToUnicodeLE(name);
|
||||
System.arraycopy(bytes, 0, _recdata, 0, bytes.length);
|
||||
// null the remaining bytes
|
||||
Arrays.fill(_recdata, 64-bytes.length, 64, (byte)0);
|
||||
}
|
||||
|
||||
public void setFontIndex(int idx){
|
||||
|
@ -17,20 +17,19 @@
|
||||
|
||||
package org.apache.poi.hslf.record;
|
||||
|
||||
import org.apache.poi.util.ArrayUtil;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.hslf.util.MutableByteArrayOutputStream;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.apache.poi.hslf.util.MutableByteArrayOutputStream;
|
||||
import org.apache.poi.util.ArrayUtil;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.Removal;
|
||||
|
||||
/**
|
||||
* Abstract class which all container records will extend. Providers
|
||||
* helpful methods for writing child records out to disk
|
||||
*
|
||||
* @author Nick Burch
|
||||
*/
|
||||
|
||||
public abstract class RecordContainer extends Record
|
||||
@ -40,12 +39,14 @@ public abstract class RecordContainer extends Record
|
||||
/**
|
||||
* Return any children
|
||||
*/
|
||||
public Record[] getChildRecords() { return _children; }
|
||||
@Override
|
||||
public Record[] getChildRecords() { return _children; }
|
||||
|
||||
/**
|
||||
* We're not an atom
|
||||
*/
|
||||
public boolean isAnAtom() { return false; }
|
||||
@Override
|
||||
public boolean isAnAtom() { return false; }
|
||||
|
||||
|
||||
/* ===============================================================
|
||||
@ -70,14 +71,16 @@ public abstract class RecordContainer extends Record
|
||||
/**
|
||||
* Adds a child record, at the very end.
|
||||
* @param newChild The child record to add
|
||||
* @return the position of the added child
|
||||
*/
|
||||
private void appendChild(Record newChild) {
|
||||
private int appendChild(Record newChild) {
|
||||
// Copy over, and pop the child in at the end
|
||||
Record[] nc = new Record[(_children.length + 1)];
|
||||
System.arraycopy(_children, 0, nc, 0, _children.length);
|
||||
// Switch the arrays
|
||||
nc[_children.length] = newChild;
|
||||
_children = nc;
|
||||
return _children.length;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,8 +141,11 @@ public abstract class RecordContainer extends Record
|
||||
Record rm = null;
|
||||
ArrayList<Record> lst = new ArrayList<Record>();
|
||||
for(Record r : _children) {
|
||||
if(r != ch) lst.add(r);
|
||||
else rm = r;
|
||||
if(r != ch) {
|
||||
lst.add(r);
|
||||
} else {
|
||||
rm = r;
|
||||
}
|
||||
}
|
||||
_children = lst.toArray(new Record[lst.size()]);
|
||||
return rm;
|
||||
@ -152,17 +158,21 @@ public abstract class RecordContainer extends Record
|
||||
|
||||
/**
|
||||
* Add a new child record onto a record's list of children.
|
||||
*
|
||||
* @param newChild the child record to be added
|
||||
* @return the position of the added child within the list, i.e. the last index
|
||||
*/
|
||||
public void appendChildRecord(Record newChild) {
|
||||
appendChild(newChild);
|
||||
public int appendChildRecord(Record newChild) {
|
||||
return appendChild(newChild);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given Child Record after the supplied record
|
||||
* @param newChild
|
||||
* @param after
|
||||
* @return the position of the added child within the list
|
||||
*/
|
||||
public void addChildAfter(Record newChild, Record after) {
|
||||
public int addChildAfter(Record newChild, Record after) {
|
||||
// Decide where we're going to put it
|
||||
int loc = findChildLocation(after);
|
||||
if(loc == -1) {
|
||||
@ -171,14 +181,16 @@ public abstract class RecordContainer extends Record
|
||||
|
||||
// Add one place after the supplied record
|
||||
addChildAt(newChild, loc+1);
|
||||
return loc+1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given Child Record before the supplied record
|
||||
* @param newChild
|
||||
* @param before
|
||||
* @return the position of the added child within the list
|
||||
*/
|
||||
public void addChildBefore(Record newChild, Record before) {
|
||||
public int addChildBefore(Record newChild, Record before) {
|
||||
// Decide where we're going to put it
|
||||
int loc = findChildLocation(before);
|
||||
if(loc == -1) {
|
||||
@ -187,18 +199,27 @@ public abstract class RecordContainer extends Record
|
||||
|
||||
// Add at the place of the supplied record
|
||||
addChildAt(newChild, loc);
|
||||
return loc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the given Child Record to before the supplied record
|
||||
*/
|
||||
*
|
||||
* @deprecated method is not used within POI and will be removed
|
||||
*/
|
||||
@Removal(version="3.19")
|
||||
@Deprecated
|
||||
public void moveChildBefore(Record child, Record before) {
|
||||
moveChildrenBefore(child, 1, before);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the given Child Records to before the supplied record
|
||||
*/
|
||||
*
|
||||
* @deprecated method is not used within POI and will be removed
|
||||
*/
|
||||
@Removal(version="3.19")
|
||||
@Deprecated
|
||||
public void moveChildrenBefore(Record firstChild, int number, Record before) {
|
||||
if(number < 1) { return; }
|
||||
|
||||
@ -220,7 +241,15 @@ public abstract class RecordContainer extends Record
|
||||
|
||||
/**
|
||||
* Moves the given Child Records to after the supplied record
|
||||
*
|
||||
* @param firstChild the first child to be moved
|
||||
* @param number the number of records to move
|
||||
* @param after the record after that the children are moved
|
||||
*
|
||||
* @deprecated method is not used within POI and will be removed
|
||||
*/
|
||||
@Removal(version="3.19")
|
||||
@Deprecated
|
||||
public void moveChildrenAfter(Record firstChild, int number, Record after) {
|
||||
if(number < 1) { return; }
|
||||
// Decide where we're going to put them
|
||||
|
@ -0,0 +1,215 @@
|
||||
/* ====================================================================
|
||||
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.hslf.usermodel;
|
||||
|
||||
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.hslf.record.FontEntityAtom;
|
||||
import org.apache.poi.util.BitField;
|
||||
import org.apache.poi.util.BitFieldFactory;
|
||||
|
||||
/**
|
||||
* Represents a Font used in a presentation.<p>
|
||||
*
|
||||
* In PowerPoint Font is a shared resource and can be shared among text object in the presentation.
|
||||
*
|
||||
* @since POI 3.17-beta2
|
||||
*/
|
||||
public class HSLFFontInfo implements FontInfo {
|
||||
|
||||
public enum FontRenderType {
|
||||
raster, device, truetype;
|
||||
}
|
||||
|
||||
/** A bit that specifies whether a subset of this font is embedded. */
|
||||
private static final BitField FLAGS_EMBED_SUBSETTED = BitFieldFactory.getInstance(0x01);
|
||||
/** Bits that specifies whether the font is a raster,device or truetype font. */
|
||||
private static final BitField FLAGS_RENDER_FONTTYPE = BitFieldFactory.getInstance(0x07);
|
||||
/** A bit that specifies whether font substitution logic is not applied for this font. */
|
||||
private static final BitField FLAGS_NO_FONT_SUBSTITUTION = BitFieldFactory.getInstance(0x08);
|
||||
|
||||
private int index = -1;
|
||||
private String typeface = "undefined";
|
||||
private FontCharset charset = FontCharset.ANSI;
|
||||
private FontRenderType renderType = FontRenderType.truetype;
|
||||
private FontFamily family = FontFamily.FF_SWISS;
|
||||
private FontPitch pitch = FontPitch.VARIABLE;
|
||||
private boolean isSubsetted = false;
|
||||
private boolean isSubstitutable = true;
|
||||
|
||||
/**
|
||||
* Creates a new instance of HSLFFontInfo with more or sensible defaults.<p>
|
||||
*
|
||||
* If you don't use default fonts (see {@link HSLFFontInfoPredefined}) then the results
|
||||
* of the font substitution will be better, if you also specify the other properties.
|
||||
*
|
||||
* @param typeface the font name
|
||||
*/
|
||||
public HSLFFontInfo(String typeface){
|
||||
setTypeface(typeface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of HSLFFontInfo and initialize it from the supplied font atom
|
||||
*/
|
||||
public HSLFFontInfo(FontEntityAtom fontAtom){
|
||||
setIndex(fontAtom.getFontIndex());
|
||||
setTypeface(fontAtom.getFontName());
|
||||
setCharset(FontCharset.valueOf(fontAtom.getCharSet()));
|
||||
// assumption: the render type is exclusive
|
||||
switch (FLAGS_RENDER_FONTTYPE.getValue(fontAtom.getFontType())) {
|
||||
case 1:
|
||||
setRenderType(FontRenderType.raster);
|
||||
break;
|
||||
case 2:
|
||||
setRenderType(FontRenderType.device);
|
||||
break;
|
||||
default:
|
||||
case 4:
|
||||
setRenderType(FontRenderType.truetype);
|
||||
break;
|
||||
}
|
||||
|
||||
byte pitchAndFamily = (byte)fontAtom.getPitchAndFamily();
|
||||
setPitch(FontPitch.valueOfPitchFamily(pitchAndFamily));
|
||||
setFamily(FontFamily.valueOfPitchFamily(pitchAndFamily));
|
||||
setEmbedSubsetted(FLAGS_EMBED_SUBSETTED.isSet(fontAtom.getFontFlags()));
|
||||
setFontSubstitutable(!FLAGS_NO_FONT_SUBSTITUTION.isSet(fontAtom.getFontType()));
|
||||
}
|
||||
|
||||
public HSLFFontInfo(FontInfo fontInfo) {
|
||||
// don't copy font index on copy constructor - it depends on the FontCollection this record is in
|
||||
setTypeface(fontInfo.getTypeface());
|
||||
setCharset(fontInfo.getCharset());
|
||||
setFamily(fontInfo.getFamily());
|
||||
setPitch(fontInfo.getPitch());
|
||||
if (fontInfo instanceof HSLFFontInfo) {
|
||||
HSLFFontInfo hFontInfo = (HSLFFontInfo)fontInfo;
|
||||
setRenderType(hFontInfo.getRenderType());
|
||||
setEmbedSubsetted(hFontInfo.isEmbedSubsetted());
|
||||
setFontSubstitutable(hFontInfo.isFontSubstitutable());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeface(){
|
||||
return typeface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTypeface(String typeface){
|
||||
if (typeface == null || "".equals(typeface)) {
|
||||
throw new IllegalArgumentException("typeface can't be null nor empty");
|
||||
}
|
||||
this.typeface = typeface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharset(FontCharset charset){
|
||||
this.charset = (charset == null) ? FontCharset.ANSI : charset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FontCharset getCharset(){
|
||||
return charset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FontFamily getFamily() {
|
||||
return family;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFamily(FontFamily family) {
|
||||
this.family = (family == null) ? FontFamily.FF_SWISS : family;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FontPitch getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPitch(FontPitch pitch) {
|
||||
this.pitch = (pitch == null) ? FontPitch.VARIABLE : pitch;
|
||||
|
||||
}
|
||||
|
||||
public FontRenderType getRenderType() {
|
||||
return renderType;
|
||||
}
|
||||
|
||||
public void setRenderType(FontRenderType renderType) {
|
||||
this.renderType = (renderType == null) ? FontRenderType.truetype : renderType;
|
||||
}
|
||||
|
||||
public boolean isEmbedSubsetted() {
|
||||
return isSubsetted;
|
||||
}
|
||||
|
||||
public void setEmbedSubsetted(boolean embedSubset) {
|
||||
this.isSubsetted = embedSubset;
|
||||
}
|
||||
|
||||
public boolean isFontSubstitutable() {
|
||||
return this.isSubstitutable;
|
||||
}
|
||||
|
||||
public void setFontSubstitutable(boolean isSubstitutable) {
|
||||
this.isSubstitutable = isSubstitutable;
|
||||
}
|
||||
|
||||
public FontEntityAtom createRecord() {
|
||||
FontEntityAtom fnt = new FontEntityAtom();
|
||||
fnt.setFontIndex(getIndex() << 4);
|
||||
fnt.setFontName(getTypeface());
|
||||
fnt.setCharSet(getCharset().getNativeId());
|
||||
fnt.setFontFlags((byte)(isEmbedSubsetted() ? 1 : 0));
|
||||
|
||||
int typeFlag;
|
||||
switch (renderType) {
|
||||
case device:
|
||||
typeFlag = FLAGS_RENDER_FONTTYPE.setValue(0, 1);
|
||||
break;
|
||||
case raster:
|
||||
typeFlag = FLAGS_RENDER_FONTTYPE.setValue(0, 2);
|
||||
break;
|
||||
default:
|
||||
case truetype:
|
||||
typeFlag = FLAGS_RENDER_FONTTYPE.setValue(0, 4);
|
||||
break;
|
||||
}
|
||||
typeFlag = FLAGS_NO_FONT_SUBSTITUTION.setBoolean(typeFlag, isFontSubstitutable());
|
||||
fnt.setFontType(typeFlag);
|
||||
|
||||
fnt.setPitchAndFamily(FontPitch.getNativeId(pitch, family));
|
||||
return fnt;
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/* ====================================================================
|
||||
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.hslf.usermodel;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Predefined fonts
|
||||
*
|
||||
* @since POI 3.17-beta2
|
||||
*/
|
||||
public enum HSLFFontInfoPredefined implements FontInfo {
|
||||
ARIAL("Arial", FontCharset.ANSI, FontPitch.VARIABLE, FontFamily.FF_SWISS),
|
||||
TIMES_NEW_ROMAN("Times New Roman", FontCharset.ANSI, FontPitch.VARIABLE, FontFamily.FF_ROMAN),
|
||||
COURIER_NEW("Courier New", FontCharset.ANSI, FontPitch.FIXED, FontFamily.FF_MODERN),
|
||||
WINGDINGS("Wingdings", FontCharset.SYMBOL, FontPitch.VARIABLE, FontFamily.FF_DONTCARE);
|
||||
|
||||
private String typeface;
|
||||
private FontCharset charset;
|
||||
private FontPitch pitch;
|
||||
private FontFamily family;
|
||||
|
||||
HSLFFontInfoPredefined(String typeface, FontCharset charset, FontPitch pitch, FontFamily family) {
|
||||
this.typeface = typeface;
|
||||
this.charset = charset;
|
||||
this.pitch = pitch;
|
||||
this.family = family;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getIndex() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIndex(int index) {
|
||||
throw new UnsupportedOperationException("Predefined enum can't be changed.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeface() {
|
||||
return typeface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTypeface(String typeface) {
|
||||
throw new UnsupportedOperationException("Predefined enum can't be changed.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FontCharset getCharset() {
|
||||
return charset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharset(FontCharset charset) {
|
||||
throw new UnsupportedOperationException("Predefined enum can't be changed.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FontFamily getFamily() {
|
||||
return family;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFamily(FontFamily family) {
|
||||
throw new UnsupportedOperationException("Predefined enum can't be changed.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FontPitch getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPitch(FontPitch pitch) {
|
||||
throw new UnsupportedOperationException("Predefined enum can't be changed.");
|
||||
}
|
||||
}
|
@ -33,6 +33,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.poi.common.usermodel.fonts.FontInfo;
|
||||
import org.apache.poi.ddf.EscherBSERecord;
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
import org.apache.poi.ddf.EscherOptRecord;
|
||||
@ -41,9 +42,34 @@ import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
|
||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||
import org.apache.poi.hslf.model.HeadersFooters;
|
||||
import org.apache.poi.hslf.model.MovieShape;
|
||||
import org.apache.poi.hslf.model.PPFont;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.hslf.record.Document;
|
||||
import org.apache.poi.hslf.record.DocumentAtom;
|
||||
import org.apache.poi.hslf.record.ExAviMovie;
|
||||
import org.apache.poi.hslf.record.ExControl;
|
||||
import org.apache.poi.hslf.record.ExEmbed;
|
||||
import org.apache.poi.hslf.record.ExEmbedAtom;
|
||||
import org.apache.poi.hslf.record.ExMCIMovie;
|
||||
import org.apache.poi.hslf.record.ExObjList;
|
||||
import org.apache.poi.hslf.record.ExObjListAtom;
|
||||
import org.apache.poi.hslf.record.ExOleObjAtom;
|
||||
import org.apache.poi.hslf.record.ExOleObjStg;
|
||||
import org.apache.poi.hslf.record.ExVideoContainer;
|
||||
import org.apache.poi.hslf.record.FontCollection;
|
||||
import org.apache.poi.hslf.record.HeadersFootersContainer;
|
||||
import org.apache.poi.hslf.record.MainMaster;
|
||||
import org.apache.poi.hslf.record.Notes;
|
||||
import org.apache.poi.hslf.record.PersistPtrHolder;
|
||||
import org.apache.poi.hslf.record.PositionDependentRecord;
|
||||
import org.apache.poi.hslf.record.PositionDependentRecordContainer;
|
||||
import org.apache.poi.hslf.record.Record;
|
||||
import org.apache.poi.hslf.record.RecordContainer;
|
||||
import org.apache.poi.hslf.record.RecordTypes;
|
||||
import org.apache.poi.hslf.record.Slide;
|
||||
import org.apache.poi.hslf.record.SlideListWithText;
|
||||
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
|
||||
import org.apache.poi.hslf.record.SlidePersistAtom;
|
||||
import org.apache.poi.hslf.record.TxMasterStyleAtom;
|
||||
import org.apache.poi.hslf.record.UserEditAtom;
|
||||
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
||||
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
@ -874,18 +900,11 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
|
||||
/**
|
||||
* Add a font in this presentation
|
||||
*
|
||||
* @param font
|
||||
* the font to add
|
||||
* @return 0-based index of the font
|
||||
* @param fontInfo the font to add
|
||||
* @return the registered HSLFFontInfo - the font info object is unique based on the typeface
|
||||
*/
|
||||
public int addFont(PPFont font) {
|
||||
FontCollection fonts = getDocumentRecord().getEnvironment().getFontCollection();
|
||||
int idx = fonts.getFontIndex(font.getFontName());
|
||||
if (idx == -1) {
|
||||
idx = fonts.addFont(font.getFontName(), font.getCharSet(), font.getFontFlags(), font
|
||||
.getFontType(), font.getPitchAndFamily());
|
||||
}
|
||||
return idx;
|
||||
public HSLFFontInfo addFont(FontInfo fontInfo) {
|
||||
return getDocumentRecord().getEnvironment().getFontCollection().addFont(fontInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -896,17 +915,8 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
|
||||
* @return of an instance of <code>PPFont</code> or <code>null</code> if not
|
||||
* found
|
||||
*/
|
||||
public PPFont getFont(int idx) {
|
||||
FontCollection fonts = getDocumentRecord().getEnvironment().getFontCollection();
|
||||
for (Record ch : fonts.getChildRecords()) {
|
||||
if (ch instanceof FontEntityAtom) {
|
||||
FontEntityAtom atom = (FontEntityAtom) ch;
|
||||
if (atom.getFontIndex() == idx) {
|
||||
return new PPFont(atom);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
public HSLFFontInfo getFont(int idx) {
|
||||
return getDocumentRecord().getEnvironment().getFontCollection().getFontInfo(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,8 +25,9 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.common.usermodel.fonts.FontGroup;
|
||||
import org.apache.poi.common.usermodel.fonts.FontInfo;
|
||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||
import org.apache.poi.hslf.model.PPFont;
|
||||
import org.apache.poi.hslf.model.textproperties.BitMaskTextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.FontAlignmentProp;
|
||||
import org.apache.poi.hslf.model.textproperties.IndentProp;
|
||||
@ -38,7 +39,6 @@ import org.apache.poi.hslf.model.textproperties.TextPropCollection;
|
||||
import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
|
||||
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||||
import org.apache.poi.hslf.record.EscherTextboxWrapper;
|
||||
import org.apache.poi.hslf.record.FontCollection;
|
||||
import org.apache.poi.hslf.record.InteractiveInfo;
|
||||
import org.apache.poi.hslf.record.MasterTextPropAtom;
|
||||
import org.apache.poi.hslf.record.OutlineTextRefAtom;
|
||||
@ -159,7 +159,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
||||
public void setParagraphStyle(TextPropCollection paragraphStyle) {
|
||||
_paragraphStyle.copy(paragraphStyle);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setting a master style reference
|
||||
*
|
||||
@ -376,11 +376,20 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
||||
|
||||
@Override
|
||||
public String getDefaultFontFamily() {
|
||||
String typeface = null;
|
||||
FontInfo fontInfo = null;
|
||||
if (!_runs.isEmpty()) {
|
||||
typeface = _runs.get(0).getFontFamily();
|
||||
HSLFTextRun tr = _runs.get(0);
|
||||
fontInfo = tr.getFontInfo(null);
|
||||
// fallback to LATIN if the font for the font group wasn't defined
|
||||
if (fontInfo == null) {
|
||||
fontInfo = tr.getFontInfo(FontGroup.LATIN);
|
||||
}
|
||||
}
|
||||
return (typeface != null) ? typeface : "Arial";
|
||||
if (fontInfo == null) {
|
||||
fontInfo = HSLFFontInfoPredefined.ARIAL;
|
||||
}
|
||||
|
||||
return fontInfo.getTypeface();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -657,10 +666,10 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
||||
return;
|
||||
}
|
||||
|
||||
FontCollection fc = getSheet().getSlideShow().getFontCollection();
|
||||
int idx = fc.addFont(typeface);
|
||||
HSLFFontInfo fi = new HSLFFontInfo(typeface);
|
||||
fi = getSheet().getSlideShow().addFont(fi);
|
||||
|
||||
setParagraphTextPropVal("bullet.font", idx);
|
||||
setParagraphTextPropVal("bullet.font", fi.getIndex());
|
||||
setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, true);
|
||||
}
|
||||
|
||||
@ -673,9 +682,9 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
||||
if (tp == null || !hasFont) {
|
||||
return getDefaultFontFamily();
|
||||
}
|
||||
PPFont ppFont = getSheet().getSlideShow().getFont(tp.getValue());
|
||||
HSLFFontInfo ppFont = getSheet().getSlideShow().getFont(tp.getValue());
|
||||
assert(ppFont != null);
|
||||
return ppFont.getFontName();
|
||||
return ppFont.getTypeface();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -754,22 +763,14 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
||||
String propNames[] = propName.split(",");
|
||||
for (String pn : propNames) {
|
||||
TextProp prop = props.findByName(pn);
|
||||
if (prop == null) {
|
||||
continue;
|
||||
if (isValidProp(prop)) {
|
||||
return prop;
|
||||
}
|
||||
|
||||
// Font properties (maybe other too???) can have an index of -1
|
||||
// so we check the master for this font index then
|
||||
if (pn.contains("font") && prop.getValue() == -1) {
|
||||
return getMasterPropVal(props, masterProps, pn);
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
|
||||
return getMasterPropVal(props, masterProps, propName);
|
||||
}
|
||||
|
||||
|
||||
private TextProp getMasterPropVal(TextPropCollection props, TextPropCollection masterProps, String propName) {
|
||||
boolean isChar = props.getTextPropType() == TextPropType.character;
|
||||
|
||||
@ -783,7 +784,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
||||
}
|
||||
|
||||
String propNames[] = propName.split(",");
|
||||
if (masterProps == null) {
|
||||
if (masterProps == null) {
|
||||
HSLFSheet sheet = getSheet();
|
||||
int txtype = getRunType();
|
||||
HSLFMasterSheet master = sheet.getMasterSheet();
|
||||
@ -794,22 +795,29 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
||||
|
||||
for (String pn : propNames) {
|
||||
TextProp prop = master.getStyleAttribute(txtype, getIndentLevel(), pn, isChar);
|
||||
if (prop != null) {
|
||||
if (isValidProp(prop)) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (String pn : propNames) {
|
||||
TextProp prop = masterProps.findByName(pn);
|
||||
if (prop != null) {
|
||||
if (isValidProp(prop)) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isValidProp(TextProp prop) {
|
||||
// Font properties (maybe other too???) can have an index of -1
|
||||
// so we check the master for this font index then
|
||||
return prop != null && (!prop.getName().contains("font") || prop.getValue() != -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the named TextProp, either by fetching it (if it exists) or
|
||||
* adding it (if it didn't)
|
||||
@ -823,7 +831,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
||||
if (getSheet() instanceof MasterSheet && masterProps != null) {
|
||||
pc = masterProps;
|
||||
}
|
||||
|
||||
|
||||
if (val == null) {
|
||||
pc.removeByName(name);
|
||||
return;
|
||||
@ -1020,7 +1028,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
||||
if (lastPTPC == null || lastRTPC == null || ptpc == null || rtpc == null) { // NOSONAR
|
||||
throw new HSLFException("Not all TextPropCollection could be determined.");
|
||||
}
|
||||
|
||||
|
||||
ptpc.updateTextSize(ptpc.getCharactersCovered() + 1);
|
||||
rtpc.updateTextSize(rtpc.getCharactersCovered() + 1);
|
||||
lastPTPC.updateTextSize(lastPTPC.getCharactersCovered() + 1);
|
||||
@ -1075,11 +1083,11 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
||||
assert(info != null && txinfo != null);
|
||||
_txtbox.appendChildRecord(info);
|
||||
_txtbox.appendChildRecord(txinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes the textbox records back to the document record
|
||||
* Writes the textbox records back to the document record
|
||||
*/
|
||||
private static void refreshRecords(List<HSLFTextParagraph> paragraphs) {
|
||||
TextHeaderAtom headerAtom = paragraphs.get(0)._headerAtom;
|
||||
@ -1624,7 +1632,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
*
|
||||
* @see RoundTripHFPlaceholder12
|
||||
*/
|
||||
@Override
|
||||
|
@ -20,6 +20,8 @@ package org.apache.poi.hslf.usermodel;
|
||||
import java.awt.Color;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.common.usermodel.fonts.FontGroup;
|
||||
import org.apache.poi.common.usermodel.fonts.FontInfo;
|
||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||
import org.apache.poi.hslf.model.textproperties.BitMaskTextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp;
|
||||
@ -49,15 +51,16 @@ public final class HSLFTextRun implements TextRun {
|
||||
/** The TextRun we belong to */
|
||||
private HSLFTextParagraph parentParagraph;
|
||||
private String _runText = "";
|
||||
private String _fontFamily;
|
||||
/** Caches the font info objects until the text runs are attached to the container */
|
||||
private HSLFFontInfo[] cachedFontInfo;
|
||||
private HSLFHyperlink link;
|
||||
|
||||
|
||||
/**
|
||||
* Our paragraph and character style.
|
||||
* Note - we may share these styles with other RichTextRuns
|
||||
*/
|
||||
private TextPropCollection characterStyle = new TextPropCollection(1, TextPropType.character);
|
||||
|
||||
|
||||
private TextPropCollection masterStyle;
|
||||
|
||||
/**
|
||||
@ -67,7 +70,7 @@ public final class HSLFTextRun implements TextRun {
|
||||
public HSLFTextRun(HSLFTextParagraph parentParagraph) {
|
||||
this.parentParagraph = parentParagraph;
|
||||
}
|
||||
|
||||
|
||||
public TextPropCollection getCharacterStyle() {
|
||||
return characterStyle;
|
||||
}
|
||||
@ -76,27 +79,29 @@ public final class HSLFTextRun implements TextRun {
|
||||
this.characterStyle.copy(characterStyle);
|
||||
this.characterStyle.updateTextSize(_runText.length());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setting a master style reference
|
||||
*
|
||||
* @param characterStyle the master style reference
|
||||
*
|
||||
*
|
||||
* @since POI 3.14-Beta1
|
||||
*/
|
||||
@Internal
|
||||
/* package */ void setMasterStyleReference(TextPropCollection masterStyle) {
|
||||
this.masterStyle = masterStyle;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Supply the SlideShow we belong to
|
||||
*/
|
||||
public void updateSheet() {
|
||||
if (_fontFamily != null) {
|
||||
setFontFamily(_fontFamily);
|
||||
_fontFamily = null;
|
||||
if (cachedFontInfo != null) {
|
||||
for (FontGroup tt : FontGroup.values()) {
|
||||
setFontInfo(cachedFontInfo[tt.ordinal()], tt);
|
||||
}
|
||||
cachedFontInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,31 +312,97 @@ public final class HSLFTextRun implements TextRun {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFontFamily(String fontFamily) {
|
||||
HSLFSheet sheet = parentParagraph.getSheet();
|
||||
@SuppressWarnings("resource")
|
||||
HSLFSlideShow slideShow = (sheet == null) ? null : sheet.getSlideShow();
|
||||
if (sheet == null || slideShow == null) {
|
||||
//we can't set font since slideshow is not assigned yet
|
||||
_fontFamily = fontFamily;
|
||||
return;
|
||||
}
|
||||
// Get the index for this font (adding if needed)
|
||||
Integer fontIdx = (fontFamily == null) ? null : slideShow.getFontCollection().addFont(fontFamily);
|
||||
setCharTextPropVal("font.index", fontIdx);
|
||||
public void setFontFamily(String typeface) {
|
||||
setFontInfo(new HSLFFontInfo(typeface), FontGroup.LATIN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFontFamily() {
|
||||
@Override
|
||||
public void setFontFamily(String typeface, FontGroup fontGroup) {
|
||||
setFontInfo(new HSLFFontInfo(typeface), fontGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFontInfo(FontInfo fontInfo, FontGroup fontGroup) {
|
||||
FontGroup fg = safeFontGroup(fontGroup);
|
||||
|
||||
HSLFSheet sheet = parentParagraph.getSheet();
|
||||
@SuppressWarnings("resource")
|
||||
HSLFSlideShow slideShow = (sheet == null) ? null : sheet.getSlideShow();
|
||||
if (sheet == null || slideShow == null) {
|
||||
// we can't set font since slideshow is not assigned yet
|
||||
if (cachedFontInfo == null) {
|
||||
cachedFontInfo = new HSLFFontInfo[FontGroup.values().length];
|
||||
}
|
||||
cachedFontInfo[fg.ordinal()] = (fontInfo != null) ? new HSLFFontInfo(fontInfo) : null;
|
||||
return;
|
||||
}
|
||||
|
||||
String propName;
|
||||
switch (fg) {
|
||||
default:
|
||||
case LATIN:
|
||||
propName = "font.index";
|
||||
break;
|
||||
case COMPLEX_SCRIPT:
|
||||
// TODO: implement TextCFException10 structure
|
||||
case EAST_ASIAN:
|
||||
propName = "asian.font.index";
|
||||
break;
|
||||
case SYMBOL:
|
||||
propName = "symbol.font.index";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Get the index for this font, if it is not to be removed (typeface == null)
|
||||
Integer fontIdx = null;
|
||||
if (fontInfo != null) {
|
||||
fontIdx = slideShow.addFont(fontInfo).getIndex();
|
||||
}
|
||||
|
||||
|
||||
setCharTextPropVal(propName, fontIdx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFontFamily() {
|
||||
return getFontFamily(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFontFamily(FontGroup fontGroup) {
|
||||
HSLFFontInfo fi = getFontInfo(fontGroup);
|
||||
return (fi != null) ? fi.getTypeface() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HSLFFontInfo getFontInfo(final FontGroup fontGroup) {
|
||||
FontGroup fg = safeFontGroup(fontGroup);
|
||||
|
||||
HSLFSheet sheet = parentParagraph.getSheet();
|
||||
@SuppressWarnings("resource")
|
||||
HSLFSlideShow slideShow = (sheet == null) ? null : sheet.getSlideShow();
|
||||
if (sheet == null || slideShow == null) {
|
||||
return _fontFamily;
|
||||
return (cachedFontInfo != null) ? cachedFontInfo[fg.ordinal()] : null;
|
||||
}
|
||||
TextProp tp = getTextParagraph().getPropVal(characterStyle, masterStyle, "font.index,asian.font.index,ansi.font.index,symbol.font.index");
|
||||
if (tp == null) { return null; }
|
||||
return slideShow.getFontCollection().getFontWithId(tp.getValue());
|
||||
|
||||
String propName;
|
||||
switch (fg) {
|
||||
default:
|
||||
case LATIN:
|
||||
propName = "font.index,ansi.font.index";
|
||||
break;
|
||||
case COMPLEX_SCRIPT:
|
||||
case EAST_ASIAN:
|
||||
propName = "asian.font.index";
|
||||
break;
|
||||
case SYMBOL:
|
||||
propName = "symbol.font.index";
|
||||
break;
|
||||
}
|
||||
|
||||
TextProp tp = getTextParagraph().getPropVal(characterStyle, masterStyle, propName);
|
||||
return (tp != null) ? slideShow.getFont(tp.getValue()) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -363,7 +434,7 @@ public final class HSLFTextRun implements TextRun {
|
||||
public void setFontColor(Color color) {
|
||||
setFontColor(DrawPaint.createSolidPaint(color));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setFontColor(PaintStyle color) {
|
||||
if (!(color instanceof SolidPaint)) {
|
||||
@ -384,7 +455,7 @@ public final class HSLFTextRun implements TextRun {
|
||||
public HSLFTextParagraph getTextParagraph() {
|
||||
return parentParagraph;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TextCap getTextCap() {
|
||||
return TextCap.NONE;
|
||||
@ -413,12 +484,12 @@ public final class HSLFTextRun implements TextRun {
|
||||
protected void setHyperlink(HSLFHyperlink link) {
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HSLFHyperlink getHyperlink() {
|
||||
return link;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HSLFHyperlink createHyperlink() {
|
||||
if (link == null) {
|
||||
@ -427,12 +498,12 @@ public final class HSLFTextRun implements TextRun {
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FieldType getFieldType() {
|
||||
HSLFTextShape ts = getTextParagraph().getParentShape();
|
||||
Placeholder ph = ts.getPlaceholder();
|
||||
|
||||
|
||||
if (ph != null) {
|
||||
switch (ph) {
|
||||
case SLIDE_NUMBER:
|
||||
@ -455,7 +526,11 @@ public final class HSLFTextRun implements TextRun {
|
||||
}
|
||||
return trList.get(0).getFieldType();
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private FontGroup safeFontGroup(FontGroup fontGroup) {
|
||||
return (fontGroup != null) ? fontGroup : FontGroup.getFontGroupFirst(getRawText());
|
||||
}
|
||||
}
|
||||
|
@ -35,9 +35,9 @@ import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.apache.poi.common.usermodel.fonts.FontInfo;
|
||||
import org.apache.poi.hwmf.record.HwmfBrushStyle;
|
||||
import org.apache.poi.hwmf.record.HwmfFont;
|
||||
import org.apache.poi.hwmf.record.HwmfHatchStyle;
|
||||
@ -48,7 +48,6 @@ import org.apache.poi.hwmf.record.HwmfPenStyle;
|
||||
import org.apache.poi.hwmf.record.HwmfPenStyle.HwmfLineDash;
|
||||
import org.apache.poi.sl.draw.DrawFactory;
|
||||
import org.apache.poi.sl.draw.DrawFontManager;
|
||||
import org.apache.poi.sl.draw.Drawable;
|
||||
import org.apache.poi.util.LocaleUtil;
|
||||
|
||||
public class HwmfGraphics {
|
||||
@ -330,9 +329,8 @@ public class HwmfGraphics {
|
||||
// TODO: another approx. ...
|
||||
double fontW = fontH/1.8;
|
||||
|
||||
int len = text.length;
|
||||
Charset charset = (font.getCharSet().getCharset() == null)?
|
||||
DEFAULT_CHARSET : font.getCharSet().getCharset();
|
||||
Charset charset = (font.getCharset().getCharset() == null)?
|
||||
DEFAULT_CHARSET : font.getCharset().getCharset();
|
||||
String textString = new String(text, charset);
|
||||
AttributedString as = new AttributedString(textString);
|
||||
if (dx == null || dx.length == 0) {
|
||||
@ -401,21 +399,10 @@ public class HwmfGraphics {
|
||||
}
|
||||
|
||||
private void addAttributes(AttributedString as, HwmfFont font) {
|
||||
DrawFontManager fontHandler = (DrawFontManager)graphicsCtx.getRenderingHint(Drawable.FONT_HANDLER);
|
||||
String fontFamily = null;
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String,String> fontMap = (Map<String,String>)graphicsCtx.getRenderingHint(Drawable.FONT_MAP);
|
||||
if (fontMap != null && fontMap.containsKey(font.getFacename())) {
|
||||
fontFamily = fontMap.get(font.getFacename());
|
||||
}
|
||||
if (fontHandler != null) {
|
||||
fontFamily = fontHandler.getRendererableFont(font.getFacename(), font.getPitchAndFamily());
|
||||
}
|
||||
if (fontFamily == null) {
|
||||
fontFamily = font.getFacename();
|
||||
}
|
||||
DrawFontManager fontHandler = DrawFactory.getInstance(graphicsCtx).getFontManager(graphicsCtx);
|
||||
FontInfo fontInfo = fontHandler.getMappedFont(graphicsCtx, font);
|
||||
|
||||
as.addAttribute(TextAttribute.FAMILY, fontFamily);
|
||||
as.addAttribute(TextAttribute.FAMILY, fontInfo.getTypeface());
|
||||
as.addAttribute(TextAttribute.SIZE, getFontHeight(font));
|
||||
as.addAttribute(TextAttribute.STRIKETHROUGH, font.isStrikeOut());
|
||||
if (font.isUnderline()) {
|
||||
|
@ -19,102 +19,18 @@ package org.apache.poi.hwmf.record;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
|
||||
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.LittleEndianConsts;
|
||||
import org.apache.poi.util.LittleEndianInputStream;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
/**
|
||||
* The Font object specifies the attributes of a logical font
|
||||
*/
|
||||
public class HwmfFont {
|
||||
|
||||
private static final POILogger logger = POILogFactory.getLogger(HwmfFont.class);
|
||||
|
||||
public enum WmfCharset {
|
||||
/** Specifies the English character set. */
|
||||
ANSI_CHARSET(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_CHARSET(0x00000001, "Cp1252"),
|
||||
/** Specifies a character set of symbols. */
|
||||
SYMBOL_CHARSET(0x00000002, ""),
|
||||
/** Specifies the Apple Macintosh character set. */
|
||||
MAC_CHARSET(0x0000004D, "MacRoman"),
|
||||
/** Specifies the Japanese character set. */
|
||||
SHIFTJIS_CHARSET(0x00000080, "Shift_JIS"),
|
||||
/** Also spelled "Hangeul". Specifies the Hangul Korean character set. */
|
||||
HANGUL_CHARSET(0x00000081, "cp949"),
|
||||
/** Also spelled "Johap". Specifies the Johab Korean character set. */
|
||||
JOHAB_CHARSET(0x00000082, "x-Johab"),
|
||||
/** Specifies the "simplified" Chinese character set for People's Republic of China. */
|
||||
GB2312_CHARSET(0x00000086, "GB2312"),
|
||||
/**
|
||||
* Specifies the "traditional" Chinese character set, used mostly in
|
||||
* Taiwan and in the Hong Kong and Macao Special Administrative Regions.
|
||||
*/
|
||||
CHINESEBIG5_CHARSET(0x00000088, "Big5"),
|
||||
/** Specifies the Greek character set. */
|
||||
GREEK_CHARSET(0x000000A1, "Cp1253"),
|
||||
/** Specifies the Turkish character set. */
|
||||
TURKISH_CHARSET(0x000000A2, "Cp1254"),
|
||||
/** Specifies the Vietnamese character set. */
|
||||
VIETNAMESE_CHARSET(0x000000A3, "Cp1258"),
|
||||
/** Specifies the Hebrew character set. */
|
||||
HEBREW_CHARSET(0x000000B1, "Cp1255"),
|
||||
/** Specifies the Arabic character set. */
|
||||
ARABIC_CHARSET(0x000000B2, "Cp1256"),
|
||||
/** Specifies the Baltic (Northeastern European) character set. */
|
||||
BALTIC_CHARSET(0x000000BA, "Cp1257"),
|
||||
/** Specifies the Russian Cyrillic character set. */
|
||||
RUSSIAN_CHARSET(0x000000CC, "Cp1251"),
|
||||
/** Specifies the Thai character set. */
|
||||
THAI_CHARSET(0x000000DE, "x-windows-874"),
|
||||
/** Specifies a Eastern European character set. */
|
||||
EASTEUROPE_CHARSET(0x000000EE, "Cp1250"),
|
||||
/**
|
||||
* Specifies a mapping to one of the OEM code pages,
|
||||
* according to the current system locale setting.
|
||||
*/
|
||||
OEM_CHARSET(0x000000FF, "Cp1252");
|
||||
|
||||
int flag;
|
||||
Charset charset;
|
||||
|
||||
WmfCharset(int flag, String javaCharsetName) {
|
||||
this.flag = flag;
|
||||
if (javaCharsetName.length() > 0) {
|
||||
try {
|
||||
charset = Charset.forName(javaCharsetName);
|
||||
return;
|
||||
} catch (UnsupportedCharsetException e) {
|
||||
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 "default"
|
||||
*/
|
||||
public Charset getCharset() {
|
||||
return charset;
|
||||
}
|
||||
|
||||
public static WmfCharset valueOf(int flag) {
|
||||
for (WmfCharset cs : values()) {
|
||||
if (cs.flag == flag) return cs;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public class HwmfFont implements FontInfo {
|
||||
|
||||
/**
|
||||
* The output precision defines how closely the output must match the requested font's height,
|
||||
@ -176,7 +92,9 @@ public class HwmfFont {
|
||||
|
||||
static WmfOutPrecision valueOf(int flag) {
|
||||
for (WmfOutPrecision op : values()) {
|
||||
if (op.flag == flag) return op;
|
||||
if (op.flag == flag) {
|
||||
return op;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -237,7 +155,9 @@ public class HwmfFont {
|
||||
|
||||
static WmfClipPrecision valueOf(int flag) {
|
||||
for (WmfClipPrecision cp : values()) {
|
||||
if (cp.flag == flag) return cp;
|
||||
if (cp.flag == flag) {
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -292,90 +212,15 @@ public class HwmfFont {
|
||||
|
||||
static WmfFontQuality valueOf(int flag) {
|
||||
for (WmfFontQuality fq : values()) {
|
||||
if (fq.flag == flag) return fq;
|
||||
if (fq.flag == flag) {
|
||||
return fq;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A property of a font that describes its general appearance.
|
||||
*/
|
||||
public enum WmfFontFamilyClass {
|
||||
/**
|
||||
* 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);
|
||||
|
||||
int flag;
|
||||
WmfFontFamilyClass(int flag) {
|
||||
this.flag = flag;
|
||||
}
|
||||
|
||||
static WmfFontFamilyClass valueOf(int flag) {
|
||||
for (WmfFontFamilyClass ff : values()) {
|
||||
if (ff.flag == flag) return ff;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A property of a font that describes the pitch, of the characters.
|
||||
*/
|
||||
public enum WmfFontPitch {
|
||||
/**
|
||||
* The default pitch, which is implementation-dependent.
|
||||
*/
|
||||
DEFAULT_PITCH (0x00),
|
||||
/**
|
||||
* A fixed pitch, which means that all the characters in the font occupy the same
|
||||
* width when output in a string.
|
||||
*/
|
||||
FIXED_PITCH (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_PITCH (0x02);
|
||||
|
||||
int flag;
|
||||
WmfFontPitch(int flag) {
|
||||
this.flag = flag;
|
||||
}
|
||||
|
||||
static WmfFontPitch valueOf(int flag) {
|
||||
for (WmfFontPitch fp : values()) {
|
||||
if (fp.flag == flag) return fp;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A 16-bit signed integer that specifies the height, in logical units, of the font's
|
||||
* character cell. The character height is computed as the character cell height minus the
|
||||
@ -454,7 +299,7 @@ public class HwmfFont {
|
||||
* If a typeface name in the FaceName field is specified, the CharSet value MUST match the
|
||||
* character set of that typeface.
|
||||
*/
|
||||
WmfCharset charSet;
|
||||
FontCharset charSet;
|
||||
|
||||
/**
|
||||
* An 8-bit unsigned integer that defines the output precision.
|
||||
@ -486,12 +331,12 @@ public class HwmfFont {
|
||||
* intended for specifying fonts when the exact typeface wanted is not available.
|
||||
* (LSB 4 bits)
|
||||
*/
|
||||
WmfFontFamilyClass family;
|
||||
FontFamily family;
|
||||
|
||||
/**
|
||||
* A property of a font that describes the pitch (MSB 2 bits)
|
||||
*/
|
||||
WmfFontPitch pitch;
|
||||
FontPitch pitch;
|
||||
|
||||
/**
|
||||
* A null-terminated string of 8-bit Latin-1 [ISO/IEC-8859-1] ANSI
|
||||
@ -509,7 +354,7 @@ public class HwmfFont {
|
||||
italic = leis.readByte() != 0;
|
||||
underline = leis.readByte() != 0;
|
||||
strikeOut = leis.readByte() != 0;
|
||||
charSet = WmfCharset.valueOf(leis.readUByte());
|
||||
charSet = FontCharset.valueOf(leis.readUByte());
|
||||
outPrecision = WmfOutPrecision.valueOf(leis.readUByte());
|
||||
clipPrecision = WmfClipPrecision.valueOf(leis.readUByte());
|
||||
quality = WmfFontQuality.valueOf(leis.readUByte());
|
||||
@ -561,10 +406,6 @@ public class HwmfFont {
|
||||
return strikeOut;
|
||||
}
|
||||
|
||||
public WmfCharset getCharSet() {
|
||||
return charSet;
|
||||
}
|
||||
|
||||
public WmfOutPrecision getOutPrecision() {
|
||||
return outPrecision;
|
||||
}
|
||||
@ -581,15 +422,53 @@ public class HwmfFont {
|
||||
return pitchAndFamily;
|
||||
}
|
||||
|
||||
public WmfFontFamilyClass getFamily() {
|
||||
return WmfFontFamilyClass.valueOf(pitchAndFamily & 0xF);
|
||||
@Override
|
||||
public FontFamily getFamily() {
|
||||
return FontFamily.valueOf(pitchAndFamily & 0xF);
|
||||
}
|
||||
|
||||
public WmfFontPitch getPitch() {
|
||||
return WmfFontPitch.valueOf((pitchAndFamily >>> 6) & 3);
|
||||
@Override
|
||||
public void setFamily(FontFamily family) {
|
||||
throw new UnsupportedOperationException("setCharset not supported by HwmfFont.");
|
||||
}
|
||||
|
||||
public String getFacename() {
|
||||
@Override
|
||||
public FontPitch getPitch() {
|
||||
return FontPitch.valueOf((pitchAndFamily >>> 6) & 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPitch(FontPitch pitch) {
|
||||
throw new UnsupportedOperationException("setPitch not supported by HwmfFont.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getIndex() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIndex(int index) {
|
||||
throw new UnsupportedOperationException("setIndex not supported by HwmfFont.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeface() {
|
||||
return facename;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTypeface(String typeface) {
|
||||
throw new UnsupportedOperationException("setTypeface not supported by HwmfFont.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FontCharset getCharset() {
|
||||
return charSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharset(FontCharset charset) {
|
||||
throw new UnsupportedOperationException("setCharset not supported by HwmfFont.");
|
||||
}
|
||||
}
|
||||
|
@ -19,13 +19,9 @@ package org.apache.poi.hwpf;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.apache.poi.hpsf.CustomProperties;
|
||||
import org.apache.poi.hpsf.DocumentSummaryInformation;
|
||||
import org.apache.poi.hpsf.Section;
|
||||
import org.apache.poi.hwmf.record.HwmfFont;
|
||||
import org.apache.poi.common.usermodel.fonts.FontCharset;
|
||||
import org.apache.poi.hwpf.model.ComplexFileTable;
|
||||
import org.apache.poi.hwpf.model.FontTable;
|
||||
import org.apache.poi.hwpf.model.OldCHPBinTable;
|
||||
@ -200,11 +196,11 @@ public class HWPFOldDocument extends HWPFDocumentCore {
|
||||
private Charset guessCodePage(OldFontTable fontTable) {
|
||||
// pick the first non-default, non-symbol charset
|
||||
for (OldFfn oldFfn : fontTable.getFontNames()) {
|
||||
HwmfFont.WmfCharset wmfCharset = HwmfFont.WmfCharset.valueOf(oldFfn.getChs()& 0xff);
|
||||
FontCharset wmfCharset = FontCharset.valueOf(oldFfn.getChs()& 0xff);
|
||||
if (wmfCharset != null &&
|
||||
wmfCharset != HwmfFont.WmfCharset.ANSI_CHARSET &&
|
||||
wmfCharset != HwmfFont.WmfCharset.DEFAULT_CHARSET &&
|
||||
wmfCharset != HwmfFont.WmfCharset.SYMBOL_CHARSET ) {
|
||||
wmfCharset != FontCharset.ANSI &&
|
||||
wmfCharset != FontCharset.DEFAULT &&
|
||||
wmfCharset != FontCharset.SYMBOL ) {
|
||||
return wmfCharset.getCharset();
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ package org.apache.poi.hwpf.model;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.apache.poi.hwmf.record.HwmfFont;
|
||||
import org.apache.poi.common.usermodel.fonts.FontCharset;
|
||||
import org.apache.poi.util.Internal;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
@ -56,7 +56,7 @@ public final class OldFfn {
|
||||
return null;
|
||||
}
|
||||
//first byte
|
||||
short fontDescriptionLength = (short) buf[offset];
|
||||
short fontDescriptionLength = buf[offset];
|
||||
offset += 1;
|
||||
if (offset + fontDescriptionLength > fontTableEnd) {
|
||||
logger.log(POILogger.WARN, "Asked to read beyond font table end. Skipping font");
|
||||
@ -67,7 +67,7 @@ public final class OldFfn {
|
||||
offset += 3;
|
||||
byte chs = buf[offset];
|
||||
Charset charset = null;
|
||||
HwmfFont.WmfCharset wmfCharset = HwmfFont.WmfCharset.valueOf(chs & 0xff);
|
||||
FontCharset wmfCharset = FontCharset.valueOf(chs & 0xff);
|
||||
if (wmfCharset == null) {
|
||||
logger.log(POILogger.WARN, "Couldn't find font for type: " + (chs & 0xff));
|
||||
} else {
|
||||
|
@ -21,12 +21,16 @@ import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.poi.common.usermodel.fonts.FontCharset;
|
||||
import org.apache.poi.common.usermodel.fonts.FontPitch;
|
||||
import org.apache.poi.hslf.usermodel.HSLFFontInfo;
|
||||
import org.apache.poi.hslf.usermodel.HSLFFontInfoPredefined;
|
||||
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/**
|
||||
* Test adding fonts to the presenataion resources
|
||||
* Test adding fonts to the presentation resources
|
||||
*/
|
||||
public final class TestPPFont {
|
||||
|
||||
@ -34,25 +38,25 @@ public final class TestPPFont {
|
||||
public void testCreate() throws IOException {
|
||||
HSLFSlideShow ppt = new HSLFSlideShow();
|
||||
assertEquals(1, ppt.getNumberOfFonts());
|
||||
assertEquals("Arial", ppt.getFont(0).getFontName());
|
||||
assertEquals("Arial", ppt.getFont(0).getTypeface());
|
||||
|
||||
//adding the same font twice
|
||||
assertEquals(0, ppt.addFont(PPFont.ARIAL));
|
||||
assertEquals(0, (int)ppt.addFont(HSLFFontInfoPredefined.ARIAL).getIndex());
|
||||
assertEquals(1, ppt.getNumberOfFonts());
|
||||
|
||||
assertEquals(1, ppt.addFont(PPFont.TIMES_NEW_ROMAN));
|
||||
assertEquals(2, ppt.addFont(PPFont.COURIER_NEW));
|
||||
assertEquals(3, ppt.addFont(PPFont.WINGDINGS));
|
||||
assertEquals(1, (int)ppt.addFont(HSLFFontInfoPredefined.TIMES_NEW_ROMAN).getIndex());
|
||||
assertEquals(2, (int)ppt.addFont(HSLFFontInfoPredefined.COURIER_NEW).getIndex());
|
||||
assertEquals(3, (int)ppt.addFont(HSLFFontInfoPredefined.WINGDINGS).getIndex());
|
||||
|
||||
assertEquals(4, ppt.getNumberOfFonts());
|
||||
|
||||
assertEquals(PPFont.TIMES_NEW_ROMAN.getFontName(), ppt.getFont(1).getFontName());
|
||||
assertEquals(PPFont.COURIER_NEW.getFontName(), ppt.getFont(2).getFontName());
|
||||
assertEquals(HSLFFontInfoPredefined.TIMES_NEW_ROMAN.getTypeface(), ppt.getFont(1).getTypeface());
|
||||
assertEquals(HSLFFontInfoPredefined.COURIER_NEW.getTypeface(), ppt.getFont(2).getTypeface());
|
||||
|
||||
PPFont font3 = ppt.getFont(3);
|
||||
assertEquals(PPFont.WINGDINGS.getFontName(), font3.getFontName());
|
||||
assertEquals(PPFont.SYMBOL_CHARSET, font3.getCharSet());
|
||||
assertEquals(PPFont.VARIABLE_PITCH, font3.getPitchAndFamily());
|
||||
HSLFFontInfo font3 = ppt.getFont(3);
|
||||
assertEquals(HSLFFontInfoPredefined.WINGDINGS.getTypeface(), font3.getTypeface());
|
||||
assertEquals(FontCharset.SYMBOL, font3.getCharset());
|
||||
assertEquals(FontPitch.VARIABLE, font3.getPitch());
|
||||
|
||||
ppt.close();
|
||||
}
|
||||
|
@ -64,8 +64,8 @@ public final class TestSlideMaster {
|
||||
|
||||
int font1 = master.get(0).getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "font.index", true).getValue();
|
||||
int font2 = master.get(1).getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "font.index", true).getValue();
|
||||
assertEquals("Arial", env.getFontCollection().getFontWithId(font1));
|
||||
assertEquals("Georgia", env.getFontCollection().getFontWithId(font2));
|
||||
assertEquals("Arial", env.getFontCollection().getFontInfo(font1).getTypeface());
|
||||
assertEquals("Georgia", env.getFontCollection().getFontInfo(font2).getTypeface());
|
||||
|
||||
CharFlagsTextProp prop1 = (CharFlagsTextProp)master.get(0).getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "char_flags", true);
|
||||
assertEquals(false, prop1.getSubValue(CharFlagsTextProp.BOLD_IDX));
|
||||
@ -83,8 +83,8 @@ public final class TestSlideMaster {
|
||||
|
||||
int b1 = master.get(0).getStyleAttribute(TextHeaderAtom.BODY_TYPE, 0, "bullet.font", false).getValue();
|
||||
int b2 = master.get(1).getStyleAttribute(TextHeaderAtom.BODY_TYPE, 0, "bullet.font", false).getValue();
|
||||
assertEquals("Arial", env.getFontCollection().getFontWithId(b1));
|
||||
assertEquals("Georgia", env.getFontCollection().getFontWithId(b2));
|
||||
assertEquals("Arial", env.getFontCollection().getFontInfo(b1).getTypeface());
|
||||
assertEquals("Georgia", env.getFontCollection().getFontInfo(b2).getTypeface());
|
||||
|
||||
ppt.close();
|
||||
}
|
||||
|
@ -18,29 +18,34 @@
|
||||
package org.apache.poi.hslf.record;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.poi.hslf.usermodel.HSLFFontInfo;
|
||||
import org.apache.poi.hslf.usermodel.HSLFFontInfoPredefined;
|
||||
import org.apache.poi.poifs.storage.RawDataUtil;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests <code>FontCollection</code> and <code>FontEntityAtom</code> records
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
* Tests {@code FontCollection} and {@code FontEntityAtom} records
|
||||
*/
|
||||
public final class TestFontCollection extends TestCase {
|
||||
public final class TestFontCollection {
|
||||
// From a real file
|
||||
private final byte[] data = new byte[] {
|
||||
0x0F, 0x00, 0xD5-256, 0x07, 0x4C, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xB7-256, 0x0F, 0x44, 0x00, 0x00, 0x00,
|
||||
0x54, 0x00, 0x69, 0x00, 0x6D, 0x00, 0x65, 0x00, 0x73, 0x00,
|
||||
0x20, 0x00, 0x4E, 0x00, 0x65, 0x00, 0x77, 0x00, 0x20, 0x00,
|
||||
0x52, 0x00, 0x6F, 0x00, 0x6D, 0x00, 0x61, 0x00, 0x6E, 0x00,
|
||||
0x00, 0x00, 0x74, 0x34, 0xB8-256, 0x00, 0x7C, 0xDA-256, 0x12, 0x00,
|
||||
0x64, 0xDA-256, 0x12, 0x00, 0x76, 0xC7-256, 0x0B, 0x30, 0x08, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xDA-256, 0x12, 0x00,
|
||||
0x28, 0xDD-256, 0x0D, 0x30, 0x00, 0x00, 0x04, 0x00 };
|
||||
private static byte[] data;
|
||||
|
||||
@BeforeClass
|
||||
public static void init() throws IOException {
|
||||
data = RawDataUtil.decompress(
|
||||
"H4sIAAAAAAAAAONnuMruwwAC2/ldgGQIQyZDLkMqQzGDAoMfkC4H0kEM+U"+
|
||||
"CxRIY8oHyJyQ6GmltCDClAXHac24CDAQJAYhp3eQ0YGFgYAAusGftUAAAA"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFonts() {
|
||||
FontCollection fonts = new FontCollection(data, 0, data.length);
|
||||
Record[] child = fonts.getChildRecords();
|
||||
@ -50,28 +55,31 @@ public final class TestFontCollection extends TestCase {
|
||||
assertEquals(fnt.getFontName(), "Times New Roman");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddFont() {
|
||||
FontCollection fonts = new FontCollection(data, 0, data.length);
|
||||
int idx = fonts.addFont("Times New Roman");
|
||||
assertEquals(idx, 0);
|
||||
idx = fonts.addFont("Helvetica");
|
||||
assertEquals(idx, 1);
|
||||
idx = fonts.addFont("Arial");
|
||||
assertEquals(idx, 2);
|
||||
idx = fonts.addFont("Arial"); //the font being added twice
|
||||
assertEquals(idx, 2);
|
||||
HSLFFontInfo fi = fonts.addFont(HSLFFontInfoPredefined.TIMES_NEW_ROMAN);
|
||||
assertEquals((int)fi.getIndex(), 0);
|
||||
fi = fonts.addFont(new HSLFFontInfo("Helvetica"));
|
||||
assertEquals((int)fi.getIndex(), 1);
|
||||
fi = fonts.addFont(HSLFFontInfoPredefined.ARIAL);
|
||||
assertEquals((int)fi.getIndex(), 2);
|
||||
//the font being added twice
|
||||
fi = fonts.addFont(HSLFFontInfoPredefined.ARIAL);
|
||||
assertEquals((int)fi.getIndex(), 2);
|
||||
|
||||
// Font collection should contain 3 fonts
|
||||
Record[] child = fonts.getChildRecords();
|
||||
assertEquals(child.length, 3);
|
||||
|
||||
// Check we get the right font name for the indicies
|
||||
assertEquals("Times New Roman", fonts.getFontWithId(0));
|
||||
assertEquals("Helvetica", fonts.getFontWithId(1));
|
||||
assertEquals("Arial", fonts.getFontWithId(2));
|
||||
assertNull(fonts.getFontWithId(3));
|
||||
assertEquals("Times New Roman", fonts.getFontInfo(0).getTypeface());
|
||||
assertEquals("Helvetica", fonts.getFontInfo(1).getTypeface());
|
||||
assertEquals("Arial", fonts.getFontInfo(2).getTypeface());
|
||||
assertNull(fonts.getFontInfo(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrite() throws Exception {
|
||||
FontCollection fonts = new FontCollection(data, 0, data.length);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
@ -49,6 +49,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.poi.POIDataSamples;
|
||||
import org.apache.poi.common.usermodel.fonts.FontGroup;
|
||||
import org.apache.poi.ddf.AbstractEscherOptRecord;
|
||||
import org.apache.poi.ddf.EscherArrayProperty;
|
||||
import org.apache.poi.ddf.EscherColorRef;
|
||||
@ -848,7 +849,7 @@ public final class TestBugs {
|
||||
for (List<HSLFTextParagraph> paraList : sl.getTextParagraphs()) {
|
||||
for (HSLFTextParagraph htp : paraList) {
|
||||
for (HSLFTextRun htr : htp) {
|
||||
String actFamily = htr.getFontFamily();
|
||||
String actFamily = htr.getFontFamily(FontGroup.EAST_ASIAN);
|
||||
assertEquals(expFamily, actFamily);
|
||||
}
|
||||
}
|
||||
|
@ -17,11 +17,9 @@
|
||||
|
||||
package org.apache.poi.hwmf;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.apache.poi.POITestCase.assertContains;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
@ -40,6 +38,8 @@ import java.util.Locale;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.apache.poi.POIDataSamples;
|
||||
import org.apache.poi.hwmf.record.HwmfFill.HwmfImageRecord;
|
||||
import org.apache.poi.hwmf.record.HwmfFont;
|
||||
@ -118,7 +118,9 @@ public class TestHwmfParsing {
|
||||
SlideShow<?,?> ss = SlideShowFactory.create(fis);
|
||||
int wmfIdx = 1;
|
||||
for (PictureData pd : ss.getPictureData()) {
|
||||
if (pd.getType() != PictureType.WMF) continue;
|
||||
if (pd.getType() != PictureType.WMF) {
|
||||
continue;
|
||||
}
|
||||
byte wmfData[] = pd.getData();
|
||||
String filename = String.format(Locale.ROOT, "%s-%04d.wmf", basename, wmfIdx);
|
||||
FileOutputStream fos = new FileOutputStream(new File(outdir, filename));
|
||||
@ -211,7 +213,7 @@ public class TestHwmfParsing {
|
||||
for (HwmfRecord r : wmf.getRecords()) {
|
||||
if (r.getRecordType().equals(HwmfRecordType.createFontIndirect)) {
|
||||
HwmfFont font = ((HwmfText.WmfCreateFontIndirect)r).getFont();
|
||||
charset = (font.getCharSet().getCharset() == null) ? LocaleUtil.CHARSET_1252 : font.getCharSet().getCharset();
|
||||
charset = (font.getCharset().getCharset() == null) ? LocaleUtil.CHARSET_1252 : font.getCharset().getCharset();
|
||||
}
|
||||
if (r.getRecordType().equals(HwmfRecordType.extTextOut)) {
|
||||
HwmfText.WmfExtTextOut textOut = (HwmfText.WmfExtTextOut)r;
|
||||
@ -239,7 +241,7 @@ public class TestHwmfParsing {
|
||||
for (HwmfRecord r : wmf.getRecords()) {
|
||||
if (r.getRecordType().equals(HwmfRecordType.createFontIndirect)) {
|
||||
HwmfFont font = ((HwmfText.WmfCreateFontIndirect)r).getFont();
|
||||
charset = (font.getCharSet().getCharset() == null) ? LocaleUtil.CHARSET_1252 : font.getCharSet().getCharset();
|
||||
charset = (font.getCharset().getCharset() == null) ? LocaleUtil.CHARSET_1252 : font.getCharset().getCharset();
|
||||
}
|
||||
if (r.getRecordType().equals(HwmfRecordType.extTextOut)) {
|
||||
HwmfText.WmfExtTextOut textOut = (HwmfText.WmfExtTextOut)r;
|
||||
|
@ -24,7 +24,7 @@ import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.apache.poi.OldFileFormatException;
|
||||
import org.apache.poi.hwmf.record.HwmfFont;
|
||||
import org.apache.poi.common.usermodel.fonts.FontCharset;
|
||||
import org.apache.poi.hwpf.HWPFOldDocument;
|
||||
import org.apache.poi.hwpf.HWPFTestCase;
|
||||
import org.apache.poi.hwpf.HWPFTestDataSamples;
|
||||
@ -201,7 +201,7 @@ public final class TestHWPFOldDocument extends HWPFTestCase {
|
||||
OldFontTable oldFontTable = doc.getOldFontTable();
|
||||
assertEquals(5, oldFontTable.getFontNames().length);
|
||||
assertEquals("\u7D30\u660E\u9AD4", oldFontTable.getFontNames()[0].getMainFontName());
|
||||
assertEquals(HwmfFont.WmfCharset.CHINESEBIG5_CHARSET.getCharset(), Charset.forName("Big5"));
|
||||
assertEquals(FontCharset.CHINESEBIG5.getCharset(), Charset.forName("Big5"));
|
||||
assertEquals("Times New Roman", oldFontTable.getFontNames()[1].getMainFontName());
|
||||
doc.close();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user