diff options
author | Glenn Adams <gadams@apache.org> | 2016-03-03 09:49:26 +0000 |
---|---|---|
committer | Glenn Adams <gadams@apache.org> | 2016-03-03 09:49:26 +0000 |
commit | c8cde713f54ca731f4a7f3bfaef8af9e8a1b9262 (patch) | |
tree | f553e13b28bd90fd2067bf390509f9290260d330 /src/java/org/apache/fop/fonts | |
parent | 82804d6ffcb68841cd7adf9740469f3a79c372c8 (diff) | |
download | xmlgraphics-fop-c8cde713f54ca731f4a7f3bfaef8af9e8a1b9262.tar.gz xmlgraphics-fop-c8cde713f54ca731f4a7f3bfaef8af9e8a1b9262.zip |
Transition source to standard maven hierarchy (initial).
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/maven@1733433 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop/fonts')
106 files changed, 0 insertions, 25375 deletions
diff --git a/src/java/org/apache/fop/fonts/AbstractCodePointMapping.java b/src/java/org/apache/fop/fonts/AbstractCodePointMapping.java deleted file mode 100644 index ca0c52d5e..000000000 --- a/src/java/org/apache/fop/fonts/AbstractCodePointMapping.java +++ /dev/null @@ -1,216 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.util.Arrays; - -import org.apache.xmlgraphics.fonts.Glyphs; - -import org.apache.fop.util.CharUtilities; - -/** - * Abstract base class for code point mapping classes (1-byte character encodings). - */ -public class AbstractCodePointMapping implements SingleByteEncoding { - - private final String name; - private char[] latin1Map; - private char[] characters; - private char[] codepoints; - private char[] unicodeMap; //code point to Unicode char - private String[] charNameMap; //all character names in the encoding - - /** - * Main constructor. - * @param name the name of the encoding - * @param table the table ([code point, unicode scalar value]+) with the mapping - */ - public AbstractCodePointMapping(String name, int[] table) { - this(name, table, null); - } - - /** - * Extended constructor. - * @param name the name of the encoding - * @param table the table ([code point, unicode scalar value]+) with the mapping - * @param charNameMap all character names in the encoding (a value of null will be converted - * to ".notdef") - */ - public AbstractCodePointMapping(String name, int[] table, String[] charNameMap) { - this.name = name; - buildFromTable(table); - if (charNameMap != null) { - this.charNameMap = new String[256]; - for (int i = 0; i < 256; i++) { - String charName = charNameMap[i]; - if (charName == null) { - this.charNameMap[i] = Glyphs.NOTDEF; - } else { - this.charNameMap[i] = charName; - } - } - } - } - - /** - * Builds the internal lookup structures based on a given table. - * @param table the table ([code point, unicode scalar value]+) with the mapping - */ - protected void buildFromTable(int[] table) { - int nonLatin1 = 0; - latin1Map = new char[256]; - unicodeMap = new char[256]; - Arrays.fill(unicodeMap, CharUtilities.NOT_A_CHARACTER); - for (int i = 0; i < table.length; i += 2) { - char unicode = (char)table[i + 1]; - if (unicode < 256) { - if (latin1Map[unicode] == 0) { - latin1Map[unicode] = (char) table[i]; - } - } else { - ++nonLatin1; - } - if (unicodeMap[table[i]] == CharUtilities.NOT_A_CHARACTER) { - unicodeMap[table[i]] = unicode; - } - } - characters = new char[nonLatin1]; - codepoints = new char[nonLatin1]; - int top = 0; - for (int i = 0; i < table.length; i += 2) { - char c = (char) table[i + 1]; - if (c >= 256) { - ++top; - for (int j = top - 1; j >= 0; --j) { - if (j > 0 && characters[j - 1] >= c) { - characters[j] = characters[j - 1]; - codepoints[j] = codepoints[j - 1]; - } else { - characters[j] = c; - codepoints[j] = (char) table[i]; - break; - } - } - } - } - } - - /** {@inheritDoc} */ - public String getName() { - return this.name; - } - - /** {@inheritDoc} */ - public final char mapChar(char c) { - if (c < 256) { - char latin1 = latin1Map[c]; - if (latin1 > 0) { - return latin1; - } - } - int bot = 0; - int top = characters.length - 1; - while (top >= bot) { - assert bot < 65536; - assert top < 65536; - int mid = (bot + top) >>> 1; - char mc = characters[mid]; - - if (c == mc) { - return codepoints[mid]; - } else if (c < mc) { - top = mid - 1; - } else { - bot = mid + 1; - } - } - return NOT_FOUND_CODE_POINT; - } - - /** - * Returns the main Unicode value that is associated with the given code point in the encoding. - * Note that multiple Unicode values can theoretically be mapped to one code point in the - * encoding. - * @param idx the code point in the encoding - * @return the Unicode value (or \uFFFF (NOT A CHARACTER) if no Unicode value is at that point) - */ - public final char getUnicodeForIndex(int idx) { - return this.unicodeMap[idx]; - } - - /** {@inheritDoc} */ - public final char[] getUnicodeCharMap() { - char[] copy = new char[this.unicodeMap.length]; - System.arraycopy(this.unicodeMap, 0, copy, 0, this.unicodeMap.length); - return copy; - } - - /** - * Returns the index of a character/glyph with the given name. Note that this - * method is relatively slow and should only be used for fallback operations. - * @param charName the character name - * @return the index of the character in the encoding or -1 if it doesn't exist - */ - public short getCodePointForGlyph(String charName) { - String[] names = this.charNameMap; - if (names == null) { - names = getCharNameMap(); - } - for (short i = 0, c = (short)names.length; i < c; i++) { - if (names[i].equals(charName)) { - return i; - } - } - return -1; - } - - public String getNameFromCodePoint(int idx) { - return getCharNameMap()[idx]; - } - - /** {@inheritDoc} */ - public String[] getCharNameMap() { - if (this.charNameMap != null) { - String[] copy = new String[this.charNameMap.length]; - System.arraycopy(this.charNameMap, 0, copy, 0, this.charNameMap.length); - return copy; - } else { - //Note: this is suboptimal but will probably never be used. - String[] derived = new String[256]; - Arrays.fill(derived, Glyphs.NOTDEF); - for (int i = 0; i < 256; i++) { - char c = getUnicodeForIndex(i); - if (c != CharUtilities.NOT_A_CHARACTER) { - String charName = Glyphs.charToGlyphName(c); - if (charName.length() > 0) { - derived[i] = charName; - } - } - } - return derived; - } - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return getName(); - } -} diff --git a/src/java/org/apache/fop/fonts/Base14Font.java b/src/java/org/apache/fop/fonts/Base14Font.java deleted file mode 100644 index fdefd0cdd..000000000 --- a/src/java/org/apache/fop/fonts/Base14Font.java +++ /dev/null @@ -1,39 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - - -/** - * Base class for all Base 14 fonts. - */ -public abstract class Base14Font extends Typeface { - - /** Thickness for underline and strikeout. */ - private static final int LINE_THICKNESS = 50; - - public int getStrikeoutPosition(int size) { - return getXHeight(size) / 2; - } - - public int getStrikeoutThickness(int size) { - return size * LINE_THICKNESS; - } - -} diff --git a/src/java/org/apache/fop/fonts/CIDFont.java b/src/java/org/apache/fop/fonts/CIDFont.java deleted file mode 100644 index dc398263e..000000000 --- a/src/java/org/apache/fop/fonts/CIDFont.java +++ /dev/null @@ -1,88 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import org.apache.fop.apps.io.InternalResourceResolver; - -//Java - -/** - * Abstract base class for CID fonts. - */ -public abstract class CIDFont extends CustomFont { - - /** Contains the character widths for all characters in the font */ - protected int[] width; - - /** - * @param resourceResolver the URI resolver for controlling file access - */ - public CIDFont(InternalResourceResolver resourceResolver) { - super(resourceResolver); - } - - // ---- Required ---- - /** - * Returns the type of the CID font. - * @return the type of the CID font - */ - public abstract CIDFontType getCIDType(); - - /** - * Returns the name of the issuer of the font. - * @return a String identifying an issuer of character collections - - * for example, Adobe - */ - public abstract String getRegistry(); - - /** - * Returns a font name for use within a registry. - * @return a String that uniquely names a character collection issued by - * a specific registry - for example, Japan1. - */ - public abstract String getOrdering(); - - /** - * Returns the supplement number of the character collection. - * @return the supplement number - */ - public abstract int getSupplement(); - - /** - * Returns the subset information for this font. - * @return the subset information - */ - public abstract CIDSet getCIDSet(); - - // ---- Optional ---- - /** - * Returns the default width for this font. - * @return the default width - */ - public int getDefaultWidth() { - return 0; - } - - /** {@inheritDoc} */ - public boolean isMultiByte() { - return true; - } - -} diff --git a/src/java/org/apache/fop/fonts/CIDFontType.java b/src/java/org/apache/fop/fonts/CIDFontType.java deleted file mode 100644 index 20a94b9dd..000000000 --- a/src/java/org/apache/fop/fonts/CIDFontType.java +++ /dev/null @@ -1,82 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import org.apache.avalon.framework.ValuedEnum; - -/** - * This class enumerates all supported CID font types. - */ -public class CIDFontType extends ValuedEnum { - - /** - * CID Font Type 0 (based on Type 1 format) - */ - public static final CIDFontType CIDTYPE0 = new CIDFontType("CIDFontType0", 0); - - /** - * CID Font Type 2 (based on TrueType format) - */ - public static final CIDFontType CIDTYPE2 = new CIDFontType("CIDFontType2", 2); - - - /** - * Construct a CID font type. - * @param name a type name - * @param value a type value - * @see org.apache.avalon.framework.Enum#Enum(String) - */ - protected CIDFontType(String name, int value) { - super(name, value); - } - - - /** - * Returns the CIDFontType by name. - * @param name Name of the CID font type to look up - * @return FontType the CID font type - */ - public static CIDFontType byName(String name) { - if (name.equalsIgnoreCase(CIDFontType.CIDTYPE0.getName())) { - return CIDFontType.CIDTYPE0; - } else if (name.equalsIgnoreCase(CIDFontType.CIDTYPE2.getName())) { - return CIDFontType.CIDTYPE2; - } else { - throw new IllegalArgumentException("Invalid CID font type: " + name); - } - } - - - /** - * Returns the CID FontType by value. - * @param value Value of the CID font type to look up - * @return FontType the CID font type - */ - public static CIDFontType byValue(int value) { - if (value == CIDFontType.CIDTYPE0.getValue()) { - return CIDFontType.CIDTYPE0; - } else if (value == CIDFontType.CIDTYPE2.getValue()) { - return CIDFontType.CIDTYPE2; - } else { - throw new IllegalArgumentException("Invalid CID font type: " + value); - } - } - -} diff --git a/src/java/org/apache/fop/fonts/CIDFull.java b/src/java/org/apache/fop/fonts/CIDFull.java deleted file mode 100644 index 1130459b7..000000000 --- a/src/java/org/apache/fop/fonts/CIDFull.java +++ /dev/null @@ -1,124 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.util.BitSet; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.apache.fop.util.CharUtilities; - -/** - * Provides methods to get font information. - * Naming: - * glyph index: original index of the glyph in the non-subset font (!= unicode index) - * character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For non-subset - * fonts, this is the same as the glyph index. - * Unicode index: The Unicode codepoint of a character. - * Glyph name: the Adobe glyph name (as found in Glyphs.java) - */ -public class CIDFull implements CIDSet { - - private BitSet glyphIndices; - private final MultiByteFont font; - - public CIDFull(MultiByteFont mbf) { - font = mbf; - } - - private void initGlyphIndices() { - // this cannot be called in the constructor since the font is not ready... - if (glyphIndices == null) { - glyphIndices = font.getGlyphIndices(); - } - } - - /** {@inheritDoc} */ - public int getOriginalGlyphIndex(int index) { - return index; - } - - /** {@inheritDoc} */ - @Override - public char getUnicodeFromGID(int glyphIndex) { - return ' '; - } - - /** {@inheritDoc} */ - @Override - public int getGIDFromChar(char ch) { - return ch; - } - - /** {@inheritDoc} */ - public char getUnicode(int index) { - initGlyphIndices(); - if (glyphIndices.get(index)) { - return (char) index; - } else { - return CharUtilities.NOT_A_CHARACTER; - } - } - - /** {@inheritDoc} */ - public int mapChar(int glyphIndex, char unicode) { - return (char) glyphIndex; - } - - /** {@inheritDoc} */ - public Map<Integer, Integer> getGlyphs() { - // this is never really called for full embedded fonts but the equivalent map would be the identity - initGlyphIndices(); - Map<Integer, Integer> glyphs = new HashMap<Integer, Integer>(); - int nextBitSet = 0; - for (int j = 0; j < glyphIndices.cardinality(); j++) { - nextBitSet = glyphIndices.nextSetBit(nextBitSet); - glyphs.put(Integer.valueOf(nextBitSet), Integer.valueOf(nextBitSet)); - nextBitSet++; - } - return Collections.unmodifiableMap(glyphs); - } - - /** {@inheritDoc} */ - public char[] getChars() { - return font.getChars(); - } - - /** {@inheritDoc} */ - public int getNumberOfGlyphs() { - initGlyphIndices(); - // note: the real number of glyphs is given by the cardinality() method (not the length()) but since - // we will pad gaps in the indices with zeros we really want the length() here. this method is only - // called when embedding a font in PostScript and this will be the value of the CIDCount entry - return glyphIndices.length(); - } - - /** {@inheritDoc} */ - public BitSet getGlyphIndices() { - initGlyphIndices(); - return glyphIndices; - } - - /** {@inheritDoc} */ - public int[] getWidths() { - return font.getWidths(); - } -} diff --git a/src/java/org/apache/fop/fonts/CIDSet.java b/src/java/org/apache/fop/fonts/CIDSet.java deleted file mode 100644 index acfc705c8..000000000 --- a/src/java/org/apache/fop/fonts/CIDSet.java +++ /dev/null @@ -1,104 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.util.BitSet; -import java.util.Map; - -/** - * Declares methods to retrieve font information (glyph indices, widths, unicode values) from a CID font. - */ -public interface CIDSet { - - /** - * Returns the original index of the glyph inside the (non-subset) font's glyph list. This - * index can be used to access the character width information, for example. - * @param index the subset index (character selector) to access the glyph - * @return the original index (or -1 if no glyph index is available for the subset index) - */ - int getOriginalGlyphIndex(int index); - - /** - * Returns the Unicode value for a subset index (character selector). If there's no such - * Unicode value, the "NOT A CHARACTER" (0xFFFF) is returned. - * @param index the subset index (character selector) - * @return the Unicode value or "NOT A CHARACTER" (0xFFFF) - */ - char getUnicode(int index); - - /** - * Gets the unicode character from the original font glyph index - * @param glyphIndex The original glyph index of the character in the font - * @return The character represented by the passed GID - */ - char getUnicodeFromGID(int glyphIndex); - - /** - * Returns the glyph index from the original font from a character - * @param ch The character - * @return The glyph index in the original font. - */ - int getGIDFromChar(char ch); - - /** - * Maps a character to a character selector for a font subset. If the character isn't in the - * subset, yet, it is added and a new character selector returned. Otherwise, the already - * allocated character selector is returned from the existing map/subset. - * @param glyphIndex the glyph index of the character - * @param unicode the Unicode index of the character - * @return the subset index - */ - int mapChar(int glyphIndex, char unicode); - - /** - * Returns an unmodifiable Map of the font subset. It maps from glyph index to - * character selector (i.e. the subset index in this case). - * @return Map Map<Integer, Integer> of the font subset - */ - Map<Integer, Integer> getGlyphs(); - - /** - * Returns a char array containing all Unicode characters that are in the subset. - * @return a char array with all used Unicode characters - */ - char[] getChars(); - - /** - * Returns the number of glyphs in the subset. - * @return the number of glyphs in the subset - */ - int getNumberOfGlyphs(); - - /** - * Returns a BitSet with bits set for each available glyph index in the subset. - * @return a BitSet indicating available glyph indices - */ - BitSet getGlyphIndices(); - - /** - * Return the array of widths. - * <p> - * This is used to get an array for inserting in an output format. - * It should not be used for lookup. - * @return an array of widths - */ - int[] getWidths(); - -} diff --git a/src/java/org/apache/fop/fonts/CIDSubset.java b/src/java/org/apache/fop/fonts/CIDSubset.java deleted file mode 100644 index 01b8495f8..000000000 --- a/src/java/org/apache/fop/fonts/CIDSubset.java +++ /dev/null @@ -1,160 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.util.BitSet; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.apache.fop.util.CharUtilities; - -/** - * Provides methods to get font information. - * Naming: - * glyph index: original index of the glyph in the non-subset font (!= unicode index) - * character selector: index into a set of glyphs. For subset CID fonts, this starts at 0. For non-subset - * fonts, this is the same as the glyph index. - * Unicode index: The Unicode codepoint of a character. - * Glyph name: the Adobe glyph name (as found in Glyphs.java) - */ -public class CIDSubset implements CIDSet { - - /** - * usedGlyphs contains orginal, new glyph index (glyph index -> char selector) - */ - private Map<Integer, Integer> usedGlyphs = new HashMap<Integer, Integer>(); - - /** - * usedGlyphsIndex contains new glyph, original index (char selector -> glyph index) - */ - private Map<Integer, Integer> usedGlyphsIndex = new HashMap<Integer, Integer>(); - private int usedGlyphsCount; - - /** - * usedCharsIndex contains new glyph, original char (char selector -> Unicode) - */ - private Map<Integer, Character> usedCharsIndex = new HashMap<Integer, Character>(); - - /** - * A map between the original character and it's GID in the original font. - */ - private Map<Character, Integer> charToGIDs = new HashMap<Character, Integer>(); - - - private final MultiByteFont font; - - public CIDSubset(MultiByteFont mbf) { - font = mbf; - // The zeroth value is reserved for .notdef - usedGlyphs.put(0, 0); - usedGlyphsIndex.put(0, 0); - usedGlyphsCount++; - } - - /** {@inheritDoc} */ - public int getOriginalGlyphIndex(int index) { - Integer glyphIndex = usedGlyphsIndex.get(index); - if (glyphIndex != null) { - return glyphIndex; - } else { - return -1; - } - } - - /** {@inheritDoc} */ - public char getUnicode(int index) { - Character mapValue = usedCharsIndex.get(index); - if (mapValue != null) { - return mapValue.charValue(); - } else { - return CharUtilities.NOT_A_CHARACTER; - } - } - - /** {@inheritDoc} */ - public int mapChar(int glyphIndex, char unicode) { - // Reencode to a new subset font or get the reencoded value - // IOW, accumulate the accessed characters and build a character map for them - Integer subsetCharSelector = usedGlyphs.get(glyphIndex); - if (subsetCharSelector == null) { - int selector = usedGlyphsCount; - usedGlyphs.put(glyphIndex, selector); - usedGlyphsIndex.put(selector, glyphIndex); - usedCharsIndex.put(selector, unicode); - charToGIDs.put(unicode, glyphIndex); - usedGlyphsCount++; - return selector; - } else { - return subsetCharSelector; - } - } - - /** {@inheritDoc} */ - public Map<Integer, Integer> getGlyphs() { - return Collections.unmodifiableMap(this.usedGlyphs); - } - - /** {@inheritDoc} */ - public char getUnicodeFromGID(int glyphIndex) { - int selector = usedGlyphs.get(glyphIndex); - return usedCharsIndex.get(selector); - } - - /** {@inheritDoc} */ - public int getGIDFromChar(char ch) { - return charToGIDs.get(ch); - } - - /** {@inheritDoc} */ - public char[] getChars() { - char[] charArray = new char[usedGlyphsCount]; - for (int i = 0; i < usedGlyphsCount; i++) { - charArray[i] = getUnicode(i); - } - return charArray; - } - - /** {@inheritDoc} */ - public int getNumberOfGlyphs() { - return this.usedGlyphsCount; - } - - /** {@inheritDoc} */ - public BitSet getGlyphIndices() { - BitSet bitset = new BitSet(); - for (Integer cid : usedGlyphs.keySet()) { - bitset.set(cid); - } - return bitset; - } - - /** {@inheritDoc} */ - public int[] getWidths() { - int[] widths = font.getWidths(); - int[] tmpWidth = new int[getNumberOfGlyphs()]; - for (int i = 0, c = getNumberOfGlyphs(); i < c; i++) { - int nwx = Math.max(0, getOriginalGlyphIndex(i)); - tmpWidth[i] = widths[nwx]; - } - return tmpWidth; - } - -} diff --git a/src/java/org/apache/fop/fonts/CMapSegment.java b/src/java/org/apache/fop/fonts/CMapSegment.java deleted file mode 100644 index 664ae727f..000000000 --- a/src/java/org/apache/fop/fonts/CMapSegment.java +++ /dev/null @@ -1,106 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -/** - * A segment in a cmap table of format 4. Unicode code points between - * {@link #getUnicodeStart()} and {@link #getUnicodeEnd()} map to contiguous glyph indices - * starting from {@link #getGlyphStartIndex()}. - */ -public final class CMapSegment { - - private final int unicodeStart; - private final int unicodeEnd; - private final int glyphStartIndex; - - /** - * Creates a new segment. - * - * @param unicodeStart Unicode start index - * @param unicodeEnd Unicode end index - * @param glyphStartIndex glyph start index - */ - public CMapSegment(int unicodeStart, int unicodeEnd, int glyphStartIndex) { - this.unicodeStart = unicodeStart; - this.unicodeEnd = unicodeEnd; - this.glyphStartIndex = glyphStartIndex; - } - - @Override - public int hashCode() { - int hc = 17; - hc = 31 * hc + unicodeStart; - hc = 31 * hc + unicodeEnd; - hc = 31 * hc + glyphStartIndex; - return hc; - } - - @Override - public boolean equals(Object o) { - if (o instanceof CMapSegment) { - CMapSegment ce = (CMapSegment) o; - return ce.unicodeStart == this.unicodeStart - && ce.unicodeEnd == this.unicodeEnd - && ce.glyphStartIndex == this.glyphStartIndex; - } - return false; - } - - /** - * Returns the unicodeStart. - * @return the Unicode start index - */ - public int getUnicodeStart() { - return unicodeStart; - } - - /** - * Returns the unicodeEnd. - * @return the Unicode end index - */ - public int getUnicodeEnd() { - return unicodeEnd; - } - - /** - * Returns the glyphStartIndex. - * @return the glyph start index - */ - public int getGlyphStartIndex() { - return glyphStartIndex; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuilder sb = new StringBuilder("CMapSegment: "); - sb.append("{ UC["); - sb.append(unicodeStart); - sb.append(','); - sb.append(unicodeEnd); - sb.append("]: GC["); - sb.append(glyphStartIndex); - sb.append(','); - sb.append(glyphStartIndex + (unicodeEnd - unicodeStart)); - sb.append("] }"); - return sb.toString(); - } - -} diff --git a/src/java/org/apache/fop/fonts/CustomFont.java b/src/java/org/apache/fop/fonts/CustomFont.java deleted file mode 100644 index 6f325d96d..000000000 --- a/src/java/org/apache/fop/fonts/CustomFont.java +++ /dev/null @@ -1,583 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.fop.apps.io.InternalResourceResolver; - - -/** - * Abstract base class for custom fonts loaded from files, for example. - */ -public abstract class CustomFont extends Typeface - implements FontDescriptor, MutableFont { - - /** Fallback thickness for underline and strikeout when not provided by the font. */ - private static final int DEFAULT_LINE_THICKNESS = 50; - - private URI fontFileURI; - private String fontName; - private String fullName; - private Set<String> familyNames; - private String fontSubName; - private URI embedFileURI; - private String embedResourceName; - private final InternalResourceResolver resourceResolver; - private EmbeddingMode embeddingMode = EmbeddingMode.AUTO; - - private int capHeight; - private int xHeight; - private int ascender; - private int descender; - private int[] fontBBox = {0, 0, 0, 0}; - private int flags = 4; - private int weight; //0 means unknown weight - private int stemV; - private int italicAngle; - private int missingWidth; - private FontType fontType = FontType.TYPE1; - private int firstChar; - private int lastChar = 255; - - private int underlinePosition; - - private int underlineThickness; - - private int strikeoutPosition; - - private int strikeoutThickness; - - private Map<Integer, Map<Integer, Integer>> kerning; - - private boolean useKerning = true; - /** the character map, mapping Unicode ranges to glyph indices. */ - protected List<CMapSegment> cmap = new ArrayList<CMapSegment>(); - private boolean useAdvanced = true; - - /** - * @param resourceResolver the URI resource resolver for controlling file access - */ - public CustomFont(InternalResourceResolver resourceResolver) { - this.resourceResolver = resourceResolver; - } - - - /** {@inheritDoc} */ - public URI getFontURI() { - return fontFileURI; - } - - /** {@inheritDoc} */ - public String getFontName() { - return fontName; - } - - /** {@inheritDoc} */ - public String getEmbedFontName() { - return getFontName(); - } - - /** {@inheritDoc} */ - public String getFullName() { - return fullName; - } - - /** - * Returns the font family names. - * @return the font family names (a Set of Strings) - */ - public Set<String> getFamilyNames() { - return Collections.unmodifiableSet(this.familyNames); - } - - /** - * Returns the font family name stripped of whitespace. - * @return the stripped font family - * @see FontUtil#stripWhiteSpace(String) - */ - public String getStrippedFontName() { - return FontUtil.stripWhiteSpace(getFontName()); - } - - /** - * Returns font's subfamily name. - * @return the font's subfamily name - */ - public String getFontSubName() { - return fontSubName; - } - - /** - * Returns an URI representing an embeddable font file. - * - * @return URI to an embeddable font file or null if not available. - */ - public URI getEmbedFileURI() { - return embedFileURI; - } - - /** - - * Returns the embedding mode for this font. - * @return embedding mode - */ - public EmbeddingMode getEmbeddingMode() { - return embeddingMode; - } - - /** - * Returns an {@link InputStream} representing an embeddable font file. - * - * @return {@link InputStream} for an embeddable font file - * @throws IOException if embedFileName is not null but Source is not found - */ - public InputStream getInputStream() throws IOException { - return resourceResolver.getResource(embedFileURI); - } - - /** - * Returns the lookup name to an embeddable font file available as a - * resource. - * (todo) Remove this method, this should be done using a resource: URI. - * @return the lookup name - */ - public String getEmbedResourceName() { - return embedResourceName; - } - - /** - * {@inheritDoc} - */ - public int getAscender() { - return ascender; - } - - /** - * {@inheritDoc} - */ - public int getDescender() { - return descender; - } - - /** - * {@inheritDoc} - */ - public int getCapHeight() { - return capHeight; - } - - /** - * {@inheritDoc} - */ - public int getAscender(int size) { - return size * ascender; - } - - /** - * {@inheritDoc} - */ - public int getDescender(int size) { - return size * descender; - } - - /** - * {@inheritDoc} - */ - public int getCapHeight(int size) { - return size * capHeight; - } - - /** - * {@inheritDoc} - */ - public int getXHeight(int size) { - return size * xHeight; - } - - /** - * {@inheritDoc} - */ - public int[] getFontBBox() { - return fontBBox; - } - - /** {@inheritDoc} */ - public int getFlags() { - return flags; - } - - /** {@inheritDoc} */ - public boolean isSymbolicFont() { - return ((getFlags() & 4) != 0) || "ZapfDingbatsEncoding".equals(getEncodingName()); - //Note: The check for ZapfDingbats is necessary as the PFM does not reliably indicate - //if a font is symbolic. - } - - /** - * Returns the font weight (100, 200...800, 900). This value may be different from the - * one that was actually used to register the font. - * @return the font weight (or 0 if the font weight is unknown) - */ - public int getWeight() { - return this.weight; - } - - /** - * {@inheritDoc} - */ - public int getStemV() { - return stemV; - } - - /** - * {@inheritDoc} - */ - public int getItalicAngle() { - return italicAngle; - } - - /** - * Returns the width to be used when no width is available. - * @return a character width - */ - public int getMissingWidth() { - return missingWidth; - } - - /** - * {@inheritDoc} - */ - public FontType getFontType() { - return fontType; - } - - /** - * Returns the index of the first character defined in this font. - * @return the index of the first character - */ - public int getFirstChar() { - return firstChar; - } - - /** - * Returns the index of the last character defined in this font. - * @return the index of the last character - */ - public int getLastChar() { - return lastChar; - } - - /** - * Used to determine if kerning is enabled. - * @return True if kerning is enabled. - */ - public boolean isKerningEnabled() { - return useKerning; - } - - /** - * {@inheritDoc} - */ - public final boolean hasKerningInfo() { - return (isKerningEnabled() && (kerning != null) && !kerning.isEmpty()); - } - - /** - * {@inheritDoc} - */ - public final Map<Integer, Map<Integer, Integer>> getKerningInfo() { - if (hasKerningInfo()) { - return kerning; - } else { - return Collections.emptyMap(); - } - } - - /** - * Used to determine if advanced typographic features are enabled. - * By default, this is false, but may be overridden by subclasses. - * @return true if enabled. - */ - public boolean isAdvancedEnabled() { - return useAdvanced; - } - - /* ---- MutableFont interface ---- */ - - /** {@inheritDoc} */ - public void setFontURI(URI uri) { - this.fontFileURI = uri; - } - - /** {@inheritDoc} */ - public void setFontName(String name) { - this.fontName = name; - } - - /** {@inheritDoc} */ - public void setFullName(String name) { - this.fullName = name; - } - - /** {@inheritDoc} */ - public void setFamilyNames(Set<String> names) { - this.familyNames = new HashSet<String>(names); - } - - /** - * Sets the font's subfamily name. - * @param subFamilyName the subfamily name of the font - */ - public void setFontSubFamilyName(String subFamilyName) { - this.fontSubName = subFamilyName; - } - - /** - * {@inheritDoc} - */ - public void setEmbedURI(URI path) { - this.embedFileURI = path; - } - - /** - * {@inheritDoc} - */ - public void setEmbedResourceName(String name) { - this.embedResourceName = name; - } - - /** - * {@inheritDoc} - */ - public void setEmbeddingMode(EmbeddingMode embeddingMode) { - this.embeddingMode = embeddingMode; - } - - /** - * {@inheritDoc} - */ - public void setCapHeight(int capHeight) { - this.capHeight = capHeight; - } - - /** - * Returns the XHeight value of the font. - * @param xHeight the XHeight value - */ - public void setXHeight(int xHeight) { - this.xHeight = xHeight; - } - - /** - * {@inheritDoc} - */ - public void setAscender(int ascender) { - this.ascender = ascender; - } - - /** - * {@inheritDoc} - */ - public void setDescender(int descender) { - this.descender = descender; - } - - /** - * {@inheritDoc} - */ - public void setFontBBox(int[] bbox) { - this.fontBBox = bbox; - } - - /** - * {@inheritDoc} - */ - public void setFlags(int flags) { - this.flags = flags; - } - - /** - * Sets the font weight. Valid values are 100, 200...800, 900. - * @param weight the font weight - */ - public void setWeight(int weight) { - weight = (weight / 100) * 100; - weight = Math.max(100, weight); - weight = Math.min(900, weight); - this.weight = weight; - } - - /** - * {@inheritDoc} - */ - public void setStemV(int stemV) { - this.stemV = stemV; - } - - /** - * {@inheritDoc} - */ - public void setItalicAngle(int italicAngle) { - this.italicAngle = italicAngle; - } - - /** - * {@inheritDoc} - */ - public void setMissingWidth(int width) { - this.missingWidth = width; - } - - /** - * {@inheritDoc} - */ - public void setFontType(FontType fontType) { - this.fontType = fontType; - } - - /** - * {@inheritDoc} - */ - public void setFirstChar(int index) { - this.firstChar = index; - } - - /** - * {@inheritDoc} - */ - public void setLastChar(int index) { - this.lastChar = index; - } - - /** - * {@inheritDoc} - */ - public void setKerningEnabled(boolean enabled) { - this.useKerning = enabled; - } - - /** - * {@inheritDoc} - */ - public void setAdvancedEnabled(boolean enabled) { - this.useAdvanced = enabled; - } - - /** {@inheritDoc} */ - public void putKerningEntry(Integer key, Map<Integer, Integer> value) { - if (kerning == null) { - kerning = new HashMap<Integer, Map<Integer, Integer>>(); - } - this.kerning.put(key, value); - } - - /** - * Replaces the existing kerning map with a new one. - * @param kerningMap the kerning map (Map<Integer, Map<Integer, Integer>, the integers are - * character codes) - */ - public void replaceKerningMap(Map<Integer, Map<Integer, Integer>> kerningMap) { - if (kerningMap == null) { - this.kerning = Collections.emptyMap(); - } else { - this.kerning = kerningMap; - } - } - - /** - * Sets the character map for this font. It maps all available Unicode characters - * to their glyph indices inside the font. - * @param cmap the character map - */ - public void setCMap(CMapSegment[] cmap) { - this.cmap.clear(); - for (CMapSegment c : cmap) { - this.cmap.add(c); - } - } - - /** - * Returns the character map for this font. It maps all available Unicode characters - * to their glyph indices inside the font. - * @return the character map - */ - public CMapSegment[] getCMap() { - return cmap.toArray(new CMapSegment[cmap.size()]); - } - - public int getUnderlinePosition(int size) { - return (underlinePosition == 0) - ? getDescender(size) / 2 - : size * underlinePosition; - } - - public void setUnderlinePosition(int underlinePosition) { - this.underlinePosition = underlinePosition; - } - - public int getUnderlineThickness(int size) { - return size * ((underlineThickness == 0) ? DEFAULT_LINE_THICKNESS : underlineThickness); - } - - public void setUnderlineThickness(int underlineThickness) { - this.underlineThickness = underlineThickness; - } - - public int getStrikeoutPosition(int size) { - return (strikeoutPosition == 0) - ? getXHeight(size) / 2 - : size * strikeoutPosition; - } - - public void setStrikeoutPosition(int strikeoutPosition) { - this.strikeoutPosition = strikeoutPosition; - } - - public int getStrikeoutThickness(int size) { - return (strikeoutThickness == 0) ? getUnderlineThickness(size) : size * strikeoutThickness; - } - - public void setStrikeoutThickness(int strikeoutThickness) { - this.strikeoutThickness = strikeoutThickness; - } - - /** - * Returns a Map of used Glyphs. - * @return Map Map of used Glyphs - */ - public abstract Map<Integer, Integer> getUsedGlyphs(); - - /** - * Returns the character from it's original glyph index in the font - * @param glyphIndex The original index of the character - * @return The character - */ - public abstract char getUnicodeFromGID(int glyphIndex); -} diff --git a/src/java/org/apache/fop/fonts/CustomFontCollection.java b/src/java/org/apache/fop/fonts/CustomFontCollection.java deleted file mode 100644 index 35231e224..000000000 --- a/src/java/org/apache/fop/fonts/CustomFontCollection.java +++ /dev/null @@ -1,73 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.util.List; - -import org.apache.fop.apps.io.InternalResourceResolver; - -/** - * Sets up a set of custom (embedded) fonts - */ -public class CustomFontCollection implements FontCollection { - - private final List<EmbedFontInfo> embedFontInfoList; - private final InternalResourceResolver uriResolver; - private final boolean useComplexScripts; - - /** - * Main constructor. - * @param fontResolver a font resolver - * @param customFonts the list of custom fonts - * @param useComplexScriptFeatures true if complex script features enabled - */ - public CustomFontCollection(InternalResourceResolver fontResolver, - List<EmbedFontInfo> customFonts, boolean useComplexScriptFeatures) { - this.uriResolver = fontResolver; - this.embedFontInfoList = customFonts; - this.useComplexScripts = useComplexScriptFeatures; - } - - /** {@inheritDoc} */ - public int setup(int num, FontInfo fontInfo) { - if (embedFontInfoList == null) { - return num; //No fonts to process - } - - String internalName = null; - - for (int i = 0; i < embedFontInfoList.size(); i++) { - EmbedFontInfo embedFontInfo = embedFontInfoList.get(i); - - internalName = "F" + num; - num++; - - LazyFont font = new LazyFont(embedFontInfo, this.uriResolver, useComplexScripts); - fontInfo.addMetrics(internalName, font); - - List<FontTriplet> triplets = embedFontInfo.getFontTriplets(); - for (int tripletIndex = 0; tripletIndex < triplets.size(); tripletIndex++) { - FontTriplet triplet = triplets.get(tripletIndex); - fontInfo.addFontProperties(internalName, triplet); - } - } - return num; - } -} diff --git a/src/java/org/apache/fop/fonts/DefaultFontConfig.java b/src/java/org/apache/fop/fonts/DefaultFontConfig.java deleted file mode 100644 index 72d2280a8..000000000 --- a/src/java/org/apache/fop/fonts/DefaultFontConfig.java +++ /dev/null @@ -1,359 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.apps.FOPException; -import org.apache.fop.events.EventProducer; -import org.apache.fop.util.LogUtil; - -/** - * The font configuration data for the more generic fonts such as TTF and Type1, that are used by - * most the renderers. - */ -public final class DefaultFontConfig implements FontConfig { - - private static final Log log = LogFactory.getLog(DefaultFontConfig.class); - - private final List<Directory> directories = new ArrayList<Directory>(); - - private final List<Font> fonts = new ArrayList<Font>(); - - private final List<String> referencedFontFamilies = new ArrayList<String>(); - - private final boolean autoDetectFonts; - - private DefaultFontConfig(boolean autoDetectFonts) { - this.autoDetectFonts = autoDetectFonts; - } - - /** - * Parses the morge generic font information. - */ - public static final class DefaultFontConfigParser implements FontConfig.FontConfigParser { - /** - * Parses the font configuration and return the configuration object. - * - * @param cfg the configuration data - * @param strict whether or not to enforce strict validation - * @return the font configuration object - * @throws FOPException if an error occurs when creating the configuration object - */ - public DefaultFontConfig parse(Configuration cfg, boolean strict) throws FOPException { - return new ParserHelper(cfg, strict).instance; - } - - /** {@inheritDoc} */ - public FontConfig parse(Configuration cfg, FontManager fontManager, boolean strict, - EventProducer eventProducer) throws FOPException { - return parse(cfg, strict); - } - } - - private static final class ParserHelper { - - private boolean strict; - - private Configuration fontInfoCfg; - - private DefaultFontConfig instance; - - private ParserHelper(Configuration cfg, boolean strict) throws FOPException { - if (cfg == null || cfg.getChild("fonts", false) == null) { - instance = null; - } else { - this.strict = strict; - this.fontInfoCfg = cfg.getChild("fonts", false); - instance = new DefaultFontConfig(fontInfoCfg.getChild("auto-detect", false) != null); - parse(); - } - } - - private void parse() throws FOPException { - parseFonts(); - parseReferencedFonts(); - parseDirectories(); - } - - private void parseFonts() throws FOPException { - for (Configuration fontCfg : fontInfoCfg.getChildren("font")) { - String embed = fontCfg.getAttribute("embed-url", null); - if (embed == null) { - LogUtil.handleError(log, "Font configuration without embed-url attribute", - strict); - continue; - } - Font font = new Font(fontCfg.getAttribute("metrics-url", null), embed, fontCfg.getAttribute( - "embed-url-afm", null), fontCfg.getAttribute("embed-url-pfm", null), - fontCfg.getAttribute("sub-font", null), - fontCfg.getAttributeAsBoolean("kerning", true), fontCfg.getAttributeAsBoolean( - "advanced", true), fontCfg.getAttribute("encoding-mode", - EncodingMode.AUTO.getName()), fontCfg.getAttribute("embedding-mode", - EncodingMode.AUTO.getName())); - instance.fonts.add(font); - boolean hasTriplets = false; - for (Configuration tripletCfg : fontCfg.getChildren("font-triplet")) { - FontTriplet fontTriplet = getFontTriplet(tripletCfg, strict); - font.tripletList.add(fontTriplet); - hasTriplets = true; - } - // no font triplet info - if (!hasTriplets) { - LogUtil.handleError(log, "font without font-triplet", strict); - } - } - } - - private void parseReferencedFonts() throws FOPException { - Configuration referencedFontsCfg = fontInfoCfg.getChild("referenced-fonts", false); - if (referencedFontsCfg != null) { - for (Configuration match : referencedFontsCfg.getChildren("match")) { - try { - instance.referencedFontFamilies.add(match.getAttribute("font-family")); - } catch (ConfigurationException ce) { - LogUtil.handleException(log, ce, strict); - continue; - } - } - } - } - - private void parseDirectories() throws FOPException { - for (Configuration directoriesCfg : fontInfoCfg.getChildren("directory")) { - boolean recursive = directoriesCfg.getAttributeAsBoolean("recursive", false); - String directory; - try { - directory = directoriesCfg.getValue(); - } catch (ConfigurationException e) { - LogUtil.handleException(log, e, strict); - continue; - } - if (directory == null) { - LogUtil.handleException(log, - new FOPException("directory defined without value"), strict); - continue; - } - instance.directories.add(new Directory(directory, recursive)); - } - } - - /** - * Creates a new FontTriplet given a triple Configuration - * - * @param tripletCfg a triplet configuration - * @return a font triplet font key - * @throws FOPException thrown if a FOP exception occurs - */ - private FontTriplet getFontTriplet(Configuration tripletCfg, boolean strict) - throws FOPException { - try { - String name = tripletCfg.getAttribute("name"); - if (name == null) { - LogUtil.handleError(log, "font-triplet without name", strict); - return null; - } - String weightStr = tripletCfg.getAttribute("weight"); - if (weightStr == null) { - LogUtil.handleError(log, "font-triplet without weight", strict); - return null; - } - int weight = FontUtil.parseCSS2FontWeight(FontUtil.stripWhiteSpace(weightStr)); - String style = tripletCfg.getAttribute("style"); - if (style == null) { - LogUtil.handleError(log, "font-triplet without style", strict); - return null; - } else { - style = FontUtil.stripWhiteSpace(style); - } - return FontInfo.createFontKey(name, style, weight); - } catch (ConfigurationException e) { - LogUtil.handleException(log, e, strict); - } - return null; - } - - } - - /** - * Returns the list of fonts that were parsed. - * @return a list of fonts - */ - public List<Font> getFonts() { - return Collections.unmodifiableList(fonts); - } - - /** - * Returns a list of directories that were parsed. - * @return a list of directories - */ - public List<Directory> getDirectories() { - return Collections.unmodifiableList(directories); - } - - /** - * Returns a list of referenced font families. - * @return the referenced font families - */ - public List<String> getReferencedFontFamily() { - return Collections.unmodifiableList(referencedFontFamilies); - } - - /** - * Whether or not to enable auto-detecting of fonts in the system. - * @return true to enable auto-detect - */ - public boolean isAutoDetectFonts() { - return autoDetectFonts; - } - - /** - * The directory to find fonts within. - */ - public static final class Directory { - - private final String directory; - - private final boolean recursive; - - private Directory(String directory, boolean recurse) { - this.directory = directory; - this.recursive = recurse; - } - - /** - * Returns a String representing the directory to find fonts within. - * @return the directory - */ - public String getDirectory() { - return directory; - } - - /** - * Returns whether or not to recurse through the directory when finding fonts. - * @return true to recurse through the directory and sub-directories - */ - public boolean isRecursive() { - return recursive; - } - } - - /** - * Represents a font object within the FOP conf. - */ - public static final class Font { - - private final String metrics; - - private final String embedUri; - - private String afm; - - private String pfm; - - private final String subFont; - - private final boolean kerning; - - private final boolean advanced; - - private final String encodingMode; - - private final String embeddingMode; - - public String getEncodingMode() { - return encodingMode; - } - - private final List<FontTriplet> tripletList = new ArrayList<FontTriplet>(); - - public List<FontTriplet> getTripletList() { - return Collections.unmodifiableList(tripletList); - } - - private Font(String metrics, String embed, String afm, String pfm, String subFont, boolean kerning, - boolean advanced, String encodingMode, String embeddingMode) { - this.metrics = metrics; - this.embedUri = embed; - this.afm = afm; - this.pfm = pfm; - this.subFont = subFont; - this.kerning = kerning; - this.advanced = advanced; - this.encodingMode = encodingMode; - this.embeddingMode = embeddingMode; - } - - /** - * Whether or not to allow kerning of glyphs. - * @return true to allow glyph kerning - */ - public boolean isKerning() { - return kerning; - } - - public boolean isAdvanced() { - return advanced; - } - - /** - * Gets the String representing the metrics file. - * @return the metrics file - */ - public String getMetrics() { - return metrics; - } - - /** - * Gets the URI of the font to embed. - * @return the font URI - */ - public String getEmbedURI() { - return embedUri; - } - - /** - * Gets the sub font within, for example, a TTC. - * @return the sub font name - */ - public String getSubFont() { - return subFont; - } - - public String getEmbeddingMode() { - return embeddingMode; - } - - public String getAfm() { - return afm; - } - - public String getPfm() { - return pfm; - } - } -} diff --git a/src/java/org/apache/fop/fonts/DefaultFontConfigurator.java b/src/java/org/apache/fop/fonts/DefaultFontConfigurator.java deleted file mode 100644 index 4a8b11f74..000000000 --- a/src/java/org/apache/fop/fonts/DefaultFontConfigurator.java +++ /dev/null @@ -1,191 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.apps.FOPException; -import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.fonts.DefaultFontConfig.Directory; -import org.apache.fop.fonts.autodetect.FontFileFinder; -import org.apache.fop.fonts.autodetect.FontInfoFinder; -import org.apache.fop.util.LogUtil; - -/** - * The default configurator for fonts. This configurator can configure the more generic fonts used - * by the renderers i.e. TTF, Type1 etc... - */ -public class DefaultFontConfigurator implements FontConfigurator<EmbedFontInfo> { - /** logger instance */ - protected static final Log log = LogFactory.getLog(DefaultFontConfigurator.class); - - private final FontManager fontManager; - private final InternalResourceResolver resourceResolver; - private final FontEventListener listener; - private final boolean strict; - - /** - * Main constructor - * @param fontManager the font manager - * @param listener the font event listener - * @param strict true if an Exception should be thrown if an error is found. - */ - public DefaultFontConfigurator(FontManager fontManager, FontEventListener listener, boolean strict) { - this.fontManager = fontManager; - this.resourceResolver = fontManager.getResourceResolver(); - this.listener = listener; - this.strict = strict; - } - - /** - * Initializes font info settings from the user configuration - * @throws FOPException if an exception occurs while processing the configuration - */ - public List<EmbedFontInfo> configure(FontConfig fontInfoConfig) throws FOPException { - List<EmbedFontInfo> fontInfoList = new ArrayList<EmbedFontInfo>(); - if (fontInfoConfig != null) { - assert fontInfoConfig instanceof DefaultFontConfig; - DefaultFontConfig adobeFontInfoConfig = (DefaultFontConfig) fontInfoConfig; - long start = 0; - if (log.isDebugEnabled()) { - log.debug("Starting font configuration..."); - start = System.currentTimeMillis(); - } - FontAdder fontAdder = new FontAdder(fontManager, resourceResolver, listener); - // native o/s search (autodetect) configuration - fontManager.autoDetectFonts(adobeFontInfoConfig.isAutoDetectFonts(), fontAdder, strict, - listener, fontInfoList); - // Add configured directories to FontInfo list - addDirectories(adobeFontInfoConfig, fontAdder, fontInfoList); - // Add configured fonts to FontInfo - FontCache fontCache = fontManager.getFontCache(); - try { - addFonts(adobeFontInfoConfig, fontCache, fontInfoList); - } catch (URISyntaxException use) { - LogUtil.handleException(log, use, strict); - } - // Update referenced fonts (fonts which are not to be embedded) - fontManager.updateReferencedFonts(fontInfoList); - // Renderer-specific referenced fonts - List<String> referencedFonts = adobeFontInfoConfig.getReferencedFontFamily(); - if (referencedFonts.size() > 0) { - FontTriplet.Matcher matcher = FontManagerConfigurator.createFontsMatcher( - referencedFonts, strict); - fontManager.updateReferencedFonts(fontInfoList, matcher); - } - // Update font cache if it has changed - fontManager.saveCache(); - if (log.isDebugEnabled()) { - log.debug("Finished font configuration in " - + (System.currentTimeMillis() - start) + "ms"); - } - } - return Collections.unmodifiableList(fontInfoList); - } - - private void addDirectories(DefaultFontConfig fontInfoConfig, FontAdder fontAdder, - List<EmbedFontInfo> fontInfoList) throws FOPException { - // directory (multiple font) configuration - List<Directory> directories = fontInfoConfig.getDirectories(); - for (Directory directory : directories) { - // add fonts found in directory - FontFileFinder fontFileFinder = new FontFileFinder(directory.isRecursive() ? -1 : 1, listener); - List<URL> fontURLList; - try { - fontURLList = fontFileFinder.find(directory.getDirectory()); - fontAdder.add(fontURLList, fontInfoList); - } catch (IOException e) { - LogUtil.handleException(log, e, strict); - } catch (URISyntaxException use) { - LogUtil.handleException(log, use, strict); - } - } - } - - private void addFonts(DefaultFontConfig fontInfoConfig, FontCache fontCache, - List<EmbedFontInfo> fontInfoList) throws FOPException, URISyntaxException { - // font file (singular) configuration - List<DefaultFontConfig.Font> fonts = fontInfoConfig.getFonts(); - for (DefaultFontConfig.Font font : fonts) { - EmbedFontInfo embedFontInfo = getFontInfo(font, fontCache); - if (embedFontInfo != null) { - fontInfoList.add(embedFontInfo); - } - } - } - - private EmbedFontInfo getFontInfo(DefaultFontConfig.Font font, FontCache fontCache) - throws FOPException, URISyntaxException { - String embed = font.getEmbedURI(); - String metrics = font.getMetrics(); - String afm = font.getAfm(); - String pfm = font.getPfm(); - URI embedUri = InternalResourceResolver.cleanURI(embed); - URI metricsUri = metrics == null ? null : InternalResourceResolver.cleanURI(metrics); - URI afmUri = (afm == null) ? null : InternalResourceResolver.cleanURI(afm); - URI pfmUri = (pfm == null) ? null : InternalResourceResolver.cleanURI(pfm); - FontUris fontUris = (afmUri != null || pfmUri != null) ? new FontUris(embedUri, metricsUri, afmUri, - pfmUri) : new FontUris(embedUri, metricsUri); - - String subFont = font.getSubFont(); - List<FontTriplet> tripletList = font.getTripletList(); - - // no font triplet info - if (tripletList.size() == 0) { - URI fontUri = resourceResolver.resolveFromBase(embedUri); - FontInfoFinder finder = new FontInfoFinder(); - finder.setEventListener(listener); - EmbedFontInfo[] infos = finder.find(fontUri, resourceResolver, fontCache); - return infos[0]; //When subFont is set, only one font is returned - } - EncodingMode encodingMode = EncodingMode.getValue(font.getEncodingMode()); - EmbeddingMode embeddingMode = EmbeddingMode.getValue(font.getEmbeddingMode()); - EmbedFontInfo embedFontInfo = new EmbedFontInfo(fontUris, font.isKerning(), font.isAdvanced(), - tripletList, subFont, encodingMode, embeddingMode); - if (fontCache != null) { - if (!fontCache.containsFont(embedFontInfo)) { - fontCache.addFont(embedFontInfo, resourceResolver); - } - } - - if (log.isDebugEnabled()) { - URI embedFile = embedFontInfo.getEmbedURI(); - log.debug("Adding font " + (embedFile != null ? embedFile + ", " : "") - + "metrics URI " + embedFontInfo.getMetricsURI()); - for (int j = 0; j < tripletList.size(); ++j) { - FontTriplet triplet = tripletList.get(j); - log.debug(" Font triplet " - + triplet.getName() + ", " - + triplet.getStyle() + ", " - + triplet.getWeight()); - } - } - return embedFontInfo; - } -} diff --git a/src/java/org/apache/fop/fonts/EmbedFontInfo.java b/src/java/org/apache/fop/fonts/EmbedFontInfo.java deleted file mode 100644 index cc96469f1..000000000 --- a/src/java/org/apache/fop/fonts/EmbedFontInfo.java +++ /dev/null @@ -1,217 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.io.IOException; -import java.io.Serializable; -import java.net.URI; -import java.util.List; - -/** - * FontInfo contains meta information on fonts (where is the metrics file etc.) - * TODO: We need to remove this class and think about more intelligent design patterns - * (Data classes => Procedural code) - */ -public class EmbedFontInfo implements Serializable { - - /** Serialization Version UID */ - private static final long serialVersionUID = 8755432068669997369L; - - /** false, to disable kerning */ - protected final boolean kerning; - /** false, to disable advanced typographic features */ - protected final boolean advanced; - /** the requested encoding mode for the font */ - private final EncodingMode encodingMode; - /** the requested embedding mode for this font */ - private final EmbeddingMode embeddingMode; - - /** the PostScript name of the font */ - protected String postScriptName; - /** the sub-fontname of the font (used for TrueType Collections, null otherwise) */ - protected String subFontName; - - /** the list of associated font triplets */ - private List<FontTriplet> fontTriplets; - - private transient boolean embedded = true; - - private FontUris fontUris; - - /** - * Main constructor - * @param metricsURI the URI of the XML resource containing font metrics - * @param kerning True if kerning should be enabled - * @param advanced true if advanced typography features should be enabled - * @param fontTriplets List of font triplets to associate with this font - * @param embedURI Path to the embeddable font file (may be null) - * @param subFontName the sub-fontname used for TrueType Collections (null otherwise) - * @param encodingMode the encoding mode to use for this font - */ - public EmbedFontInfo(FontUris fontUris, boolean kerning, boolean advanced, - List<FontTriplet> fontTriplets, String subFontName, - EncodingMode encodingMode, EmbeddingMode embeddingMode) { - this.kerning = kerning; - this.advanced = advanced; - this.fontTriplets = fontTriplets; - this.subFontName = subFontName; - this.encodingMode = encodingMode; - this.embeddingMode = embeddingMode; - this.fontUris = fontUris; - } - - /** - * Main constructor - * @param metricsURI the URI of the XML resource containing font metrics - * @param kerning True if kerning should be enabled - * @param fontTriplets List of font triplets to associate with this font - * @param embedURI Path to the embeddable font file (may be null) - * @param subFontName the sub-fontname used for TrueType Collections (null otherwise) - */ - public EmbedFontInfo(FontUris fontUris, boolean kerning, boolean advanced, - List<FontTriplet> fontTriplets, String subFontName) { - this(fontUris, kerning, advanced, fontTriplets, subFontName, EncodingMode.AUTO, - EmbeddingMode.AUTO); - } - - /** - * Returns the URI of the metrics XML resource - * - * @return the metrics file path - */ - public URI getMetricsURI() { - return fontUris.getMetrics(); - } - - /** - * Returns the URI to the embeddable font resource - * - * @return the font resource URI - */ - public URI getEmbedURI() { - return fontUris.getEmbed(); - } - - /** - * Determines if kerning is enabled - * @return true if enabled - */ - public boolean getKerning() { - return kerning; - } - - /** - * Determines if advanced typographic features are enabled - * @return true if enabled - */ - public boolean getAdvanced() { - return advanced; - } - - /** - * Returns the sub-font name of the font. This is primarily used for TrueType Collections - * to select one of the sub-fonts. For all other fonts, this is always null. - * @return the sub-font name (or null) - */ - public String getSubFontName() { - return this.subFontName; - } - - /** - * Returns the PostScript name of the font. - * @return the PostScript name - */ - public String getPostScriptName() { - return postScriptName; - } - - /** - * Sets the PostScript name of the font - * @param postScriptName the PostScript name - */ - public void setPostScriptName(String postScriptName) { - this.postScriptName = postScriptName; - } - - /** - * Returns the list of font triplets associated with this font. - * @return List of font triplets - */ - public List<FontTriplet> getFontTriplets() { - return fontTriplets; - } - - /** - * Indicates whether the font is only referenced rather than embedded. - * @return true if the font is embedded, false if it is referenced. - */ - public boolean isEmbedded() { - if (fontUris.getEmbed() == null) { - return false; - } else { - return this.embedded; - } - } - - /** - * Returns the embedding mode for this font. - * @return the embedding mode. - */ - public EmbeddingMode getEmbeddingMode() { - return embeddingMode; - } - - /** - * Defines whether the font is embedded or not. - * @param value true to embed the font, false to reference it - */ - public void setEmbedded(boolean value) { - this.embedded = value; - } - - /** - * Returns the requested encoding mode for this font. - * @return the encoding mode - */ - public EncodingMode getEncodingMode() { - return this.encodingMode; - } - - private void readObject(java.io.ObjectInputStream in) - throws IOException, ClassNotFoundException { - in.defaultReadObject(); - this.embedded = true; - } - - /** {@inheritDoc} */ - public String toString() { - return "metrics-uri=" + fontUris.getMetrics() + ", embed-uri=" + fontUris.getEmbed() - + ", kerning=" + kerning - + ", advanced=" + advanced - + ", enc-mode=" + encodingMode - + ", font-triplet=" + fontTriplets - + (getSubFontName() != null ? ", sub-font=" + getSubFontName() : "") - + (isEmbedded() ? "" : ", NOT embedded"); - } - - public FontUris getFontUris() { - return fontUris; - } -} diff --git a/src/java/org/apache/fop/fonts/EmbeddingMode.java b/src/java/org/apache/fop/fonts/EmbeddingMode.java deleted file mode 100644 index 5a3e905c9..000000000 --- a/src/java/org/apache/fop/fonts/EmbeddingMode.java +++ /dev/null @@ -1,58 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.util.Locale; - -/** - * This enumerates the embedding mode of fonts; full; subset; auto (auto defaults to full for - * Type 1 fonts and subset for TrueType fonts. - */ -public enum EmbeddingMode { - /** Default option: assumes FULL for Type 1 fonts and SUBSET for TrueType fonts. */ - AUTO, - /** Full font embedding: This means the whole of the font is written to file. */ - FULL, - /** Subset font embedding: Only the mandatory tables and a subset of glyphs are written - * to file.*/ - SUBSET; - - /** - * Returns the name of this embedding mode. - * @return the name of this embedding mode in lower case. - */ - public String getName() { - return this.toString().toLowerCase(Locale.ENGLISH); - } - - /** - * Returns the embedding mode corresponding to the given name. - * @param value the name of an embedding mode (not case sensitive) - * @return the corresponding embedding mode - */ - public static EmbeddingMode getValue(String value) { - for (EmbeddingMode mode : EmbeddingMode.values()) { - if (mode.toString().equalsIgnoreCase(value)) { - return mode; - } - } - throw new IllegalArgumentException("Invalid embedding-mode: " + value); - } -} diff --git a/src/java/org/apache/fop/fonts/EncodingMode.java b/src/java/org/apache/fop/fonts/EncodingMode.java deleted file mode 100644 index 78ffb7ac6..000000000 --- a/src/java/org/apache/fop/fonts/EncodingMode.java +++ /dev/null @@ -1,69 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -/** - * This class enumerates all supported encoding modes for fonts: auto, single-byte and CID. - */ -public enum EncodingMode { - - /** Automatic selection of encoding mode. */ - AUTO("auto"), - - /** Single-byte encoding */ - SINGLE_BYTE("single-byte"), - - /** CID encoding */ - CID("cid"); - - private String name; - - private EncodingMode(String name) { - this.name = name; - } - - /** - * Returns the encoding mode name. - * @return the encoding mode name - */ - public String getName() { - return this.name; - } - - /** - * Returns the {@link EncodingMode} by name. - * @param name the name of the encoding mode to look up - * @return the encoding mode constant - */ - public static EncodingMode getValue(String name) { - for (EncodingMode em : EncodingMode.values()) { - if (name.equalsIgnoreCase(em.getName())) { - return em; - } - } - throw new IllegalArgumentException("Invalid encoding mode: " + name); - } - - /** {@inheritDoc} */ - public String toString() { - return "EncodingMode: " + getName(); - } - -} diff --git a/src/java/org/apache/fop/fonts/Font.java b/src/java/org/apache/fop/fonts/Font.java deleted file mode 100644 index b3cea0d6f..000000000 --- a/src/java/org/apache/fop/fonts/Font.java +++ /dev/null @@ -1,465 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.complexscripts.fonts.Positionable; -import org.apache.fop.complexscripts.fonts.Substitutable; - -/** - * This class holds font state information and provides access to the font - * metrics. - */ -public class Font implements Substitutable, Positionable { - - /** Extra Bold font weight */ - public static final int WEIGHT_EXTRA_BOLD = 800; - - /** Bold font weight */ - public static final int WEIGHT_BOLD = 700; - - /** Normal font weight */ - public static final int WEIGHT_NORMAL = 400; - - /** Light font weight */ - public static final int WEIGHT_LIGHT = 200; - - /** Normal font style */ - public static final String STYLE_NORMAL = "normal"; - - /** Italic font style */ - public static final String STYLE_ITALIC = "italic"; - - /** Oblique font style */ - public static final String STYLE_OBLIQUE = "oblique"; - - /** Inclined font style */ - public static final String STYLE_INCLINED = "inclined"; - - /** Default selection priority */ - public static final int PRIORITY_DEFAULT = 0; - - /** Default fallback key */ - public static final FontTriplet DEFAULT_FONT = new FontTriplet( - "any", STYLE_NORMAL, WEIGHT_NORMAL, PRIORITY_DEFAULT); - - /** logger */ - private static Log log = LogFactory.getLog(Font.class); - - private final String fontName; - private final FontTriplet triplet; - private final int fontSize; - - /** - * normal or small-caps font - */ - //private int fontVariant; - - private final FontMetrics metric; - - /** - * Main constructor - * @param key key of the font - * @param triplet the font triplet that was used to lookup this font (may be null) - * @param met font metrics - * @param fontSize font size - */ - public Font(String key, FontTriplet triplet, FontMetrics met, int fontSize) { - this.fontName = key; - this.triplet = triplet; - this.metric = met; - this.fontSize = fontSize; - } - - /** - * Returns the associated font metrics object. - * @return the font metrics - */ - public FontMetrics getFontMetrics() { - return this.metric; - } - - /** - * Determines whether the font is a multibyte font. - * @return True if it is multibyte - */ - public boolean isMultiByte() { - return getFontMetrics().isMultiByte(); - } - - /** - * Returns the font's ascender. - * @return the ascender - */ - public int getAscender() { - return metric.getAscender(fontSize) / 1000; - } - - /** - * Returns the font's CapHeight. - * @return the capital height - */ - public int getCapHeight() { - return metric.getCapHeight(fontSize) / 1000; - } - - /** - * Returns the font's Descender. - * @return the descender - */ - public int getDescender() { - return metric.getDescender(fontSize) / 1000; - } - - /** - * Returns the font's name. - * @return the font name - */ - public String getFontName() { - return fontName; - } - - /** @return the font triplet that selected this font */ - public FontTriplet getFontTriplet() { - return this.triplet; - } - - /** - * Returns the font size - * @return the font size - */ - public int getFontSize() { - return fontSize; - } - - /** - * Returns the XHeight - * @return the XHeight - */ - public int getXHeight() { - return metric.getXHeight(fontSize) / 1000; - } - - /** @return true if the font has kerning info */ - public boolean hasKerning() { - return metric.hasKerningInfo(); - } - - /** @return true if the font has feature (i.e., at least one lookup matches) */ - public boolean hasFeature(int tableType, String script, String language, String feature) { - return metric.hasFeature(tableType, script, language, feature); - } - - /** - * Returns the font's kerning table - * @return the kerning table - */ - public Map<Integer, Map<Integer, Integer>> getKerning() { - if (metric.hasKerningInfo()) { - return metric.getKerningInfo(); - } else { - return Collections.emptyMap(); - } - } - - /** - * Returns the amount of kerning between two characters. - * - * The value returned measures in pt. So it is already adjusted for font size. - * - * @param ch1 first character - * @param ch2 second character - * @return the distance to adjust for kerning, 0 if there's no kerning - */ - public int getKernValue(char ch1, char ch2) { - Map<Integer, Integer> kernPair = getKerning().get((int) ch1); - if (kernPair != null) { - Integer width = kernPair.get((int) ch2); - if (width != null) { - return width.intValue() * getFontSize() / 1000; - } - } - return 0; - } - - /** - * Returns the amount of kerning between two characters. - * - * The value returned measures in pt. So it is already adjusted for font size. - * - * @param ch1 first character - * @param ch2 second character - * @return the distance to adjust for kerning, 0 if there's no kerning - */ - public int getKernValue(int ch1, int ch2) { - // TODO !BMP - if (ch1 > 0x10000) { - return 0; - } else if ((ch1 >= 0xD800) && (ch1 <= 0xE000)) { - return 0; - } else if (ch2 > 0x10000) { - return 0; - } else if ((ch2 >= 0xD800) && (ch2 <= 0xE000)) { - return 0; - } else { - return getKernValue((char) ch1, (char) ch2); - } - } - - /** - * Returns the width of a character - * @param charnum character to look up - * @return width of the character - */ - public int getWidth(int charnum) { - // returns width of given character number in millipoints - return (metric.getWidth(charnum, fontSize) / 1000); - } - - /** - * Map a java character (unicode) to a font character. - * Default uses CodePointMapping. - * @param c character to map - * @return the mapped character - */ - public char mapChar(char c) { - - if (metric instanceof org.apache.fop.fonts.Typeface) { - return ((org.apache.fop.fonts.Typeface)metric).mapChar(c); - } - - // Use default CodePointMapping - char d = CodePointMapping.getMapping("WinAnsiEncoding").mapChar(c); - if (d != SingleByteEncoding.NOT_FOUND_CODE_POINT) { - c = d; - } else { - log.warn("Glyph " + (int) c + " not available in font " + fontName); - c = Typeface.NOT_FOUND; - } - - return c; - } - - /** - * Determines whether this font contains a particular character/glyph. - * @param c character to check - * @return True if the character is supported, Falso otherwise - */ - public boolean hasChar(char c) { - if (metric instanceof org.apache.fop.fonts.Typeface) { - return ((org.apache.fop.fonts.Typeface)metric).hasChar(c); - } else { - // Use default CodePointMapping - return (CodePointMapping.getMapping("WinAnsiEncoding").mapChar(c) > 0); - } - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - StringBuffer sbuf = new StringBuffer(super.toString()); - sbuf.append('{'); - /* - sbuf.append(fontFamily); - sbuf.append(',');*/ - sbuf.append(fontName); - sbuf.append(','); - sbuf.append(fontSize); - /* - sbuf.append(','); - sbuf.append(fontStyle); - sbuf.append(','); - sbuf.append(fontWeight);*/ - sbuf.append('}'); - return sbuf.toString(); - } - - /** - * Helper method for getting the width of a unicode char - * from the current fontstate. - * This also performs some guessing on widths on various - * versions of space that might not exists in the font. - * @param c character to inspect - * @return the width of the character or -1 if no width available - */ - public int getCharWidth(char c) { - int width; - - if ((c == '\n') || (c == '\r') || (c == '\t') || (c == '\u00A0')) { - width = getCharWidth(' '); - } else { - if (hasChar(c)) { - int mappedChar = mapChar(c); - width = getWidth(mappedChar); - } else { - width = -1; - } - if (width <= 0) { - // Estimate the width of spaces not represented in - // the font - int em = getFontSize(); //http://en.wikipedia.org/wiki/Em_(typography) - int en = em / 2; //http://en.wikipedia.org/wiki/En_(typography) - - if (c == ' ') { - width = em; - } else if (c == '\u2000') { - width = en; - } else if (c == '\u2001') { - width = em; - } else if (c == '\u2002') { - width = em / 2; - } else if (c == '\u2003') { - width = getFontSize(); - } else if (c == '\u2004') { - width = em / 3; - } else if (c == '\u2005') { - width = em / 4; - } else if (c == '\u2006') { - width = em / 6; - } else if (c == '\u2007') { - width = getCharWidth('0'); - } else if (c == '\u2008') { - width = getCharWidth('.'); - } else if (c == '\u2009') { - width = em / 5; - } else if (c == '\u200A') { - width = em / 10; - } else if (c == '\u200B') { - width = 0; - } else if (c == '\u202F') { - width = getCharWidth(' ') / 2; - } else if (c == '\u2060') { - width = 0; - } else if (c == '\u3000') { - width = getCharWidth(' ') * 2; - } else if (c == '\ufeff') { - width = 0; - } else { - //Will be internally replaced by "#" if not found - width = getWidth(mapChar(c)); - } - } - } - - return width; - } - - /** - * Helper method for getting the width of a unicode char - * from the current fontstate. - * This also performs some guessing on widths on various - * versions of space that might not exists in the font. - * @param c character to inspect - * @return the width of the character or -1 if no width available - */ - public int getCharWidth(int c) { - if (c < 0x10000) { - return getCharWidth((char) c); - } else { - // TODO !BMP - return -1; - } - } - - /** - * Calculates the word width. - * @param word text to get width for - * @return the width of the text - */ - public int getWordWidth(String word) { - if (word == null) { - return 0; - } - int wordLength = word.length(); - int width = 0; - char[] characters = new char[wordLength]; - word.getChars(0, wordLength, characters, 0); - for (int i = 0; i < wordLength; i++) { - width += getCharWidth(characters[i]); - } - return width; - } - - /** {@inheritDoc} */ - public boolean performsSubstitution() { - if (metric instanceof Substitutable) { - Substitutable s = (Substitutable) metric; - return s.performsSubstitution(); - } else { - return false; - } - } - - /** {@inheritDoc} */ - public CharSequence performSubstitution(CharSequence cs, - String script, String language, List associations, boolean retainControls) { - if (metric instanceof Substitutable) { - Substitutable s = (Substitutable) metric; - return s.performSubstitution(cs, script, language, associations, retainControls); - } else { - throw new UnsupportedOperationException(); - } - } - - /** {@inheritDoc} */ - public CharSequence reorderCombiningMarks(CharSequence cs, int[][] gpa, - String script, String language, List associations) { - if (metric instanceof Substitutable) { - Substitutable s = (Substitutable) metric; - return s.reorderCombiningMarks(cs, gpa, script, language, associations); - } else { - throw new UnsupportedOperationException(); - } - } - - /** {@inheritDoc} */ - public boolean performsPositioning() { - if (metric instanceof Positionable) { - Positionable p = (Positionable) metric; - return p.performsPositioning(); - } else { - return false; - } - } - - /** {@inheritDoc} */ - public int[][] performPositioning(CharSequence cs, String script, String language, int fontSize) { - if (metric instanceof Positionable) { - Positionable p = (Positionable) metric; - return p.performPositioning(cs, script, language, fontSize); - } else { - throw new UnsupportedOperationException(); - } - } - - /** {@inheritDoc} */ - public int[][] performPositioning(CharSequence cs, String script, String language) { - return performPositioning(cs, script, language, fontSize); - } - -} diff --git a/src/java/org/apache/fop/fonts/FontAdder.java b/src/java/org/apache/fop/fonts/FontAdder.java deleted file mode 100644 index f585dbfa5..000000000 --- a/src/java/org/apache/fop/fonts/FontAdder.java +++ /dev/null @@ -1,75 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.net.URISyntaxException; -import java.net.URL; -import java.util.List; - -import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.fonts.autodetect.FontInfoFinder; - -/** - * Adds a list of fonts to a given font info list - */ -public class FontAdder { - private final FontEventListener listener; - private final InternalResourceResolver resourceResolver; - private final FontManager manager; - - /** - * Main constructor - * @param manager a font manager - * @param resourceResolver a font resolver - * @param listener a font event handler - */ - public FontAdder(FontManager manager, InternalResourceResolver resourceResolver, - FontEventListener listener) { - this.manager = manager; - this.resourceResolver = resourceResolver; - this.listener = listener; - } - - /** - * Iterates over font url list adding to font info list - * @param fontURLList font file list - * @param fontInfoList a configured font info list - * @throws URISyntaxException if a URI syntax error is found - */ - public void add(List<URL> fontURLList, List<EmbedFontInfo> fontInfoList) - throws URISyntaxException { - FontCache cache = manager.getFontCache(); - FontInfoFinder finder = new FontInfoFinder(); - finder.setEventListener(listener); - - for (URL fontURL : fontURLList) { - EmbedFontInfo[] embedFontInfos = finder.find(fontURL.toURI(), resourceResolver, cache); - if (embedFontInfos == null) { - continue; - } - for (int i = 0, c = embedFontInfos.length; i < c; i++) { - EmbedFontInfo fontInfo = embedFontInfos[i]; - if (fontInfo != null) { - fontInfoList.add(fontInfo); - } - } - } - } -} diff --git a/src/java/org/apache/fop/fonts/FontCache.java b/src/java/org/apache/fop/fonts/FontCache.java deleted file mode 100644 index 1f5b96b80..000000000 --- a/src/java/org/apache/fop/fonts/FontCache.java +++ /dev/null @@ -1,549 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; -import java.io.Serializable; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.net.URLConnection; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.apps.FOPException; -import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.util.LogUtil; - -/** - * Fop cache (currently only used for font info caching) - */ -public final class FontCache implements Serializable { - - /** - * Serialization Version UID. Change this value if you want to make sure the - * user's cache file is purged after an update. - */ - private static final long serialVersionUID = 9129238336422194339L; - - /** logging instance */ - private static Log log = LogFactory.getLog(FontCache.class); - - /** FOP's user directory name */ - private static final String FOP_USER_DIR = ".fop"; - - /** font cache file path */ - private static final String DEFAULT_CACHE_FILENAME = "fop-fonts.cache"; - - /** has this cache been changed since it was last read? */ - private transient boolean changed; - - /** change lock */ - private final boolean[] changeLock = new boolean[1]; - - /** - * master mapping of font url -> font info. This needs to be a list, since a - * TTC file may contain more than 1 font. - * @serial - */ - private Map<String, CachedFontFile> fontfileMap; - - /** - * mapping of font url -> file modified date (for all fonts that have failed - * to load) - * @serial - */ - private Map<String, Long> failedFontMap; - - private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { - ois.defaultReadObject(); - } - - private static File getUserHome() { - return toDirectory(System.getProperty("user.home")); - } - - private static File getTempDirectory() { - return toDirectory(System.getProperty("java.io.tmpdir")); - } - - private static File toDirectory(String path) { - if (path != null) { - File dir = new File(path); - if (dir.exists()) { - return dir; - } - } - return null; - } - - /** - * Returns the default font cache file. - * - * @param forWriting - * true if the user directory should be created - * @return the default font cache file - */ - public static File getDefaultCacheFile(boolean forWriting) { - File userHome = getUserHome(); - if (userHome != null) { - File fopUserDir = new File(userHome, FOP_USER_DIR); - if (forWriting) { - boolean writable = fopUserDir.canWrite(); - if (!fopUserDir.exists()) { - writable = fopUserDir.mkdir(); - } - if (!writable) { - userHome = getTempDirectory(); - fopUserDir = new File(userHome, FOP_USER_DIR); - fopUserDir.mkdir(); - } - } - return new File(fopUserDir, DEFAULT_CACHE_FILENAME); - } - return new File(FOP_USER_DIR); - } - - /** - * Reads the default font cache file and returns its contents. - * - * @return the font cache deserialized from the file (or null if no cache - * file exists or if it could not be read) - * @deprecated use {@link #loadFrom(File)} instead - */ - public static FontCache load() { - return loadFrom(getDefaultCacheFile(false)); - } - - /** - * Reads a font cache file and returns its contents. - * - * @param cacheFile - * the cache file - * @return the font cache deserialized from the file (or null if no cache - * file exists or if it could not be read) - */ - public static FontCache loadFrom(File cacheFile) { - if (cacheFile.exists()) { - try { - if (log.isTraceEnabled()) { - log.trace("Loading font cache from " - + cacheFile.getCanonicalPath()); - } - InputStream in = new BufferedInputStream(new FileInputStream(cacheFile)); - ObjectInputStream oin = new ObjectInputStream(in); - try { - return (FontCache) oin.readObject(); - } finally { - IOUtils.closeQuietly(oin); - } - } catch (ClassNotFoundException e) { - // We don't really care about the exception since it's just a - // cache file - log.warn("Could not read font cache. Discarding font cache file. Reason: " - + e.getMessage()); - } catch (IOException ioe) { - // We don't really care about the exception since it's just a - // cache file - log.warn("I/O exception while reading font cache (" - + ioe.getMessage() + "). Discarding font cache file."); - try { - cacheFile.delete(); - } catch (SecurityException ex) { - log.warn("Failed to delete font cache file: " - + cacheFile.getAbsolutePath()); - } - } - } - return null; - } - - /** - * Writes the font cache to disk. - * - * @throws FOPException fop exception - * @deprecated use {@link #saveTo(File)} instead - */ - public void save() throws FOPException { - saveTo(getDefaultCacheFile(true)); - } - - /** - * Writes the font cache to disk. - * - * @param cacheFile - * the file to write to - * @throws FOPException - * fop exception - */ - public void saveTo(File cacheFile) throws FOPException { - synchronized (changeLock) { - if (changed) { - try { - log.trace("Writing font cache to " + cacheFile.getCanonicalPath()); - OutputStream out = new java.io.FileOutputStream(cacheFile); - out = new java.io.BufferedOutputStream(out); - ObjectOutputStream oout = new ObjectOutputStream(out); - try { - oout.writeObject(this); - } finally { - IOUtils.closeQuietly(oout); - } - } catch (IOException ioe) { - LogUtil.handleException(log, ioe, true); - } - changed = false; - log.trace("Cache file written."); - } - } - } - - /** - * creates a key given a font info for the font mapping - * - * @param fontInfo - * font info - * @return font cache key - */ - protected static String getCacheKey(EmbedFontInfo fontInfo) { - if (fontInfo != null) { - URI embedFile = fontInfo.getEmbedURI(); - URI metricsFile = fontInfo.getMetricsURI(); - return (embedFile != null) ? embedFile.toASCIIString() : metricsFile.toASCIIString(); - } - return null; - } - - /** - * cache has been updated since it was read - * - * @return if this cache has changed - */ - public boolean hasChanged() { - return this.changed; - } - - /** - * is this font in the cache? - * - * @param embedUrl - * font info - * @return boolean - */ - public boolean containsFont(String embedUrl) { - return (embedUrl != null && getFontFileMap().containsKey(embedUrl)); - } - - /** - * is this font info in the cache? - * - * @param fontInfo - * font info - * @return font - */ - public boolean containsFont(EmbedFontInfo fontInfo) { - return (fontInfo != null && getFontFileMap().containsKey( - getCacheKey(fontInfo))); - } - - /** - * Tries to identify a File instance from an array of URLs. If there's no - * file URL in the array, the method returns null. - * - * @param urls - * array of possible font urls - * @return file font file - */ - public static File getFileFromUrls(String[] urls) { - for (int i = 0; i < urls.length; i++) { - String urlStr = urls[i]; - if (urlStr != null) { - File fontFile = null; - if (urlStr.startsWith("file:")) { - try { - URL url = new URL(urlStr); - fontFile = FileUtils.toFile(url); - } catch (MalformedURLException mfue) { - // do nothing - } - } - if (fontFile == null) { - fontFile = new File(urlStr); - } - if (fontFile.exists() && fontFile.canRead()) { - return fontFile; - } - } - } - return null; - } - - private Map<String, CachedFontFile> getFontFileMap() { - if (fontfileMap == null) { - fontfileMap = new HashMap<String, CachedFontFile>(); - } - return fontfileMap; - } - - /** - * Adds a font info to cache - * - * @param fontInfo - * font info - */ - public void addFont(EmbedFontInfo fontInfo, InternalResourceResolver resourceResolver) { - String cacheKey = getCacheKey(fontInfo); - synchronized (changeLock) { - CachedFontFile cachedFontFile; - if (containsFont(cacheKey)) { - cachedFontFile = getFontFileMap().get(cacheKey); - if (!cachedFontFile.containsFont(fontInfo)) { - cachedFontFile.put(fontInfo); - } - } else { - // try and determine modified date - URI fontUri = resourceResolver.resolveFromBase(fontInfo.getEmbedURI()); - File fontFile = new File(fontUri); - long lastModified = fontFile.lastModified(); - cachedFontFile = new CachedFontFile(lastModified); - if (log.isTraceEnabled()) { - log.trace("Font added to cache: " + cacheKey); - } - cachedFontFile.put(fontInfo); - getFontFileMap().put(cacheKey, cachedFontFile); - changed = true; - } - } - } - - /** - * Returns a font from the cache. - * - * @param embedUrl - * font info - * @return CachedFontFile object - */ - public CachedFontFile getFontFile(String embedUrl) { - return containsFont(embedUrl) ? getFontFileMap().get(embedUrl) : null; - } - - /** - * Returns the EmbedFontInfo instances belonging to a font file. If the font - * file was modified since it was cached the entry is removed and null is - * returned. - * - * @param embedUrl - * the font URL - * @param lastModified - * the last modified date/time of the font file - * @return the EmbedFontInfo instances or null if there's no cached entry or - * if it is outdated - */ - public EmbedFontInfo[] getFontInfos(String embedUrl, long lastModified) { - CachedFontFile cff = getFontFile(embedUrl); - if (cff.lastModified() == lastModified) { - return cff.getEmbedFontInfos(); - } else { - removeFont(embedUrl); - return null; - } - } - - /** - * removes font from cache - * - * @param embedUrl - * embed url - */ - public void removeFont(String embedUrl) { - synchronized (changeLock) { - if (containsFont(embedUrl)) { - if (log.isTraceEnabled()) { - log.trace("Font removed from cache: " + embedUrl); - } - getFontFileMap().remove(embedUrl); - changed = true; - } - } - } - - /** - * has this font previously failed to load? - * - * @param embedUrl - * embed url - * @param lastModified - * last modified - * @return whether this is a failed font - */ - public boolean isFailedFont(String embedUrl, long lastModified) { - synchronized (changeLock) { - if (getFailedFontMap().containsKey(embedUrl)) { - long failedLastModified = getFailedFontMap().get( - embedUrl).longValue(); - if (lastModified != failedLastModified) { - // this font has been changed so lets remove it - // from failed font map for now - getFailedFontMap().remove(embedUrl); - changed = true; - } - return true; - } else { - return false; - } - } - } - - /** - * Registers a failed font with the cache - * - * @param embedUrl - * embed url - * @param lastModified - * time last modified - */ - public void registerFailedFont(String embedUrl, long lastModified) { - synchronized (changeLock) { - if (!getFailedFontMap().containsKey(embedUrl)) { - getFailedFontMap().put(embedUrl, new Long(lastModified)); - changed = true; - } - } - } - - private Map<String, Long> getFailedFontMap() { - if (failedFontMap == null) { - failedFontMap = new HashMap<String, Long>(); - } - return failedFontMap; - } - - /** - * Clears font cache - */ - public void clear() { - synchronized (changeLock) { - if (log.isTraceEnabled()) { - log.trace("Font cache cleared."); - } - fontfileMap = null; - failedFontMap = null; - changed = true; - } - } - - /** - * Retrieve the last modified date/time of a URI. - * - * @param uri the URI - * @return the last modified date/time - */ - public static long getLastModified(URI uri) { - try { - URL url = uri.toURL(); - URLConnection conn = url.openConnection(); - try { - return conn.getLastModified(); - } finally { - // An InputStream is created even if it's not accessed, but we - // need to close it. - IOUtils.closeQuietly(conn.getInputStream()); - } - } catch (IOException e) { - // Should never happen, because URL must be local - log.debug("IOError: " + e.getMessage()); - return 0; - } - } - - private static class CachedFontFile implements Serializable { - private static final long serialVersionUID = 4524237324330578883L; - - /** file modify date (if available) */ - private long lastModified = -1; - - private Map<String, EmbedFontInfo> filefontsMap; - - public CachedFontFile(long lastModified) { - setLastModified(lastModified); - } - - private Map<String, EmbedFontInfo> getFileFontsMap() { - if (filefontsMap == null) { - filefontsMap = new HashMap<String, EmbedFontInfo>(); - } - return filefontsMap; - } - - void put(EmbedFontInfo efi) { - getFileFontsMap().put(efi.getPostScriptName(), efi); - } - - public boolean containsFont(EmbedFontInfo efi) { - return efi.getPostScriptName() != null - && getFileFontsMap().containsKey(efi.getPostScriptName()); - } - - public EmbedFontInfo[] getEmbedFontInfos() { - return getFileFontsMap().values().toArray( - new EmbedFontInfo[getFileFontsMap().size()]); - } - - /** - * Gets the modified timestamp for font file (not always available) - * - * @return modified timestamp - */ - public long lastModified() { - return this.lastModified; - } - - /** - * Gets the modified timestamp for font file (used for the purposes of - * font info caching) - * - * @param lastModified - * modified font file timestamp - */ - public void setLastModified(long lastModified) { - this.lastModified = lastModified; - } - - /** - * @return string representation of this object {@inheritDoc} - */ - public String toString() { - return super.toString() + ", lastModified=" + lastModified; - } - - } -} diff --git a/src/java/org/apache/fop/fonts/FontCacheManager.java b/src/java/org/apache/fop/fonts/FontCacheManager.java deleted file mode 100644 index a4acd43a4..000000000 --- a/src/java/org/apache/fop/fonts/FontCacheManager.java +++ /dev/null @@ -1,55 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.net.URI; - -import org.apache.fop.apps.FOPException; - - -/** - * Fop cache (currently only used for font info caching) - */ -public interface FontCacheManager { - - /** - * Sets the font cache file given the URI pointing to the file. - * @param fontCacheURI the font cache URI - */ - void setCacheFile(URI fontCacheURI); - - /** - * Loads the font cache into memory from the given file. - * @return the de-serialized font cache - */ - FontCache load(); - - /** - * Serializes the font cache to file. - * @throws FOPException if an error occurs serializing the font cache - */ - void save() throws FOPException; - - /** - * Deletes the font cache from the file-system. - * @throws FOPException if an error occurs deleting the font cache - */ - void delete() throws FOPException; -} diff --git a/src/java/org/apache/fop/fonts/FontCacheManagerFactory.java b/src/java/org/apache/fop/fonts/FontCacheManagerFactory.java deleted file mode 100644 index c1d736b0d..000000000 --- a/src/java/org/apache/fop/fonts/FontCacheManagerFactory.java +++ /dev/null @@ -1,111 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.io.File; -import java.net.URI; - -import org.apache.fop.apps.FOPException; - -/** - * A factory that provides the font caching manager mechanism. - * - */ -public final class FontCacheManagerFactory { - - private FontCacheManagerFactory() { - } - - /** - * Create the default font caching mechanism. - * @return the font cache manager - */ - public static FontCacheManager createDefault() { - return new FontCacheManagerImpl(); - } - - /** - * Create a disabled font caching mechanism which by definition does nothing to cache fonts. - * @return a completely restricted font cache manager - */ - public static FontCacheManager createDisabled() { - return new DisabledFontCacheManager(); - } - - private static final class FontCacheManagerImpl implements FontCacheManager { - - /** Provides a font cache file path **/ - private File cacheFile; - - private FontCache fontCache; - - public FontCache load() { - if (fontCache == null) { - fontCache = FontCache.loadFrom(getCacheFile(false)); - if (fontCache == null) { - fontCache = new FontCache(); - } - } - return fontCache; - } - - public void save() throws FOPException { - if (fontCache != null && fontCache.hasChanged()) { - fontCache.saveTo(getCacheFile(true)); - } - } - - public void delete() throws FOPException { - if (!getCacheFile(true).delete()) { - throw new FOPException("Failed to flush the font cache file '" + cacheFile + "'."); - } - } - - private File getCacheFile(boolean forWriting) { - if (cacheFile != null) { - return cacheFile; - } - return FontCache.getDefaultCacheFile(forWriting); - } - - public void setCacheFile(URI fontCacheURI) { - cacheFile = new File(fontCacheURI); - } - } - - private static final class DisabledFontCacheManager implements FontCacheManager { - - public FontCache load() { - return null; - } - - public void save() throws FOPException { - // nop - } - - public void delete() throws FOPException { - throw new FOPException("Font Cache disabled"); - } - - public void setCacheFile(URI fontCacheURI) { - // nop - } - } -} diff --git a/src/java/org/apache/fop/fonts/FontCollection.java b/src/java/org/apache/fop/fonts/FontCollection.java deleted file mode 100644 index d481ae2f9..000000000 --- a/src/java/org/apache/fop/fonts/FontCollection.java +++ /dev/null @@ -1,39 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - - -/** - * Sets up a set of fonts - */ -public interface FontCollection { - - /** - * Sets up fonts in a font info object. - * - * Adds metrics for basic fonts and useful family-style-weight - * triplets for lookup. - * - * @param start the font starting number - * @param fontInfo the font info to set up - * @return the starting font number for the next font to be added - */ - int setup(int start, FontInfo fontInfo); -} diff --git a/src/java/org/apache/fop/fonts/FontConfig.java b/src/java/org/apache/fop/fonts/FontConfig.java deleted file mode 100644 index 167baf09e..000000000 --- a/src/java/org/apache/fop/fonts/FontConfig.java +++ /dev/null @@ -1,50 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import org.apache.avalon.framework.configuration.Configuration; - -import org.apache.fop.apps.FOPException; -import org.apache.fop.events.EventProducer; - -/** - * An interface for font configuration information. - */ -public interface FontConfig { - - /** - * An interface for parsing font configuration information. - */ - public interface FontConfigParser { - - /** - * Parse the font configuration and return an object containing all the necessary data. - * - * @param cfg the configuration object - * @param fontManager the font manager - * @param strict whether or not to enforce strict validation - * @param eventProducer the event producer for handling font events - * @return the configuration object - * @throws FOPException if an error occurs creating the font configuration object - */ - FontConfig parse(Configuration cfg, FontManager fontManager, boolean strict, - EventProducer eventProducer) throws FOPException; - } -} diff --git a/src/java/org/apache/fop/fonts/FontConfigurator.java b/src/java/org/apache/fop/fonts/FontConfigurator.java deleted file mode 100644 index c1ddb4296..000000000 --- a/src/java/org/apache/fop/fonts/FontConfigurator.java +++ /dev/null @@ -1,39 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.util.List; - -import org.apache.fop.apps.FOPException; - -/** - * An abstract FontInfo configurator - */ -// TODO: Make T extends some interface to make the font info type explicit -public interface FontConfigurator<T> { - - /** - * Initializes font info settings from the user configuration - * @return a font info list - * @throws FOPException if an exception occurs while processing the configuration - */ - List<T> configure(FontConfig fontInfoConfig) throws FOPException; - -} diff --git a/src/java/org/apache/fop/fonts/FontDescriptor.java b/src/java/org/apache/fop/fonts/FontDescriptor.java deleted file mode 100644 index 8aea105be..000000000 --- a/src/java/org/apache/fop/fonts/FontDescriptor.java +++ /dev/null @@ -1,95 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - - -/** - * This interface enhances the font metrics interface with access methods to - * value needed to register fonts in various target formats like PDF or - * PostScript. - */ -public interface FontDescriptor extends FontMetrics { - - /** - * Returns the ascender value of the font. (Ascent in pdf spec) - * @return the ascender - */ - int getAscender(); - - - /** - * Returns the capital height of the font. - * @return the capital height - */ - int getCapHeight(); - - - /** - * Returns the descender value of the font. (Descent in pdf spec) - * @return the descender value - */ - int getDescender(); - - - /** - * Returns the flags for the font. (See pdf spec) - * @return the flags - */ - int getFlags(); - - /** - * Indicates whether the font is a symbolic font. - * @return true if the font is a symbolic font (i.e. Symbol or ZapfDingbats) - */ - boolean isSymbolicFont(); - /** - * Returns the font's bounding box. - * @return the bounding box - */ - int[] getFontBBox(); - - - /** - * Returns the italic angle for the font. - * @return the italic angle - */ - int getItalicAngle(); - - - /** - * Returns the vertical stem width for the font. - * @return the vertical stem width - */ - int getStemV(); - - - /** - * Indicates if this font may be embedded. - * @return True, if embedding is possible/permitted - */ - boolean isEmbeddable(); - - /** - * Indicates whether this font is subset embedded. - * @return true if this font is subset embedded - */ - boolean isSubsetEmbedded(); - -} diff --git a/src/java/org/apache/fop/fonts/FontDetector.java b/src/java/org/apache/fop/fonts/FontDetector.java deleted file mode 100644 index 71965f4a4..000000000 --- a/src/java/org/apache/fop/fonts/FontDetector.java +++ /dev/null @@ -1,34 +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. - */ - -/* $Id$ */ - - -package org.apache.fop.fonts; - -import java.util.List; - -import org.apache.fop.apps.FOPException; - -/** - * An interface for the font detecting mechanism. - */ - -public interface FontDetector { - void detect(FontManager fontManager, FontAdder fontAdder, boolean strict, - FontEventListener eventListener, List<EmbedFontInfo> fontInfoList) throws FOPException; -} diff --git a/src/java/org/apache/fop/fonts/FontDetectorFactory.java b/src/java/org/apache/fop/fonts/FontDetectorFactory.java deleted file mode 100644 index dd96e4a1a..000000000 --- a/src/java/org/apache/fop/fonts/FontDetectorFactory.java +++ /dev/null @@ -1,119 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.List; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.xmlgraphics.util.ClasspathResource; - -import org.apache.fop.apps.FOPException; -import org.apache.fop.fonts.autodetect.FontFileFinder; -import org.apache.fop.util.LogUtil; - -/** - * A factory that provides the font detecting machanism. - */ -public final class FontDetectorFactory { - private FontDetectorFactory() { - } - - /** - * Creates the default font detector - * @return the default font detector - */ - public static FontDetector createDefault() { - return new DefaultFontDetector(); - } - - /** - * Creates a disabled font detector which, by definition, does nothing to detect fonts. - * @return the completely restricted font detector - */ - public static FontDetector createDisabled() { - return new DisabledFontDetector(); - } - - - private static class DisabledFontDetector implements FontDetector { - public void detect(FontManager fontManager, FontAdder fontAdder, boolean strict, - FontEventListener eventListener, List<EmbedFontInfo> fontInfoList) - throws FOPException { - // nop - } - } - - /** - * Detector of operating system and classpath fonts - */ - private static class DefaultFontDetector implements FontDetector { - private static Log log = LogFactory.getLog(DefaultFontDetector.class); - - private static final String[] FONT_MIMETYPES = { - "application/x-font", "application/x-font-truetype" - }; - - /** - * Detect installed fonts on the system - * @param fontInfoList a list of fontinfo to populate - * @throws FOPException thrown if a problem occurred during detection - */ - public void detect(FontManager fontManager, FontAdder fontAdder, boolean strict, - FontEventListener eventListener, List<EmbedFontInfo> fontInfoList) - throws FOPException { - try { - // search in font base if it is defined and - // is a directory but don't recurse - FontFileFinder fontFileFinder = new FontFileFinder(eventListener); - URI fontBaseURI = fontManager.getResourceResolver().getBaseURI(); - File fontBase = FileUtils.toFile(fontBaseURI.toURL()); - if (fontBase != null) { - List<URL> fontURLList = fontFileFinder.find(fontBase.getAbsolutePath()); - fontAdder.add(fontURLList, fontInfoList); - - //Can only use the font base URL if it's a file URL - } - - // native o/s font directory finding - List<URL> systemFontList; - systemFontList = fontFileFinder.find(); - fontAdder.add(systemFontList, fontInfoList); - - // classpath font finding - ClasspathResource resource = ClasspathResource.getInstance(); - for (String mimeTypes : FONT_MIMETYPES) { - fontAdder.add(resource.listResourcesOfMimeType(mimeTypes), fontInfoList); - } - } catch (IOException e) { - LogUtil.handleException(log, e, strict); - } catch (URISyntaxException use) { - LogUtil.handleException(log, use, strict); - } - } - } -} diff --git a/src/java/org/apache/fop/fonts/FontEventAdapter.java b/src/java/org/apache/fop/fonts/FontEventAdapter.java deleted file mode 100644 index e8078a796..000000000 --- a/src/java/org/apache/fop/fonts/FontEventAdapter.java +++ /dev/null @@ -1,74 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import org.apache.fop.events.EventBroadcaster; - -/** - * Event listener interface for font-related events. This interface extends FontEventListener - * and EventProducer for integration into FOP's event subsystem. - */ -public class FontEventAdapter implements FontEventListener { - - private final EventBroadcaster eventBroadcaster; - - private FontEventProducer eventProducer; - - /** - * Creates a new FontEventAdapter. - * @param broadcaster the event broadcaster to send the generated events to - */ - public FontEventAdapter(EventBroadcaster broadcaster) { - this.eventBroadcaster = broadcaster; - } - - private FontEventProducer getEventProducer() { - if (eventProducer == null) { - eventProducer = FontEventProducer.Provider.get(eventBroadcaster); - } - return eventProducer; - } - - /** {@inheritDoc} */ - public void fontSubstituted(Object source, FontTriplet requested, FontTriplet effective) { - getEventProducer().fontSubstituted(source, requested, effective); - } - - /** {@inheritDoc} */ - public void fontLoadingErrorAtAutoDetection(Object source, String fontURL, Exception e) { - getEventProducer().fontLoadingErrorAtAutoDetection(source, fontURL, e); - } - - /** {@inheritDoc} */ - public void glyphNotAvailable(Object source, char ch, String fontName) { - getEventProducer().glyphNotAvailable(source, ch, fontName); - } - - /** {@inheritDoc} */ - public void fontDirectoryNotFound(Object source, String dir) { - getEventProducer().fontDirectoryNotFound(source, dir); - } - - /** {@inheritDoc} */ - public void svgTextStrokedAsShapes(Object source, String fontFamily) { - getEventProducer().svgTextStrokedAsShapes(source, fontFamily); - } - -} diff --git a/src/java/org/apache/fop/fonts/FontEventListener.java b/src/java/org/apache/fop/fonts/FontEventListener.java deleted file mode 100644 index 419a3fcd2..000000000 --- a/src/java/org/apache/fop/fonts/FontEventListener.java +++ /dev/null @@ -1,64 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -/** - * Event listener interface for font-related events. - */ -public interface FontEventListener { - - /** - * Notifies about a font being substituted as the requested one isn't available. - * @param source the event source - * @param requested the requested font triplet - * @param effective the effective font triplet - */ - void fontSubstituted(Object source, FontTriplet requested, FontTriplet effective); - - /** - * An error occurred while loading a font for auto-detection. - * @param source the event source - * @param fontURL the font URL - * @param e the original exception - */ - void fontLoadingErrorAtAutoDetection(Object source, String fontURL, Exception e); - - /** - * A glyph has been requested that is not available in the font. - * @param source the event source - * @param ch the character for which the glyph isn't available - * @param fontName the name of the font - */ - void glyphNotAvailable(Object source, char ch, String fontName); - - /** - * An error occurred trying to find the font directory specified in the config file. - * @param source the event source - * @param dir the directory in the config file - */ - void fontDirectoryNotFound(Object source, String dir); - - /** - * The SVG text will be stroked as shapes. - * @param source the event source - * @param fontFamily the family name of the font that is being stroked - */ - void svgTextStrokedAsShapes(Object source, String fontFamily); -} diff --git a/src/java/org/apache/fop/fonts/FontEventProducer.java b/src/java/org/apache/fop/fonts/FontEventProducer.java deleted file mode 100644 index c6aaef662..000000000 --- a/src/java/org/apache/fop/fonts/FontEventProducer.java +++ /dev/null @@ -1,89 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import org.apache.fop.events.EventBroadcaster; -import org.apache.fop.events.EventProducer; - -/** - * Event producer for fonts-related events. - */ -public interface FontEventProducer extends EventProducer { - - /** - * Provider class for the event producer. - */ - final class Provider { - - private Provider() { } - - /** - * Returns an event producer. - * @param broadcaster the event broadcaster to use - * @return the event producer - */ - public static FontEventProducer get(EventBroadcaster broadcaster) { - return broadcaster.getEventProducerFor(FontEventProducer.class); - } - } - - /** - * Notifies about a font being substituted as the requested one isn't available. - * @param source the event source - * @param requested the requested font triplet - * @param effective the effective font triplet - * @event.severity WARN - */ - void fontSubstituted(Object source, FontTriplet requested, FontTriplet effective); - - /** - * An error occurred while loading a font for auto-detection. - * @param source the event source - * @param fontURL the font URL - * @param e the original exception - * @event.severity WARN - */ - void fontLoadingErrorAtAutoDetection(Object source, String fontURL, Exception e); - - /** - * A glyph has been requested that is not available in the font. - * @param source the event source - * @param ch the character for which the glyph isn't available - * @param fontName the name of the font - * @event.severity WARN - */ - void glyphNotAvailable(Object source, char ch, String fontName); - - /** - * An error occurred trying to find the font directory specified in the config file. - * @param source the event source - * @param dir the directory in the config file - * @event.severity WARN - */ - void fontDirectoryNotFound(Object source, String dir); - - /** - * The SVG text will be stroked as shapes. - * @param source the event source - * @param fontFamily the family name of the font that is being stroked - * @event.severity WARN - */ - void svgTextStrokedAsShapes(Object source, String fontFamily); -} diff --git a/src/java/org/apache/fop/fonts/FontEventProducer.xml b/src/java/org/apache/fop/fonts/FontEventProducer.xml deleted file mode 100644 index d7ce27e7a..000000000 --- a/src/java/org/apache/fop/fonts/FontEventProducer.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - 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. ---> -<!-- $Id$ --> -<catalogue xml:lang="en"> - <message key="fontSubstituted">Font "{requested}" not found. Substituting with "{effective}".</message> - <message key="fontLoadingErrorAtAutoDetection">Unable to load font file: {fontURL}.[ Reason: {e}]</message> - <message key="glyphNotAvailable">Glyph "{ch}" (0x{ch,hex}[, {ch,glyph-name}]) not available in font "{fontName}".</message> - <message key="fontDirectoryNotFound">The font directory {dir} could not be found.</message> - <message key="svgTextStrokedAsShapes">The SVG text for font {fontFamily} will be stroked as shapes.</message> -</catalogue> diff --git a/src/java/org/apache/fop/fonts/FontInfo.java b/src/java/org/apache/fop/fonts/FontInfo.java deleted file mode 100644 index 617b5a4a7..000000000 --- a/src/java/org/apache/fop/fonts/FontInfo.java +++ /dev/null @@ -1,659 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -/** - * The FontInfo holds font information for the layout and rendering of a fo document. - * This stores the list of available fonts that are setup by - * the renderer. The font name can be retrieved for the - * family style and weight. - * <br> - * Currently font supported font-variant small-caps is not - * implemented. - */ -public class FontInfo { - - /** logging instance */ - protected static final Log log = LogFactory.getLog(FontInfo.class); - - /** Map containing fonts that have been used */ - private Map<String, Typeface> usedFonts; //(String = font key) - - /** look up a font-triplet to find a font-name */ - private Map<FontTriplet, String> triplets; //(String = font key) - - /** look up a font-triplet to find its priority - * (only used inside addFontProperties()) */ - private Map<FontTriplet, Integer> tripletPriorities; //Map<FontTriplet,Integer> - - /** look up a font-name to get a font (that implements FontMetrics at least) */ - private Map<String, Typeface> fonts; //(String = font key) - - /** Cache for Font instances. */ - private Map<FontTriplet, Map<Integer, Font>> fontInstanceCache; - - /** Event listener for font events */ - private FontEventListener eventListener; - - /** - * Main constructor - */ - public FontInfo() { - this.triplets = new HashMap<FontTriplet, String>(); - this.tripletPriorities = new HashMap<FontTriplet, Integer>(); - this.fonts = new HashMap<String, Typeface>(); - this.usedFonts = new HashMap<String, Typeface>(); - } - - /** - * Sets the font event listener that can be used to receive events about particular events - * in this class. - * @param listener the font event listener - */ - public void setEventListener(FontEventListener listener) { - this.eventListener = listener; - } - - /** - * Checks if the font setup is valid (At least the ultimate fallback font - * must be registered.) - * @return True if valid - */ - public boolean isSetupValid() { - //We're only called when font setup is done: - tripletPriorities = null; // candidate for garbage collection - return triplets.containsKey(Font.DEFAULT_FONT); - } - - /** - * Adds a new font triplet. - * @param name internal key - * @param family font family name - * @param style font style (normal, italic, oblique...) - * @param weight font weight - */ - public void addFontProperties(String name, String family, String style, int weight) { - addFontProperties(name, createFontKey(family, style, weight)); - } - - /** - * Adds a series of new font triplets given an array of font family names. - * @param name internal key - * @param families an array of font family names - * @param style font style (normal, italic, oblique...) - * @param weight font weight - */ - public void addFontProperties(String name, String[] families, String style, int weight) { - for (int i = 0; i < families.length; i++) { - addFontProperties(name, families[i], style, weight); - } - } - - /** - * Adds a new font triplet. - * @param internalFontKey internal font key - * @param triplet the font triplet to associate with the internal key - */ - public void addFontProperties(String internalFontKey, FontTriplet triplet) { - /* - * add the given family, style and weight as a lookup for the font - * with the given name - */ - if (log.isDebugEnabled()) { - log.debug("Registering: " + triplet + " under " + internalFontKey); - } - String oldName = triplets.get(triplet); - int newPriority = triplet.getPriority(); - if (oldName != null) { - int oldPriority = tripletPriorities.get(triplet).intValue(); - if (oldPriority < newPriority) { - logDuplicateFont(triplet, false, oldName, oldPriority, internalFontKey, newPriority); - return; - } else { - logDuplicateFont(triplet, true, oldName, oldPriority, internalFontKey, newPriority); - } - } - this.triplets.put(triplet, internalFontKey); - this.tripletPriorities.put(triplet, Integer.valueOf(newPriority)); - } - - /** - * Log warning about duplicate font triplets. - * - * @param triplet the duplicate font triplet - * @param replacing true iff the new font will replace the old one - * @param oldKey the old internal font name - * @param oldPriority the priority of the existing font mapping - * @param newKey the new internal font name - * @param newPriority the priority of the duplicate font mapping - */ - private void logDuplicateFont(FontTriplet triplet, boolean replacing, String oldKey, int oldPriority, - String newKey, int newPriority) { - if (log.isDebugEnabled()) { - log.debug(triplet - + (replacing ? ": Replacing " : ": Not replacing ") - + fonts.get(triplets.get(triplet)).getFullName() - + " (priority=" + oldPriority + ") by " - + fonts.get(newKey).getFullName() - + " (priority=" + newPriority + ")"); - } - } - - /** - * Adds font metrics for a specific font. - * @param internalFontKey internal key - * @param metrics metrics to register - */ - public void addMetrics(String internalFontKey, FontMetrics metrics) { - // add the given metrics as a font with the given name - - if (metrics instanceof Typeface) { - ((Typeface)metrics).setEventListener(this.eventListener); - } - this.fonts.put(internalFontKey, (Typeface)metrics); - } - - /** - * Lookup a font. - * <br> - * Locate the font name for a given family, style and weight. - * The font name can then be used as a key as it is unique for - * the associated document. - * This also adds the font to the list of used fonts. - * @param family font family - * @param style font style - * @param weight font weight - * @param substitutable true if the font may be substituted with the - * default font if not found - * @return internal font triplet key - */ - private FontTriplet fontLookup(String family, String style, int weight, boolean substitutable) { - if (log.isTraceEnabled()) { - log.trace("Font lookup: " + family + " " + style + " " + weight - + (substitutable ? " substitutable" : "")); - } - - FontTriplet startKey = createFontKey(family, style, weight); - FontTriplet fontTriplet = startKey; - // first try given parameters - String internalFontKey = getInternalFontKey(fontTriplet); - if (internalFontKey == null) { - fontTriplet = fuzzyFontLookup(family, style, weight, startKey, substitutable); - } - - if (fontTriplet != null) { - if (fontTriplet != startKey) { - notifyFontReplacement(startKey, fontTriplet); - } - return fontTriplet; - } else { - return null; - } - } - - private FontTriplet fuzzyFontLookup(String family, String style, - int weight, FontTriplet startKey, boolean substitutable) { - FontTriplet key; - String internalFontKey = null; - if (!family.equals(startKey.getName())) { - key = createFontKey(family, style, weight); - internalFontKey = getInternalFontKey(key); - if (internalFontKey != null) { - return key; - } - } - - // adjust weight, favouring normal or bold - key = findAdjustWeight(family, style, weight); - if (key != null) { - internalFontKey = getInternalFontKey(key); - } - - // return null if not found and not substitutable - if (!substitutable && internalFontKey == null) { - return null; - } - - // only if the font may be substituted - // fallback 1: try the same font-family and weight with default style - if (internalFontKey == null && !style.equals(Font.STYLE_NORMAL)) { - key = createFontKey(family, Font.STYLE_NORMAL, weight); - internalFontKey = getInternalFontKey(key); - } - - // fallback 2: try the same font-family with default style and try to adjust weight - if (internalFontKey == null && !style.equals(Font.STYLE_NORMAL)) { - key = findAdjustWeight(family, Font.STYLE_NORMAL, weight); - if (key != null) { - internalFontKey = getInternalFontKey(key); - } - } - - // fallback 3: try any family with original style/weight - if (internalFontKey == null) { - return fuzzyFontLookup("any", style, weight, startKey, false); - } - - // last resort: use default - if (key == null && internalFontKey == null) { - key = Font.DEFAULT_FONT; - internalFontKey = getInternalFontKey(key); - } - - if (internalFontKey != null) { - return key; - } else { - return null; - } - } - - /** - * Tells this class that the font with the given internal name has been used. - * @param internalName the internal font name (F1, F2 etc.) - */ - public void useFont(String internalName) { - usedFonts.put(internalName, fonts.get(internalName)); - } - - private Map<FontTriplet, Map<Integer, Font>> getFontInstanceCache() { - if (fontInstanceCache == null) { - fontInstanceCache = new HashMap<FontTriplet, Map<Integer, Font>>(); - } - return fontInstanceCache; - } - - /** - * Retrieves a (possibly cached) Font instance based on a FontTriplet and a font size. - * - * @param triplet the font triplet designating the requested font - * @param fontSize the font size - * @return the requested Font instance - */ - public Font getFontInstance(FontTriplet triplet, int fontSize) { - Map<Integer, Font> sizes = getFontInstanceCache().get(triplet); - if (sizes == null) { - sizes = new HashMap<Integer, Font>(); - getFontInstanceCache().put(triplet, sizes); - } - Integer size = Integer.valueOf(fontSize); - Font font = sizes.get(size); - if (font == null) { - String fontKey = getInternalFontKey(triplet); - useFont(fontKey); - FontMetrics metrics = getMetricsFor(fontKey); - font = new Font(fontKey, triplet, metrics, fontSize); - sizes.put(size, font); - } - return font; - } - - private List<FontTriplet> getTripletsForName(String fontName) { - List<FontTriplet> matchedTriplets = new ArrayList<FontTriplet>(); - for (FontTriplet triplet : triplets.keySet()) { - String tripletName = triplet.getName(); - if (tripletName.toLowerCase().equals(fontName.toLowerCase())) { - matchedTriplets.add(triplet); - } - } - return matchedTriplets; - } - - /** - * Returns a suitable internal font given an AWT Font instance. - * - * @param awtFont the AWT font - * @return a best matching internal Font - */ - public Font getFontInstanceForAWTFont(java.awt.Font awtFont) { - String awtFontName = awtFont.getName(); - String awtFontFamily = awtFont.getFamily(); - String awtFontStyle = awtFont.isItalic() ? Font.STYLE_ITALIC : Font.STYLE_NORMAL; - int awtFontWeight = awtFont.isBold() ? Font.WEIGHT_BOLD : Font.WEIGHT_NORMAL; - - FontTriplet matchedTriplet = null; - List<FontTriplet> triplets = getTripletsForName(awtFontName); - if (!triplets.isEmpty()) { - for (FontTriplet triplet : triplets) { - boolean styleMatched = triplet.getStyle().equals(awtFontStyle); - boolean weightMatched = triplet.getWeight() == awtFontWeight; - if (styleMatched && weightMatched) { - matchedTriplet = triplet; - break; - } - } - } - - // not matched on font name so do a lookup using family - if (matchedTriplet == null) { - if (awtFontFamily.equals("sanserif")) { - awtFontFamily = "sans-serif"; - } - matchedTriplet = fontLookup(awtFontFamily, awtFontStyle, awtFontWeight); - } - int fontSize = Math.round(awtFont.getSize2D() * 1000); - return getFontInstance(matchedTriplet, fontSize); - } - - /** - * Lookup a font. - * <br> - * Locate the font name for a given family, style and weight. - * The font name can then be used as a key as it is unique for - * the associated document. - * This also adds the font to the list of used fonts. - * @param family font family - * @param style font style - * @param weight font weight - * @return the font triplet of the font chosen - */ - public FontTriplet fontLookup(String family, String style, int weight) { - return fontLookup(family, style, weight, true); - } - - private List<FontTriplet> fontLookup(String[] families, String style, int weight, boolean substitutable) { - List<FontTriplet> matchingTriplets = new ArrayList<FontTriplet>(); - FontTriplet triplet = null; - for (int i = 0; i < families.length; i++) { - triplet = fontLookup(families[i], style, weight, substitutable); - if (triplet != null) { - matchingTriplets.add(triplet); - } - } - return matchingTriplets; - } - - /** - * Looks up a set of fonts. - * <br> - * Locate the font name(s) for the given families, style and weight. - * The font name(s) can then be used as a key as they are unique for - * the associated document. - * This also adds the fonts to the list of used fonts. - * @param families font families (priority list) - * @param style font style - * @param weight font weight - * @return the set of font triplets of all supported and chosen font-families - * in the specified style and weight. - */ - public FontTriplet[] fontLookup(String[] families, String style, int weight) { - if (families.length == 0) { - throw new IllegalArgumentException("Specify at least one font family"); - } - - // try matching without substitutions - List<FontTriplet> matchedTriplets = fontLookup(families, style, weight, false); - - // if there are no matching font triplets found try with substitutions - if (matchedTriplets.size() == 0) { - matchedTriplets = fontLookup(families, style, weight, true); - } - - // no matching font triplets found! - if (matchedTriplets.size() == 0) { - StringBuffer sb = new StringBuffer(); - for (int i = 0, c = families.length; i < c; i++) { - if (i > 0) { - sb.append(", "); - } - sb.append(families[i]); - } - throw new IllegalStateException( - "fontLookup must return an array with at least one " - + "FontTriplet on the last call. Lookup: " + sb.toString()); - - } - FontTriplet[] fontTriplets = new FontTriplet[matchedTriplets.size()]; - matchedTriplets.toArray(fontTriplets); - - // found some matching fonts so return them - return fontTriplets; - } - - private void notifyFontReplacement(FontTriplet replacedKey, FontTriplet newKey) { - if (this.eventListener != null) { - this.eventListener.fontSubstituted(this, replacedKey, newKey); - } - } - - /** - * Notify listeners that the SVG text for the given font will be stroked as shapes. - * @param fontFamily a SVG font family - */ - public void notifyStrokingSVGTextAsShapes(String fontFamily) { - if (this.eventListener != null) { - this.eventListener.svgTextStrokedAsShapes(this, fontFamily); - } - } - - /** - * Find a font with a given family and style by trying - * different font weights according to the spec. - * @param family font family - * @param style font style - * @param weight font weight - * @return internal key - */ - public FontTriplet findAdjustWeight(String family, String style, int weight) { - FontTriplet key = null; - String f = null; - int newWeight = weight; - if (newWeight < 400) { - while (f == null && newWeight > 100) { - newWeight -= 100; - key = createFontKey(family, style, newWeight); - f = getInternalFontKey(key); - } - newWeight = weight; - while (f == null && newWeight < 400) { - newWeight += 100; - key = createFontKey(family, style, newWeight); - f = getInternalFontKey(key); - } - } else if (newWeight == 400 || newWeight == 500) { - key = createFontKey(family, style, 400); - f = getInternalFontKey(key); - } else if (newWeight > 500) { - while (f == null && newWeight < 1000) { - newWeight += 100; - key = createFontKey(family, style, newWeight); - f = getInternalFontKey(key); - } - newWeight = weight; - while (f == null && newWeight > 400) { - newWeight -= 100; - key = createFontKey(family, style, newWeight); - f = getInternalFontKey(key); - } - } - if (f == null && weight != 400) { - key = createFontKey(family, style, 400); - f = getInternalFontKey(key); - } - - if (f != null) { - return key; - } else { - return null; - } - } - - /** - * Determines if a particular font is available. - * @param family font family - * @param style font style - * @param weight font weight - * @return True if available - */ - public boolean hasFont(String family, String style, int weight) { - FontTriplet key = createFontKey(family, style, weight); - return this.triplets.containsKey(key); - } - - /** - * Returns the internal font key (F1, F2, F3 etc.) for a given triplet. - * @param triplet the font triplet - * @return the associated internal key or null, if not found - */ - public String getInternalFontKey(FontTriplet triplet) { - return triplets.get(triplet); - } - - /** - * Creates a key from the given strings. - * @param family font family - * @param style font style - * @param weight font weight - * @return internal key - */ - public static FontTriplet createFontKey(String family, String style, int weight) { - return new FontTriplet(family, style, weight); - } - - /** - * Gets a Map of all registered fonts. - * @return a read-only Map with font key/FontMetrics pairs - */ - public Map<String, Typeface> getFonts() { - return Collections.unmodifiableMap(this.fonts); - } - - /** - * Gets a Map of all registered font triplets. - * @return a Map with FontTriplet/font key pairs - */ - public Map<FontTriplet, String> getFontTriplets() { - return this.triplets; - } - - /** - * This is used by the renderers to retrieve all the - * fonts used in the document. - * This is for embedded font or creating a list of used fonts. - * @return a read-only Map with font key/FontMetrics pairs - */ - public Map<String, Typeface> getUsedFonts() { - return this.usedFonts; - } - - /** - * Returns the FontMetrics for a particular font - * @param fontName internal key - * @return font metrics - */ - public FontMetrics getMetricsFor(String fontName) { - Typeface metrics = fonts.get(fontName); - usedFonts.put(fontName, metrics); - return metrics; - } - - /** - * Returns all font triplet matching the given font name. - * @param fontName The font name we are looking for - * @return A list of matching font triplets - */ - public List<FontTriplet> getTripletsFor(String fontName) { - List<FontTriplet> foundTriplets = new ArrayList<FontTriplet>(); - for (Map.Entry<FontTriplet, String> tripletEntry : triplets.entrySet()) { - if (fontName.equals((tripletEntry.getValue()))) { - foundTriplets.add(tripletEntry.getKey()); - } - } - return foundTriplets; - } - - /** - * Returns the first triplet matching the given font name. - * As there may be multiple triplets matching the font name - * the result set is sorted first to guarantee consistent results. - * @param fontName The font name we are looking for - * @return The first triplet for the given font name - */ - public FontTriplet getTripletFor(String fontName) { - List<FontTriplet> foundTriplets = getTripletsFor(fontName); - if (foundTriplets.size() > 0) { - Collections.sort(foundTriplets); - return foundTriplets.get(0); - } - return null; - } - - /** - * Returns the font style for a particular font. - * There may be multiple font styles matching this font. Only the first - * found is returned. Searching is done on a sorted list to guarantee consistent - * results. - * @param fontName internal key - * @return font style - */ - public String getFontStyleFor(String fontName) { - FontTriplet triplet = getTripletFor(fontName); - if (triplet != null) { - return triplet.getStyle(); - } else { - return ""; - } - } - - /** - * Returns the font weight for a particular font. - * There may be multiple font weights matching this font. Only the first - * found is returned. Searching is done on a sorted list to guarantee consistent - * results. - * @param fontName internal key - * @return font weight - */ - public int getFontWeightFor(String fontName) { - FontTriplet triplet = getTripletFor(fontName); - if (triplet != null) { - return triplet.getWeight(); - } else { - return 0; - } - } - - /** - * Diagnostic method for logging all registered fonts to System.out. - */ - public void dumpAllTripletsToSystemOut() { - SortedSet<String> entries = new TreeSet<String>(); - for (FontTriplet triplet : this.triplets.keySet()) { - String key = getInternalFontKey(triplet); - FontMetrics metrics = getMetricsFor(key); - entries.add(triplet.toString() + " -> " + key + " -> " + metrics.getFontName() + "\n"); - } - StringBuffer stringBuffer = new StringBuffer(); - for (String str : entries) { - stringBuffer.append(str); - } - System.out.println(stringBuffer.toString()); - } -} diff --git a/src/java/org/apache/fop/fonts/FontLoader.java b/src/java/org/apache/fop/fonts/FontLoader.java deleted file mode 100644 index 92656ca2d..000000000 --- a/src/java/org/apache/fop/fonts/FontLoader.java +++ /dev/null @@ -1,128 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.io.IOException; -import java.net.URI; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.fonts.truetype.OFFontLoader; -import org.apache.fop.fonts.type1.Type1FontLoader; - -/** - * Base class for font loaders. - */ -public abstract class FontLoader { - - /** logging instance */ - protected static final Log log = LogFactory.getLog(FontLoader.class); - - /** URI representing the font file */ - protected final URI fontFileURI; - /** the resource resolver to use for font URI resolution */ - protected final InternalResourceResolver resourceResolver; - /** the loaded font */ - protected CustomFont returnFont; - - /** true if the font has been loaded */ - protected boolean loaded; - /** true if the font will be embedded, false if it will be referenced only. */ - protected boolean embedded; - /** true if kerning information false be loaded if available. */ - protected boolean useKerning; - /** true if advanced typographic information shall be loaded if available. */ - protected boolean useAdvanced; - - /** - * Default constructor. - * @param fontFileURI the URI to the PFB file of a Type 1 font - * @param embedded indicates whether the font is embedded or referenced - * @param useKerning indicates whether kerning information shall be loaded if available - * @param useAdvanced indicates whether advanced typographic information shall be loaded if - * available - * @param resourceResolver the font resolver used to resolve URIs - */ - public FontLoader(URI fontFileURI, boolean embedded, boolean useKerning, - boolean useAdvanced, InternalResourceResolver resourceResolver) { - this.fontFileURI = fontFileURI; - this.embedded = embedded; - this.useKerning = useKerning; - this.useAdvanced = useAdvanced; - this.resourceResolver = resourceResolver; - } - - private static boolean isType1(URI fontURI) { - return fontURI.toASCIIString().toLowerCase().endsWith(".pfb"); - } - - /** - * Loads a custom font from a URI. In the case of Type 1 fonts, the PFB file must be specified. - * @param fontFileURI the URI to the font - * @param subFontName the sub-fontname of a font (for TrueType Collections, null otherwise) - * @param embedded indicates whether the font is embedded or referenced - * @param embeddingMode the embedding mode of the font - * @param encodingMode the requested encoding mode - * @param useKerning indicates whether kerning information should be loaded if available - * @param useAdvanced indicates whether advanced typographic information shall be loaded if - * available - * @param resourceResolver the font resolver to use when resolving URIs - * @return the newly loaded font - * @throws IOException In case of an I/O error - */ - public static CustomFont loadFont(FontUris fontUris, String subFontName, - boolean embedded, EmbeddingMode embeddingMode, EncodingMode encodingMode, - boolean useKerning, boolean useAdvanced, InternalResourceResolver resourceResolver) throws IOException { - boolean type1 = isType1(fontUris.getEmbed()); - FontLoader loader; - if (type1) { - if (encodingMode == EncodingMode.CID) { - throw new IllegalArgumentException( - "CID encoding mode not supported for Type 1 fonts"); - } - loader = new Type1FontLoader(fontUris, embedded, embeddingMode, useKerning, - resourceResolver); - } else { - loader = new OFFontLoader(fontUris.getEmbed(), subFontName, embedded, embeddingMode, - encodingMode, useKerning, useAdvanced, resourceResolver); - } - return loader.getFont(); - } - - /** - * Reads/parses the font data. - * @throws IOException In case of an I/O error - */ - protected abstract void read() throws IOException; - - /** - * Returns the custom font that was read using this instance of FontLoader. - * @return the newly loaded font - * @throws IOException if an I/O error occurs - */ - public CustomFont getFont() throws IOException { - if (!loaded) { - read(); - } - return this.returnFont; - } -} diff --git a/src/java/org/apache/fop/fonts/FontManager.java b/src/java/org/apache/fop/fonts/FontManager.java deleted file mode 100644 index 266220d14..000000000 --- a/src/java/org/apache/fop/fonts/FontManager.java +++ /dev/null @@ -1,232 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.net.URI; -import java.util.List; - -import org.apache.fop.apps.FOPException; -import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.fonts.FontTriplet.Matcher; -import org.apache.fop.fonts.substitute.FontSubstitutions; - -// TODO: Refactor fonts package so major font activities (autodetection etc) -// are all centrally managed and delegated from this class - -/** - * The manager of fonts. The class holds a reference to the font cache and information about - * font substitution, referenced fonts and similar. - */ -public class FontManager { - - /** The resource resolver */ - private InternalResourceResolver resourceResolver; - - private final FontDetector fontDetector; - - private FontCacheManager fontCacheManager; - - /** Font substitutions */ - private FontSubstitutions fontSubstitutions; - - /** Allows enabling kerning on the base 14 fonts, default is false */ - private boolean enableBase14Kerning; - - /** FontTriplet matcher for fonts that shall be referenced rather than embedded. */ - private FontTriplet.Matcher referencedFontsMatcher; - - /** - * Main constructor - * - * @param resourceResolver the URI resolver - * @param fontDetector the font detector - * @param fontCacheManager the font cache manager - */ - public FontManager(InternalResourceResolver resourceResolver, FontDetector fontDetector, - FontCacheManager fontCacheManager) { - this.resourceResolver = resourceResolver; - this.fontDetector = fontDetector; - this.fontCacheManager = fontCacheManager; - } - - /** - * Sets the font resource resolver - * @param resourceResolver resource resolver - */ - public void setResourceResolver(InternalResourceResolver resourceResolver) { - this.resourceResolver = resourceResolver; - } - - public InternalResourceResolver getResourceResolver() { - return this.resourceResolver; - } - - /** @return true if kerning on base 14 fonts is enabled */ - public boolean isBase14KerningEnabled() { - return this.enableBase14Kerning; - } - - /** - * Controls whether kerning is activated on base 14 fonts. - * @param value true if kerning should be activated - */ - public void setBase14KerningEnabled(boolean value) { - this.enableBase14Kerning = value; - } - - /** - * Sets the font substitutions - * @param substitutions font substitutions - */ - public void setFontSubstitutions(FontSubstitutions substitutions) { - this.fontSubstitutions = substitutions; - } - - /** - * Returns the font substitution catalog - * @return the font substitution catalog - */ - protected FontSubstitutions getFontSubstitutions() { - if (fontSubstitutions == null) { - this.fontSubstitutions = new FontSubstitutions(); - } - return fontSubstitutions; - } - - /** - * Sets the font cache file - * @param cacheFileURI the URI of the font cache file - */ - public void setCacheFile(URI cacheFileURI) { - fontCacheManager.setCacheFile(resourceResolver.resolveFromBase(cacheFileURI)); - } - - /** - * Whether or not to cache results of font triplet detection/auto-config - */ - public void disableFontCache() { - fontCacheManager = FontCacheManagerFactory.createDisabled(); - } - - /** - * Returns the font cache instance used by this font manager. - * @return the font cache - */ - public FontCache getFontCache() { - return fontCacheManager.load(); - } - - /** - * Saves the FontCache as necessary - * - * @throws FOPException fop exception - */ - public void saveCache() throws FOPException { - fontCacheManager.save(); - } - - /** - * Deletes the current FontCache file - * @throws FOPException if an error was thrown while deleting the cache - */ - public void deleteCache() throws FOPException { - fontCacheManager.delete(); - } - - /** - * Sets up the fonts on a given FontInfo object. The fonts to setup are defined by an - * array of {@link FontCollection} objects. - * @param fontInfo the FontInfo object to set up - * @param fontCollections the array of font collections/sources - */ - public void setup(FontInfo fontInfo, FontCollection[] fontCollections) { - int startNum = 1; - - for (int i = 0, c = fontCollections.length; i < c; i++) { - startNum = fontCollections[i].setup(startNum, fontInfo); - } - // Make any defined substitutions in the font info - getFontSubstitutions().adjustFontInfo(fontInfo); - } - - /** - * Sets the {@link FontTriplet.Matcher} that can be used to identify the fonts that shall - * be referenced rather than embedded. - * @param matcher the font triplet matcher - */ - public void setReferencedFontsMatcher(FontTriplet.Matcher matcher) { - this.referencedFontsMatcher = matcher; - } - - /** - * Gets the {@link FontTriplet.Matcher} that can be used to identify the fonts that shall - * be referenced rather than embedded. - * @return the font triplet matcher (or null if none is set) - */ - public Matcher getReferencedFontsMatcher() { - return this.referencedFontsMatcher; - } - - /** - * Updates the referenced font list using the FontManager's referenced fonts matcher - * ({@link #getReferencedFontsMatcher()}). - * @param fontInfoList a font info list - */ - public void updateReferencedFonts(List<EmbedFontInfo> fontInfoList) { - Matcher matcher = getReferencedFontsMatcher(); - updateReferencedFonts(fontInfoList, matcher); - } - - /** - * Updates the referenced font list. - * @param fontInfoList a font info list - * @param matcher the font triplet matcher to use - */ - public void updateReferencedFonts(List<EmbedFontInfo> fontInfoList, Matcher matcher) { - if (matcher == null) { - return; //No referenced fonts - } - for (EmbedFontInfo fontInfo : fontInfoList) { - for (FontTriplet triplet : fontInfo.getFontTriplets()) { - if (matcher.matches(triplet)) { - fontInfo.setEmbedded(false); - break; - } - } - } - } - - /** - * Detect fonts from the operating system via FOPs autodetect mechanism. - * - * @param autoDetectFonts if autodetect has been enabled - * @param fontAdder the font adding mechanism - * @param strict whether to enforce strict validation - * @param listener the listener for font related events - * @param fontInfoList a list of font info objects - * @throws FOPException if an exception was thrown auto-detecting fonts - */ - public void autoDetectFonts(boolean autoDetectFonts, FontAdder fontAdder, boolean strict, - FontEventListener listener, List<EmbedFontInfo> fontInfoList) throws FOPException { - if (autoDetectFonts) { - fontDetector.detect(this, fontAdder, strict, listener, fontInfoList); - } - } -} diff --git a/src/java/org/apache/fop/fonts/FontManagerConfigurator.java b/src/java/org/apache/fop/fonts/FontManagerConfigurator.java deleted file mode 100644 index 72c1684b6..000000000 --- a/src/java/org/apache/fop/fonts/FontManagerConfigurator.java +++ /dev/null @@ -1,217 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.List; -import java.util.regex.Pattern; - -import org.apache.avalon.framework.configuration.Configuration; -import org.apache.avalon.framework.configuration.ConfigurationException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.xmlgraphics.io.ResourceResolver; - -import org.apache.fop.apps.FOPException; -import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.apps.io.ResourceResolverFactory; -import org.apache.fop.fonts.substitute.FontSubstitutions; -import org.apache.fop.fonts.substitute.FontSubstitutionsConfigurator; -import org.apache.fop.util.LogUtil; - -/** - * Configurator of the FontManager - */ -public class FontManagerConfigurator { - - /** logger instance */ - private static Log log = LogFactory.getLog(FontManagerConfigurator.class); - - private final Configuration cfg; - - private final URI baseURI; - - private final URI fallbackURI; - - private final ResourceResolver resourceResolver; - - /** - * Main constructor - * @param cfg the font manager configuration object - * @param baseURI the URI against which to resolve relative URIs - * @param fallbackURI the URI to use as a fallback if font-base is unspecified - * @param resourceResolver the resource resolver - */ - public FontManagerConfigurator(Configuration cfg, URI baseURI, URI fallbackURI, - ResourceResolver resourceResolver) { - this.cfg = cfg; - this.baseURI = baseURI; - this.fallbackURI = fallbackURI; - this.resourceResolver = resourceResolver; - } - - /** - * Initializes font settings from the user configuration - * @param fontManager a font manager - * @param strict true if strict checking of the configuration is enabled - * @throws FOPException if an exception occurs while processing the configuration - */ - public void configure(FontManager fontManager, boolean strict) throws FOPException { - if (cfg.getChild("font-base", false) != null) { - try { - URI fontBase = InternalResourceResolver.getBaseURI(cfg.getChild("font-base") - .getValue(null)); - fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver( - baseURI.resolve(fontBase), resourceResolver)); - } catch (URISyntaxException use) { - LogUtil.handleException(log, use, true); - } - } else { - fontManager.setResourceResolver(ResourceResolverFactory.createInternalResourceResolver( - fallbackURI, resourceResolver)); - } - // caching (fonts) - if (cfg.getChild("use-cache", false) != null) { - try { - if (!cfg.getChild("use-cache").getValueAsBoolean()) { - fontManager.disableFontCache(); - } else { - if (cfg.getChild("cache-file", false) != null) { - - fontManager.setCacheFile(URI.create(cfg.getChild("cache-file").getValue())); - } - } - } catch (ConfigurationException mfue) { - LogUtil.handleException(log, mfue, true); - } - } - // [GA] permit configuration control over base14 kerning; without this, - // there is no way for a user to enable base14 kerning other than by - // programmatic API; - if (cfg.getChild("base14-kerning", false) != null) { - try { - fontManager - .setBase14KerningEnabled(cfg.getChild("base14-kerning").getValueAsBoolean()); - } catch (ConfigurationException e) { - LogUtil.handleException(log, e, true); - } - } - - // global font configuration - Configuration fontsCfg = cfg.getChild("fonts", false); - if (fontsCfg != null) { - // font substitution - Configuration substitutionsCfg = fontsCfg.getChild("substitutions", false); - if (substitutionsCfg != null) { - FontSubstitutions substitutions = new FontSubstitutions(); - new FontSubstitutionsConfigurator(substitutionsCfg).configure(substitutions); - fontManager.setFontSubstitutions(substitutions); - } - // referenced fonts (fonts which are not to be embedded) - Configuration referencedFontsCfg = fontsCfg.getChild("referenced-fonts", false); - if (referencedFontsCfg != null) { - FontTriplet.Matcher matcher = createFontsMatcher( - referencedFontsCfg, strict); - fontManager.setReferencedFontsMatcher(matcher); - } - } - } - - /** - * Creates a font triplet matcher from a configuration object. - * @param cfg the configuration object - * @param strict true for strict configuraton error handling - * @return the font matcher - * @throws FOPException if an error occurs while building the matcher - */ - public static FontTriplet.Matcher createFontsMatcher( - Configuration cfg, boolean strict) throws FOPException { - List<FontTriplet.Matcher> matcherList = new java.util.ArrayList<FontTriplet.Matcher>(); - Configuration[] matches = cfg.getChildren("match"); - for (int i = 0; i < matches.length; i++) { - try { - matcherList.add(new FontFamilyRegExFontTripletMatcher( - matches[i].getAttribute("font-family"))); - } catch (ConfigurationException ce) { - LogUtil.handleException(log, ce, strict); - continue; - } - } - FontTriplet.Matcher orMatcher = new OrFontTripletMatcher( - matcherList.toArray(new FontTriplet.Matcher[matcherList.size()])); - return orMatcher; - } - - /** - * Creates a font triplet matcher from a configuration object. - * @param fontFamilies the list of font families - * @param strict true for strict configuraton error handling - * @return the font matcher - * @throws FOPException if an error occurs while building the matcher - */ - public static FontTriplet.Matcher createFontsMatcher( - List<String> fontFamilies, boolean strict) throws FOPException { - List<FontTriplet.Matcher> matcherList = new java.util.ArrayList<FontTriplet.Matcher>(); - for (String fontFamily : fontFamilies) { - matcherList.add(new FontFamilyRegExFontTripletMatcher(fontFamily)); - } - FontTriplet.Matcher orMatcher = new OrFontTripletMatcher( - matcherList.toArray(new FontTriplet.Matcher[matcherList.size()])); - return orMatcher; - } - - private static class OrFontTripletMatcher implements FontTriplet.Matcher { - - private final FontTriplet.Matcher[] matchers; - - public OrFontTripletMatcher(FontTriplet.Matcher[] matchers) { - this.matchers = matchers; - } - - /** {@inheritDoc} */ - public boolean matches(FontTriplet triplet) { - for (int i = 0, c = matchers.length; i < c; i++) { - if (matchers[i].matches(triplet)) { - return true; - } - } - return false; - } - - } - - private static class FontFamilyRegExFontTripletMatcher implements FontTriplet.Matcher { - - private final Pattern regex; - - public FontFamilyRegExFontTripletMatcher(String regex) { - this.regex = Pattern.compile(regex); - } - - /** {@inheritDoc} */ - public boolean matches(FontTriplet triplet) { - return regex.matcher(triplet.getName()).matches(); - } - - } - -} diff --git a/src/java/org/apache/fop/fonts/FontMetrics.java b/src/java/org/apache/fop/fonts/FontMetrics.java deleted file mode 100644 index ce00e34b9..000000000 --- a/src/java/org/apache/fop/fonts/FontMetrics.java +++ /dev/null @@ -1,200 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.awt.Rectangle; -import java.net.URI; -import java.util.Map; -import java.util.Set; - -/** - * Main interface for access to font metrics. - */ -public interface FontMetrics { - - /** - * Returns the URI of the font file from which these metrics were loaded. - * @return the font file's URI - */ - URI getFontURI(); - - /** - * Returns the "PostScript" font name (Example: "Helvetica-BoldOblique"). - * @return the font name - */ - String getFontName(); - - /** - * Returns the font's full name (Example: "Helvetica Bold Oblique"). - * @return the font's full name - */ - String getFullName(); - - /** - * Returns the font's family names as a Set of Strings (Example: "Helvetica"). - * @return the font's family names (a Set of Strings) - */ - Set<String> getFamilyNames(); - - /** - * Returns the font name for font embedding (may include a prefix, Example: "1E28bcArialMT"). - * @return the name for font embedding - */ - String getEmbedFontName(); - - /** - * Returns the type of the font. - * @return the font type - */ - FontType getFontType(); - - - /** - * Returns the maximum ascent of the font described by this - * FontMetrics object. Note: This is not the same as getAscender(). - * @param size font size - * @return ascent in milliponts - */ - int getMaxAscent(int size); - - /** - * Returns the ascent of the font described by this - * FontMetrics object. It returns the nominal ascent within the em box. - * @param size font size - * @return ascent in milliponts - */ - int getAscender(int size); - - /** - * Returns the size of a capital letter measured from the font's baseline. - * @param size font size - * @return height of capital characters - */ - int getCapHeight(int size); - - - /** - * Returns the descent of the font described by this - * FontMetrics object. - * @param size font size - * @return descent in milliponts - */ - int getDescender(int size); - - - /** - * Determines the typical font height of this - * FontMetrics object - * @param size font size - * @return font height in millipoints - */ - int getXHeight(int size); - - /** - * Return the width (in 1/1000ths of point size) of the character at - * code point i. - * @param i code point index - * @param size font size - * @return the width of the character - */ - int getWidth(int i, int size); - - /** - * Return the array of widths. - * <p> - * This is used to get an array for inserting in an output format. - * It should not be used for lookup. - * @return an array of widths - */ - int[] getWidths(); - - /** - * Returns the bounding box of the glyph at the given index, for the given font size. - * - * @param glyphIndex glyph index - * @param size font size - * @return the scaled bounding box scaled in 1/1000ths of the given size - */ - Rectangle getBoundingBox(int glyphIndex, int size); - - /** - * Indicates if the font has kerning information. - * @return true if kerning is available. - */ - boolean hasKerningInfo(); - - /** - * Returns the kerning map for the font. - * @return the kerning map - */ - Map<Integer, Map<Integer, Integer>> getKerningInfo(); - - /** - * Returns the distance from the baseline to the center of the underline (negative - * value indicates below baseline). - * - * @param size font size - * @return the position in 1/1000ths of the font size - */ - int getUnderlinePosition(int size); - - /** - * Returns the thickness of the underline. - * - * @param size font size - * @return the thickness in 1/1000ths of the font size - */ - int getUnderlineThickness(int size); - - /** - * Returns the distance from the baseline to the center of the strikeout line - * (negative value indicates below baseline). - * - * @param size font size - * @return the position in 1/1000ths of the font size - */ - int getStrikeoutPosition(int size); - - /** - * Returns the thickness of the strikeout line. - * - * @param size font size - * @return the thickness in 1/1000ths of the font size - */ - int getStrikeoutThickness(int size); - - /** - * Determine if metrics supports specific feature in specified font table. - * - * @param tableType type of table (GSUB, GPOS, ...), see GlyphTable.GLYPH_TABLE_TYPE_* - * @param script to qualify feature lookup - * @param language to qualify feature lookup - * @param feature to test - * @return true if feature supported (and has at least one lookup) - */ - boolean hasFeature(int tableType, String script, String language, String feature); - - /** - * Determines whether the font is a multibyte font. - * @return True if it is multibyte - */ - boolean isMultiByte(); - -} diff --git a/src/java/org/apache/fop/fonts/FontReader.java b/src/java/org/apache/fop/fonts/FontReader.java deleted file mode 100644 index 9f5d54396..000000000 --- a/src/java/org/apache/fop/fonts/FontReader.java +++ /dev/null @@ -1,309 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -//Java -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.xml.parsers.SAXParserFactory; - -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.DefaultHandler; - -import org.apache.fop.apps.FOPException; -import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.fonts.apps.TTFReader; - -/** - * Class for reading a metric.xml file and creating a font object. - * Typical usage: - * <pre> - * FontReader reader = new FontReader(<path til metrics.xml>); - * reader.setFontEmbedPath(<path to a .ttf or .pfb file or null to diable embedding>); - * reader.useKerning(true); - * Font f = reader.getFont(); - * </pre> - */ -public class FontReader extends DefaultHandler { - - private boolean isCID; - private CustomFont returnFont; - private MultiByteFont multiFont; - private SingleByteFont singleFont; - private final InternalResourceResolver resourceResolver; - private StringBuffer text = new StringBuffer(); - - private List<Integer> cidWidths; - //private int cidWidthIndex; - - private Map<Integer, Integer> currentKerning; - - private List<CMapSegment> bfranges; - - /** - * Construct a FontReader object from a path to a metric.xml file - * and read metric data - * @param source Source of the font metric file - * @throws FOPException if loading the font fails - */ - public FontReader(InputSource source, InternalResourceResolver resourceResolver) throws FOPException { - this.resourceResolver = resourceResolver; - createFont(source); - } - - private void createFont(InputSource source) throws FOPException { - XMLReader parser = null; - - try { - final SAXParserFactory factory = javax.xml.parsers.SAXParserFactory.newInstance(); - factory.setNamespaceAware(true); - parser = factory.newSAXParser().getXMLReader(); - } catch (Exception e) { - throw new FOPException(e); - } - if (parser == null) { - throw new FOPException("Unable to create SAX parser"); - } - - try { - parser.setFeature("http://xml.org/sax/features/namespace-prefixes", false); - } catch (SAXException e) { - throw new FOPException("You need a SAX parser which supports SAX version 2", e); - } - - parser.setContentHandler(this); - - try { - parser.parse(source); - } catch (SAXException e) { - throw new FOPException(e); - } catch (IOException e) { - throw new FOPException(e); - } - - } - - /** - * Sets the path to embed a font. A null value disables font embedding. - * @param path URI for the embeddable file - */ - public void setFontEmbedURI(URI path) { - returnFont.setEmbedURI(path); - } - - /** - * Enable/disable use of kerning for the font - * @param enabled true to enable kerning, false to disable - */ - public void setKerningEnabled(boolean enabled) { - returnFont.setKerningEnabled(enabled); - } - - /** - * Enable/disable use of advanced typographic features for the font - * @param enabled true to enable, false to disable - */ - public void setAdvancedEnabled(boolean enabled) { - returnFont.setAdvancedEnabled(enabled); - } - - /** - * Get the generated font object - * @return the font - */ - public Typeface getFont() { - return returnFont; - } - - /** - * {@inheritDoc} - */ - @Override - public void startDocument() { - } - - /** - * {@inheritDoc} - */ - public void startElement(String uri, String localName, String qName, Attributes attributes) - throws SAXException { - if (localName.equals("font-metrics")) { - if ("TYPE0".equals(attributes.getValue("type"))) { - multiFont = new MultiByteFont(resourceResolver, EmbeddingMode.AUTO); - returnFont = multiFont; - isCID = true; - TTFReader.checkMetricsVersion(attributes); - } else if ("TRUETYPE".equals(attributes.getValue("type"))) { - singleFont = new SingleByteFont(resourceResolver, EmbeddingMode.AUTO); - singleFont.setFontType(FontType.TRUETYPE); - returnFont = singleFont; - isCID = false; - TTFReader.checkMetricsVersion(attributes); - } else { - singleFont = new SingleByteFont(resourceResolver, EmbeddingMode.AUTO); - singleFont.setFontType(FontType.TYPE1); - returnFont = singleFont; - isCID = false; - } - } else if ("embed".equals(localName)) { - try { - returnFont.setEmbedURI(InternalResourceResolver.cleanURI(attributes.getValue("file"))); - } catch (URISyntaxException e) { - throw new SAXException("URI syntax error in metrics file: " + e.getMessage(), e); - } - returnFont.setEmbedResourceName(attributes.getValue("class")); - } else if ("cid-widths".equals(localName)) { - // This is unused - // cidWidthIndex = getInt(attributes.getValue("start-index")); - cidWidths = new ArrayList<Integer>(); - } else if ("kerning".equals(localName)) { - currentKerning = new HashMap<Integer, Integer>(); - returnFont.putKerningEntry(getInt(attributes.getValue("kpx1")), - currentKerning); - } else if ("bfranges".equals(localName)) { - bfranges = new ArrayList<CMapSegment>(); - } else if ("bf".equals(localName)) { - CMapSegment entry = new CMapSegment(getInt(attributes.getValue("us")), - getInt(attributes.getValue("ue")), - getInt(attributes.getValue("gi"))); - bfranges.add(entry); - } else if ("wx".equals(localName)) { - cidWidths.add(getInt(attributes.getValue("w"))); - // } else if ("widths".equals(localName)) { - // singleFont.width = new int[256]; - } else if ("char".equals(localName)) { - try { - singleFont.setWidth(getInt(attributes.getValue("idx")), - getInt(attributes.getValue("wdt"))); - } catch (NumberFormatException ne) { - throw new SAXException("Malformed width in metric file: " + ne.getMessage(), ne); - } - } else if ("pair".equals(localName)) { - currentKerning.put(getInt(attributes.getValue("kpx2")), - getInt(attributes.getValue("kern"))); - } - - } - - private int getInt(String str) throws SAXException { - int ret = 0; - try { - ret = Integer.parseInt(str); - } catch (Exception e) { - throw new SAXException("Error while parsing integer value: " + str, e); - } - return ret; - } - - /** - * {@inheritDoc} - */ - @Override - public void endElement(String uri, String localName, String qName) throws SAXException { - String content = text.toString().trim(); - if ("font-name".equals(localName)) { - returnFont.setFontName(content); - } else if ("full-name".equals(localName)) { - returnFont.setFullName(content); - } else if ("family-name".equals(localName)) { - Set<String> s = new HashSet<String>(); - s.add(content); - returnFont.setFamilyNames(s); - } else if ("ttc-name".equals(localName) && isCID) { - multiFont.setTTCName(content); - } else if ("encoding".equals(localName)) { - if (singleFont != null && singleFont.getFontType() == FontType.TYPE1) { - singleFont.setEncoding(content); - } - } else if ("cap-height".equals(localName)) { - returnFont.setCapHeight(getInt(content)); - } else if ("x-height".equals(localName)) { - returnFont.setXHeight(getInt(content)); - } else if ("ascender".equals(localName)) { - returnFont.setAscender(getInt(content)); - } else if ("descender".equals(localName)) { - returnFont.setDescender(getInt(content)); - } else if ("left".equals(localName)) { - int[] bbox = returnFont.getFontBBox(); - bbox[0] = getInt(content); - returnFont.setFontBBox(bbox); - } else if ("bottom".equals(localName)) { - int[] bbox = returnFont.getFontBBox(); - bbox[1] = getInt(content); - returnFont.setFontBBox(bbox); - } else if ("right".equals(localName)) { - int[] bbox = returnFont.getFontBBox(); - bbox[2] = getInt(content); - returnFont.setFontBBox(bbox); - } else if ("top".equals(localName)) { - int[] bbox = returnFont.getFontBBox(); - bbox[3] = getInt(content); - returnFont.setFontBBox(bbox); - } else if ("first-char".equals(localName)) { - returnFont.setFirstChar(getInt(content)); - } else if ("last-char".equals(localName)) { - returnFont.setLastChar(getInt(content)); - } else if ("flags".equals(localName)) { - returnFont.setFlags(getInt(content)); - } else if ("stemv".equals(localName)) { - returnFont.setStemV(getInt(content)); - } else if ("italic-angle".equals(localName)) { - returnFont.setItalicAngle(getInt(content)); - } else if ("missing-width".equals(localName)) { - returnFont.setMissingWidth(getInt(content)); - } else if ("cid-type".equals(localName)) { - multiFont.setCIDType(CIDFontType.byName(content)); - } else if ("default-width".equals(localName)) { - multiFont.setDefaultWidth(getInt(content)); - } else if ("cid-widths".equals(localName)) { - int[] wds = new int[cidWidths.size()]; - int j = 0; - for (int count = 0; count < cidWidths.size(); count++) { - wds[j++] = cidWidths.get(count).intValue(); - } - - //multiFont.addCIDWidthEntry(cidWidthIndex, wds); - multiFont.setWidthArray(wds); - - } else if ("bfranges".equals(localName)) { - multiFont.setCMap(bfranges.toArray(new CMapSegment[bfranges.size()])); - } - text.setLength(0); //Reset text buffer (see characters()) - } - - /** - * {@inheritDoc} - */ - @Override - public void characters(char[] ch, int start, int length) { - text.append(ch, start, length); - } -} diff --git a/src/java/org/apache/fop/fonts/FontSelector.java b/src/java/org/apache/fop/fonts/FontSelector.java deleted file mode 100644 index a80a0e368..000000000 --- a/src/java/org/apache/fop/fonts/FontSelector.java +++ /dev/null @@ -1,143 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import org.apache.fop.datatypes.PercentBaseContext; -import org.apache.fop.fo.FONode; -import org.apache.fop.fo.FOText; -import org.apache.fop.fo.flow.Character; -import org.apache.fop.fo.properties.CommonFont; - -/** - * Helper class for automatic font selection. - * <p> - * TODO: Check if this could be merged with another font class, such as - * {@link FontManager}. - */ -public final class FontSelector { - private FontSelector() { - // Static since this is an utility class. - } - - private static Font selectFontForCharacter(char c, FONode fonode, - CommonFont commonFont, PercentBaseContext context) { - FontInfo fi = fonode.getFOEventHandler().getFontInfo(); - FontTriplet[] fontkeys = commonFont.getFontState(fi); - for (int i = 0; i < fontkeys.length; i++) { - Font font = fi.getFontInstance(fontkeys[i], commonFont.fontSize - .getValue(context)); - if (font.hasChar(c)) { - return font; - } - } - return fi.getFontInstance(fontkeys[0], commonFont.fontSize - .getValue(context)); - - } - - /** - * Selects a font which is able to display the given character. - * - * @param fobj - * a Character object containing the character and its - * attributes. - * @param context - * the Percent-based context needed for creating the actual font. - * @return a Font object. - */ - public static Font selectFontForCharacter(Character fobj, - PercentBaseContext context) { - return FontSelector.selectFontForCharacter(fobj.getCharacter(), fobj, - fobj.getCommonFont(), context); - } - - /** - * Selects a font which is able to display the given character. - * - * @param c - * character to find. - * @param text - * the text object which contains the character - * @param context - * the Percent-based context needed for creating the actual font. - * @return a Font object. - */ - public static Font selectFontForCharacterInText(char c, FOText text, - PercentBaseContext context) { - return FontSelector.selectFontForCharacter(c, text, text - .getCommonFont(), context); - } - - /** - * Selects a font which is able to display the most of the given characters. - * - * @param charSeq - * Text to go through - * @param firstIndex - * first index within text. - * @param breakIndex - * last index +1 within text. - * @param text - * the text object which contains the character - * @param context - * the Percent-based context needed for creating the actual font. - * @return a Font object. - */ - public static Font selectFontForCharactersInText(CharSequence charSeq, - int firstIndex, int breakIndex, FOText text, - PercentBaseContext context) { - - final FontInfo fi = text.getFOEventHandler().getFontInfo(); - final CommonFont commonFont = text.getCommonFont(); - final FontTriplet[] fontkeys = commonFont.getFontState(fi); - final int numFonts = fontkeys.length; - final Font[] fonts = new Font[numFonts]; - final int[] fontCount = new int[numFonts]; - - for (int fontnum = 0; fontnum < numFonts; fontnum++) { - final Font font = fi.getFontInstance(fontkeys[fontnum], - commonFont.fontSize.getValue(context)); - fonts[fontnum] = font; - for (int pos = firstIndex; pos < breakIndex; pos++) { - if (font.hasChar(charSeq.charAt(pos))) { - fontCount[fontnum]++; - } - } - - // quick fall through if all characters can be displayed - if (fontCount[fontnum] == (breakIndex - firstIndex)) { - return font; - } - } - - Font font = fonts[0]; - int max = fontCount[0]; - - for (int fontnum = 1; fontnum < numFonts; fontnum++) { - final int curCount = fontCount[fontnum]; - if (curCount > max) { - font = fonts[fontnum]; - max = curCount; - } - } - return font; - } - -} diff --git a/src/java/org/apache/fop/fonts/FontSetup.java b/src/java/org/apache/fop/fonts/FontSetup.java deleted file mode 100644 index f9bae3332..000000000 --- a/src/java/org/apache/fop/fonts/FontSetup.java +++ /dev/null @@ -1,217 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -// FOP (base 14 fonts) -import java.util.List; - -import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.fonts.base14.Courier; -import org.apache.fop.fonts.base14.CourierBold; -import org.apache.fop.fonts.base14.CourierBoldOblique; -import org.apache.fop.fonts.base14.CourierOblique; -import org.apache.fop.fonts.base14.Helvetica; -import org.apache.fop.fonts.base14.HelveticaBold; -import org.apache.fop.fonts.base14.HelveticaBoldOblique; -import org.apache.fop.fonts.base14.HelveticaOblique; -import org.apache.fop.fonts.base14.Symbol; -import org.apache.fop.fonts.base14.TimesBold; -import org.apache.fop.fonts.base14.TimesBoldItalic; -import org.apache.fop.fonts.base14.TimesItalic; -import org.apache.fop.fonts.base14.TimesRoman; -import org.apache.fop.fonts.base14.ZapfDingbats; - -//TODO remove small dependency on and refactor this - -/** - * Default fonts for FOP application; currently this uses PDF's fonts - * by default. - * - * Assigns the font (with metrics) to internal names like "F1" and - * assigns family-style-weight triplets to the fonts - */ -public final class FontSetup { - - private FontSetup() { - } - - /** - * Sets up a font info - * @param fontInfo font info - * @param base14Kerning true if base14 kerning applies - */ - public static void setup(FontInfo fontInfo, boolean base14Kerning) { - setup(fontInfo, null, null, base14Kerning); - } - - /** - * Sets up the font info object. - * - * Adds metrics for basic fonts and useful family-style-weight - * triplets for lookup. - * - * @param fontInfo the font info object to set up - * @param embedFontInfoList a list of EmbedFontInfo objects - * @param resourceResolver the font resolver - * @param base14Kerning true if base14 kerning applies - */ - public static void setup(FontInfo fontInfo, List embedFontInfoList, - InternalResourceResolver resourceResolver, boolean base14Kerning) { - fontInfo.addMetrics("F1", new Helvetica(base14Kerning)); - fontInfo.addMetrics("F2", new HelveticaOblique(base14Kerning)); - fontInfo.addMetrics("F3", new HelveticaBold(base14Kerning)); - fontInfo.addMetrics("F4", new HelveticaBoldOblique(base14Kerning)); - fontInfo.addMetrics("F5", new TimesRoman(base14Kerning)); - fontInfo.addMetrics("F6", new TimesItalic(base14Kerning)); - fontInfo.addMetrics("F7", new TimesBold(base14Kerning)); - fontInfo.addMetrics("F8", new TimesBoldItalic(base14Kerning)); - fontInfo.addMetrics("F9", new Courier(base14Kerning)); - fontInfo.addMetrics("F10", new CourierOblique(base14Kerning)); - fontInfo.addMetrics("F11", new CourierBold(base14Kerning)); - fontInfo.addMetrics("F12", new CourierBoldOblique(base14Kerning)); - fontInfo.addMetrics("F13", new Symbol()); - fontInfo.addMetrics("F14", new ZapfDingbats()); - - // Custom type 1 fonts step 1/2 - // fontInfo.addMetrics("F15", new OMEP()); - // fontInfo.addMetrics("F16", new GaramondLightCondensed()); - // fontInfo.addMetrics("F17", new BauerBodoniBoldItalic()); - - /* any is treated as serif */ - fontInfo.addFontProperties("F5", "any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "any", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "any", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F7", "any", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "any", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "any", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - - fontInfo.addFontProperties("F1", "sans-serif", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F2", "sans-serif", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F2", "sans-serif", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F3", "sans-serif", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F4", "sans-serif", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F4", "sans-serif", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F1", "SansSerif", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F2", "SansSerif", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F2", "SansSerif", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F3", "SansSerif", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F4", "SansSerif", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F4", "SansSerif", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F5", "serif", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "serif", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "serif", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F7", "serif", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "serif", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "serif", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F9", "monospace", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F10", "monospace", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F10", "monospace", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F11", "monospace", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F12", "monospace", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F12", "monospace", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F9", "Monospaced", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F10", "Monospaced", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F10", "Monospaced", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F11", "Monospaced", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F12", "Monospaced", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F12", "Monospaced", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - - fontInfo.addFontProperties("F1", "Helvetica", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F2", "Helvetica", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F2", "Helvetica", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F3", "Helvetica", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F4", "Helvetica", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F4", "Helvetica", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F5", "Times", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "Times", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "Times", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F7", "Times", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "Times", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "Times", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F9", "Courier", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F10", "Courier", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F10", "Courier", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F11", "Courier", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F12", "Courier", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F12", "Courier", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F13", "Symbol", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F14", "ZapfDingbats", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - - // Custom type 1 fonts step 2/2 - // fontInfo.addFontProperties("F15", "OMEP", "normal", FontInfo.NORMAL); - // fontInfo.addFontProperties("F16", "Garamond-LightCondensed", "normal", FontInfo.NORMAL); - // fontInfo.addFontProperties("F17", "BauerBodoni", "italic", FontInfo.BOLD); - - /* for compatibility with PassiveTex */ - fontInfo.addFontProperties("F5", "Times-Roman", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "Times-Roman", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "Times-Roman", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F7", "Times-Roman", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "Times-Roman", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "Times-Roman", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F5", "Times Roman", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "Times Roman", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "Times Roman", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F7", "Times Roman", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "Times Roman", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "Times Roman", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F9", "Computer-Modern-Typewriter", - Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - - // All base 14 configured now, so any custom embedded fonts start from 15 - final int startNum = 15; - - /* Add configured fonts */ - addConfiguredFonts(fontInfo, embedFontInfoList, startNum, resourceResolver, base14Kerning); - } - - /** - * Add fonts from configuration file starting with internal name F<num>. - * @param fontInfo the font info to set up - * @param embedFontInfoList a list of EmbedFontInfo objects - * @param num starting index for internal font numbering - * @param resourceResolver the font resolver - */ - private static void addConfiguredFonts(FontInfo fontInfo, - List<EmbedFontInfo> embedFontInfoList, int num, - InternalResourceResolver resourceResolver, - boolean base14Kerning) { - if (embedFontInfoList == null) { - return; //No fonts to process - } - assert resourceResolver != null; - - String internalName = null; - - for (EmbedFontInfo embedFontInfo : embedFontInfoList) { - internalName = "F" + num; - num++; - - LazyFont font = new LazyFont(embedFontInfo, resourceResolver, false); - fontInfo.addMetrics(internalName, font); - - List<FontTriplet> triplets = embedFontInfo.getFontTriplets(); - for (int tripletIndex = 0; tripletIndex < triplets.size(); tripletIndex++) { - FontTriplet triplet = triplets.get(tripletIndex); - fontInfo.addFontProperties(internalName, triplet); - } - } - } -} diff --git a/src/java/org/apache/fop/fonts/FontTriplet.java b/src/java/org/apache/fop/fonts/FontTriplet.java deleted file mode 100644 index a9728428a..000000000 --- a/src/java/org/apache/fop/fonts/FontTriplet.java +++ /dev/null @@ -1,152 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.Serializable; - - -/** - * FontTriplet contains information on name, style and weight of one font - */ -public class FontTriplet implements Comparable<FontTriplet>, Serializable { - - public static final FontTriplet DEFAULT_FONT_TRIPLET - = new FontTriplet("any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - - /** serial version UID */ - private static final long serialVersionUID = 1168991106658033508L; - - private String name; - private String style; - private int weight; - private int priority; // priority of this triplet/font mapping - - //This is only a cache - private transient String key; - - public FontTriplet() { - this(null, null, 0); - } - - /** - * Creates a new font triplet. - * @param name font name - * @param style font style (normal, italic etc.) - * @param weight font weight (100, 200, 300...800, 900) - */ - public FontTriplet(String name, String style, int weight) { - this(name, style, weight, Font.PRIORITY_DEFAULT); - } - - /** - * Creates a new font triplet. - * @param name font name - * @param style font style (normal, italic etc.) - * @param weight font weight (100, 200, 300...800, 900) - * @param priority priority of this triplet/font mapping - */ - public FontTriplet(String name, String style, int weight, int priority) { - this.name = name; - this.style = style; - this.weight = weight; - this.priority = priority; - } - - private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { - ois.defaultReadObject(); - } - - /** @return the font name */ - public String getName() { - return name; - } - - /** @return the font style */ - public String getStyle() { - return style; - } - - /** @return the font weight */ - public int getWeight() { - return weight; - } - - /** @return the priority of this triplet/font mapping */ - public int getPriority() { - return priority; - } - - private String getKey() { - if (this.key == null) { - //This caches the combined key - this.key = getName() + "," + getStyle() + "," + getWeight(); - } - return this.key; - } - - /** {@inheritDoc} */ - public int compareTo(FontTriplet o) { - return getKey().compareTo(o.getKey()); - } - - /** {@inheritDoc} */ - public int hashCode() { - return toString().hashCode(); - } - - /** {@inheritDoc} */ - public boolean equals(Object obj) { - if (obj == null) { - return false; - } else if (obj == this) { - return true; - } else { - if (obj instanceof FontTriplet) { - FontTriplet other = (FontTriplet)obj; - return (getName().equals(other.getName()) - && getStyle().equals(other.getStyle()) - && (getWeight() == other.getWeight())); - } - } - return false; - } - - /** {@inheritDoc} */ - public String toString() { - return getKey(); - } - - - /** - * Matcher interface for {@link FontTriplet}. - */ - public interface Matcher { - - /** - * Indicates whether the given {@link FontTriplet} matches a particular criterium. - * @param triplet the font triplet - * @return true if the font triplet is a match - */ - boolean matches(FontTriplet triplet); - } -} - diff --git a/src/java/org/apache/fop/fonts/FontType.java b/src/java/org/apache/fop/fonts/FontType.java deleted file mode 100644 index fc820c8b9..000000000 --- a/src/java/org/apache/fop/fonts/FontType.java +++ /dev/null @@ -1,142 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -/** - * This class enumerates all supported font types. - */ -public class FontType { - - /** - * Collective identifier for "other" font types - */ - public static final FontType OTHER = new FontType("Other", 0); - /** - * Adobe Type 0 fonts (composite font) - */ - public static final FontType TYPE0 = new FontType("Type0", 1); - /** - * Adobe Type 1 fonts - */ - public static final FontType TYPE1 = new FontType("Type1", 2); - /** - * Adobe Multiple Master Type 1 fonts - */ - public static final FontType MMTYPE1 = new FontType("MMType1", 3); - /** - * Adobe Type 3 fonts ("user-defined" fonts) - */ - public static final FontType TYPE3 = new FontType("Type3", 4); - /** - * TrueType fonts - */ - public static final FontType TRUETYPE = new FontType("TrueType", 5); - - public static final FontType TYPE1C = new FontType("Type1C", 6); - - public static final FontType CIDTYPE0 = new FontType("CIDFontType0", 7); - - private final String name; - private final int value; - - - /** - * Construct a font type. - * @param name a font type name - * @param value a font type value - * @see org.apache.avalon.framework.Enum#Enum(String) - */ - protected FontType(String name, int value) { - this.name = name; - this.value = value; - } - - - /** - * Returns the FontType by name. - * @param name Name of the font type to look up - * @return the font type - */ - public static FontType byName(String name) { - if (name.equalsIgnoreCase(FontType.OTHER.getName())) { - return FontType.OTHER; - } else if (name.equalsIgnoreCase(FontType.TYPE0.getName())) { - return FontType.TYPE0; - } else if (name.equalsIgnoreCase(FontType.TYPE1.getName())) { - return FontType.TYPE1; - } else if (name.equalsIgnoreCase(FontType.MMTYPE1.getName())) { - return FontType.MMTYPE1; - } else if (name.equalsIgnoreCase(FontType.TYPE3.getName())) { - return FontType.TYPE3; - } else if (name.equalsIgnoreCase(FontType.TRUETYPE.getName())) { - return FontType.TRUETYPE; - } else { - throw new IllegalArgumentException("Invalid font type: " + name); - } - } - - - /** - * Returns the FontType by value. - * @param value Value of the font type to look up - * @return the font type - */ - public static FontType byValue(int value) { - if (value == FontType.OTHER.getValue()) { - return FontType.OTHER; - } else if (value == FontType.TYPE0.getValue()) { - return FontType.TYPE0; - } else if (value == FontType.TYPE1.getValue()) { - return FontType.TYPE1; - } else if (value == FontType.MMTYPE1.getValue()) { - return FontType.MMTYPE1; - } else if (value == FontType.TYPE3.getValue()) { - return FontType.TYPE3; - } else if (value == FontType.TRUETYPE.getValue()) { - return FontType.TRUETYPE; - } else { - throw new IllegalArgumentException("Invalid font type: " + value); - } - } - - /** - * Returns the name - * - * @return the name - */ - public String getName() { - return name; - } - - /** - * Returns the value - * - * @return the value - */ - public int getValue() { - return value; - } - - @Override - public String toString() { - return name; - } - -} diff --git a/src/java/org/apache/fop/fonts/FontUris.java b/src/java/org/apache/fop/fonts/FontUris.java deleted file mode 100644 index fe0dfc21a..000000000 --- a/src/java/org/apache/fop/fonts/FontUris.java +++ /dev/null @@ -1,65 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.io.Serializable; -import java.net.URI; - -public class FontUris implements Serializable { - - private static final long serialVersionUID = 8571060588775532701L; - - private final URI embed; - private final URI metrics; - private final URI afm; - private final URI pfm; - - public FontUris(URI embed, URI metrics, URI afm, URI pfm) { - this.embed = embed; - this.metrics = metrics; - this.afm = afm; - this.pfm = pfm; - } - - public FontUris(URI embed, URI metrics) { - this.embed = embed; - this.metrics = metrics; - this.afm = null; - this.pfm = null; - } - - public URI getEmbed() { - return embed; - } - - public URI getMetrics() { - return metrics; - } - - public URI getAfm() { - return afm; - } - - public URI getPfm() { - return pfm; - } - -} - diff --git a/src/java/org/apache/fop/fonts/FontUtil.java b/src/java/org/apache/fop/fonts/FontUtil.java deleted file mode 100644 index 1966d9fca..000000000 --- a/src/java/org/apache/fop/fonts/FontUtil.java +++ /dev/null @@ -1,159 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - - -/** - * Font utilities. - */ -public final class FontUtil { - - private FontUtil() { - } - - /** - * Parses an CSS2 (SVG and XSL-FO) font weight (normal, bold, 100-900) to - * an integer. - * See http://www.w3.org/TR/REC-CSS2/fonts.html#propdef-font-weight - * TODO: Implement "lighter" and "bolder". - * @param text the font weight to parse - * @return an integer between 100 and 900 (100, 200, 300...) - */ - public static int parseCSS2FontWeight(String text) { - int weight = 400; - try { - weight = Integer.parseInt(text); - weight = (weight / 100) * 100; - weight = Math.max(weight, 100); - weight = Math.min(weight, 900); - } catch (NumberFormatException nfe) { - //weight is no number, so convert symbolic name to number - if (text.equals("normal")) { - weight = 400; - } else if (text.equals("bold")) { - weight = 700; - } else { - throw new IllegalArgumentException( - "Illegal value for font weight: '" - + text - + "'. Use one of: 100, 200, 300, " - + "400, 500, 600, 700, 800, 900, " - + "normal (=400), bold (=700)"); - } - } - return weight; - } - - /** - * Removes all white space from a string (used primarily for font names) - * @param str the string - * @return the processed result - */ - public static String stripWhiteSpace(String str) { - if (str != null) { - StringBuffer stringBuffer = new StringBuffer(str.length()); - for (int i = 0, strLen = str.length(); i < strLen; i++) { - final char ch = str.charAt(i); - if (ch != ' ' && ch != '\r' && ch != '\n' && ch != '\t') { - stringBuffer.append(ch); - } - } - return stringBuffer.toString(); - } - return str; - } - - /** font constituent names which identify a font as being of "italic" style */ - private static final String[] ITALIC_WORDS = { - Font.STYLE_ITALIC, Font.STYLE_OBLIQUE, Font.STYLE_INCLINED - }; - - /** font constituent names which identify a font as being of "light" weight */ - private static final String[] LIGHT_WORDS = {"light"}; - /** font constituent names which identify a font as being of "medium" weight */ - private static final String[] MEDIUM_WORDS = {"medium"}; - /** font constituent names which identify a font as being of "demi/semi" weight */ - private static final String[] DEMI_WORDS = {"demi", "semi"}; - /** font constituent names which identify a font as being of "bold" weight */ - private static final String[] BOLD_WORDS = {"bold"}; - /** font constituent names which identify a font as being of "extra bold" weight */ - private static final String[] EXTRA_BOLD_WORDS = {"extrabold", "extra bold", "black", - "heavy", "ultra", "super"}; - - /** - * Guesses the font style of a font using its name. - * @param fontName the font name - * @return "normal" or "italic" - */ - public static String guessStyle(String fontName) { - if (fontName != null) { - for (int i = 0; i < ITALIC_WORDS.length; i++) { - if (fontName.indexOf(ITALIC_WORDS[i]) != -1) { - return Font.STYLE_ITALIC; - } - } - } - return Font.STYLE_NORMAL; - } - - /** - * Guesses the font weight of a font using its name. - * @param fontName the font name - * @return an integer between 100 and 900 - */ - public static int guessWeight(String fontName) { - // weight - int weight = Font.WEIGHT_NORMAL; - - for (int i = 0; i < BOLD_WORDS.length; i++) { - if (fontName.indexOf(BOLD_WORDS[i]) != -1) { - weight = Font.WEIGHT_BOLD; - break; - } - } - for (int i = 0; i < MEDIUM_WORDS.length; i++) { - if (fontName.indexOf(MEDIUM_WORDS[i]) != -1) { - weight = Font.WEIGHT_NORMAL + 100; //500 - break; - } - } - //Search for "semi/demi" before "light", but after "bold" - //(normally semi/demi-bold is meant, but it can also be semi/demi-light) - for (int i = 0; i < DEMI_WORDS.length; i++) { - if (fontName.indexOf(DEMI_WORDS[i]) != -1) { - weight = Font.WEIGHT_BOLD - 100; //600 - break; - } - } - for (int i = 0; i < EXTRA_BOLD_WORDS.length; i++) { - if (fontName.indexOf(EXTRA_BOLD_WORDS[i]) != -1) { - weight = Font.WEIGHT_EXTRA_BOLD; - break; - } - } - for (int i = 0; i < LIGHT_WORDS.length; i++) { - if (fontName.indexOf(LIGHT_WORDS[i]) != -1) { - weight = Font.WEIGHT_LIGHT; - break; - } - } - return weight; - } -} diff --git a/src/java/org/apache/fop/fonts/GlyphMapping.java b/src/java/org/apache/fop/fonts/GlyphMapping.java deleted file mode 100644 index 95db0ff48..000000000 --- a/src/java/org/apache/fop/fonts/GlyphMapping.java +++ /dev/null @@ -1,340 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.complexscripts.fonts.GlyphPositioningTable; -import org.apache.fop.complexscripts.fonts.GlyphTable; -import org.apache.fop.complexscripts.util.CharScript; -import org.apache.fop.traits.MinOptMax; -import org.apache.fop.util.CharUtilities; - -/** - * Stores the mapping of a text fragment to glyphs, along with various information. - */ -public class GlyphMapping { - - private static final Log LOG = LogFactory.getLog(GlyphMapping.class); - /** Inclusive. */ - public final int startIndex; - /** Exclusive. */ - public final int endIndex; - private int wordCharLength; - public final int wordSpaceCount; - public int letterSpaceCount; - public MinOptMax areaIPD; - public final boolean isHyphenated; - public final boolean isSpace; - public boolean breakOppAfter; - public final Font font; - public final int level; - public final int[][] gposAdjustments; - public String mapping; - public List associations; - - public GlyphMapping(int startIndex, int endIndex, int wordSpaceCount, int letterSpaceCount, - MinOptMax areaIPD, boolean isHyphenated, boolean isSpace, boolean breakOppAfter, - Font font, int level, int[][] gposAdjustments) { - this(startIndex, endIndex, wordSpaceCount, letterSpaceCount, areaIPD, isHyphenated, - isSpace, breakOppAfter, font, level, gposAdjustments, null, null); - } - - public GlyphMapping(int startIndex, int endIndex, int wordSpaceCount, int letterSpaceCount, - MinOptMax areaIPD, boolean isHyphenated, boolean isSpace, boolean breakOppAfter, - Font font, int level, int[][] gposAdjustments, String mapping, List associations) { - assert startIndex <= endIndex; - this.startIndex = startIndex; - this.endIndex = endIndex; - this.wordCharLength = -1; - this.wordSpaceCount = wordSpaceCount; - this.letterSpaceCount = letterSpaceCount; - this.areaIPD = areaIPD; - this.isHyphenated = isHyphenated; - this.isSpace = isSpace; - this.breakOppAfter = breakOppAfter; - this.font = font; - this.level = level; - this.gposAdjustments = gposAdjustments; - this.mapping = mapping; - this.associations = associations; - } - - public static GlyphMapping doGlyphMapping(TextFragment text, int startIndex, int endIndex, - Font font, MinOptMax letterSpaceIPD, MinOptMax[] letterSpaceAdjustArray, - char precedingChar, char breakOpportunityChar, final boolean endsWithHyphen, int level, - boolean dontOptimizeForIdentityMapping, boolean retainAssociations, boolean retainControls) { - GlyphMapping mapping; - if (font.performsSubstitution() || font.performsPositioning()) { - mapping = processWordMapping(text, startIndex, endIndex, font, - breakOpportunityChar, endsWithHyphen, level, - dontOptimizeForIdentityMapping, retainAssociations, retainControls); - } else { - mapping = processWordNoMapping(text, startIndex, endIndex, font, - letterSpaceIPD, letterSpaceAdjustArray, precedingChar, breakOpportunityChar, endsWithHyphen, level); - } - return mapping; - } - - private static GlyphMapping processWordMapping(TextFragment text, int startIndex, - int endIndex, final Font font, final char breakOpportunityChar, - final boolean endsWithHyphen, int level, - boolean dontOptimizeForIdentityMapping, boolean retainAssociations, boolean retainControls) { - int e = endIndex; // end index of word in FOText character buffer - int nLS = 0; // # of letter spaces - String script = text.getScript(); - String language = text.getLanguage(); - - if (LOG.isDebugEnabled()) { - LOG.debug("PW: [" + startIndex + "," + endIndex + "]: {" - + " +M" - + ", level = " + level - + " }"); - } - - // 1. extract unmapped character sequence. - CharSequence ics = text.subSequence(startIndex, e); - - // 2. if script is not specified (by FO property) or it is specified as 'auto', - // then compute dominant script. - if ((script == null) || "auto".equals(script)) { - script = CharScript.scriptTagFromCode(CharScript.dominantScript(ics)); - } - if ((language == null) || "none".equals(language)) { - language = "dflt"; - } - - // 3. perform mapping of chars to glyphs ... to glyphs ... to chars, retaining - // associations if requested. - List associations = retainAssociations ? new java.util.ArrayList() : null; - CharSequence mcs = font.performSubstitution(ics, script, language, associations, retainControls); - - // 4. compute glyph position adjustments on (substituted) characters. - int[][] gpa = null; - if (font.performsPositioning()) { - // handle GPOS adjustments - gpa = font.performPositioning(mcs, script, language); - } - if (useKerningAdjustments(font, script, language)) { - // handle standard (non-GPOS) kerning adjustments - gpa = getKerningAdjustments(mcs, font, gpa); - } - - // 5. reorder combining marks so that they precede (within the mapped char sequence) the - // base to which they are applied; N.B. position adjustments (gpa) are reordered in place. - mcs = font.reorderCombiningMarks(mcs, gpa, script, language, associations); - - // 6. compute word ipd based on final position adjustments. - MinOptMax ipd = MinOptMax.ZERO; - for (int i = 0, n = mcs.length(); i < n; i++) { - int c = mcs.charAt(i); - // TODO !BMP - int w = font.getCharWidth(c); - if (w < 0) { - w = 0; - } - if (gpa != null) { - w += gpa[i][GlyphPositioningTable.Value.IDX_X_ADVANCE]; - } - ipd = ipd.plus(w); - } - - // [TBD] - handle letter spacing - - return new GlyphMapping(startIndex, e, 0, nLS, ipd, endsWithHyphen, false, - breakOpportunityChar != 0, font, level, gpa, - !dontOptimizeForIdentityMapping && CharUtilities.isSameSequence(mcs, ics) ? null : mcs.toString(), - associations); - } - - private static boolean useKerningAdjustments(final Font font, String script, String language) { - return font.hasKerning() && !font.hasFeature(GlyphTable.GLYPH_TABLE_TYPE_POSITIONING, script, language, "kern"); - } - - /** - * Given a mapped character sequence MCS, obtain glyph position adjustments from the - * font's kerning data. - * - * @param mcs mapped character sequence - * @param font applicable font - * @return glyph position adjustments (or null if no kerning) - */ - private static int[][] getKerningAdjustments(CharSequence mcs, final Font font, int[][] gpa) { - int nc = mcs.length(); - // extract kerning array - int[] ka = new int[nc]; // kerning array - for (int i = 0, n = nc, cPrev = -1; i < n; i++) { - int c = mcs.charAt(i); - // TODO !BMP - if (cPrev >= 0) { - ka[i] = font.getKernValue(cPrev, c); - } - cPrev = c; - } - // was there a non-zero kerning? - boolean hasKerning = false; - for (int i = 0, n = nc; i < n; i++) { - if (ka[i] != 0) { - hasKerning = true; - break; - } - } - // if non-zero kerning, then create and return glyph position adjustment array - if (hasKerning) { - if (gpa == null) { - gpa = new int[nc][4]; - } - for (int i = 0, n = nc; i < n; i++) { - if (i > 0) { - gpa [i - 1][GlyphPositioningTable.Value.IDX_X_ADVANCE] += ka[i]; - } - } - return gpa; - } else { - return null; - } - } - - private static GlyphMapping processWordNoMapping(TextFragment text, int startIndex, int endIndex, - final Font font, MinOptMax letterSpaceIPD, MinOptMax[] letterSpaceAdjustArray, - char precedingChar, final char breakOpportunityChar, final boolean endsWithHyphen, int level) { - boolean kerning = font.hasKerning(); - MinOptMax wordIPD = MinOptMax.ZERO; - - if (LOG.isDebugEnabled()) { - LOG.debug("PW: [" + startIndex + "," + endIndex + "]: {" - + " -M" - + ", level = " + level - + " }"); - } - - for (int i = startIndex; i < endIndex; i++) { - char currentChar = text.charAt(i); - - // character width - int charWidth = font.getCharWidth(currentChar); - wordIPD = wordIPD.plus(charWidth); - - // kerning - if (kerning) { - int kern = 0; - if (i > startIndex) { - char previousChar = text.charAt(i - 1); - kern = font.getKernValue(previousChar, currentChar); - } else if (precedingChar != 0) { - kern = font.getKernValue(precedingChar, currentChar); - } - if (kern != 0) { - addToLetterAdjust(letterSpaceAdjustArray, i, kern); - wordIPD = wordIPD.plus(kern); - } - } - } - if (kerning - && (breakOpportunityChar != 0) - && !isSpace(breakOpportunityChar) - && endIndex > 0 - && endsWithHyphen) { - int kern = font.getKernValue(text.charAt(endIndex - 1), breakOpportunityChar); - if (kern != 0) { - addToLetterAdjust(letterSpaceAdjustArray, endIndex, kern); - // TODO: add kern to wordIPD? - } - } - // shy+chars at start of word: wordLength == 0 && breakOpportunity - // shy only characters in word: wordLength == 0 && !breakOpportunity - int wordLength = endIndex - startIndex; - int letterSpaces = 0; - if (wordLength != 0) { - letterSpaces = wordLength - 1; - // if there is a break opportunity and the next one (break character) - // is not a space, it could be used as a line end; - // add one more letter space, in case other text follows - if ((breakOpportunityChar != 0) && !isSpace(breakOpportunityChar)) { - letterSpaces++; - } - } - assert letterSpaces >= 0; - wordIPD = wordIPD.plus(letterSpaceIPD.mult(letterSpaces)); - - // create and return the AreaInfo object - return new GlyphMapping(startIndex, endIndex, 0, letterSpaces, wordIPD, endsWithHyphen, false, - (breakOpportunityChar != 0) && !isSpace(breakOpportunityChar), font, level, null); - } - - private static void addToLetterAdjust(MinOptMax[] letterSpaceAdjustArray, int index, int width) { - if (letterSpaceAdjustArray[index] == null) { - letterSpaceAdjustArray[index] = MinOptMax.getInstance(width); - } else { - letterSpaceAdjustArray[index] = letterSpaceAdjustArray[index].plus(width); - } - } - - /** - * Indicates whether a character is a space in terms of this layout manager. - * - * @param ch the character - * @return true if it's a space - */ - public static boolean isSpace(final char ch) { - return ch == CharUtilities.SPACE - || CharUtilities.isNonBreakableSpace(ch) - || CharUtilities.isFixedWidthSpace(ch); - } - - /** - * Obtain number of 'characters' contained in word. If word is mapped, then this - * number may be less than or greater than the original length (breakIndex - - * startIndex). We compute and memoize thius length upon first invocation of this - * method. - */ - public int getWordLength() { - if (wordCharLength == -1) { - if (mapping != null) { - wordCharLength = mapping.length(); - } else { - assert endIndex >= startIndex; - wordCharLength = endIndex - startIndex; - } - } - return wordCharLength; - } - - public void addToAreaIPD(MinOptMax idp) { - areaIPD = areaIPD.plus(idp); - } - - public String toString() { - return super.toString() + "{" - + "interval = [" + startIndex + "," + endIndex + "]" - + ", isSpace = " + isSpace - + ", level = " + level - + ", areaIPD = " + areaIPD - + ", letterSpaceCount = " + letterSpaceCount - + ", wordSpaceCount = " + wordSpaceCount - + ", isHyphenated = " + isHyphenated - + ", font = " + font - + "}"; - } - -} diff --git a/src/java/org/apache/fop/fonts/Glyphs.java b/src/java/org/apache/fop/fonts/Glyphs.java deleted file mode 100644 index 04098f590..000000000 --- a/src/java/org/apache/fop/fonts/Glyphs.java +++ /dev/null @@ -1,1318 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -/** - * This class provides a number of constants for glyph management. - * @deprecated Use the Glyphs class from XML Graphics Commons instead! - */ -public final class Glyphs { - - private Glyphs() { - } - - /** - * Glyph name for the "notdef" glyph - */ - public static final String NOTDEF = ".notdef"; - - /** - * Glyph names for Mac encoding - */ - public static final String[] MAC_GLYPH_NAMES = { - /* 0x00 */ - NOTDEF, ".null", "CR", "space", "exclam", "quotedbl", "numbersign", - "dollar", "percent", "ampersand", "quotesingle", "parenleft", - "parenright", "asterisk", "plus", "comma", /* 0x10 */ - "hyphen", "period", "slash", "zero", "one", "two", "three", "four", - "five", "six", "seven", "eight", "nine", "colon", - "semicolon", "less", /* 0x20 */ - "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", - "G", "H", "I", "J", "K", "L", /* 0x30 */ - "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", - "bracketleft", "backslash", /* 0x40 */ - "bracketright", "asciicircum", "underscore", "grave", "a", "b", "c", - "d", "e", "f", "g", "h", "i", "j", "k", "l", - /* 0x50 */ - "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", - "braceleft", "bar", /* 0x60 */ - "braceright", "asciitilde", "Adieresis", "Aring", "Ccedilla", - "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute", - "agrave", "acircumflex", "adieresis", "atilde", - "aring", "ccedilla", /* 0x70 */ - "eacute", "egrave", "ecircumflex", "edieresis", "iacute", "igrave", - "icircumflex", "idieresis", "ntilde", "oacute", "ograve", - "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", - /* 0x80 */ - "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling", - "section", "bullet", "paragraph", "germandbls", - "registered", "copyright", "trademark", "acute", - "dieresis", "notequal", /* 0x90 */ - "AE", "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", - "yen", "mu", "partialdiff", "Sigma", "Pi", "pi", "integral", - "ordfeminine", "ordmasculine", "Omega", /* 0xa0 */ - "ae", "oslash", "questiondown", "exclamdown", "logicalnot", - "radical", "florin", "approxequal", "Delta", "guillemotleft", - "guillemotright", "ellipsis", "nbspace", "Agrave", "Atilde", - "Otilde", /* 0xb0 */ - "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright", - "quoteleft", "quoteright", "divide", "lozenge", "ydieresis", - "Ydieresis", "fraction", "currency", "guilsinglleft", - "guilsinglright", /* 0xc0 */ - "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase", - "quotedblbase", "perthousand", "Acircumflex", "Ecircumflex", - "Aacute", "Edieresis", "Egrave", "Iacute", "Icircumflex", - "Idieresis", "Igrave", /* 0xd0 */ - "Oacute", "Ocircumflex", "applelogo", "Ograve", "Uacute", - "Ucircumflex", "Ugrave", "dotlessi", "circumflex", "tilde", - "macron", "breve", "dotaccent", "ring", "cedilla", - "hungarumlaut", /* 0xe0 */ - "ogonek", "caron", "Lslash", "lslash", "Scaron", "scaron", "Zcaron", - "zcaron", "brokenbar", "Eth", "eth", "Yacute", "yacute", - "Thorn", "thorn", "minus", /* 0xf0 */ - "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", - "onequarter", "threequarters", "franc", "Gbreve", - "gbreve", "Idot", "Scedilla", "scedilla", "Cacute", - "cacute", "Ccaron", /* 0x100 */ - "ccaron", "dmacron" - }; - - /** - * Glyph names for tex8r encoding - */ - public static final String[] TEX8R_GLYPH_NAMES = { - // 0x00 - NOTDEF, "dotaccent", "fi", "fl", "fraction", "hungarumlaut", - "Lslash", "lslash", "ogonek", "ring", ".notdef", "breve", - "minus", ".notdef", "Zcaron", "zcaron", // 0x10 - "caron", "dotlessi", "dotlessj", "ff", "ffi", "ffl", ".notdef", - ".notdef", ".notdef", ".notdef", ".notdef", ".notdef", - ".notdef", ".notdef", "grave", "quotesingle", // 0x20 - "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", - "ampersand", "quoteright", "parenleft", "parenright", - "asterisk", "plus", "comma", "hyphen", "period", "slash", - // 0x30 - "zero", "one", "two", "three", "four", "five", "six", "seven", - "eight", "nine", "colon", "semicolon", "less", "equal", - "greater", "question", // 0x40 - "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", - "M", "N", "O", // 0x50 - "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", - "backslash", "bracketright", "asciicircum", "underscore", // 0x60 - "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", - "l", "m", "n", "o", // 0x70 - "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", - "bar", "braceright", "asciitilde", ".notdef", // 0x80 - "Euro", ".notdef", "quotesinglbase", "florin", "quotedblbase", - "ellipsis", "dagger", "daggerdbl", "circumflex", - "perthousand", "Scaron", "guilsinglleft", "OE", ".notdef", - ".notdef", ".notdef", // 0x90 - ".notdef", ".notdef", ".notdef", "quotedblleft", "quotedblright", - "bullet", "endash", "emdash", "tilde", "trademark", - "scaron", "guilsinglright", "oe", ".notdef", ".notdef", - "Ydieresis", // 0xA0 - ".notdef", "exclamdown", "cent", "sterling", "currency", "yen", - "brokenbar", "section", "dieresis", "copyright", - "ordfeminine", "guillemotleft", "logicalnot", "hyphen", - "registered", "macron", // 0xB0 - "degree", "plusminus", "twosuperior", "threesuperior", "acute", "mu", - "paragraph", "periodcentered", "cedilla", "onesuperior", - "ordmasculine", "guillemotright", "onequarter", "onehalf", - "threequarters", "questiondown", // 0xC0 - "Agrave", "Aacute", "Acircumflex", "Atilde", "Adieresis", "Aring", - "AE", "Ccedilla", "Egrave", "Eacute", "Ecircumflex", - "Edieresis", "Igrave", "Iacute", "Icircumflex", - "Idieresis", // 0xD0 - "Eth", "Ntilde", "Ograve", "Oacute", "Ocircumflex", "Otilde", - "Odieresis", "multiply", "Oslash", "Ugrave", "Uacute", - "Ucircumflex", "Udieresis", "Yacute", "Thorn", "germandbls", - // 0xE0 - "agrave", "aacute", "acircumflex", "atilde", "adieresis", "aring", - "ae", "ccedilla", "egrave", "eacute", "ecircumflex", - "edieresis", "igrave", "iacute", "icircumflex", - "idieresis", // 0xF0 - "eth", "ntilde", "ograve", "oacute", "ocircumflex", "otilde", - "odieresis", "divide", "oslash", "ugrave", "uacute", - "ucircumflex", "udieresis", "yacute", "thorn", "ydieresis" - }; - - /** - * The characters in WinAnsiEncoding - */ - public static final char[] WINANSI_ENCODING = { - // not used until char 32 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20 - ' ', '\u0021', '\"', '\u0023', '$', '%', '&', '\'', '(', ')', '*', '+', ',', - '\u002d', '\u002e', '/', // 0x30 - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', - '>', '?', '@', // 0x40 - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', // 0x50 - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u005b', '\\', - '\u005d', '^', '_', // 0x60 - '\u2018', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', // 0x70 - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\u007b', '\u007c', '\u007d', - '\u007e', '\u2022', // 0x80 - '\u20ac', '\u2022', '\u201a', '\u0192', '\u201e', '\u2026', '\u2020', - '\u2021', '\u02c6', '\u2030', '\u0160', '\u2039', '\u0152', '\u2022', - '\u017d', '\u2022', // 0x90 - '\u2022', '\u2018', // quoteleft - '\u2019', // quoteright - '\u201c', // quotedblleft - '\u201d', // quotedblright - '\u2022', // bullet - '\u2013', // endash - '\u2014', // emdash - '~', - '\u2122', // trademark - '\u0161', '\u203a', '\u0153', '\u2022', '\u017e', '\u0178', // 0xA0 - ' ', '\u00a1', '\u00a2', '\u00a3', '\u00a4', '\u00a5', - '\u00a6', '\u00a7', '\u00a8', '\u00a9', '\u00aa', '\u00ab', - '\u00ac', '\u00ad', '\u00ae', '\u00af', // 0xb0 - '\u00b0', '\u00b1', '\u00b2', '\u00b3', '\u00b4', - '\u00b5', // This is hand-coded, the rest is assumption - '\u00b6', // and *might* not be correct... - '\u00b7', '\u00b8', '\u00b9', '\u00ba', '\u00bb', '\u00bc', '\u00bd', - '\u00be', '\u00bf', // 0xc0 - '\u00c0', '\u00c1', '\u00c2', '\u00c3', '\u00c4', '\u00c5', // Aring - '\u00c6', // AE - '\u00c7', '\u00c8', '\u00c9', '\u00ca', '\u00cb', '\u00cc', - '\u00cd', '\u00ce', '\u00cf', // 0xd0 - '\u00d0', '\u00d1', '\u00d2', '\u00d3', '\u00d4', '\u00d5', - '\u00d6', '\u00d7', '\u00d8', // Oslash - '\u00d9', '\u00da', '\u00db', '\u00dc', '\u00dd', '\u00de', - '\u00df', // 0xe0 - '\u00e0', '\u00e1', '\u00e2', '\u00e3', '\u00e4', '\u00e5', // aring - '\u00e6', // ae - '\u00e7', '\u00e8', '\u00e9', '\u00ea', '\u00eb', '\u00ec', - '\u00ed', '\u00ee', '\u00ef', // 0xf0 - '\u00f0', '\u00f1', '\u00f2', '\u00f3', '\u00f4', '\u00f5', - '\u00f6', '\u00f7', '\u00f8', '\u00f9', '\u00fa', '\u00fb', - '\u00fc', '\u00fd', '\u00fe', '\u00ff' - }; - - /** - * List of unicode glyphs - */ - public static final String[] UNICODE_GLYPHS = { - "\u0041", "A", - "\u00C6", "AE", - "\u01FC", "AEacute", - "\uF7E6", "AEsmall", - "\u00C1", "Aacute", - "\uF7E1", "Aacutesmall", - "\u0102", "Abreve", - "\u00C2", "Acircumflex", - "\uF7E2", "Acircumflexsmall", - "\uF6C9", "Acute", - "\uF7B4", "Acutesmall", - "\u00C4", "Adieresis", - "\uF7E4", "Adieresissmall", - "\u00C0", "Agrave", - "\uF7E0", "Agravesmall", - "\u0391", "Alpha", - "\u0386", "Alphatonos", - "\u0100", "Amacron", - "\u0104", "Aogonek", - "\u00C5", "Aring", - "\u01FA", "Aringacute", - "\uF7E5", "Aringsmall", - "\uF761", "Asmall", - "\u00C3", "Atilde", - "\uF7E3", "Atildesmall", - "\u0042", "B", - "\u0392", "Beta", - "\uF6F4", "Brevesmall", - "\uF762", "Bsmall", - "\u0043", "C", - "\u0106", "Cacute", - "\uF6CA", "Caron", - "\uF6F5", "Caronsmall", - "\u010C", "Ccaron", - "\u00C7", "Ccedilla", - "\uF7E7", "Ccedillasmall", - "\u0108", "Ccircumflex", - "\u010A", "Cdotaccent", - "\uF7B8", "Cedillasmall", - "\u03A7", "Chi", - "\uF6F6", "Circumflexsmall", - "\uF763", "Csmall", - "\u0044", "D", - "\u010E", "Dcaron", - "\u0110", "Dcroat", - "\u2206", "Delta", - "\u0394", "Delta", - "\uF6CB", "Dieresis", - "\uF6CC", "DieresisAcute", - "\uF6CD", "DieresisGrave", - "\uF7A8", "Dieresissmall", - "\uF6F7", "Dotaccentsmall", - "\uF764", "Dsmall", - "\u0045", "E", - "\u00C9", "Eacute", - "\uF7E9", "Eacutesmall", - "\u0114", "Ebreve", - "\u011A", "Ecaron", - "\u00CA", "Ecircumflex", - "\uF7EA", "Ecircumflexsmall", - "\u00CB", "Edieresis", - "\uF7EB", "Edieresissmall", - "\u0116", "Edotaccent", - "\u00C8", "Egrave", - "\uF7E8", "Egravesmall", - "\u0112", "Emacron", - "\u014A", "Eng", - "\u0118", "Eogonek", - "\u0395", "Epsilon", - "\u0388", "Epsilontonos", - "\uF765", "Esmall", - "\u0397", "Eta", - "\u0389", "Etatonos", - "\u00D0", "Eth", - "\uF7F0", "Ethsmall", - "\u20AC", "Euro", - "\u0046", "F", - "\uF766", "Fsmall", - "\u0047", "G", - "\u0393", "Gamma", - "\u011E", "Gbreve", - "\u01E6", "Gcaron", - "\u011C", "Gcircumflex", - "\u0122", "Gcommaaccent", - "\u0120", "Gdotaccent", - "\uF6CE", "Grave", - "\uF760", "Gravesmall", - "\uF767", "Gsmall", - "\u0048", "H", - "\u25CF", "H18533", - "\u25AA", "H18543", - "\u25AB", "H18551", - "\u25A1", "H22073", - "\u0126", "Hbar", - "\u0124", "Hcircumflex", - "\uF768", "Hsmall", - "\uF6CF", "Hungarumlaut", - "\uF6F8", "Hungarumlautsmall", - "\u0049", "I", - "\u0132", "IJ", - "\u00CD", "Iacute", - "\uF7ED", "Iacutesmall", - "\u012C", "Ibreve", - "\u00CE", "Icircumflex", - "\uF7EE", "Icircumflexsmall", - "\u00CF", "Idieresis", - "\uF7EF", "Idieresissmall", - "\u0130", "Idotaccent", - "\u2111", "Ifraktur", - "\u00CC", "Igrave", - "\uF7EC", "Igravesmall", - "\u012A", "Imacron", - "\u012E", "Iogonek", - "\u0399", "Iota", - "\u03AA", "Iotadieresis", - "\u038A", "Iotatonos", - "\uF769", "Ismall", - "\u0128", "Itilde", - "\u004A", "J", - "\u0134", "Jcircumflex", - "\uF76A", "Jsmall", - "\u004B", "K", - "\u039A", "Kappa", - "\u0136", "Kcommaaccent", - "\uF76B", "Ksmall", - "\u004C", "L", - "\uF6BF", "LL", - "\u0139", "Lacute", - "\u039B", "Lambda", - "\u013D", "Lcaron", - "\u013B", "Lcommaaccent", - "\u013F", "Ldot", - "\u0141", "Lslash", - "\uF6F9", "Lslashsmall", - "\uF76C", "Lsmall", - "\u004D", "M", - "\uF6D0", "Macron", - "\uF7AF", "Macronsmall", - "\uF76D", "Msmall", - "\u039C", "Mu", - "\u004E", "N", - "\u0143", "Nacute", - "\u0147", "Ncaron", - "\u0145", "Ncommaaccent", - "\uF76E", "Nsmall", - "\u00D1", "Ntilde", - "\uF7F1", "Ntildesmall", - "\u039D", "Nu", - "\u004F", "O", - "\u0152", "OE", - "\uF6FA", "OEsmall", - "\u00D3", "Oacute", - "\uF7F3", "Oacutesmall", - "\u014E", "Obreve", - "\u00D4", "Ocircumflex", - "\uF7F4", "Ocircumflexsmall", - "\u00D6", "Odieresis", - "\uF7F6", "Odieresissmall", - "\uF6FB", "Ogoneksmall", - "\u00D2", "Ograve", - "\uF7F2", "Ogravesmall", - "\u01A0", "Ohorn", - "\u0150", "Ohungarumlaut", - "\u014C", "Omacron", - "\u2126", "Omega", - "\u03A9", "Omega", - "\u038F", "Omegatonos", - "\u039F", "Omicron", - "\u038C", "Omicrontonos", - "\u00D8", "Oslash", - "\u01FE", "Oslashacute", - "\uF7F8", "Oslashsmall", - "\uF76F", "Osmall", - "\u00D5", "Otilde", - "\uF7F5", "Otildesmall", - "\u0050", "P", - "\u03A6", "Phi", - "\u03A0", "Pi", - "\u03A8", "Psi", - "\uF770", "Psmall", - "\u0051", "Q", - "\uF771", "Qsmall", - "\u0052", "R", - "\u0154", "Racute", - "\u0158", "Rcaron", - "\u0156", "Rcommaaccent", - "\u211C", "Rfraktur", - "\u03A1", "Rho", - "\uF6FC", "Ringsmall", - "\uF772", "Rsmall", - "\u0053", "S", - "\u250C", "SF010000", - "\u2514", "SF020000", - "\u2510", "SF030000", - "\u2518", "SF040000", - "\u253C", "SF050000", - "\u252C", "SF060000", - "\u2534", "SF070000", - "\u251C", "SF080000", - "\u2524", "SF090000", - "\u2500", "SF100000", - "\u2502", "SF110000", - "\u2561", "SF190000", - "\u2562", "SF200000", - "\u2556", "SF210000", - "\u2555", "SF220000", - "\u2563", "SF230000", - "\u2551", "SF240000", - "\u2557", "SF250000", - "\u255D", "SF260000", - "\u255C", "SF270000", - "\u255B", "SF280000", - "\u255E", "SF360000", - "\u255F", "SF370000", - "\u255A", "SF380000", - "\u2554", "SF390000", - "\u2569", "SF400000", - "\u2566", "SF410000", - "\u2560", "SF420000", - "\u2550", "SF430000", - "\u256C", "SF440000", - "\u2567", "SF450000", - "\u2568", "SF460000", - "\u2564", "SF470000", - "\u2565", "SF480000", - "\u2559", "SF490000", - "\u2558", "SF500000", - "\u2552", "SF510000", - "\u2553", "SF520000", - "\u256B", "SF530000", - "\u256A", "SF540000", - "\u015A", "Sacute", - "\u0160", "Scaron", - "\uF6FD", "Scaronsmall", - "\u015E", "Scedilla", - "\uF6C1", "Scedilla", - "\u015C", "Scircumflex", - "\u0218", "Scommaaccent", - "\u03A3", "Sigma", - "\uF773", "Ssmall", - "\u0054", "T", - "\u03A4", "Tau", - "\u0166", "Tbar", - "\u0164", "Tcaron", - "\u0162", "Tcommaaccent", - "\u021A", "Tcommaaccent", - "\u0398", "Theta", - "\u00DE", "Thorn", - "\uF7FE", "Thornsmall", - "\uF6FE", "Tildesmall", - "\uF774", "Tsmall", - "\u0055", "U", - "\u00DA", "Uacute", - "\uF7FA", "Uacutesmall", - "\u016C", "Ubreve", - "\u00DB", "Ucircumflex", - "\uF7FB", "Ucircumflexsmall", - "\u00DC", "Udieresis", - "\uF7FC", "Udieresissmall", - "\u00D9", "Ugrave", - "\uF7F9", "Ugravesmall", - "\u01AF", "Uhorn", - "\u0170", "Uhungarumlaut", - "\u016A", "Umacron", - "\u0172", "Uogonek", - "\u03A5", "Upsilon", - "\u03D2", "Upsilon1", - "\u03AB", "Upsilondieresis", - "\u038E", "Upsilontonos", - "\u016E", "Uring", - "\uF775", "Usmall", - "\u0168", "Utilde", - "\u0056", "V", - "\uF776", "Vsmall", - "\u0057", "W", - "\u1E82", "Wacute", - "\u0174", "Wcircumflex", - "\u1E84", "Wdieresis", - "\u1E80", "Wgrave", - "\uF777", "Wsmall", - "\u0058", "X", - "\u039E", "Xi", - "\uF778", "Xsmall", - "\u0059", "Y", - "\u00DD", "Yacute", - "\uF7FD", "Yacutesmall", - "\u0176", "Ycircumflex", - "\u0178", "Ydieresis", - "\uF7FF", "Ydieresissmall", - "\u1EF2", "Ygrave", - "\uF779", "Ysmall", - "\u005A", "Z", - "\u0179", "Zacute", - "\u017D", "Zcaron", - "\uF6FF", "Zcaronsmall", - "\u017B", "Zdotaccent", - "\u0396", "Zeta", - "\uF77A", "Zsmall", - "\u0061", "a", - "\u00E1", "aacute", - "\u0103", "abreve", - "\u00E2", "acircumflex", - "\u00B4", "acute", - "\u0301", "acutecomb", - "\u00E4", "adieresis", - "\u00E6", "ae", - "\u01FD", "aeacute", - "\u2015", "afii00208", - "\u0410", "afii10017", - "\u0411", "afii10018", - "\u0412", "afii10019", - "\u0413", "afii10020", - "\u0414", "afii10021", - "\u0415", "afii10022", - "\u0401", "afii10023", - "\u0416", "afii10024", - "\u0417", "afii10025", - "\u0418", "afii10026", - "\u0419", "afii10027", - "\u041A", "afii10028", - "\u041B", "afii10029", - "\u041C", "afii10030", - "\u041D", "afii10031", - "\u041E", "afii10032", - "\u041F", "afii10033", - "\u0420", "afii10034", - "\u0421", "afii10035", - "\u0422", "afii10036", - "\u0423", "afii10037", - "\u0424", "afii10038", - "\u0425", "afii10039", - "\u0426", "afii10040", - "\u0427", "afii10041", - "\u0428", "afii10042", - "\u0429", "afii10043", - "\u042A", "afii10044", - "\u042B", "afii10045", - "\u042C", "afii10046", - "\u042D", "afii10047", - "\u042E", "afii10048", - "\u042F", "afii10049", - "\u0490", "afii10050", - "\u0402", "afii10051", - "\u0403", "afii10052", - "\u0404", "afii10053", - "\u0405", "afii10054", - "\u0406", "afii10055", - "\u0407", "afii10056", - "\u0408", "afii10057", - "\u0409", "afii10058", - "\u040A", "afii10059", - "\u040B", "afii10060", - "\u040C", "afii10061", - "\u040E", "afii10062", - "\uF6C4", "afii10063", - "\uF6C5", "afii10064", - "\u0430", "afii10065", - "\u0431", "afii10066", - "\u0432", "afii10067", - "\u0433", "afii10068", - "\u0434", "afii10069", - "\u0435", "afii10070", - "\u0451", "afii10071", - "\u0436", "afii10072", - "\u0437", "afii10073", - "\u0438", "afii10074", - "\u0439", "afii10075", - "\u043A", "afii10076", - "\u043B", "afii10077", - "\u043C", "afii10078", - "\u043D", "afii10079", - "\u043E", "afii10080", - "\u043F", "afii10081", - "\u0440", "afii10082", - "\u0441", "afii10083", - "\u0442", "afii10084", - "\u0443", "afii10085", - "\u0444", "afii10086", - "\u0445", "afii10087", - "\u0446", "afii10088", - "\u0447", "afii10089", - "\u0448", "afii10090", - "\u0449", "afii10091", - "\u044A", "afii10092", - "\u044B", "afii10093", - "\u044C", "afii10094", - "\u044D", "afii10095", - "\u044E", "afii10096", - "\u044F", "afii10097", - "\u0491", "afii10098", - "\u0452", "afii10099", - "\u0453", "afii10100", - "\u0454", "afii10101", - "\u0455", "afii10102", - "\u0456", "afii10103", - "\u0457", "afii10104", - "\u0458", "afii10105", - "\u0459", "afii10106", - "\u045A", "afii10107", - "\u045B", "afii10108", - "\u045C", "afii10109", - "\u045E", "afii10110", - "\u040F", "afii10145", - "\u0462", "afii10146", - "\u0472", "afii10147", - "\u0474", "afii10148", - "\uF6C6", "afii10192", - "\u045F", "afii10193", - "\u0463", "afii10194", - "\u0473", "afii10195", - "\u0475", "afii10196", - "\uF6C7", "afii10831", - "\uF6C8", "afii10832", - "\u04D9", "afii10846", - "\u200E", "afii299", - "\u200F", "afii300", - "\u200D", "afii301", - "\u066A", "afii57381", - "\u060C", "afii57388", - "\u0660", "afii57392", - "\u0661", "afii57393", - "\u0662", "afii57394", - "\u0663", "afii57395", - "\u0664", "afii57396", - "\u0665", "afii57397", - "\u0666", "afii57398", - "\u0667", "afii57399", - "\u0668", "afii57400", - "\u0669", "afii57401", - "\u061B", "afii57403", - "\u061F", "afii57407", - "\u0621", "afii57409", - "\u0622", "afii57410", - "\u0623", "afii57411", - "\u0624", "afii57412", - "\u0625", "afii57413", - "\u0626", "afii57414", - "\u0627", "afii57415", - "\u0628", "afii57416", - "\u0629", "afii57417", - "\u062A", "afii57418", - "\u062B", "afii57419", - "\u062C", "afii57420", - "\u062D", "afii57421", - "\u062E", "afii57422", - "\u062F", "afii57423", - "\u0630", "afii57424", - "\u0631", "afii57425", - "\u0632", "afii57426", - "\u0633", "afii57427", - "\u0634", "afii57428", - "\u0635", "afii57429", - "\u0636", "afii57430", - "\u0637", "afii57431", - "\u0638", "afii57432", - "\u0639", "afii57433", - "\u063A", "afii57434", - "\u0640", "afii57440", - "\u0641", "afii57441", - "\u0642", "afii57442", - "\u0643", "afii57443", - "\u0644", "afii57444", - "\u0645", "afii57445", - "\u0646", "afii57446", - "\u0648", "afii57448", - "\u0649", "afii57449", - "\u064A", "afii57450", - "\u064B", "afii57451", - "\u064C", "afii57452", - "\u064D", "afii57453", - "\u064E", "afii57454", - "\u064F", "afii57455", - "\u0650", "afii57456", - "\u0651", "afii57457", - "\u0652", "afii57458", - "\u0647", "afii57470", - "\u06A4", "afii57505", - "\u067E", "afii57506", - "\u0686", "afii57507", - "\u0698", "afii57508", - "\u06AF", "afii57509", - "\u0679", "afii57511", - "\u0688", "afii57512", - "\u0691", "afii57513", - "\u06BA", "afii57514", - "\u06D2", "afii57519", - "\u06D5", "afii57534", - "\u20AA", "afii57636", - "\u05BE", "afii57645", - "\u05C3", "afii57658", - "\u05D0", "afii57664", - "\u05D1", "afii57665", - "\u05D2", "afii57666", - "\u05D3", "afii57667", - "\u05D4", "afii57668", - "\u05D5", "afii57669", - "\u05D6", "afii57670", - "\u05D7", "afii57671", - "\u05D8", "afii57672", - "\u05D9", "afii57673", - "\u05DA", "afii57674", - "\u05DB", "afii57675", - "\u05DC", "afii57676", - "\u05DD", "afii57677", - "\u05DE", "afii57678", - "\u05DF", "afii57679", - "\u05E0", "afii57680", - "\u05E1", "afii57681", - "\u05E2", "afii57682", - "\u05E3", "afii57683", - "\u05E4", "afii57684", - "\u05E5", "afii57685", - "\u05E6", "afii57686", - "\u05E7", "afii57687", - "\u05E8", "afii57688", - "\u05E9", "afii57689", - "\u05EA", "afii57690", - "\uFB2A", "afii57694", - "\uFB2B", "afii57695", - "\uFB4B", "afii57700", - "\uFB1F", "afii57705", - "\u05F0", "afii57716", - "\u05F1", "afii57717", - "\u05F2", "afii57718", - "\uFB35", "afii57723", - "\u05B4", "afii57793", - "\u05B5", "afii57794", - "\u05B6", "afii57795", - "\u05BB", "afii57796", - "\u05B8", "afii57797", - "\u05B7", "afii57798", - "\u05B0", "afii57799", - "\u05B2", "afii57800", - "\u05B1", "afii57801", - "\u05B3", "afii57802", - "\u05C2", "afii57803", - "\u05C1", "afii57804", - "\u05B9", "afii57806", - "\u05BC", "afii57807", - "\u05BD", "afii57839", - "\u05BF", "afii57841", - "\u05C0", "afii57842", - "\u02BC", "afii57929", - "\u2105", "afii61248", - "\u2113", "afii61289", - "\u2116", "afii61352", - "\u202C", "afii61573", - "\u202D", "afii61574", - "\u202E", "afii61575", - "\u200C", "afii61664", - "\u066D", "afii63167", - "\u02BD", "afii64937", - "\u00E0", "agrave", - "\u2135", "aleph", - "\u03B1", "alpha", - "\u03AC", "alphatonos", - "\u0101", "amacron", - "\u0026", "ampersand", - "\uF726", "ampersandsmall", - "\u2220", "angle", - "\u2329", "angleleft", - "\u232A", "angleright", - "\u0387", "anoteleia", - "\u0105", "aogonek", - "\u2248", "approxequal", - "\u00E5", "aring", - "\u01FB", "aringacute", - "\u2194", "arrowboth", - "\u21D4", "arrowdblboth", - "\u21D3", "arrowdbldown", - "\u21D0", "arrowdblleft", - "\u21D2", "arrowdblright", - "\u21D1", "arrowdblup", - "\u2193", "arrowdown", - "\uF8E7", "arrowhorizex", - "\u2190", "arrowleft", - "\u2192", "arrowright", - "\u2191", "arrowup", - "\u2195", "arrowupdn", - "\u21A8", "arrowupdnbse", - "\uF8E6", "arrowvertex", - "\u005E", "asciicircum", - "\u007E", "asciitilde", - "\u002A", "asterisk", - "\u2217", "asteriskmath", - "\uF6E9", "asuperior", - "\u0040", "at", - "\u00E3", "atilde", - "\u0062", "b", - //"\u005C", "backslash", - "\\", "backslash", - "\u007C", "bar", - "\u03B2", "beta", - "\u2588", "block", - "\uF8F4", "braceex", - "\u007B", "braceleft", - "\uF8F3", "braceleftbt", - "\uF8F2", "braceleftmid", - "\uF8F1", "bracelefttp", - "\u007D", "braceright", - "\uF8FE", "bracerightbt", - "\uF8FD", "bracerightmid", - "\uF8FC", "bracerighttp", - "\u005B", "bracketleft", - "\uF8F0", "bracketleftbt", - "\uF8EF", "bracketleftex", - "\uF8EE", "bracketlefttp", - "\u005D", "bracketright", - "\uF8FB", "bracketrightbt", - "\uF8FA", "bracketrightex", - "\uF8F9", "bracketrighttp", - "\u02D8", "breve", - "\u00A6", "brokenbar", - "\uF6EA", "bsuperior", - "\u2022", "bullet", - "\u0063", "c", - "\u0107", "cacute", - "\u02C7", "caron", - "\u21B5", "carriagereturn", - "\u010D", "ccaron", - "\u00E7", "ccedilla", - "\u0109", "ccircumflex", - "\u010B", "cdotaccent", - "\u00B8", "cedilla", - "\u00A2", "cent", - "\uF6DF", "centinferior", - "\uF7A2", "centoldstyle", - "\uF6E0", "centsuperior", - "\u03C7", "chi", - "\u25CB", "circle", - "\u2297", "circlemultiply", - "\u2295", "circleplus", - "\u02C6", "circumflex", - "\u2663", "club", - "\u003A", "colon", - "\u20A1", "colonmonetary", - "\u002C", "comma", - "\uF6C3", "commaaccent", - "\uF6E1", "commainferior", - "\uF6E2", "commasuperior", - "\u2245", "congruent", - "\u00A9", "copyright", - "\uF8E9", "copyrightsans", - "\uF6D9", "copyrightserif", - "\u00A4", "currency", - "\uF6D1", "cyrBreve", - "\uF6D2", "cyrFlex", - "\uF6D4", "cyrbreve", - "\uF6D5", "cyrflex", - "\u0064", "d", - "\u2020", "dagger", - "\u2021", "daggerdbl", - "\uF6D3", "dblGrave", - "\uF6D6", "dblgrave", - "\u010F", "dcaron", - "\u0111", "dcroat", - "\u00B0", "degree", - "\u03B4", "delta", - "\u2666", "diamond", - "\u00A8", "dieresis", - "\uF6D7", "dieresisacute", - "\uF6D8", "dieresisgrave", - "\u0385", "dieresistonos", - "\u00F7", "divide", - "\u2593", "dkshade", - "\u2584", "dnblock", - "\u0024", "dollar", - "\uF6E3", "dollarinferior", - "\uF724", "dollaroldstyle", - "\uF6E4", "dollarsuperior", - "\u20AB", "dong", - "\u02D9", "dotaccent", - "\u0323", "dotbelowcomb", - "\u0131", "dotlessi", - "\uF6BE", "dotlessj", - "\u22C5", "dotmath", - "\uF6EB", "dsuperior", - "\u0065", "e", - "\u00E9", "eacute", - "\u0115", "ebreve", - "\u011B", "ecaron", - "\u00EA", "ecircumflex", - "\u00EB", "edieresis", - "\u0117", "edotaccent", - "\u00E8", "egrave", - "\u0038", "eight", - "\u2088", "eightinferior", - "\uF738", "eightoldstyle", - "\u2078", "eightsuperior", - "\u2208", "element", - "\u2026", "ellipsis", - "\u0113", "emacron", - "\u2014", "emdash", - "\u2205", "emptyset", - "\u2013", "endash", - "\u014B", "eng", - "\u0119", "eogonek", - "\u03B5", "epsilon", - "\u03AD", "epsilontonos", - "\u003D", "equal", - "\u2261", "equivalence", - "\u212E", "estimated", - "\uF6EC", "esuperior", - "\u03B7", "eta", - "\u03AE", "etatonos", - "\u00F0", "eth", - "\u0021", "exclam", - "\u203C", "exclamdbl", - "\u00A1", "exclamdown", - "\uF7A1", "exclamdownsmall", - "\uF721", "exclamsmall", - "\u2203", "existential", - "\u0066", "f", - "\u2640", "female", - "\uFB00", "ff", - "\uFB03", "ffi", - "\uFB04", "ffl", - "\uFB01", "fi", - "\u2012", "figuredash", - "\u25A0", "filledbox", - "\u25AC", "filledrect", - "\u0035", "five", - "\u215D", "fiveeighths", - "\u2085", "fiveinferior", - "\uF735", "fiveoldstyle", - "\u2075", "fivesuperior", - "\uFB02", "fl", - "\u0192", "florin", - "\u0034", "four", - "\u2084", "fourinferior", - "\uF734", "fouroldstyle", - "\u2074", "foursuperior", - "\u2044", "fraction", - "\u2215", "fraction", - "\u20A3", "franc", - "\u0067", "g", - "\u03B3", "gamma", - "\u011F", "gbreve", - "\u01E7", "gcaron", - "\u011D", "gcircumflex", - "\u0123", "gcommaaccent", - "\u0121", "gdotaccent", - "\u00DF", "germandbls", - "\u2207", "gradient", - "\u0060", "grave", - "\u0300", "gravecomb", - "\u003E", "greater", - "\u2265", "greaterequal", - "\u00AB", "guillemotleft", - "\u00BB", "guillemotright", - "\u2039", "guilsinglleft", - "\u203A", "guilsinglright", - "\u0068", "h", - "\u0127", "hbar", - "\u0125", "hcircumflex", - "\u2665", "heart", - "\u0309", "hookabovecomb", - "\u2302", "house", - "\u02DD", "hungarumlaut", - "\u002D", "hyphen", - "\u00AD", "hyphen", - "\uF6E5", "hypheninferior", - "\uF6E6", "hyphensuperior", - "\u0069", "i", - "\u00ED", "iacute", - "\u012D", "ibreve", - "\u00EE", "icircumflex", - "\u00EF", "idieresis", - "\u00EC", "igrave", - "\u0133", "ij", - "\u012B", "imacron", - "\u221E", "infinity", - "\u222B", "integral", - "\u2321", "integralbt", - "\uF8F5", "integralex", - "\u2320", "integraltp", - "\u2229", "intersection", - "\u25D8", "invbullet", - "\u25D9", "invcircle", - "\u263B", "invsmileface", - "\u012F", "iogonek", - "\u03B9", "iota", - "\u03CA", "iotadieresis", - "\u0390", "iotadieresistonos", - "\u03AF", "iotatonos", - "\uF6ED", "isuperior", - "\u0129", "itilde", - "\u006A", "j", - "\u0135", "jcircumflex", - "\u006B", "k", - "\u03BA", "kappa", - "\u0137", "kcommaaccent", - "\u0138", "kgreenlandic", - "\u006C", "l", - "\u013A", "lacute", - "\u03BB", "lambda", - "\u013E", "lcaron", - "\u013C", "lcommaaccent", - "\u0140", "ldot", - "\u003C", "less", - "\u2264", "lessequal", - "\u258C", "lfblock", - "\u20A4", "lira", - "\uF6C0", "ll", - "\u2227", "logicaland", - "\u00AC", "logicalnot", - "\u2228", "logicalor", - "\u017F", "longs", - "\u25CA", "lozenge", - "\u0142", "lslash", - "\uF6EE", "lsuperior", - "\u2591", "ltshade", - "\u006D", "m", - "\u00AF", "macron", - "\u02C9", "macron", - "\u2642", "male", - "\u2212", "minus", - "\u2032", "minute", - "\uF6EF", "msuperior", - "\u00B5", "mu", - "\u03BC", "mu", - "\u00D7", "multiply", - "\u266A", "musicalnote", - "\u266B", "musicalnotedbl", - "\u006E", "n", - "\u0144", "nacute", - "\u0149", "napostrophe", - "\u0148", "ncaron", - "\u0146", "ncommaaccent", - "\u0039", "nine", - "\u2089", "nineinferior", - "\uF739", "nineoldstyle", - "\u2079", "ninesuperior", - "\u2209", "notelement", - "\u2260", "notequal", - "\u2284", "notsubset", - "\u207F", "nsuperior", - "\u00F1", "ntilde", - "\u03BD", "nu", - "\u0023", "numbersign", - "\u006F", "o", - "\u00F3", "oacute", - "\u014F", "obreve", - "\u00F4", "ocircumflex", - "\u00F6", "odieresis", - "\u0153", "oe", - "\u02DB", "ogonek", - "\u00F2", "ograve", - "\u01A1", "ohorn", - "\u0151", "ohungarumlaut", - "\u014D", "omacron", - "\u03C9", "omega", - "\u03D6", "omega1", - "\u03CE", "omegatonos", - "\u03BF", "omicron", - "\u03CC", "omicrontonos", - "\u0031", "one", - "\u2024", "onedotenleader", - "\u215B", "oneeighth", - "\uF6DC", "onefitted", - "\u00BD", "onehalf", - "\u2081", "oneinferior", - "\uF731", "oneoldstyle", - "\u00BC", "onequarter", - "\u00B9", "onesuperior", - "\u2153", "onethird", - "\u25E6", "openbullet", - "\u00AA", "ordfeminine", - "\u00BA", "ordmasculine", - "\u221F", "orthogonal", - "\u00F8", "oslash", - "\u01FF", "oslashacute", - "\uF6F0", "osuperior", - "\u00F5", "otilde", - "\u0070", "p", - "\u00B6", "paragraph", - "\u0028", "parenleft", - "\uF8ED", "parenleftbt", - "\uF8EC", "parenleftex", - "\u208D", "parenleftinferior", - "\u207D", "parenleftsuperior", - "\uF8EB", "parenlefttp", - "\u0029", "parenright", - "\uF8F8", "parenrightbt", - "\uF8F7", "parenrightex", - "\u208E", "parenrightinferior", - "\u207E", "parenrightsuperior", - "\uF8F6", "parenrighttp", - "\u2202", "partialdiff", - "\u0025", "percent", - "\u002E", "period", - "\u00B7", "periodcentered", - "\u2219", "periodcentered", - "\uF6E7", "periodinferior", - "\uF6E8", "periodsuperior", - "\u22A5", "perpendicular", - "\u2030", "perthousand", - "\u20A7", "peseta", - "\u03C6", "phi", - "\u03D5", "phi1", - "\u03C0", "pi", - "\u002B", "plus", - "\u00B1", "plusminus", - "\u211E", "prescription", - "\u220F", "product", - "\u2282", "propersubset", - "\u2283", "propersuperset", - "\u221D", "proportional", - "\u03C8", "psi", - "\u0071", "q", - "\u003F", "question", - "\u00BF", "questiondown", - "\uF7BF", "questiondownsmall", - "\uF73F", "questionsmall", - "\"", "quotedbl", -// "\u0022", "quotedbl", - "\u201E", "quotedblbase", - "\u201C", "quotedblleft", - "\u201D", "quotedblright", - "\u2018", "quoteleft", - "\u201B", "quotereversed", - "\u2019", "quoteright", - "\u201A", "quotesinglbase", - "\u0027", "quotesingle", - "\u0072", "r", - "\u0155", "racute", - "\u221A", "radical", - "\uF8E5", "radicalex", - "\u0159", "rcaron", - "\u0157", "rcommaaccent", - "\u2286", "reflexsubset", - "\u2287", "reflexsuperset", - "\u00AE", "registered", - "\uF8E8", "registersans", - "\uF6DA", "registerserif", - "\u2310", "revlogicalnot", - "\u03C1", "rho", - "\u02DA", "ring", - "\uF6F1", "rsuperior", - "\u2590", "rtblock", - "\uF6DD", "rupiah", - "\u0073", "s", - "\u015B", "sacute", - "\u0161", "scaron", - "\u015F", "scedilla", - "\uF6C2", "scedilla", - "\u015D", "scircumflex", - "\u0219", "scommaaccent", - "\u2033", "second", - "\u00A7", "section", - "\u003B", "semicolon", - "\u0037", "seven", - "\u215E", "seveneighths", - "\u2087", "seveninferior", - "\uF737", "sevenoldstyle", - "\u2077", "sevensuperior", - "\u2592", "shade", - "\u03C3", "sigma", - "\u03C2", "sigma1", - "\u223C", "similar", - "\u0036", "six", - "\u2086", "sixinferior", - "\uF736", "sixoldstyle", - "\u2076", "sixsuperior", - "\u002F", "slash", - "\u263A", "smileface", - "\u0020", "space", - "\u00A0", "space", - "\u2660", "spade", - "\uF6F2", "ssuperior", - "\u00A3", "sterling", - "\u220B", "suchthat", - "\u2211", "summation", - "\u263C", "sun", - "\u0074", "t", - "\u03C4", "tau", - "\u0167", "tbar", - "\u0165", "tcaron", - "\u0163", "tcommaaccent", - "\u021B", "tcommaaccent", - "\u2234", "therefore", - "\u03B8", "theta", - "\u03D1", "theta1", - "\u00FE", "thorn", - "\u0033", "three", - "\u215C", "threeeighths", - "\u2083", "threeinferior", - "\uF733", "threeoldstyle", - "\u00BE", "threequarters", - "\uF6DE", "threequartersemdash", - "\u00B3", "threesuperior", - "\u02DC", "tilde", - "\u0303", "tildecomb", - "\u0384", "tonos", - "\u2122", "trademark", - "\uF8EA", "trademarksans", - "\uF6DB", "trademarkserif", - "\u25BC", "triagdn", - "\u25C4", "triaglf", - "\u25BA", "triagrt", - "\u25B2", "triagup", - "\uF6F3", "tsuperior", - "\u0032", "two", - "\u2025", "twodotenleader", - "\u2082", "twoinferior", - "\uF732", "twooldstyle", - "\u00B2", "twosuperior", - "\u2154", "twothirds", - "\u0075", "u", - "\u00FA", "uacute", - "\u016D", "ubreve", - "\u00FB", "ucircumflex", - "\u00FC", "udieresis", - "\u00F9", "ugrave", - "\u01B0", "uhorn", - "\u0171", "uhungarumlaut", - "\u016B", "umacron", - "\u005F", "underscore", - "\u2017", "underscoredbl", - "\u222A", "union", - "\u2200", "universal", - "\u0173", "uogonek", - "\u2580", "upblock", - "\u03C5", "upsilon", - "\u03CB", "upsilondieresis", - "\u03B0", "upsilondieresistonos", - "\u03CD", "upsilontonos", - "\u016F", "uring", - "\u0169", "utilde", - "\u0076", "v", - "\u0077", "w", - "\u1E83", "wacute", - "\u0175", "wcircumflex", - "\u1E85", "wdieresis", - "\u2118", "weierstrass", - "\u1E81", "wgrave", - "\u0078", "x", - "\u03BE", "xi", - "\u0079", "y", - "\u00FD", "yacute", - "\u0177", "ycircumflex", - "\u00FF", "ydieresis", - "\u00A5", "yen", - "\u1EF3", "ygrave", - "\u007A", "z", - "\u017A", "zacute", - "\u017E", "zcaron", - "\u017C", "zdotaccent", - "\u0030", "zero", - "\u2080", "zeroinferior", - "\uF730", "zerooldstyle", - "\u2070", "zerosuperior", - "\u03B6", "zeta" - }; - - /** - * Return the glyphname from a character, - * eg, charToGlyphName('\\') returns "backslash" - * - * @param ch glyph to evaluate - * @return the name of the glyph - */ - public static String charToGlyphName(char ch) { - return stringToGlyph(Character.toString(ch)); - } - - /** - * Return the glyphname from a string, - * eg, glyphToString("\\") returns "backslash" - * - * @param name glyph to evaluate - * @return the name of the glyph - * TODO: javadocs for glyphToString and stringToGlyph are confused - * TODO: Improve method names - */ - public static String glyphToString(String name) { - for (int i = 0; i < UNICODE_GLYPHS.length; i += 2) { - if (UNICODE_GLYPHS[i + 1].equals(name)) { - return UNICODE_GLYPHS[i]; - } - } - return ""; - } - - /** - * Return the string representation of a glyphname, - * eg stringToGlyph("backslash") returns "\\" - * - * @param name name of the glyph - * @return the string representation - */ - public static String stringToGlyph(String name) { - for (int i = 0; i < UNICODE_GLYPHS.length; i += 2) { - if (UNICODE_GLYPHS[i].equals(name)) { - return UNICODE_GLYPHS[i + 1]; - } - } - return ""; - } - -} - diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java deleted file mode 100644 index 06b106534..000000000 --- a/src/java/org/apache/fop/fonts/LazyFont.java +++ /dev/null @@ -1,502 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; -import java.awt.Rectangle; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.xml.sax.InputSource; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.apps.FOPException; -import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.complexscripts.fonts.Positionable; -import org.apache.fop.complexscripts.fonts.Substitutable; - -/** - * This class is used to defer the loading of a font until it is really used. - */ -public class LazyFont extends Typeface implements FontDescriptor, Substitutable, Positionable { - - private static Log log = LogFactory.getLog(LazyFont.class); - - private final FontUris fontUris; - - private final boolean useKerning; - private final boolean useAdvanced; - private final EncodingMode encodingMode; - private final EmbeddingMode embeddingMode; - private final String subFontName; - private final boolean embedded; - private final InternalResourceResolver resourceResolver; - - private boolean isMetricsLoaded; - private Typeface realFont; - private FontDescriptor realFontDescriptor; - - /** - * Main constructor - * @param fontInfo the font info to embed - * @param resourceResolver the font resolver to handle font URIs - */ - public LazyFont(EmbedFontInfo fontInfo, InternalResourceResolver resourceResolver, - boolean useComplexScripts) { - - this.fontUris = fontInfo.getFontUris(); - this.useKerning = fontInfo.getKerning(); - if (resourceResolver != null) { - this.useAdvanced = useComplexScripts; - } else { - this.useAdvanced = fontInfo.getAdvanced(); - } - this.encodingMode = fontInfo.getEncodingMode() != null ? fontInfo.getEncodingMode() - : EncodingMode.AUTO; - this.embeddingMode = fontInfo.getEmbeddingMode() != null ? fontInfo.getEmbeddingMode() - : EmbeddingMode.AUTO; - this.subFontName = fontInfo.getSubFontName(); - this.embedded = fontInfo.isEmbedded(); - this.resourceResolver = resourceResolver; - } - - /** {@inheritDoc} */ - public String toString() { - StringBuffer sbuf = new StringBuffer(super.toString()); - sbuf.append('{'); - sbuf.append("metrics-url=" + fontUris.getMetrics()); - sbuf.append(",embed-url=" + fontUris.getEmbed()); - sbuf.append(",kerning=" + useKerning); - sbuf.append(",advanced=" + useAdvanced); - sbuf.append('}'); - return sbuf.toString(); - } - - private void load(boolean fail) { - if (!isMetricsLoaded) { - try { - if (fontUris.getMetrics() != null) { - /**@todo Possible thread problem here */ - FontReader reader = null; - InputStream in = resourceResolver.getResource(fontUris.getMetrics()); - InputSource src = new InputSource(in); - src.setSystemId(fontUris.getMetrics().toASCIIString()); - reader = new FontReader(src, resourceResolver); - reader.setKerningEnabled(useKerning); - reader.setAdvancedEnabled(useAdvanced); - if (this.embedded) { - reader.setFontEmbedURI(fontUris.getEmbed()); - } - realFont = reader.getFont(); - } else { - if (fontUris.getEmbed() == null) { - throw new RuntimeException("Cannot load font. No font URIs available."); - } - realFont = FontLoader.loadFont(fontUris, subFontName, embedded, - embeddingMode, encodingMode, useKerning, useAdvanced, resourceResolver); - } - if (realFont instanceof FontDescriptor) { - realFontDescriptor = (FontDescriptor) realFont; - } - } catch (FOPException fopex) { - log.error("Failed to read font metrics file " + fontUris.getMetrics(), fopex); - if (fail) { - throw new RuntimeException(fopex); - } - } catch (IOException ioex) { - log.error("Failed to read font metrics file " + fontUris.getMetrics(), ioex); - if (fail) { - throw new RuntimeException(ioex); - } - } - realFont.setEventListener(this.eventListener); - isMetricsLoaded = true; - } - } - - /** - * Gets the real font. - * @return the real font - */ - public Typeface getRealFont() { - load(false); - return realFont; - } - - // ---- Font ---- - /** {@inheritDoc} */ - public String getEncodingName() { - load(true); - return realFont.getEncodingName(); - } - - /** - * {@inheritDoc} - */ - public char mapChar(char c) { - if (!isMetricsLoaded) { - load(true); - } - return realFont.mapChar(c); - } - - /** - * {@inheritDoc} - */ - public boolean hadMappingOperations() { - load(true); - return realFont.hadMappingOperations(); - } - - /** - * {@inheritDoc} - */ - public boolean hasChar(char c) { - if (!isMetricsLoaded) { - load(true); - } - return realFont.hasChar(c); - } - - /** - * {@inheritDoc} - */ - public boolean isMultiByte() { - load(true); - return realFont.isMultiByte(); - } - - // ---- FontMetrics interface ---- - /** {@inheritDoc} */ - public URI getFontURI() { - load(true); - return realFont.getFontURI(); - } - - /** {@inheritDoc} */ - public String getFontName() { - load(true); - return realFont.getFontName(); - } - - /** {@inheritDoc} */ - public String getEmbedFontName() { - load(true); - return realFont.getEmbedFontName(); - } - - /** {@inheritDoc} */ - public String getFullName() { - load(true); - return realFont.getFullName(); - } - - /** {@inheritDoc} */ - public Set<String> getFamilyNames() { - load(true); - return realFont.getFamilyNames(); - } - - /** - * {@inheritDoc} - */ - public int getMaxAscent(int size) { - load(true); - return realFont.getMaxAscent(size); - } - - /** - * {@inheritDoc} - */ - public int getAscender(int size) { - load(true); - return realFont.getAscender(size); - } - - /** - * {@inheritDoc} - */ - public int getCapHeight(int size) { - load(true); - return realFont.getCapHeight(size); - } - - /** - * {@inheritDoc} - */ - public int getDescender(int size) { - load(true); - return realFont.getDescender(size); - } - - /** - * {@inheritDoc} - */ - public int getXHeight(int size) { - load(true); - return realFont.getXHeight(size); - } - - public int getUnderlinePosition(int size) { - load(true); - return realFont.getUnderlinePosition(size); - } - - public int getUnderlineThickness(int size) { - load(true); - return realFont.getUnderlineThickness(size); - } - - public int getStrikeoutPosition(int size) { - load(true); - return realFont.getStrikeoutPosition(size); - } - - public int getStrikeoutThickness(int size) { - load(true); - return realFont.getStrikeoutThickness(size); - } - - /** - * {@inheritDoc} - */ - public int getWidth(int i, int size) { - if (!isMetricsLoaded) { - load(true); - } - return realFont.getWidth(i, size); - } - - /** - * {@inheritDoc} - */ - public int[] getWidths() { - load(true); - return realFont.getWidths(); - } - - public Rectangle getBoundingBox(int glyphIndex, int size) { - load(true); - return realFont.getBoundingBox(glyphIndex, size); - } - - /** - * {@inheritDoc} - */ - public boolean hasKerningInfo() { - load(true); - return realFont.hasKerningInfo(); - } - - /** - * {@inheritDoc} - */ - public Map<Integer, Map<Integer, Integer>> getKerningInfo() { - load(true); - return realFont.getKerningInfo(); - } - - /** {@inheritDoc} */ - public boolean hasFeature(int tableType, String script, String language, String feature) { - load(true); - return realFont.hasFeature(tableType, script, language, feature); - } - - // ---- FontDescriptor interface ---- - /** - * {@inheritDoc} - */ - public int getCapHeight() { - load(true); - return realFontDescriptor.getCapHeight(); - } - - /** - * {@inheritDoc} - */ - public int getDescender() { - load(true); - return realFontDescriptor.getDescender(); - } - - /** - * {@inheritDoc} - */ - public int getAscender() { - load(true); - return realFontDescriptor.getAscender(); - } - - /** {@inheritDoc} */ - public int getFlags() { - load(true); - return realFontDescriptor.getFlags(); - } - - /** {@inheritDoc} */ - public boolean isSymbolicFont() { - load(true); - return realFontDescriptor.isSymbolicFont(); - } - - /** - * {@inheritDoc} - */ - public int[] getFontBBox() { - load(true); - return realFontDescriptor.getFontBBox(); - } - - /** - * {@inheritDoc} - */ - public int getItalicAngle() { - load(true); - return realFontDescriptor.getItalicAngle(); - } - - /** - * {@inheritDoc} - */ - public int getStemV() { - load(true); - return realFontDescriptor.getStemV(); - } - - /** - * {@inheritDoc} - */ - public FontType getFontType() { - load(true); - return realFontDescriptor.getFontType(); - } - - /** - * {@inheritDoc} - */ - public boolean isEmbeddable() { - load(true); - return realFontDescriptor.isEmbeddable(); - } - - /** - * {@inheritDoc} - */ - public boolean performsSubstitution() { - load(true); - if (realFontDescriptor instanceof Substitutable) { - return ((Substitutable)realFontDescriptor).performsSubstitution(); - } else { - return false; - } - } - - /** - * {@inheritDoc} - */ - public CharSequence performSubstitution(CharSequence cs, String script, String language, List associations, - boolean retainControls) { - load(true); - if (realFontDescriptor instanceof Substitutable) { - return ((Substitutable)realFontDescriptor).performSubstitution(cs, - script, language, associations, retainControls); - } else { - return cs; - } - } - - /** - * {@inheritDoc} - */ - public CharSequence reorderCombiningMarks( - CharSequence cs, int[][] gpa, String script, String language, List associations) { - if (!isMetricsLoaded) { - load(true); - } - if (realFontDescriptor instanceof Substitutable) { - return ((Substitutable)realFontDescriptor) - .reorderCombiningMarks(cs, gpa, script, language, associations); - } else { - return cs; - } - } - - /** - * {@inheritDoc} - */ - public boolean performsPositioning() { - if (!isMetricsLoaded) { - load(true); - } - if (realFontDescriptor instanceof Positionable) { - return ((Positionable)realFontDescriptor).performsPositioning(); - } else { - return false; - } - } - - /** - * {@inheritDoc} - */ - public int[][] - performPositioning(CharSequence cs, String script, String language, int fontSize) { - if (!isMetricsLoaded) { - load(true); - } - if (realFontDescriptor instanceof Positionable) { - return ((Positionable)realFontDescriptor) - .performPositioning(cs, script, language, fontSize); - } else { - return null; - } - } - - /** - * {@inheritDoc} - */ - public int[][] - performPositioning(CharSequence cs, String script, String language) { - if (!isMetricsLoaded) { - load(true); - } - if (realFontDescriptor instanceof Positionable) { - return ((Positionable)realFontDescriptor) - .performPositioning(cs, script, language); - } else { - return null; - } - } - - /** - * {@inheritDoc} - */ - public boolean isSubsetEmbedded() { - load(true); - if (realFont.isMultiByte() && this.embeddingMode == EmbeddingMode.FULL) { - return false; - } - return realFont.isMultiByte(); - } -} - diff --git a/src/java/org/apache/fop/fonts/MultiByteFont.java b/src/java/org/apache/fop/fonts/MultiByteFont.java deleted file mode 100644 index db72bee0c..000000000 --- a/src/java/org/apache/fop/fonts/MultiByteFont.java +++ /dev/null @@ -1,807 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.awt.Rectangle; -import java.io.InputStream; -import java.nio.CharBuffer; -import java.nio.IntBuffer; -import java.util.BitSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.complexscripts.fonts.GlyphDefinitionTable; -import org.apache.fop.complexscripts.fonts.GlyphPositioningTable; -import org.apache.fop.complexscripts.fonts.GlyphSubstitutionTable; -import org.apache.fop.complexscripts.fonts.GlyphTable; -import org.apache.fop.complexscripts.fonts.Positionable; -import org.apache.fop.complexscripts.fonts.Substitutable; -import org.apache.fop.complexscripts.util.CharAssociation; -import org.apache.fop.complexscripts.util.CharNormalize; -import org.apache.fop.complexscripts.util.GlyphSequence; -import org.apache.fop.util.CharUtilities; - -/** - * Generic MultiByte (CID) font - */ -public class MultiByteFont extends CIDFont implements Substitutable, Positionable { - - /** logging instance */ - private static final Log log - = LogFactory.getLog(MultiByteFont.class); - - private String ttcName; - private String encoding = "Identity-H"; - - private int defaultWidth; - private CIDFontType cidType = CIDFontType.CIDTYPE2; - - protected final CIDSet cidSet; - - /* advanced typographic support */ - private GlyphDefinitionTable gdef; - private GlyphSubstitutionTable gsub; - private GlyphPositioningTable gpos; - - /* dynamic private use (character) mappings */ - private int numMapped; - private int numUnmapped; - private int nextPrivateUse = 0xE000; - private int firstPrivate; - private int lastPrivate; - private int firstUnmapped; - private int lastUnmapped; - - /** Contains the character bounding boxes for all characters in the font */ - protected Rectangle[] boundingBoxes; - - private boolean isOTFFile; - - // since for most users the most likely glyphs are in the first cmap segments we store their mapping. - private static final int NUM_MOST_LIKELY_GLYPHS = 256; - private int[] mostLikelyGlyphs = new int[NUM_MOST_LIKELY_GLYPHS]; - - //A map to store each used glyph from the CID set against the glyph name. - private LinkedHashMap<Integer, String> usedGlyphNames = new LinkedHashMap<Integer, String>(); - - /** - * Default constructor - */ - public MultiByteFont(InternalResourceResolver resourceResolver, EmbeddingMode embeddingMode) { - super(resourceResolver); - setFontType(FontType.TYPE0); - setEmbeddingMode(embeddingMode); - if (embeddingMode != EmbeddingMode.FULL) { - cidSet = new CIDSubset(this); - } else { - cidSet = new CIDFull(this); - } - } - - /** {@inheritDoc} */ - @Override - public int getDefaultWidth() { - return defaultWidth; - } - - /** {@inheritDoc} */ - @Override - public String getRegistry() { - return "Adobe"; - } - - /** {@inheritDoc} */ - @Override - public String getOrdering() { - return "UCS"; - } - - /** {@inheritDoc} */ - @Override - public int getSupplement() { - return 0; - } - - /** {@inheritDoc} */ - @Override - public CIDFontType getCIDType() { - return cidType; - } - - public void setIsOTFFile(boolean isOTFFile) { - this.isOTFFile = isOTFFile; - } - - public boolean isOTFFile() { - return this.isOTFFile; - } - - /** - * Sets the CIDType. - * @param cidType The cidType to set - */ - public void setCIDType(CIDFontType cidType) { - this.cidType = cidType; - } - - /** {@inheritDoc} */ - @Override - public String getEmbedFontName() { - if (isEmbeddable()) { - return FontUtil.stripWhiteSpace(super.getFontName()); - } else { - return super.getFontName(); - } - } - - /** {@inheritDoc} */ - public boolean isEmbeddable() { - return !(getEmbedFileURI() == null && getEmbedResourceName() == null); - } - - public boolean isSubsetEmbedded() { - if (getEmbeddingMode() == EmbeddingMode.FULL) { - return false; - } - return true; - } - - /** {@inheritDoc} */ - @Override - public CIDSet getCIDSet() { - return this.cidSet; - } - - public void mapUsedGlyphName(int gid, String value) { - usedGlyphNames.put(gid, value); - } - - public LinkedHashMap<Integer, String> getUsedGlyphNames() { - return usedGlyphNames; - } - - /** {@inheritDoc} */ - @Override - public String getEncodingName() { - return encoding; - } - - /** {@inheritDoc} */ - public int getWidth(int i, int size) { - if (isEmbeddable()) { - int glyphIndex = cidSet.getOriginalGlyphIndex(i); - return size * width[glyphIndex]; - } else { - return size * width[i]; - } - } - - /** {@inheritDoc} */ - public int[] getWidths() { - int[] arr = new int[width.length]; - System.arraycopy(width, 0, arr, 0, width.length); - return arr; - } - - public Rectangle getBoundingBox(int glyphIndex, int size) { - int index = isEmbeddable() ? cidSet.getOriginalGlyphIndex(glyphIndex) : glyphIndex; - Rectangle bbox = boundingBoxes[index]; - return new Rectangle(bbox.x * size, bbox.y * size, bbox.width * size, bbox.height * size); - } - - /** - * Returns the glyph index for a Unicode character. The method returns 0 if there's no - * such glyph in the character map. - * @param c the Unicode character index - * @return the glyph index (or 0 if the glyph is not available) - */ - // [TBD] - needs optimization, i.e., change from linear search to binary search - public int findGlyphIndex(int c) { - int idx = c; - int retIdx = SingleByteEncoding.NOT_FOUND_CODE_POINT; - - // for most users the most likely glyphs are in the first cmap segments (meaning the one with - // the lowest unicode start values) - if (idx < NUM_MOST_LIKELY_GLYPHS && mostLikelyGlyphs[idx] != 0) { - return mostLikelyGlyphs[idx]; - } - for (CMapSegment i : cmap) { - if (retIdx == 0 - && i.getUnicodeStart() <= idx - && i.getUnicodeEnd() >= idx) { - retIdx = i.getGlyphStartIndex() - + idx - - i.getUnicodeStart(); - if (idx < NUM_MOST_LIKELY_GLYPHS) { - mostLikelyGlyphs[idx] = retIdx; - } - if (retIdx != 0) { - break; - } - } - } - return retIdx; - } - - /** - * Add a private use mapping {PU,GI} to the existing character map. - * N.B. Does not insert in order, merely appends to end of existing map. - */ - protected synchronized void addPrivateUseMapping(int pu, int gi) { - assert findGlyphIndex(pu) == SingleByteEncoding.NOT_FOUND_CODE_POINT; - cmap.add(new CMapSegment(pu, pu, gi)); - } - - /** - * Given a glyph index, create a new private use mapping, augmenting the bfentries - * table. This is needed to accommodate the presence of an (output) glyph index in a - * complex script glyph substitution that does not correspond to a character in the - * font's CMAP. The creation of such private use mappings is deferred until an - * attempt is actually made to perform the reverse lookup from the glyph index. This - * is necessary in order to avoid exhausting the private use space on fonts containing - * many such non-mapped glyph indices, if these mappings had been created statically - * at font load time. - * @param gi glyph index - * @returns unicode scalar value - */ - private int createPrivateUseMapping(int gi) { - while ((nextPrivateUse < 0xF900) - && (findGlyphIndex(nextPrivateUse) != SingleByteEncoding.NOT_FOUND_CODE_POINT)) { - nextPrivateUse++; - } - if (nextPrivateUse < 0xF900) { - int pu = nextPrivateUse; - addPrivateUseMapping(pu, gi); - if (firstPrivate == 0) { - firstPrivate = pu; - } - lastPrivate = pu; - numMapped++; - if (log.isDebugEnabled()) { - log.debug("Create private use mapping from " - + CharUtilities.format(pu) - + " to glyph index " + gi - + " in font '" + getFullName() + "'"); - } - return pu; - } else { - if (firstUnmapped == 0) { - firstUnmapped = gi; - } - lastUnmapped = gi; - numUnmapped++; - log.warn("Exhausted private use area: unable to map " - + numUnmapped + " glyphs in glyph index range [" - + firstUnmapped + "," + lastUnmapped - + "] (inclusive) of font '" + getFullName() + "'"); - return 0; - } - } - - /** - * Returns the Unicode scalar value that corresponds to the glyph index. If more than - * one correspondence exists, then the first one is returned (ordered by bfentries[]). - * @param gi glyph index - * @returns unicode scalar value - */ - // [TBD] - needs optimization, i.e., change from linear search to binary search - private int findCharacterFromGlyphIndex(int gi, boolean augment) { - int cc = 0; - for (CMapSegment segment : cmap) { - int s = segment.getGlyphStartIndex(); - int e = s + (segment.getUnicodeEnd() - segment.getUnicodeStart()); - if ((gi >= s) && (gi <= e)) { - cc = segment.getUnicodeStart() + (gi - s); - break; - } - } - if ((cc == 0) && augment) { - cc = createPrivateUseMapping(gi); - } - return cc; - } - - private int findCharacterFromGlyphIndex(int gi) { - return findCharacterFromGlyphIndex(gi, true); - } - - protected BitSet getGlyphIndices() { - BitSet bitset = new BitSet(); - bitset.set(0); - bitset.set(1); - bitset.set(2); - for (CMapSegment i : cmap) { - int start = i.getUnicodeStart(); - int end = i.getUnicodeEnd(); - int glyphIndex = i.getGlyphStartIndex(); - while (start++ < end + 1) { - bitset.set(glyphIndex++); - } - } - return bitset; - } - - protected char[] getChars() { - // the width array is set when the font is built - char[] chars = new char[width.length]; - for (CMapSegment i : cmap) { - int start = i.getUnicodeStart(); - int end = i.getUnicodeEnd(); - int glyphIndex = i.getGlyphStartIndex(); - while (start < end + 1) { - chars[glyphIndex++] = (char) start++; - } - } - return chars; - } - - /** {@inheritDoc} */ - @Override - public char mapChar(char c) { - notifyMapOperation(); - int glyphIndex = findGlyphIndex(c); - if (glyphIndex == SingleByteEncoding.NOT_FOUND_CODE_POINT) { - warnMissingGlyph(c); - if (!isOTFFile) { - glyphIndex = findGlyphIndex(Typeface.NOT_FOUND); - } - } - if (isEmbeddable()) { - glyphIndex = cidSet.mapChar(glyphIndex, c); - } - return (char) glyphIndex; - } - - /** {@inheritDoc} */ - @Override - public boolean hasChar(char c) { - return (findGlyphIndex(c) != SingleByteEncoding.NOT_FOUND_CODE_POINT); - } - - /** - * Sets the defaultWidth. - * @param defaultWidth The defaultWidth to set - */ - public void setDefaultWidth(int defaultWidth) { - this.defaultWidth = defaultWidth; - } - - /** - * Returns the TrueType Collection Name. - * @return the TrueType Collection Name - */ - public String getTTCName() { - return ttcName; - } - - /** - * Sets the the TrueType Collection Name. - * @param ttcName the TrueType Collection Name - */ - public void setTTCName(String ttcName) { - this.ttcName = ttcName; - } - - /** - * Sets the width array. - * @param wds array of widths. - */ - public void setWidthArray(int[] wds) { - this.width = wds; - } - - /** - * Sets the bounding boxes array. - * @param boundingBoxes array of bounding boxes. - */ - public void setBBoxArray(Rectangle[] boundingBoxes) { - this.boundingBoxes = boundingBoxes; - } - - /** - * Returns a Map of used Glyphs. - * @return Map Map of used Glyphs - */ - public Map<Integer, Integer> getUsedGlyphs() { - return cidSet.getGlyphs(); - } - - /** - * Returns the character from it's original glyph index in the font - * @param glyphIndex The original index of the character - * @return The character - */ - public char getUnicodeFromGID(int glyphIndex) { - return cidSet.getUnicodeFromGID(glyphIndex); - } - - /** - * Gets the original glyph index in the font from a character. - * @param ch The character - * @return The glyph index in the font - */ - public int getGIDFromChar(char ch) { - return cidSet.getGIDFromChar(ch); - } - - /** - * Establishes the glyph definition table. - * @param gdef the glyph definition table to be used by this font - */ - public void setGDEF(GlyphDefinitionTable gdef) { - if ((this.gdef == null) || (gdef == null)) { - this.gdef = gdef; - } else { - throw new IllegalStateException("font already associated with GDEF table"); - } - } - - /** - * Obtain glyph definition table. - * @return glyph definition table or null if none is associated with font - */ - public GlyphDefinitionTable getGDEF() { - return gdef; - } - - /** - * Establishes the glyph substitution table. - * @param gsub the glyph substitution table to be used by this font - */ - public void setGSUB(GlyphSubstitutionTable gsub) { - if ((this.gsub == null) || (gsub == null)) { - this.gsub = gsub; - } else { - throw new IllegalStateException("font already associated with GSUB table"); - } - } - - /** - * Obtain glyph substitution table. - * @return glyph substitution table or null if none is associated with font - */ - public GlyphSubstitutionTable getGSUB() { - return gsub; - } - - /** - * Establishes the glyph positioning table. - * @param gpos the glyph positioning table to be used by this font - */ - public void setGPOS(GlyphPositioningTable gpos) { - if ((this.gpos == null) || (gpos == null)) { - this.gpos = gpos; - } else { - throw new IllegalStateException("font already associated with GPOS table"); - } - } - - /** - * Obtain glyph positioning table. - * @return glyph positioning table or null if none is associated with font - */ - public GlyphPositioningTable getGPOS() { - return gpos; - } - - /** {@inheritDoc} */ - public boolean performsSubstitution() { - return gsub != null; - } - - /** {@inheritDoc} */ - public CharSequence performSubstitution(CharSequence cs, String script, String language, List associations, - boolean retainControls) { - if (gsub != null) { - CharSequence ncs = normalize(cs, associations); - GlyphSequence igs = mapCharsToGlyphs(ncs, associations); - GlyphSequence ogs = gsub.substitute(igs, script, language); - if (associations != null) { - associations.clear(); - associations.addAll(ogs.getAssociations()); - } - if (!retainControls) { - ogs = elideControls(ogs); - } - CharSequence ocs = mapGlyphsToChars(ogs); - return ocs; - } else { - return cs; - } - } - - /** {@inheritDoc} */ - public CharSequence reorderCombiningMarks( - CharSequence cs, int[][] gpa, String script, String language, List associations) { - if (gdef != null) { - GlyphSequence igs = mapCharsToGlyphs(cs, associations); - GlyphSequence ogs = gdef.reorderCombiningMarks(igs, getUnscaledWidths(igs), gpa, script, language); - if (associations != null) { - associations.clear(); - associations.addAll(ogs.getAssociations()); - } - CharSequence ocs = mapGlyphsToChars(ogs); - return ocs; - } else { - return cs; - } - } - - protected int[] getUnscaledWidths(GlyphSequence gs) { - int[] widths = new int[gs.getGlyphCount()]; - for (int i = 0, n = widths.length; i < n; ++i) { - if (i < width.length) { - widths[i] = width[i]; - } - } - return widths; - } - - /** {@inheritDoc} */ - public boolean performsPositioning() { - return gpos != null; - } - - /** {@inheritDoc} */ - public int[][] - performPositioning(CharSequence cs, String script, String language, int fontSize) { - if (gpos != null) { - GlyphSequence gs = mapCharsToGlyphs(cs, null); - int[][] adjustments = new int [ gs.getGlyphCount() ] [ 4 ]; - if (gpos.position(gs, script, language, fontSize, this.width, adjustments)) { - return scaleAdjustments(adjustments, fontSize); - } else { - return null; - } - } else { - return null; - } - } - - /** {@inheritDoc} */ - public int[][] performPositioning(CharSequence cs, String script, String language) { - throw new UnsupportedOperationException(); - } - - - private int[][] scaleAdjustments(int[][] adjustments, int fontSize) { - if (adjustments != null) { - for (int i = 0, n = adjustments.length; i < n; i++) { - int[] gpa = adjustments [ i ]; - for (int k = 0; k < 4; k++) { - gpa [ k ] = (gpa [ k ] * fontSize) / 1000; - } - } - return adjustments; - } else { - return null; - } - } - - /** - * Map sequence CS, comprising a sequence of UTF-16 encoded Unicode Code Points, to - * an output character sequence GS, comprising a sequence of Glyph Indices. N.B. Unlike - * mapChar(), this method does not make use of embedded subset encodings. - * @param cs a CharSequence containing UTF-16 encoded Unicode characters - * @returns a CharSequence containing glyph indices - */ - private GlyphSequence mapCharsToGlyphs(CharSequence cs, List associations) { - IntBuffer cb = IntBuffer.allocate(cs.length()); - IntBuffer gb = IntBuffer.allocate(cs.length()); - int gi; - int giMissing = findGlyphIndex(Typeface.NOT_FOUND); - for (int i = 0, n = cs.length(); i < n; i++) { - int cc = cs.charAt(i); - if ((cc >= 0xD800) && (cc < 0xDC00)) { - if ((i + 1) < n) { - int sh = cc; - int sl = cs.charAt(++i); - if ((sl >= 0xDC00) && (sl < 0xE000)) { - cc = 0x10000 + ((sh - 0xD800) << 10) + ((sl - 0xDC00) << 0); - } else { - throw new IllegalArgumentException( - "ill-formed UTF-16 sequence, " - + "contains isolated high surrogate at index " + i); - } - } else { - throw new IllegalArgumentException( - "ill-formed UTF-16 sequence, " - + "contains isolated high surrogate at end of sequence"); - } - } else if ((cc >= 0xDC00) && (cc < 0xE000)) { - throw new IllegalArgumentException( - "ill-formed UTF-16 sequence, " - + "contains isolated low surrogate at index " + i); - } - notifyMapOperation(); - gi = findGlyphIndex(cc); - if (gi == SingleByteEncoding.NOT_FOUND_CODE_POINT) { - warnMissingGlyph((char) cc); - gi = giMissing; - } - cb.put(cc); - gb.put(gi); - } - cb.flip(); - gb.flip(); - if ((associations != null) && (associations.size() == cs.length())) { - associations = new java.util.ArrayList(associations); - } else { - associations = null; - } - return new GlyphSequence(cb, gb, associations); - } - - /** - * Map sequence GS, comprising a sequence of Glyph Indices, to output sequence CS, - * comprising a sequence of UTF-16 encoded Unicode Code Points. - * @param gs a GlyphSequence containing glyph indices - * @returns a CharSequence containing UTF-16 encoded Unicode characters - */ - private CharSequence mapGlyphsToChars(GlyphSequence gs) { - int ng = gs.getGlyphCount(); - CharBuffer cb = CharBuffer.allocate(ng); - int ccMissing = Typeface.NOT_FOUND; - for (int i = 0, n = ng; i < n; i++) { - int gi = gs.getGlyph(i); - int cc = findCharacterFromGlyphIndex(gi); - if ((cc == 0) || (cc > 0x10FFFF)) { - cc = ccMissing; - log.warn("Unable to map glyph index " + gi - + " to Unicode scalar in font '" - + getFullName() + "', substituting missing character '" - + (char) cc + "'"); - } - if (cc > 0x00FFFF) { - int sh; - int sl; - cc -= 0x10000; - sh = ((cc >> 10) & 0x3FF) + 0xD800; - sl = ((cc >> 0) & 0x3FF) + 0xDC00; - cb.put((char) sh); - cb.put((char) sl); - } else { - cb.put((char) cc); - } - } - cb.flip(); - return cb; - } - - private CharSequence normalize(CharSequence cs, List associations) { - return hasDecomposable(cs) ? decompose(cs, associations) : cs; - } - - private boolean hasDecomposable(CharSequence cs) { - for (int i = 0, n = cs.length(); i < n; i++) { - int cc = cs.charAt(i); - if (CharNormalize.isDecomposable(cc)) { - return true; - } - } - return false; - } - - private CharSequence decompose(CharSequence cs, List associations) { - StringBuffer sb = new StringBuffer(cs.length()); - int[] daBuffer = new int[CharNormalize.maximumDecompositionLength()]; - for (int i = 0, n = cs.length(); i < n; i++) { - int cc = cs.charAt(i); - int[] da = CharNormalize.decompose(cc, daBuffer); - for (int j = 0; j < da.length; j++) { - if (da[j] > 0) { - sb.append((char) da[j]); - } else { - break; - } - } - } - return sb; - } - - private static GlyphSequence elideControls(GlyphSequence gs) { - if (hasElidableControl(gs)) { - int[] ca = gs.getCharacterArray(false); - IntBuffer ngb = IntBuffer.allocate(gs.getGlyphCount()); - List nal = new java.util.ArrayList(gs.getGlyphCount()); - for (int i = 0, n = gs.getGlyphCount(); i < n; ++i) { - CharAssociation a = gs.getAssociation(i); - int s = a.getStart(); - int e = a.getEnd(); - while (s < e) { - int ch = ca [ s ]; - if (isElidableControl(ch)) { - break; - } else { - ++s; - } - } - if (s == e) { - ngb.put(gs.getGlyph(i)); - nal.add(a); - } - } - ngb.flip(); - return new GlyphSequence(gs.getCharacters(), ngb, nal, gs.getPredications()); - } else { - return gs; - } - } - - private static boolean hasElidableControl(GlyphSequence gs) { - int[] ca = gs.getCharacterArray(false); - for (int i = 0, n = ca.length; i < n; ++i) { - int ch = ca [ i ]; - if (isElidableControl(ch)) { - return true; - } - } - return false; - } - - private static boolean isElidableControl(int ch) { - if (ch < 0x0020) { - return true; - } else if ((ch >= 0x80) && (ch < 0x00A0)) { - return true; - } else if ((ch >= 0x2000) && (ch <= 0x206F)) { - if ((ch >= 0x200B) && (ch <= 0x200F)) { - return true; - } else if ((ch >= 0x2028) && (ch <= 0x202E)) { - return true; - } else if ((ch >= 0x2066) && (ch <= 0x206F)) { - return true; - } else { - return ch == 0x2060; - } - } else { - return false; - } - } - - @Override - public boolean hasFeature(int tableType, String script, String language, String feature) { - GlyphTable table; - if (tableType == GlyphTable.GLYPH_TABLE_TYPE_SUBSTITUTION) { - table = getGSUB(); - } else if (tableType == GlyphTable.GLYPH_TABLE_TYPE_POSITIONING) { - table = getGPOS(); - } else if (tableType == GlyphTable.GLYPH_TABLE_TYPE_DEFINITION) { - table = getGDEF(); - } else { - table = null; - } - return (table != null) && table.hasFeature(script, language, feature); - } - - public Map<Integer, Integer> getWidthsMap() { - return null; - } - - public InputStream getCmapStream() { - return null; - } -} - diff --git a/src/java/org/apache/fop/fonts/MutableFont.java b/src/java/org/apache/fop/fonts/MutableFont.java deleted file mode 100644 index f02eb2b49..000000000 --- a/src/java/org/apache/fop/fonts/MutableFont.java +++ /dev/null @@ -1,161 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.net.URI; -import java.util.Map; -import java.util.Set; - - - -/** - * This interface is used to set the values of a font during configuration time. - */ -public interface MutableFont { - - /** - * Sets the URI from which this font is or will be loaded. - * @param uri URI from which font is or will be loaded - */ - void setFontURI(URI uri); - - /** - * Sets the "PostScript" font name (Example: "Helvetica-BoldOblique"). - * @param name font name - */ - void setFontName(String name); - - /** - * Sets the font's full name (usually the one that the operating system displays). Example: - * "Helvetica Bold Oblique". - * @param name font' full name - */ - void setFullName(String name); - - /** - * Sets the font's family names (Example: "Helvetica"). - * @param names the font's family names (a Set of Strings) - */ - void setFamilyNames(Set<String> names); - - /** - * Sets the URI to the embeddable font. - * @param path URI to the font - */ - void setEmbedURI(URI path); - - /** - * Sets the resource name of the embeddable font file. - * @param name resource name - */ - void setEmbedResourceName(String name); - - /** - * Sets the embedding mode. - * @param embeddingMode the embedding mode - */ - void setEmbeddingMode(EmbeddingMode embeddingMode); - - /** - * Sets the capital height value. - * @param capHeight capital height - */ - void setCapHeight(int capHeight); - - /** - * Sets the ascent value. - * @param ascender ascent height - */ - void setAscender(int ascender); - - /** - * Sets the descent value. - * @param descender descent value - */ - void setDescender(int descender); - - /** - * Sets the font's bounding box - * @param bbox bounding box - */ - void setFontBBox(int[] bbox); - - /** - * Sets the font's flags - * @param flags flags - */ - void setFlags(int flags); - - /** - * Sets the font's StemV value. - * @param stemV StemV - */ - void setStemV(int stemV); - - /** - * Sets the font's italic angle. - * @param italicAngle italic angle - */ - void setItalicAngle(int italicAngle); - - /** - * Sets the font's default width - * @param width default width - */ - void setMissingWidth(int width); - - /** - * Sets the font type. - * @param fontType font type - */ - void setFontType(FontType fontType); - - /** - * Sets the index of the first character in the character table. - * @param index index of first character - */ - void setFirstChar(int index); - - /** - * Sets the index of the last character in the character table. - * @param index index of the last character - */ - void setLastChar(int index); - - /** - * Enables/disabled kerning. - * @param enabled True if kerning should be enabled if available - */ - void setKerningEnabled(boolean enabled); - - /** - * Enables/disabled advanced typographic features. - * @param enabled true if advanced typographic features should be enabled if available - */ - void setAdvancedEnabled(boolean enabled); - - /** - * Adds an entry to the kerning table. - * @param key Kerning key - * @param value Kerning value - */ - void putKerningEntry(Integer key, Map<Integer, Integer> value); - -} diff --git a/src/java/org/apache/fop/fonts/NamedCharacter.java b/src/java/org/apache/fop/fonts/NamedCharacter.java deleted file mode 100644 index 9877ec6ec..000000000 --- a/src/java/org/apache/fop/fonts/NamedCharacter.java +++ /dev/null @@ -1,142 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import org.apache.xmlgraphics.fonts.Glyphs; - -import org.apache.fop.util.CharUtilities; - -/** - * Represents an named character with character name (from the Adobe glyph list) and a Unicode - * sequence that this character represents. - */ -public class NamedCharacter { - - private String charName; - private String unicodeSequence; - - /** - * Main constructor. - * @param charName the character name - * @param unicodeSequence the Unicode sequence associated with this character - */ - public NamedCharacter(String charName, String unicodeSequence) { - if (charName == null) { - throw new NullPointerException("charName must not be null"); - } - this.charName = charName; - if (unicodeSequence != null) { - this.unicodeSequence = unicodeSequence; - } else { - this.unicodeSequence = Glyphs.getUnicodeSequenceForGlyphName(charName); - } - } - - /** - * Simple constructor. - * @param charName the character name - */ - public NamedCharacter(String charName) { - this(charName, null); - } - - /** {@inheritDoc} */ - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((charName == null) ? 0 : charName.hashCode()); - return result; - } - - /** {@inheritDoc} */ - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final NamedCharacter other = (NamedCharacter)obj; - return charName.equals(other.charName); - } - - /** - * Returns the character name (as defined by the Adobe glyph list). - * @return the character name - */ - public String getName() { - return this.charName; - } - - /** - * Returns the Unicode sequence associated with this character. - * @return the Unicode sequence (or null if no Unicode sequence is associated) - */ - public String getUnicodeSequence() { - return this.unicodeSequence; - } - - /** - * Indicates whether a single Unicode value is associated with this character. - * @return true if exactly one Unicode value is associated with this character, false otherwise - */ - public boolean hasSingleUnicodeValue() { - return (this.unicodeSequence != null && this.unicodeSequence.length() == 1); - } - - /** - * Returns the single Unicode value associated with this named character. Check - * {@link #hasSingleUnicodeValue()} before you call this method because an - * IllegalStateException is thrown is a Unicode sequence with more than one character is - * associated with this character. - * @return the single Unicode value (or FFFF ("NOT A CHARACTER") if no Unicode value is - * available) - * @throws IllegalStateException if a Unicode sequence with more than one value is associated - * with the named character - */ - public char getSingleUnicodeValue() throws IllegalStateException { - if (this.unicodeSequence == null) { - return CharUtilities.NOT_A_CHARACTER; - } - if (this.unicodeSequence.length() > 1) { - throw new IllegalStateException("getSingleUnicodeValue() may not be called for a" - + " named character that has more than one Unicode value (a sequence)" - + " associated with the named character!"); - } - return this.unicodeSequence.charAt(0); - } - - /** {@inheritDoc} */ - public String toString() { - StringBuffer sb = new StringBuffer(this.unicodeSequence); - sb.append(" ("); - if (this.unicodeSequence != null) { - for (int i = 0, c = this.unicodeSequence.length(); i < c; i++) { - sb.append("0x").append(Integer.toHexString(this.unicodeSequence.charAt(0))); - } - sb.append(", "); - } - sb.append(getName()).append(')'); - return sb.toString(); - } -} diff --git a/src/java/org/apache/fop/fonts/SimpleSingleByteEncoding.java b/src/java/org/apache/fop/fonts/SimpleSingleByteEncoding.java deleted file mode 100644 index 0180d4540..000000000 --- a/src/java/org/apache/fop/fonts/SimpleSingleByteEncoding.java +++ /dev/null @@ -1,160 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.xmlgraphics.fonts.Glyphs; - -import org.apache.fop.util.CharUtilities; - -/** - * A simple implementation of the OneByteEncoding mostly used for encodings that are constructed - * on-the-fly. - */ -public class SimpleSingleByteEncoding implements SingleByteEncoding { - - private final String name; - private final List<NamedCharacter> mapping = new ArrayList<NamedCharacter>(); - private final Map<Character, Character> charMap = new HashMap<Character, Character>(); - - /** - * Main constructor. - * @param name the encoding's name - */ - public SimpleSingleByteEncoding(String name) { - this.name = name; - } - - /** {@inheritDoc} */ - public String getName() { - return this.name; - } - - /** {@inheritDoc} */ - public char mapChar(char c) { - Character nc = charMap.get(Character.valueOf(c)); - if (nc != null) { - return nc.charValue(); - } - return NOT_FOUND_CODE_POINT; - } - - /** {@inheritDoc} */ - public String[] getCharNameMap() { - String[] map = new String[getSize()]; - Arrays.fill(map, Glyphs.NOTDEF); - for (int i = getFirstChar(); i <= getLastChar(); i++) { - NamedCharacter ch = this.mapping.get(i - 1); - map[i] = ch.getName(); - } - return map; - } - - /** - * Returns the index of the first defined character. - * @return the index of the first defined character (always 1 for this class) - */ - public int getFirstChar() { - return 1; - } - - /** - * Returns the index of the last defined character. - * @return the index of the last defined character - */ - public int getLastChar() { - return this.mapping.size(); - } - - /** - * Returns the number of characters defined by this encoding. - * @return the number of characters - */ - public int getSize() { - return this.mapping.size() + 1; - } - - /** - * Indicates whether the encoding is full (with 256 code points). - * @return true if the encoding is full - */ - public boolean isFull() { - return (getSize() == 256); - } - - /** - * Adds a new character to the encoding. - * @param ch the named character - * @return the code point assigned to the character - */ - public char addCharacter(NamedCharacter ch) { - if (!ch.hasSingleUnicodeValue()) { - throw new IllegalArgumentException("Only NamedCharacters with a single Unicode value" - + " are currently supported!"); - } - if (isFull()) { - throw new IllegalStateException("Encoding is full!"); - } - char newSlot = (char)(getLastChar() + 1); - this.mapping.add(ch); - this.charMap.put(Character.valueOf(ch.getSingleUnicodeValue()), Character.valueOf(newSlot)); - return newSlot; - } - - /** - * Returns the named character at a given code point in the encoding. - * @param codePoint the code point of the character - * @return the NamedCharacter (or null if no character is at this position) - */ - public NamedCharacter getCharacterForIndex(int codePoint) { - if (codePoint < 0 || codePoint > 255) { - throw new IllegalArgumentException("codePoint must be between 0 and 255"); - } - if (codePoint <= getLastChar()) { - return this.mapping.get(codePoint - 1); - } else { - return null; - } - } - - /** {@inheritDoc} */ - public char[] getUnicodeCharMap() { - char[] map = new char[getLastChar() + 1]; - for (int i = 0; i < getFirstChar(); i++) { - map[i] = CharUtilities.NOT_A_CHARACTER; - } - for (int i = getFirstChar(); i <= getLastChar(); i++) { - map[i] = getCharacterForIndex(i).getSingleUnicodeValue(); - } - return map; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return getName() + " (" + getSize() + " chars)"; - } - -} diff --git a/src/java/org/apache/fop/fonts/SingleByteEncoding.java b/src/java/org/apache/fop/fonts/SingleByteEncoding.java deleted file mode 100644 index ad9d691f6..000000000 --- a/src/java/org/apache/fop/fonts/SingleByteEncoding.java +++ /dev/null @@ -1,58 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -/** - * The interface defines a 1-byte character encoding (with 256 characters). - */ -public interface SingleByteEncoding { - - /** Code point that is used if no code point for a specific character has been found. */ - char NOT_FOUND_CODE_POINT = '\0'; - - /** - * Returns the encoding's name. - * @return the name of the encoding - */ - String getName(); - - /** - * Maps a Unicode character to a code point in the encoding. - * @param c the Unicode character to map - * @return the code point in the encoding or 0 (=.notdef) if not found - */ - char mapChar(char c); - - /** - * Returns the array of character names for this encoding. - * @return the array of character names - * (unmapped code points are represented by a ".notdef" value) - */ - String[] getCharNameMap(); - - /** - * Returns a character array with Unicode scalar values which can be used to map encoding - * code points to Unicode values. Note that this does not return all possible Unicode values - * that the encoding maps. - * @return a character array with Unicode scalar values - */ - char[] getUnicodeCharMap(); - -} diff --git a/src/java/org/apache/fop/fonts/SingleByteFont.java b/src/java/org/apache/fop/fonts/SingleByteFont.java deleted file mode 100644 index e3037a524..000000000 --- a/src/java/org/apache/fop/fonts/SingleByteFont.java +++ /dev/null @@ -1,552 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.awt.Rectangle; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.xmlgraphics.fonts.Glyphs; - -import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.fonts.truetype.OpenFont.PostScriptVersion; -import org.apache.fop.util.CharUtilities; - -/** - * Generic SingleByte font - */ -public class SingleByteFont extends CustomFont { - - /** logger */ - private static Log log = LogFactory.getLog(SingleByteFont.class); - - protected SingleByteEncoding mapping; - private boolean useNativeEncoding; - - protected int[] width; - - private Rectangle[] boundingBoxes; - - private Map<Character, UnencodedCharacter> unencodedCharacters; - private List<SimpleSingleByteEncoding> additionalEncodings; - private Map<Character, Character> alternativeCodes; - - private PostScriptVersion ttPostScriptVersion; - - private int usedGlyphsCount; - private LinkedHashMap<Integer, String> usedGlyphNames; - private Map<Integer, Integer> usedGlyphs; - private Map<Integer, Character> usedCharsIndex; - private Map<Character, Integer> charGIDMappings; - - public SingleByteFont(InternalResourceResolver resourceResolver) { - super(resourceResolver); - setEncoding(CodePointMapping.WIN_ANSI_ENCODING); - } - - public SingleByteFont(InternalResourceResolver resourceResolver, EmbeddingMode embeddingMode) { - this(resourceResolver); - setEmbeddingMode(embeddingMode); - if (embeddingMode != EmbeddingMode.FULL) { - usedGlyphNames = new LinkedHashMap<Integer, String>(); - usedGlyphs = new HashMap<Integer, Integer>(); - usedCharsIndex = new HashMap<Integer, Character>(); - charGIDMappings = new HashMap<Character, Integer>(); - - // The zeroth value is reserved for .notdef - usedGlyphs.put(0, 0); - usedGlyphsCount++; - } - } - - /** {@inheritDoc} */ - public boolean isEmbeddable() { - return (!(getEmbedFileURI() == null - && getEmbedResourceName() == null)); - } - - /** {@inheritDoc} */ - public boolean isSubsetEmbedded() { - return getEmbeddingMode() != EmbeddingMode.FULL; - } - - /** {@inheritDoc} */ - public String getEncodingName() { - return this.mapping.getName(); - } - - /** - * Returns the code point mapping (encoding) of this font. - * @return the code point mapping - */ - public SingleByteEncoding getEncoding() { - return this.mapping; - } - - /** {@inheritDoc} */ - public int getWidth(int i, int size) { - if (i < 256) { - int idx = i - getFirstChar(); - if (idx >= 0 && idx < width.length) { - return size * width[idx]; - } - } else if (this.additionalEncodings != null) { - int encodingIndex = (i / 256) - 1; - SimpleSingleByteEncoding encoding = getAdditionalEncoding(encodingIndex); - int codePoint = i % 256; - NamedCharacter nc = encoding.getCharacterForIndex(codePoint); - UnencodedCharacter uc - = this.unencodedCharacters.get(Character.valueOf(nc.getSingleUnicodeValue())); - return size * uc.getWidth(); - } - return 0; - } - - /** {@inheritDoc} */ - public int[] getWidths() { - int[] arr = new int[width.length]; - System.arraycopy(width, 0, arr, 0, width.length); - return arr; - } - - public Rectangle getBoundingBox(int glyphIndex, int size) { - Rectangle bbox = null; - if (glyphIndex < 256) { - int idx = glyphIndex - getFirstChar(); - if (idx >= 0 && idx < boundingBoxes.length) { - bbox = boundingBoxes[idx]; - } - } else if (this.additionalEncodings != null) { - int encodingIndex = (glyphIndex / 256) - 1; - SimpleSingleByteEncoding encoding = getAdditionalEncoding(encodingIndex); - int codePoint = glyphIndex % 256; - NamedCharacter nc = encoding.getCharacterForIndex(codePoint); - UnencodedCharacter uc = this.unencodedCharacters.get(Character.valueOf(nc.getSingleUnicodeValue())); - bbox = uc.getBBox(); - } - return bbox == null ? null : new Rectangle(bbox.x * size, bbox.y * size, bbox.width * size, bbox.height * size); - } - - /** - * Lookup a character using its alternative names. If found, cache it so we - * can speed up lookups. - * @param c the character - * @return the suggested alternative character present in the font - */ - private char findAlternative(char c) { - char d; - if (alternativeCodes == null) { - alternativeCodes = new java.util.HashMap<Character, Character>(); - } else { - Character alternative = alternativeCodes.get(c); - if (alternative != null) { - return alternative; - } - } - String charName = Glyphs.charToGlyphName(c); - String[] charNameAlternatives = Glyphs.getCharNameAlternativesFor(charName); - if (charNameAlternatives != null && charNameAlternatives.length > 0) { - for (int i = 0; i < charNameAlternatives.length; i++) { - if (log.isDebugEnabled()) { - log.debug("Checking alternative for char " + c + " (charname=" - + charName + "): " + charNameAlternatives[i]); - } - String s = Glyphs.getUnicodeSequenceForGlyphName(charNameAlternatives[i]); - if (s != null) { - d = lookupChar(s.charAt(0)); - if (d != SingleByteEncoding.NOT_FOUND_CODE_POINT) { - alternativeCodes.put(c, d); - return d; - } - } - } - } - - return SingleByteEncoding.NOT_FOUND_CODE_POINT; - } - - private char lookupChar(char c) { - char d = mapping.mapChar(c); - if (d != SingleByteEncoding.NOT_FOUND_CODE_POINT) { - return d; - } - - // Check unencoded characters which are available in the font by - // character name - d = mapUnencodedChar(c); - return d; - } - - private boolean isSubset() { - return getEmbeddingMode() == EmbeddingMode.SUBSET; - } - - /** {@inheritDoc} */ - @Override - public char mapChar(char c) { - notifyMapOperation(); - char d = lookupChar(c); - if (d == SingleByteEncoding.NOT_FOUND_CODE_POINT) { - // Check for alternative - d = findAlternative(c); - if (d != SingleByteEncoding.NOT_FOUND_CODE_POINT) { - return d; - } else { - this.warnMissingGlyph(c); - return Typeface.NOT_FOUND; - } - } - if (isEmbeddable() && isSubset()) { - mapChar(d, c); - } - return d; - } - - private int mapChar(int glyphIndex, char unicode) { - // Reencode to a new subset font or get the reencoded value - // IOW, accumulate the accessed characters and build a character map for them - Integer subsetCharSelector = usedGlyphs.get(glyphIndex); - if (subsetCharSelector == null) { - int selector = usedGlyphsCount; - usedGlyphs.put(glyphIndex, selector); - usedCharsIndex.put(selector, unicode); - charGIDMappings.put(unicode, glyphIndex); - usedGlyphsCount++; - return selector; - } else { - return subsetCharSelector; - } - } - - private char getUnicode(int index) { - Character mapValue = usedCharsIndex.get(index); - if (mapValue != null) { - return mapValue.charValue(); - } else { - return CharUtilities.NOT_A_CHARACTER; - } - } - - private char mapUnencodedChar(char ch) { - if (this.unencodedCharacters != null) { - UnencodedCharacter unencoded = this.unencodedCharacters.get(Character.valueOf(ch)); - if (unencoded != null) { - if (this.additionalEncodings == null) { - this.additionalEncodings = new ArrayList<SimpleSingleByteEncoding>(); - } - SimpleSingleByteEncoding encoding = null; - char mappedStart = 0; - int additionalsCount = this.additionalEncodings.size(); - for (int i = 0; i < additionalsCount; i++) { - mappedStart += 256; - encoding = getAdditionalEncoding(i); - char alt = encoding.mapChar(ch); - if (alt != 0) { - return (char)(mappedStart + alt); - } - } - if (encoding != null && encoding.isFull()) { - encoding = null; - } - if (encoding == null) { - encoding = new SimpleSingleByteEncoding( - getFontName() + "EncodingSupp" + (additionalsCount + 1)); - this.additionalEncodings.add(encoding); - mappedStart += 256; - } - return (char)(mappedStart + encoding.addCharacter(unencoded.getCharacter())); - } - } - return 0; - } - - /** {@inheritDoc} */ - @Override - public boolean hasChar(char c) { - char d = mapping.mapChar(c); - if (d != SingleByteEncoding.NOT_FOUND_CODE_POINT) { - return true; - } - //Check unencoded characters which are available in the font by character name - d = mapUnencodedChar(c); - if (d != SingleByteEncoding.NOT_FOUND_CODE_POINT) { - return true; - } - // Check if an alternative exists - d = findAlternative(c); - if (d != SingleByteEncoding.NOT_FOUND_CODE_POINT) { - return true; - } - return false; - } - - /* ---- single byte font specific setters --- */ - - /** - * Updates the mapping variable based on the encoding. - * @param encoding the name of the encoding - */ - protected void updateMapping(String encoding) { - try { - this.mapping = CodePointMapping.getMapping(encoding); - } catch (UnsupportedOperationException e) { - log.error("Font '" + super.getFontName() + "': " + e.getMessage()); - } - } - - /** - * Sets the encoding of the font. - * @param encoding the encoding (ex. "WinAnsiEncoding" or "SymbolEncoding") - */ - public void setEncoding(String encoding) { - updateMapping(encoding); - } - - /** - * Sets the encoding of the font. - * @param encoding the encoding information - */ - public void setEncoding(CodePointMapping encoding) { - this.mapping = encoding; - } - - /** - * Controls whether the font is configured to use its native encoding or if it - * may need to be re-encoded for the target format. - * @param value true indicates that the configured encoding is the font's native encoding - */ - public void setUseNativeEncoding(boolean value) { - this.useNativeEncoding = value; - } - - /** - * Indicates whether this font is configured to use its native encoding. This - * method is used to determine whether the font needs to be re-encoded. - * @return true if the font uses its native encoding. - */ - public boolean isUsingNativeEncoding() { - return this.useNativeEncoding; - } - - /** - * Sets a width for a character. - * @param index index of the character - * @param w the width of the character - */ - public void setWidth(int index, int w) { - if (this.width == null) { - this.width = new int[getLastChar() - getFirstChar() + 1]; - } - this.width[index - getFirstChar()] = w; - } - - public void setBoundingBox(int index, Rectangle bbox) { - if (this.boundingBoxes == null) { - this.boundingBoxes = new Rectangle[getLastChar() - getFirstChar() + 1]; - } - this.boundingBoxes[index - getFirstChar()] = bbox; - } - - /** - * Adds an unencoded character (one that is not supported by the primary encoding). - * @param ch the named character - * @param width the width of the character - */ - public void addUnencodedCharacter(NamedCharacter ch, int width, Rectangle bbox) { - if (this.unencodedCharacters == null) { - this.unencodedCharacters = new HashMap<Character, UnencodedCharacter>(); - } - if (ch.hasSingleUnicodeValue()) { - UnencodedCharacter uc = new UnencodedCharacter(ch, width, bbox); - this.unencodedCharacters.put(Character.valueOf(ch.getSingleUnicodeValue()), uc); - } else { - //Cannot deal with unicode sequences, so ignore this character - } - } - - /** - * Makes all unencoded characters available through additional encodings. This method - * is used in cases where the fonts need to be encoded in the target format before - * all text of the document is processed (for example in PostScript when resource optimization - * is disabled). - */ - public void encodeAllUnencodedCharacters() { - if (this.unencodedCharacters != null) { - Set<Character> sortedKeys = new TreeSet<Character>(this.unencodedCharacters.keySet()); - for (Character ch : sortedKeys) { - char mapped = mapChar(ch.charValue()); - assert mapped != Typeface.NOT_FOUND; - } - } - } - - /** - * Indicates whether the encoding has additional encodings besides the primary encoding. - * @return true if there are additional encodings. - */ - public boolean hasAdditionalEncodings() { - return (this.additionalEncodings != null) && (this.additionalEncodings.size() > 0); - } - - /** - * Returns the number of additional encodings this single-byte font maintains. - * @return the number of additional encodings - */ - public int getAdditionalEncodingCount() { - if (hasAdditionalEncodings()) { - return this.additionalEncodings.size(); - } else { - return 0; - } - } - - /** - * Returns an additional encoding. - * @param index the index of the additional encoding - * @return the additional encoding - * @throws IndexOutOfBoundsException if the index is out of bounds - */ - public SimpleSingleByteEncoding getAdditionalEncoding(int index) - throws IndexOutOfBoundsException { - if (hasAdditionalEncodings()) { - return this.additionalEncodings.get(index); - } else { - throw new IndexOutOfBoundsException("No additional encodings available"); - } - } - - /** - * Returns an array with the widths for an additional encoding. - * @param index the index of the additional encoding - * @return the width array - */ - public int[] getAdditionalWidths(int index) { - SimpleSingleByteEncoding enc = getAdditionalEncoding(index); - int[] arr = new int[enc.getLastChar() - enc.getFirstChar() + 1]; - for (int i = 0, c = arr.length; i < c; i++) { - NamedCharacter nc = enc.getCharacterForIndex(enc.getFirstChar() + i); - UnencodedCharacter uc = this.unencodedCharacters.get( - Character.valueOf(nc.getSingleUnicodeValue())); - arr[i] = uc.getWidth(); - } - return arr; - } - - private static final class UnencodedCharacter { - - private final NamedCharacter character; - private final int width; - private final Rectangle bbox; - - public UnencodedCharacter(NamedCharacter character, int width, Rectangle bbox) { - this.character = character; - this.width = width; - this.bbox = bbox; - } - - public NamedCharacter getCharacter() { - return this.character; - } - - public int getWidth() { - return this.width; - } - - public Rectangle getBBox() { - return bbox; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return getCharacter().toString(); - } - } - - /** - * Sets the version of the PostScript table stored in the TrueType font represented by - * this instance. - * - * @param version version of the <q>post</q> table - */ - public void setTrueTypePostScriptVersion(PostScriptVersion version) { - ttPostScriptVersion = version; - } - - /** - * Returns the version of the PostScript table stored in the TrueType font represented by - * this instance. - * - * @return the version of the <q>post</q> table - */ - public PostScriptVersion getTrueTypePostScriptVersion() { - assert getFontType() == FontType.TRUETYPE; - return ttPostScriptVersion; - } - - /** - * Returns a Map of used Glyphs. - * @return Map Map of used Glyphs - */ - public Map<Integer, Integer> getUsedGlyphs() { - return Collections.unmodifiableMap(usedGlyphs); - } - - public char getUnicodeFromSelector(int selector) { - return getUnicode(selector); - } - - public int getGIDFromChar(char ch) { - return charGIDMappings.get(ch); - } - - public char getUnicodeFromGID(int glyphIndex) { - int selector = usedGlyphs.get(glyphIndex); - return usedCharsIndex.get(selector); - } - - public void mapUsedGlyphName(int gid, String value) { - usedGlyphNames.put(gid, value); - } - - public Map<Integer, String> getUsedGlyphNames() { - return usedGlyphNames; - } - - public String getGlyphName(int idx) { - if (idx < mapping.getCharNameMap().length) { - return mapping.getCharNameMap()[idx]; - } else { - int selector = usedGlyphs.get(idx); - char theChar = usedCharsIndex.get(selector); - return unencodedCharacters.get(theChar).getCharacter().getName(); - } - } -} - diff --git a/src/java/org/apache/fop/fonts/TextFragment.java b/src/java/org/apache/fop/fonts/TextFragment.java deleted file mode 100644 index 8722ecf2e..000000000 --- a/src/java/org/apache/fop/fonts/TextFragment.java +++ /dev/null @@ -1,71 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.text.CharacterIterator; - -/** - * Encapsulates a sub-sequence (fragement) of a text iterator (or other text source), - * where begin index and end index are indices into larger text iterator that denote - * [begin,end) of sub-sequence range. Additionally associated with a designated script - * (or "auto"), a designated language (or "none"), and a (single) bidi level (or -1 - * if not known). - */ -public interface TextFragment { - - /** - * Obtain reference to underlying iterator. - */ - CharacterIterator getIterator(); - - /** - * Obtain beginning index (inclusive) of sub-sequence of fragment in overall text source. - */ - int getBeginIndex(); - - /** - * Obtain ending index (exclusive) of sub-sequence of fragment in overall text source. - */ - int getEndIndex(); - - /** - * Obtain associated script (if designated) or "auto" if not. - */ - String getScript(); - - /** - * Obtain associated language (if designated) or "none" if not. - */ - String getLanguage(); - - /** - * Obtain associated bidi level (if known) or -1 if not. - */ - int getBidiLevel(); - - /** - * Obtain character at specified index within this fragment's sub-sequence, - * where index 0 corresponds to beginning index in overal text source, and - * subSequenceIndex must be less than ending index - beginning index. - */ - char charAt(int subSequenceIndex); - - CharSequence subSequence(int startIndex, int endIndex); -} diff --git a/src/java/org/apache/fop/fonts/Typeface.java b/src/java/org/apache/fop/fonts/Typeface.java deleted file mode 100644 index 3232d7605..000000000 --- a/src/java/org/apache/fop/fonts/Typeface.java +++ /dev/null @@ -1,158 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts; - -import java.util.HashSet; -import java.util.Set; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.xmlgraphics.fonts.Glyphs; - -/** - * Base class for font classes - */ -public abstract class Typeface implements FontMetrics { - - /** - * Code point that is used if no code point for a specific character has - * been found. - */ - public static final char NOT_FOUND = '#'; - - /** logger */ - private static Log log = LogFactory.getLog(Typeface.class); - - /** - * Used to identify whether a font has been used (a character map operation - * is used as the trigger). This could just as well be a boolean but is a - * long out of statistical interest. - */ - private long charMapOps; - - /** An optional event listener that receives events such as missing glyphs etc. */ - protected FontEventListener eventListener; - - private Set<Character> warnedChars; - - /** - * Get the encoding of the font. - * @return the encoding - */ - public abstract String getEncodingName(); - - /** - * Map a Unicode character to a code point in the font. - * @param c character to map - * @return the mapped character - */ - public abstract char mapChar(char c); - - /** - * Used for keeping track of character mapping operations in order to determine if a font - * was used at all or not. - */ - protected void notifyMapOperation() { - this.charMapOps++; - } - - /** - * Indicates whether this font had to do any character mapping operations. If that was - * not the case, it's an indication that the font has never actually been used. - * @return true if the font had to do any character mapping operations - */ - public boolean hadMappingOperations() { - return (this.charMapOps > 0); - } - - /** - * Determines whether this font contains a particular character/glyph. - * @param c character to check - * @return True if the character is supported, Falso otherwise - */ - public abstract boolean hasChar(char c); - - /** - * Determines whether the font is a multibyte font. - * @return True if it is multibyte - */ - public boolean isMultiByte() { - return false; - } - - /** {@inheritDoc} */ - public int getMaxAscent(int size) { - return getAscender(size); - } - - /** {@inheritDoc} */ - public boolean hasFeature(int tableType, String script, String language, String feature) { - return false; - } - - /** - * Sets the font event listener that can be used to receive events about particular events - * in this class. - * @param listener the font event listener - */ - public void setEventListener(FontEventListener listener) { - this.eventListener = listener; - } - - /** - * Provide proper warning if a glyph is not available. - * - * @param c - * the character which is missing. - */ - protected void warnMissingGlyph(char c) { - // Give up, character is not available - Character ch = new Character(c); - if (warnedChars == null) { - warnedChars = new HashSet<Character>(); - } - if (warnedChars.size() < 8 && !warnedChars.contains(ch)) { - warnedChars.add(ch); - if (this.eventListener != null) { - this.eventListener.glyphNotAvailable(this, c, getFontName()); - } else { - if (warnedChars.size() == 8) { - log.warn("Many requested glyphs are not available in font " - + getFontName()); - } else { - log.warn("Glyph " + (int) c + " (0x" - + Integer.toHexString(c) + ", " - + Glyphs.charToGlyphName(c) - + ") not available in font " + getFontName()); - } - } - } - } - - /** {@inheritDoc} */ - public String toString() { - StringBuffer sbuf = new StringBuffer(super.toString()); - sbuf.append('{'); - sbuf.append(getFullName()); - sbuf.append('}'); - return sbuf.toString(); - } -} diff --git a/src/java/org/apache/fop/fonts/apps/AbstractFontReader.java b/src/java/org/apache/fop/fonts/apps/AbstractFontReader.java deleted file mode 100644 index 4aa9b77a2..000000000 --- a/src/java/org/apache/fop/fonts/apps/AbstractFontReader.java +++ /dev/null @@ -1,142 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.apps; - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.util.List; -import java.util.Map; - -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Abstract base class for the PFM and TTF Reader command-line applications. - */ -public abstract class AbstractFontReader { - - /** Logger instance */ - protected static final Log log = LogFactory.getLog(AbstractFontReader.class); - - /** - * Main constructor. - */ - protected AbstractFontReader() { - } - - /** - * Parse commandline arguments. put options in the HashMap and return - * arguments in the String array - * the arguments: -fn Perpetua,Bold -cn PerpetuaBold per.ttf Perpetua.xml - * returns a String[] with the per.ttf and Perpetua.xml. The hash - * will have the (key, value) pairs: (-fn, Perpetua) and (-cn, PerpetuaBold) - * @param options Map that will receive options - * @param args the command-line arguments - * @return the arguments - */ - protected static String[] parseArguments(Map options, String[] args) { - List arguments = new java.util.ArrayList(); - for (int i = 0; i < args.length; i++) { - if (args[i].startsWith("-")) { - if ("-t".equals(args[i]) || "-d".equals(args[i]) || "-q".equals(args[i])) { - options.put(args[i], ""); - } else if ((i + 1) < args.length && !args[i + 1].startsWith("-")) { - options.put(args[i], args[i + 1]); - i++; - } else { - options.put(args[i], ""); - } - } else { - arguments.add(args[i]); - } - } - return (String[])arguments.toArray(new String[arguments.size()]); - } - - /** - * Sets the logging level. - * @param level the logging level ("debug", "info", "error" etc., see Jakarta Commons Logging) - */ - protected static void setLogLevel(String level) { - // Set the evel for future loggers. - LogFactory.getFactory().setAttribute("level", level); - } - - /** - * Determines the log level based of the options from the command-line. - * @param options the command-line options - */ - protected static void determineLogLevel(Map options) { - //Determine log level - if (options.get("-t") != null) { - setLogLevel("trace"); - } else if (options.get("-d") != null) { - setLogLevel("debug"); - } else if (options.get("-q") != null) { - setLogLevel("error"); - } else { - setLogLevel("info"); - } - } - - /** - * Writes the generated DOM Document to a file. - * - * @param doc The DOM Document to save. - * @param target The target filename for the XML file. - * @throws TransformerException if an error occurs during serialization - */ - public void writeFontXML(org.w3c.dom.Document doc, String target) throws TransformerException { - writeFontXML(doc, new File(target)); - } - - /** - * Writes the generated DOM Document to a file. - * - * @param doc The DOM Document to save. - * @param target The target file for the XML file. - * @throws TransformerException if an error occurs during serialization - */ - public void writeFontXML(org.w3c.dom.Document doc, File target) throws TransformerException { - log.info("Writing xml font file " + target + "..."); - - try { - OutputStream out = new java.io.FileOutputStream(target); - out = new java.io.BufferedOutputStream(out); - try { - TransformerFactory factory = TransformerFactory.newInstance(); - Transformer transformer = factory.newTransformer(); - transformer.transform( - new javax.xml.transform.dom.DOMSource(doc), - new javax.xml.transform.stream.StreamResult(out)); - } finally { - out.close(); - } - } catch (IOException ioe) { - throw new TransformerException("Error writing the output file", ioe); - } - } - -} diff --git a/src/java/org/apache/fop/fonts/apps/PFMReader.java b/src/java/org/apache/fop/fonts/apps/PFMReader.java deleted file mode 100644 index dd7f7343c..000000000 --- a/src/java/org/apache/fop/fonts/apps/PFMReader.java +++ /dev/null @@ -1,328 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.apps; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Iterator; -import java.util.Map; - -import javax.xml.parsers.DocumentBuilderFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import org.apache.fop.Version; -import org.apache.fop.fonts.type1.PFMFile; - -/** - * A tool which reads PFM files from Adobe Type 1 fonts and creates - * XML font metrics file for use in FOP. - */ -public class PFMReader extends AbstractFontReader { - - /** - * Main constructor. - */ - public PFMReader() { - super(); - } - - private static void displayUsage() { - System.out.println( - "java " + PFMReader.class.getName() + " [options] metricfile.pfm xmlfile.xml"); - System.out.println(); - System.out.println("where options can be:"); - System.out.println("-d Debug mode"); - System.out.println("-q Quiet mode"); - System.out.println("-fn <fontname>"); - System.out.println(" default is to use the fontname in the .pfm file, but"); - System.out.println(" you can override that name to make sure that the"); - System.out.println(" embedded font is used (if you're embedding fonts)"); - System.out.println(" instead of installed fonts when viewing documents "); - System.out.println(" with Acrobat Reader."); - } - - - /** - * The main method for the PFM reader tool. - * - * @param args Command-line arguments: [options] metricfile.pfm xmlfile.xml - * where options can be: - * -fn <fontname> - * default is to use the fontname in the .pfm file, but you can override - * that name to make sure that the embedded font is used instead of installed - * fonts when viewing documents with Acrobat Reader. - * -cn <classname> - * default is to use the fontname - * -ef <path to the Type1 .pfb fontfile> - * will add the possibility to embed the font. When running fop, fop will look - * for this file to embed it - * -er <path to Type1 fontfile relative to org/apache/fop/render/pdf/fonts> - * you can also include the fontfile in the fop.jar file when building fop. - * You can use both -ef and -er. The file specified in -ef will be searched first, - * then the -er file. - */ - public static void main(String[] args) { - String embFile = null; - String embResource = null; - String className = null; - String fontName = null; - - Map options = new java.util.HashMap(); - String[] arguments = parseArguments(options, args); - - determineLogLevel(options); - - PFMReader app = new PFMReader(); - - log.info("PFM Reader for Apache FOP " + Version.getVersion() + "\n"); - - if (options.get("-ef") != null) { - embFile = (String)options.get("-ef"); - } - - if (options.get("-er") != null) { - embResource = (String)options.get("-er"); - } - - if (options.get("-fn") != null) { - fontName = (String)options.get("-fn"); - } - - if (options.get("-cn") != null) { - className = (String)options.get("-cn"); - } - - if (arguments.length != 2 || options.get("-h") != null - || options.get("-help") != null || options.get("--help") != null) { - displayUsage(); - } else { - try { - log.info("Parsing font..."); - PFMFile pfm = app.loadPFM(arguments[0]); - if (pfm != null) { - app.preview(pfm); - - Document doc = app.constructFontXML(pfm, - fontName, className, embResource, embFile); - - app.writeFontXML(doc, arguments[1]); - } - log.info("XML font metrics file successfullly created."); - } catch (Exception e) { - log.error("Error while building XML font metrics file", e); - System.exit(-1); - } - } - } - - /** - * Read a PFM file and returns it as an object. - * - * @param filename The filename of the PFM file. - * @return The PFM as an object. - * @throws IOException In case of an I/O problem - */ - public PFMFile loadPFM(String filename) throws IOException { - log.info("Reading " + filename + "..."); - log.info(""); - InputStream in = new java.io.FileInputStream(filename); - try { - PFMFile pfm = new PFMFile(); - pfm.load(in); - return pfm; - } finally { - in.close(); - } - } - - /** - * Displays a preview of the PFM file on the console. - * - * @param pfm The PFM file to preview. - */ - public void preview(PFMFile pfm) { - if (log != null && log.isInfoEnabled()) { - log.info("Font: " + pfm.getWindowsName()); - log.info("Name: " + pfm.getPostscriptName()); - log.info("CharSet: " + pfm.getCharSetName()); - log.info("CapHeight: " + pfm.getCapHeight()); - log.info("XHeight: " + pfm.getXHeight()); - log.info("LowerCaseAscent: " + pfm.getLowerCaseAscent()); - log.info("LowerCaseDescent: " + pfm.getLowerCaseDescent()); - log.info("Having widths for " + (pfm.getLastChar() - pfm.getFirstChar()) - + " characters (" + pfm.getFirstChar() - + "-" + pfm.getLastChar() + ")."); - log.info("for example: Char " + pfm.getFirstChar() - + " has a width of " + pfm.getCharWidth(pfm.getFirstChar())); - log.info(""); - } - } - - /** - * Generates the font metrics file from the PFM file. - * - * @param pfm The PFM file to generate the font metrics from. - * @param fontName name of the font - * @param className class name for the font - * @param resource path to the font as embedded resource - * @param file path to the font as file - * @return The DOM document representing the font metrics file. - */ - public org.w3c.dom.Document constructFontXML(PFMFile pfm, - String fontName, String className, String resource, String file) { - log.info("Creating xml font file..."); - log.info(""); - - Document doc; - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - doc = factory.newDocumentBuilder().newDocument(); - } catch (javax.xml.parsers.ParserConfigurationException e) { - log.error("Can't create DOM implementation", e); - return null; - } - Element root = doc.createElement("font-metrics"); - doc.appendChild(root); - root.setAttribute("type", "TYPE1"); - - Element el = doc.createElement("font-name"); - root.appendChild(el); - el.appendChild(doc.createTextNode(pfm.getPostscriptName())); - - // Currently unused. - // String s = pfm.getPostscriptName(); - // int pos = s.indexOf("-"); - // if (pos >= 0) { - // char[] sb = new char[s.length() - 1]; - // s.getChars(0, pos, sb, 0); - // s.getChars(pos + 1, s.length(), sb, pos); - // s = new String(sb); - // } - - el = doc.createElement("embed"); - root.appendChild(el); - if (file != null) { - el.setAttribute("file", file); - } - if (resource != null) { - el.setAttribute("class", resource); - } - - el = doc.createElement("encoding"); - root.appendChild(el); - el.appendChild(doc.createTextNode(pfm.getCharSetName() + "Encoding")); - - el = doc.createElement("cap-height"); - root.appendChild(el); - Integer value = new Integer(pfm.getCapHeight()); - el.appendChild(doc.createTextNode(value.toString())); - - el = doc.createElement("x-height"); - root.appendChild(el); - value = new Integer(pfm.getXHeight()); - el.appendChild(doc.createTextNode(value.toString())); - - el = doc.createElement("ascender"); - root.appendChild(el); - value = new Integer(pfm.getLowerCaseAscent()); - el.appendChild(doc.createTextNode(value.toString())); - - el = doc.createElement("descender"); - root.appendChild(el); - value = new Integer(pfm.getLowerCaseDescent()); - el.appendChild(doc.createTextNode(value.toString())); - - Element bbox = doc.createElement("bbox"); - root.appendChild(bbox); - int[] bb = pfm.getFontBBox(); - final String[] names = {"left", "bottom", "right", "top"}; - for (int i = 0; i < names.length; i++) { - el = doc.createElement(names[i]); - bbox.appendChild(el); - value = new Integer(bb[i]); - el.appendChild(doc.createTextNode(value.toString())); - } - - el = doc.createElement("flags"); - root.appendChild(el); - value = new Integer(pfm.getFlags()); - el.appendChild(doc.createTextNode(value.toString())); - - el = doc.createElement("stemv"); - root.appendChild(el); - value = new Integer(pfm.getStemV()); - el.appendChild(doc.createTextNode(value.toString())); - - el = doc.createElement("italicangle"); - root.appendChild(el); - value = new Integer(pfm.getItalicAngle()); - el.appendChild(doc.createTextNode(value.toString())); - - el = doc.createElement("first-char"); - root.appendChild(el); - value = new Integer(pfm.getFirstChar()); - el.appendChild(doc.createTextNode(value.toString())); - - el = doc.createElement("last-char"); - root.appendChild(el); - value = new Integer(pfm.getLastChar()); - el.appendChild(doc.createTextNode(value.toString())); - - Element widths = doc.createElement("widths"); - root.appendChild(widths); - - for (short i = pfm.getFirstChar(); i <= pfm.getLastChar(); i++) { - el = doc.createElement("char"); - widths.appendChild(el); - el.setAttribute("idx", Integer.toString(i)); - el.setAttribute("wdt", Integer.toString(pfm.getCharWidth(i))); - } - - - // Get kerning - Iterator iter = pfm.getKerning().keySet().iterator(); - while (iter.hasNext()) { - Integer kpx1 = (Integer)iter.next(); - el = doc.createElement("kerning"); - el.setAttribute("kpx1", kpx1.toString()); - root.appendChild(el); - Element el2 = null; - - Map h2 = (Map) pfm.getKerning().get(kpx1); - Iterator enum2 = h2.entrySet().iterator(); - while (enum2.hasNext()) { - Map.Entry entry = (Map.Entry) enum2.next(); - Integer kpx2 = (Integer) entry.getKey(); - el2 = doc.createElement("pair"); - el2.setAttribute("kpx2", kpx2.toString()); - Integer val = (Integer) entry.getValue(); - el2.setAttribute("kern", val.toString()); - el.appendChild(el2); - } - } - return doc; - } -} - - - - diff --git a/src/java/org/apache/fop/fonts/apps/TTFReader.java b/src/java/org/apache/fop/fonts/apps/TTFReader.java deleted file mode 100644 index 6f80fd098..000000000 --- a/src/java/org/apache/fop/fonts/apps/TTFReader.java +++ /dev/null @@ -1,514 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.apps; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; -import java.util.Set; - -import javax.xml.parsers.DocumentBuilderFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; - -import org.apache.fop.Version; -import org.apache.fop.fonts.CMapSegment; -import org.apache.fop.fonts.FontUtil; -import org.apache.fop.fonts.truetype.FontFileReader; -import org.apache.fop.fonts.truetype.OFFontLoader; -import org.apache.fop.fonts.truetype.TTFFile; - -/** - * A tool which reads TTF files and generates - * XML font metrics file for use in FOP. - */ -public class TTFReader extends AbstractFontReader { - - /** Used to detect incompatible versions of the generated XML files */ - public static final String METRICS_VERSION_ATTR = "metrics-version"; - /** Current version number for the metrics file */ - public static final int METRICS_VERSION = 2; - - /** - * Main constructor. - */ - public TTFReader() { - super(); - } - - private static void displayUsage() { - System.out.println( - "java " + TTFReader.class.getName() + " [options] fontfile.ttf xmlfile.xml"); - System.out.println(); - System.out.println("where options can be:"); - System.out.println("-t Trace mode"); - System.out.println("-d Debug mode"); - System.out.println("-q Quiet mode"); - System.out.println("-enc ansi"); - System.out.println(" With this option you create a WinAnsi encoded font."); - System.out.println(" The default is to create a CID keyed font."); - System.out.println(" If you're not going to use characters outside the"); - System.out.println(" pdfencoding range (almost the same as iso-8889-1)"); - System.out.println(" you can add this option."); - System.out.println("-ttcname <fontname>"); - System.out.println(" If you're reading data from a TrueType Collection"); - System.out.println(" (.ttc file) you must specify which font from the"); - System.out.println(" collection you will read metrics from. If you read"); - System.out.println(" from a .ttc file without this option, the fontnames"); - System.out.println(" will be listed for you."); - System.out.println(" -fn <fontname>"); - System.out.println(" default is to use the fontname in the .ttf file, but"); - System.out.println(" you can override that name to make sure that the"); - System.out.println(" embedded font is used (if you're embedding fonts)"); - System.out.println(" instead of installed fonts when viewing documents "); - System.out.println(" with Acrobat Reader."); - } - - - /** - * The main method for the TTFReader tool. - * - * @param args Command-line arguments: [options] fontfile.ttf xmlfile.xml - * where options can be: - * -fn <fontname> - * default is to use the fontname in the .ttf file, but you can override - * that name to make sure that the embedded font is used instead of installed - * fonts when viewing documents with Acrobat Reader. - * -cn <classname> - * default is to use the fontname - * -ef <path to the truetype fontfile> - * will add the possibility to embed the font. When running fop, fop will look - * for this file to embed it - * -er <path to truetype fontfile relative to org/apache/fop/render/pdf/fonts> - * you can also include the fontfile in the fop.jar file when building fop. - * You can use both -ef and -er. The file specified in -ef will be searched first, - * then the -er file. - * -nocs - * if complex script features are disabled - */ - public static void main(String[] args) { - String embFile = null; - String embResource = null; - String className = null; - String fontName = null; - String ttcName = null; - boolean isCid = true; - - Map options = new java.util.HashMap(); - String[] arguments = parseArguments(options, args); - - determineLogLevel(options); - - TTFReader app = new TTFReader(); - - log.info("TTF Reader for Apache FOP " + Version.getVersion() + "\n"); - - if (options.get("-enc") != null) { - String enc = (String)options.get("-enc"); - if ("ansi".equals(enc)) { - isCid = false; - } - } - - if (options.get("-ttcname") != null) { - ttcName = (String)options.get("-ttcname"); - } - - if (options.get("-ef") != null) { - embFile = (String)options.get("-ef"); - } - - if (options.get("-er") != null) { - embResource = (String)options.get("-er"); - } - - if (options.get("-fn") != null) { - fontName = (String)options.get("-fn"); - } - - if (options.get("-cn") != null) { - className = (String)options.get("-cn"); - } - - boolean useKerning = true; - boolean useAdvanced = true; - if (options.get("-nocs") != null) { - useAdvanced = false; - } - - if (arguments.length != 2 || options.get("-h") != null - || options.get("-help") != null || options.get("--help") != null) { - displayUsage(); - } else { - try { - log.info("Parsing font..."); - TTFFile ttf = app.loadTTF(arguments[0], ttcName, useKerning, useAdvanced); - if (ttf != null) { - org.w3c.dom.Document doc = app.constructFontXML(ttf, - fontName, className, embResource, embFile, isCid, - ttcName); - - if (isCid) { - log.info("Creating CID encoded metrics..."); - } else { - log.info("Creating WinAnsi encoded metrics..."); - } - - if (doc != null) { - app.writeFontXML(doc, arguments[1]); - } - - if (ttf.isEmbeddable()) { - log.info("This font contains no embedding license restrictions."); - } else { - log.info("** Note: This font contains license retrictions for\n" - + " embedding. This font shouldn't be embedded."); - } - } - log.info(""); - log.info("XML font metrics file successfully created."); - } catch (Exception e) { - log.error("Error while building XML font metrics file.", e); - System.exit(-1); - } - } - } - - /** - * Read a TTF file and returns it as an object. - * - * @param fileName The filename of the TTF file. - * @param fontName The name of the font - * @param useKerning true if should load kerning data - * @param useAdvanced true if should load advanced typographic table data - * @return The TTF as an object, null if the font is incompatible. - * @throws IOException In case of an I/O problem - */ - public TTFFile loadTTF(String fileName, String fontName, boolean useKerning, boolean useAdvanced) - throws IOException { - TTFFile ttfFile = new TTFFile(useKerning, useAdvanced); - log.info("Reading " + fileName + "..."); - InputStream stream = new FileInputStream(fileName); - try { - FontFileReader reader = new FontFileReader(stream); - String header = OFFontLoader.readHeader(reader); - boolean supported = ttfFile.readFont(reader, header, fontName); - if (!supported) { - return null; - } - } finally { - stream.close(); - } - - log.info("Font Family: " + ttfFile.getFamilyNames()); - if (ttfFile.isCFF()) { - throw new UnsupportedOperationException( - "OpenType fonts with CFF data are not supported, yet"); - } - return ttfFile; - } - - - /** - * Generates the font metrics file from the TTF/TTC file. - * - * @param ttf The PFM file to generate the font metrics from. - * @param fontName Name of the font - * @param className Class name for the font - * @param resource path to the font as embedded resource - * @param file path to the font as file - * @param isCid True if the font is CID encoded - * @param ttcName Name of the TrueType Collection - * @return The DOM document representing the font metrics file. - */ - public org.w3c.dom.Document constructFontXML(TTFFile ttf, - String fontName, String className, String resource, String file, - boolean isCid, String ttcName) { - log.info("Creating xml font file..."); - - Document doc; - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - doc = factory.newDocumentBuilder().newDocument(); - } catch (javax.xml.parsers.ParserConfigurationException e) { - log.error("Can't create DOM implementation", e); - return null; - } - Element root = doc.createElement("font-metrics"); - doc.appendChild(root); - root.setAttribute(METRICS_VERSION_ATTR, String.valueOf(METRICS_VERSION)); - if (isCid) { - root.setAttribute("type", "TYPE0"); - } else { - root.setAttribute("type", "TRUETYPE"); - } - - Element el = doc.createElement("font-name"); - root.appendChild(el); - - // Note that the PostScript name usually is something like - // "Perpetua-Bold", but the TrueType spec says that in the ttf file - // it should be "Perpetua,Bold". - - String s = FontUtil.stripWhiteSpace(ttf.getPostScriptName()); - - if (fontName != null) { - el.appendChild(doc.createTextNode(FontUtil.stripWhiteSpace(fontName))); - } else { - el.appendChild(doc.createTextNode(s)); - } - if (ttf.getFullName() != null) { - el = doc.createElement("full-name"); - root.appendChild(el); - el.appendChild(doc.createTextNode(ttf.getFullName())); - } - Set<String> familyNames = ttf.getFamilyNames(); - if (familyNames.size() > 0) { - String familyName = familyNames.iterator().next(); - el = doc.createElement("family-name"); - root.appendChild(el); - el.appendChild(doc.createTextNode(familyName)); - } - - el = doc.createElement("embed"); - root.appendChild(el); - if (file != null && ttf.isEmbeddable()) { - el.setAttribute("file", file); - } - if (resource != null && ttf.isEmbeddable()) { - el.setAttribute("class", resource); - } - - el = doc.createElement("cap-height"); - root.appendChild(el); - el.appendChild(doc.createTextNode(String.valueOf(ttf.getCapHeight()))); - - el = doc.createElement("x-height"); - root.appendChild(el); - el.appendChild(doc.createTextNode(String.valueOf(ttf.getXHeight()))); - - el = doc.createElement("ascender"); - root.appendChild(el); - el.appendChild(doc.createTextNode(String.valueOf(ttf.getLowerCaseAscent()))); - - el = doc.createElement("descender"); - root.appendChild(el); - el.appendChild(doc.createTextNode(String.valueOf(ttf.getLowerCaseDescent()))); - - Element bbox = doc.createElement("bbox"); - root.appendChild(bbox); - int[] bb = ttf.getFontBBox(); - final String[] names = {"left", "bottom", "right", "top"}; - for (int i = 0; i < names.length; i++) { - el = doc.createElement(names[i]); - bbox.appendChild(el); - el.appendChild(doc.createTextNode(String.valueOf(bb[i]))); - } - - el = doc.createElement("flags"); - root.appendChild(el); - el.appendChild(doc.createTextNode(String.valueOf(ttf.getFlags()))); - - el = doc.createElement("stemv"); - root.appendChild(el); - el.appendChild(doc.createTextNode(ttf.getStemV())); - - el = doc.createElement("italicangle"); - root.appendChild(el); - el.appendChild(doc.createTextNode(ttf.getItalicAngle())); - - if (ttcName != null) { - el = doc.createElement("ttc-name"); - root.appendChild(el); - el.appendChild(doc.createTextNode(ttcName)); - } - - el = doc.createElement("subtype"); - root.appendChild(el); - - // Fill in extras for CID keyed fonts - if (isCid) { - el.appendChild(doc.createTextNode("TYPE0")); - - generateDOM4MultiByteExtras(root, ttf, isCid); - } else { - // Fill in extras for singlebyte fonts - el.appendChild(doc.createTextNode("TRUETYPE")); - - generateDOM4SingleByteExtras(root, ttf, isCid); - } - - generateDOM4Kerning(root, ttf, isCid); - - return doc; - } - - private void generateDOM4MultiByteExtras(Element parent, TTFFile ttf, boolean isCid) { - Element el; - Document doc = parent.getOwnerDocument(); - - Element mel = doc.createElement("multibyte-extras"); - parent.appendChild(mel); - - el = doc.createElement("cid-type"); - mel.appendChild(el); - el.appendChild(doc.createTextNode("CIDFontType2")); - - el = doc.createElement("default-width"); - mel.appendChild(el); - el.appendChild(doc.createTextNode("0")); - - el = doc.createElement("bfranges"); - mel.appendChild(el); - for (CMapSegment ce : ttf.getCMaps()) { - Element el2 = doc.createElement("bf"); - el.appendChild(el2); - el2.setAttribute("us", String.valueOf(ce.getUnicodeStart())); - el2.setAttribute("ue", String.valueOf(ce.getUnicodeEnd())); - el2.setAttribute("gi", String.valueOf(ce.getGlyphStartIndex())); - } - - el = doc.createElement("cid-widths"); - el.setAttribute("start-index", "0"); - mel.appendChild(el); - - int[] wx = ttf.getWidths(); - for (int i = 0; i < wx.length; i++) { - Element wxel = doc.createElement("wx"); - wxel.setAttribute("w", String.valueOf(wx[i])); - int[] bbox = ttf.getBBox(i); - wxel.setAttribute("xMin", String.valueOf(bbox[0])); - wxel.setAttribute("yMin", String.valueOf(bbox[1])); - wxel.setAttribute("xMax", String.valueOf(bbox[2])); - wxel.setAttribute("yMax", String.valueOf(bbox[3])); - el.appendChild(wxel); - } - } - - private void generateDOM4SingleByteExtras(Element parent, TTFFile ttf, boolean isCid) { - Element el; - Document doc = parent.getOwnerDocument(); - - Element sel = doc.createElement("singlebyte-extras"); - parent.appendChild(sel); - - el = doc.createElement("encoding"); - sel.appendChild(el); - el.appendChild(doc.createTextNode(ttf.getCharSetName())); - - el = doc.createElement("first-char"); - sel.appendChild(el); - el.appendChild(doc.createTextNode(String.valueOf(ttf.getFirstChar()))); - - el = doc.createElement("last-char"); - sel.appendChild(el); - el.appendChild(doc.createTextNode(String.valueOf(ttf.getLastChar()))); - - Element widths = doc.createElement("widths"); - sel.appendChild(widths); - - for (short i = ttf.getFirstChar(); i <= ttf.getLastChar(); i++) { - el = doc.createElement("char"); - widths.appendChild(el); - el.setAttribute("idx", String.valueOf(i)); - el.setAttribute("wdt", String.valueOf(ttf.getCharWidth(i))); - } - } - - private void generateDOM4Kerning(Element parent, TTFFile ttf, boolean isCid) { - Element el; - Document doc = parent.getOwnerDocument(); - - // Get kerning - Set<Integer> kerningKeys; - if (isCid) { - kerningKeys = ttf.getKerning().keySet(); - } else { - kerningKeys = ttf.getAnsiKerning().keySet(); - } - - for (Integer kpx1 : kerningKeys) { - - el = doc.createElement("kerning"); - el.setAttribute("kpx1", kpx1.toString()); - parent.appendChild(el); - Element el2 = null; - - Map<Integer, Integer> h2; - if (isCid) { - h2 = ttf.getKerning().get(kpx1); - } else { - h2 = ttf.getAnsiKerning().get(kpx1); - } - - for (Map.Entry<Integer, Integer> e : h2.entrySet()) { - Integer kpx2 = e.getKey(); - if (isCid || kpx2.intValue() < 256) { - el2 = doc.createElement("pair"); - el2.setAttribute("kpx2", kpx2.toString()); - Integer val = e.getValue(); - el2.setAttribute("kern", val.toString()); - el.appendChild(el2); - } - } - } - } - - /** - * Bugzilla 40739, check that attr has a metrics-version attribute - * compatible with ours. - * @param attr attributes read from the root element of a metrics XML file - * @throws SAXException if incompatible - */ - public static void checkMetricsVersion(Attributes attr) throws SAXException { - String err = null; - final String str = attr.getValue(METRICS_VERSION_ATTR); - if (str == null) { - err = "Missing " + METRICS_VERSION_ATTR + " attribute"; - } else { - int version = 0; - try { - version = Integer.parseInt(str); - if (version < METRICS_VERSION) { - err = "Incompatible " + METRICS_VERSION_ATTR - + " value (" + version + ", should be " + METRICS_VERSION - + ")"; - } - } catch (NumberFormatException e) { - err = "Invalid " + METRICS_VERSION_ATTR - + " attribute value (" + str + ")"; - } - } - - if (err != null) { - throw new SAXException( - err - + " - please regenerate the font metrics file with " - + "a more recent version of FOP." - ); - } - } - -} - diff --git a/src/java/org/apache/fop/fonts/apps/package.html b/src/java/org/apache/fop/fonts/apps/package.html deleted file mode 100644 index 5e0551c23..000000000 --- a/src/java/org/apache/fop/fonts/apps/package.html +++ /dev/null @@ -1,23 +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. ---> -<!-- $Id$ --> -<HTML> -<TITLE>org.apache.fop.fonts.apps Package</TITLE> -<BODY> -<P>Command-line tools for generating XML font metric files from Type 1 and TrueType fonts.</P> -</BODY> -</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/fonts/autodetect/FontDirFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontDirFinder.java deleted file mode 100644 index 383c5283d..000000000 --- a/src/java/org/apache/fop/fonts/autodetect/FontDirFinder.java +++ /dev/null @@ -1,41 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.autodetect; - -import java.io.File; -import java.io.IOException; -import java.util.List; - -/** - * Implementers provide find method for searching native operating system - * for available fonts. - */ -public interface FontDirFinder { - - /** - * Finds a list of font files. - * - * @return list of font files. - * @throws IOException - * In case of an I/O problem - */ - List<File> find() throws IOException; - -} diff --git a/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java deleted file mode 100644 index 8100c4b9b..000000000 --- a/src/java/org/apache/fop/fonts/autodetect/FontFileFinder.java +++ /dev/null @@ -1,179 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.autodetect; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Collection; -import java.util.List; - -import org.apache.commons.io.DirectoryWalker; -import org.apache.commons.io.IOCase; -import org.apache.commons.io.filefilter.FileFilterUtils; -import org.apache.commons.io.filefilter.IOFileFilter; -import org.apache.commons.io.filefilter.WildcardFileFilter; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.fonts.FontEventListener; - -/** - * Helps to autodetect/locate available operating system fonts. - */ -public class FontFileFinder extends DirectoryWalker implements FontFinder { - - /** logging instance */ - private final Log log = LogFactory.getLog(FontFileFinder.class); - - /** default depth limit of recursion when searching for font files **/ - public static final int DEFAULT_DEPTH_LIMIT = -1; - private final FontEventListener eventListener; - - /** - * Default constructor - * @param listener for throwing font related events - */ - public FontFileFinder(FontEventListener listener) { - this(DEFAULT_DEPTH_LIMIT, listener); - } - - /** - * Constructor - * @param depthLimit recursion depth limit - * @param listener for throwing font related events - */ - public FontFileFinder(int depthLimit, FontEventListener listener) { - super(getDirectoryFilter(), getFileFilter(), depthLimit); - eventListener = listener; - } - - /** - * Font directory filter. Currently ignores hidden directories. - * @return IOFileFilter font directory filter - */ - protected static IOFileFilter getDirectoryFilter() { - return FileFilterUtils.andFileFilter( - FileFilterUtils.directoryFileFilter(), - FileFilterUtils.notFileFilter(FileFilterUtils.prefixFileFilter(".")) - ); - } - - /** - * Font file filter. Currently searches for files with .ttf, .ttc, .otf, and .pfb extensions. - * @return IOFileFilter font file filter - */ - protected static IOFileFilter getFileFilter() { - return FileFilterUtils.andFileFilter( - FileFilterUtils.fileFileFilter(), - new WildcardFileFilter( - new String[] {"*.ttf", "*.otf", "*.pfb", "*.ttc"}, - IOCase.INSENSITIVE) - ); - } - - /** - * @param directory directory to handle - * @param depth recursion depth - * @param results collection - * @return whether directory should be handled - * {@inheritDoc} - */ - @Override - protected boolean handleDirectory(File directory, int depth, Collection results) { - return true; - } - - /** - * @param file file to handle - * @param depth recursion depth - * @param results collection - * {@inheritDoc} - */ - @Override - protected void handleFile(File file, int depth, Collection results) { - try { - // Looks Strange, but is actually recommended over just .URL() - results.add(file.toURI().toURL()); - } catch (MalformedURLException e) { - log.debug("MalformedURLException" + e.getMessage()); - } - } - - /** - * @param directory the directory being processed - * @param depth the current directory level - * @param results the collection of results objects - * {@inheritDoc} - */ - @Override - protected void handleDirectoryEnd(File directory, int depth, Collection results) { - if (log.isDebugEnabled()) { - log.debug(directory + ": found " + results.size() + " font" - + ((results.size() == 1) ? "" : "s")); - } - } - - /** - * Automagically finds a list of font files on local system - * - * @return List<URL> of font files - * @throws IOException io exception - * {@inheritDoc} - */ - public List<URL> find() throws IOException { - final FontDirFinder fontDirFinder; - final String osName = System.getProperty("os.name"); - if (osName.startsWith("Windows")) { - fontDirFinder = new WindowsFontDirFinder(); - } else { - if (osName.startsWith("Mac")) { - fontDirFinder = new MacFontDirFinder(); - } else { - fontDirFinder = new UnixFontDirFinder(); - } - } - List<File> fontDirs = fontDirFinder.find(); - List<URL> results = new java.util.ArrayList<URL>(); - for (File dir : fontDirs) { - super.walk(dir, results); - } - return results; - } - - /** - * Searches a given directory for font files - * - * @param dir directory to search - * @return list of font files - * @throws IOException thrown if an I/O exception of some sort has occurred - */ - public List<URL> find(String dir) throws IOException { - List<URL> results = new java.util.ArrayList<URL>(); - File directory = new File(dir); - if (!directory.isDirectory()) { - eventListener.fontDirectoryNotFound(this, dir); - } else { - super.walk(directory, results); - } - return results; - } -} diff --git a/src/java/org/apache/fop/fonts/autodetect/FontFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontFinder.java deleted file mode 100644 index 51e79443a..000000000 --- a/src/java/org/apache/fop/fonts/autodetect/FontFinder.java +++ /dev/null @@ -1,41 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.autodetect; - -import java.io.IOException; -import java.net.URL; -import java.util.List; - -/** - * Implementers provide find method for searching native operating system - * for available fonts. - */ -public interface FontFinder { - - /** - * Finds a list of font files. - * - * @return list of font files. - * @throws IOException - * In case of an I/O problem - */ - List<URL> find() throws IOException; - -} diff --git a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java b/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java deleted file mode 100644 index a1d65459a..000000000 --- a/src/java/org/apache/fop/fonts/autodetect/FontInfoFinder.java +++ /dev/null @@ -1,279 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.autodetect; - -import java.io.InputStream; -import java.net.URI; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.regex.Pattern; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.fonts.CustomFont; -import org.apache.fop.fonts.EmbedFontInfo; -import org.apache.fop.fonts.EmbeddingMode; -import org.apache.fop.fonts.EncodingMode; -import org.apache.fop.fonts.Font; -import org.apache.fop.fonts.FontCache; -import org.apache.fop.fonts.FontEventListener; -import org.apache.fop.fonts.FontLoader; -import org.apache.fop.fonts.FontTriplet; -import org.apache.fop.fonts.FontUris; -import org.apache.fop.fonts.FontUtil; -import org.apache.fop.fonts.MultiByteFont; -import org.apache.fop.fonts.truetype.FontFileReader; -import org.apache.fop.fonts.truetype.OFFontLoader; -import org.apache.fop.fonts.truetype.TTFFile; - -/** - * Attempts to determine correct FontInfo - */ -public class FontInfoFinder { - - /** logging instance */ - private final Log log = LogFactory.getLog(FontInfoFinder.class); - - private FontEventListener eventListener; - - /** - * Sets the font event listener that can be used to receive events about particular events - * in this class. - * @param listener the font event listener - */ - public void setEventListener(FontEventListener listener) { - this.eventListener = listener; - } - - /** - * Attempts to determine FontTriplets from a given CustomFont. - * It seems to be fairly accurate but will probably require some tweaking over time - * - * @param customFont CustomFont - * @param triplets Collection that will take the generated triplets - */ - private void generateTripletsFromFont(CustomFont customFont, Collection<FontTriplet> triplets) { - if (log.isTraceEnabled()) { - log.trace("Font: " + customFont.getFullName() - + ", family: " + customFont.getFamilyNames() - + ", PS: " + customFont.getFontName() - + ", EmbedName: " + customFont.getEmbedFontName()); - } - - // default style and weight triplet vales (fallback) - String strippedName = stripQuotes(customFont.getStrippedFontName()); - //String subName = customFont.getFontSubName(); - String fullName = stripQuotes(customFont.getFullName()); - String searchName = fullName.toLowerCase(); - - String style = guessStyle(customFont, searchName); - int weight; //= customFont.getWeight(); - int guessedWeight = FontUtil.guessWeight(searchName); - //We always take the guessed weight for now since it yield much better results. - //OpenType's OS/2 usWeightClass value proves to be unreliable. - weight = guessedWeight; - - //Full Name usually includes style/weight info so don't use these traits - //If we still want to use these traits, we have to make FontInfo.fontLookup() smarter - triplets.add(new FontTriplet(fullName, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL)); - if (!fullName.equals(strippedName)) { - triplets.add(new FontTriplet(strippedName, Font.STYLE_NORMAL, Font.WEIGHT_NORMAL)); - } - Set<String> familyNames = customFont.getFamilyNames(); - for (String familyName : familyNames) { - familyName = stripQuotes(familyName); - if (!fullName.equals(familyName)) { - /* Heuristic: - * The more similar the family name to the full font name, - * the higher the priority of its triplet. - * (Lower values indicate higher priorities.) */ - int priority = fullName.startsWith(familyName) - ? fullName.length() - familyName.length() - : fullName.length(); - triplets.add(new FontTriplet(familyName, style, weight, priority)); - } - } - } - - private final Pattern quotePattern = Pattern.compile("'"); - - private String stripQuotes(String name) { - return quotePattern.matcher(name).replaceAll(""); - } - - private String guessStyle(CustomFont customFont, String fontName) { - // style - String style = Font.STYLE_NORMAL; - if (customFont.getItalicAngle() > 0) { - style = Font.STYLE_ITALIC; - } else { - style = FontUtil.guessStyle(fontName); - } - return style; - } - - /** - * Attempts to determine FontInfo from a given custom font - * @param fontUri the font URI - * @param customFont the custom font - * @param fontCache font cache (may be null) - * @return FontInfo from the given custom font - */ - private EmbedFontInfo getFontInfoFromCustomFont(URI fontUri, CustomFont customFont, - FontCache fontCache, InternalResourceResolver resourceResolver) { - FontUris fontUris = new FontUris(fontUri, null); - List<FontTriplet> fontTripletList = new java.util.ArrayList<FontTriplet>(); - generateTripletsFromFont(customFont, fontTripletList); - String subFontName = null; - if (customFont instanceof MultiByteFont) { - subFontName = ((MultiByteFont) customFont).getTTCName(); - } - EmbedFontInfo fontInfo = new EmbedFontInfo(fontUris, customFont.isKerningEnabled(), - customFont.isAdvancedEnabled(), fontTripletList, subFontName, - EncodingMode.AUTO, EmbeddingMode.AUTO); - fontInfo.setPostScriptName(customFont.getFontName()); - if (fontCache != null) { - fontCache.addFont(fontInfo, resourceResolver); - } - return fontInfo; - } - - /** - * Attempts to determine EmbedFontInfo from a given font file. - * - * @param fontURI the URI of the font resource - * @param resourceResolver font resolver used to resolve font - * @param fontCache font cache (may be null) - * @return an array of newly created embed font info. Generally, this array - * will have only one entry, unless the fontUrl is a TrueType Collection - */ - public EmbedFontInfo[] find(URI fontURI, InternalResourceResolver resourceResolver, FontCache fontCache) { - URI embedUri = resourceResolver.resolveFromBase(fontURI); - String embedStr = embedUri.toASCIIString(); - boolean useKerning = true; - boolean useAdvanced = true; - - long fileLastModified = -1; - if (fontCache != null) { - fileLastModified = FontCache.getLastModified(fontURI); - // firstly try and fetch it from cache before loading/parsing the font file - if (fontCache.containsFont(embedStr)) { - EmbedFontInfo[] fontInfos = fontCache.getFontInfos(embedStr, fileLastModified); - if (fontInfos != null) { - return fontInfos; - } - // is this a previously failed parsed font? - } else if (fontCache.isFailedFont(embedStr, fileLastModified)) { - if (log.isDebugEnabled()) { - log.debug("Skipping font file that failed to load previously: " + embedUri); - } - return null; - } - } - - - // try to determine triplet information from font file - CustomFont customFont = null; - if (fontURI.toASCIIString().toLowerCase().endsWith(".ttc")) { - // Get a list of the TTC Font names - List<String> ttcNames = null; - InputStream in = null; - try { - in = resourceResolver.getResource(fontURI); - TTFFile ttf = new TTFFile(false, false); - FontFileReader reader = new FontFileReader(in); - ttcNames = ttf.getTTCnames(reader); - } catch (Exception e) { - if (this.eventListener != null) { - this.eventListener.fontLoadingErrorAtAutoDetection(this, - fontURI.toASCIIString(), e); - } - return null; - } finally { - IOUtils.closeQuietly(in); - } - - List<EmbedFontInfo> embedFontInfoList = new java.util.ArrayList<EmbedFontInfo>(); - - // For each font name ... - for (String fontName : ttcNames) { - if (log.isDebugEnabled()) { - log.debug("Loading " + fontName); - } - try { - OFFontLoader ttfLoader = new OFFontLoader(fontURI, fontName, true, - EmbeddingMode.AUTO, EncodingMode.AUTO, useKerning, useAdvanced, - resourceResolver); - customFont = ttfLoader.getFont(); - if (this.eventListener != null) { - customFont.setEventListener(this.eventListener); - } - } catch (Exception e) { - if (fontCache != null) { - fontCache.registerFailedFont(embedUri.toASCIIString(), fileLastModified); - } - if (this.eventListener != null) { - this.eventListener.fontLoadingErrorAtAutoDetection(this, - embedUri.toASCIIString(), e); - } - continue; - } - EmbedFontInfo fi = getFontInfoFromCustomFont(fontURI, customFont, fontCache, - resourceResolver); - if (fi != null) { - embedFontInfoList.add(fi); - } - } - return embedFontInfoList.toArray( - new EmbedFontInfo[embedFontInfoList.size()]); - } else { - // The normal case - try { - FontUris fontUris = new FontUris(fontURI, null); - customFont = FontLoader.loadFont(fontUris, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO, - useKerning, useAdvanced, resourceResolver); - if (this.eventListener != null) { - customFont.setEventListener(this.eventListener); - } - } catch (Exception e) { - if (fontCache != null) { - fontCache.registerFailedFont(embedUri.toASCIIString(), fileLastModified); - } - if (this.eventListener != null) { - this.eventListener.fontLoadingErrorAtAutoDetection(this, - embedUri.toASCIIString(), e); - } - return null; - } - EmbedFontInfo fi = getFontInfoFromCustomFont(fontURI, customFont, fontCache, resourceResolver); - if (fi != null) { - return new EmbedFontInfo[] {fi}; - } else { - return null; - } - } - - } - -} diff --git a/src/java/org/apache/fop/fonts/autodetect/MacFontDirFinder.java b/src/java/org/apache/fop/fonts/autodetect/MacFontDirFinder.java deleted file mode 100644 index 1231badf2..000000000 --- a/src/java/org/apache/fop/fonts/autodetect/MacFontDirFinder.java +++ /dev/null @@ -1,39 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.autodetect; - -/** - * Mac font directory finder - */ -public class MacFontDirFinder extends NativeFontDirFinder { - - /** - * Some guesses at possible unix font directory locations - * @return a array of possible font directory locations - */ - protected String[] getSearchableDirectories() { - return new String[] { - System.getProperty("user.home") + "/Library/Fonts/", // user - "/Library/Fonts/", // local - "/System/Library/Fonts/", // system - "/Network/Library/Fonts/" // network - }; - } -} diff --git a/src/java/org/apache/fop/fonts/autodetect/NativeFontDirFinder.java b/src/java/org/apache/fop/fonts/autodetect/NativeFontDirFinder.java deleted file mode 100644 index 9f723a308..000000000 --- a/src/java/org/apache/fop/fonts/autodetect/NativeFontDirFinder.java +++ /dev/null @@ -1,55 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.autodetect; - -import java.io.File; -import java.util.List; - -/** - * Native font finder base class - */ -public abstract class NativeFontDirFinder implements FontDirFinder { - - /** - * Generic method used by Mac and Unix font finders. - * @return list of natively existing font directories - * {@inheritDoc} - */ - public List<File> find() { - List<File> fontDirList = new java.util.ArrayList<File>(); - String[] searchableDirectories = getSearchableDirectories(); - if (searchableDirectories != null) { - for (int i = 0; i < searchableDirectories.length; i++) { - File fontDir = new File(searchableDirectories[i]); - if (fontDir.exists() && fontDir.canRead()) { - fontDirList.add(fontDir); - } - } - } - return fontDirList; - } - - /** - * Returns an array of directories to search for fonts in. - * @return an array of directories - */ - protected abstract String[] getSearchableDirectories(); - -} diff --git a/src/java/org/apache/fop/fonts/autodetect/UnixFontDirFinder.java b/src/java/org/apache/fop/fonts/autodetect/UnixFontDirFinder.java deleted file mode 100644 index b6d596f03..000000000 --- a/src/java/org/apache/fop/fonts/autodetect/UnixFontDirFinder.java +++ /dev/null @@ -1,40 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.autodetect; - -/** - * Unix font directory finder - */ -public class UnixFontDirFinder extends NativeFontDirFinder { - - /** - * Some guesses at possible unix font directory locations - * @return a list of possible font locations - */ - protected String[] getSearchableDirectories() { - return new String[] { - System.getProperty("user.home") + "/.fonts", // user - "/usr/local/fonts", // local - "/usr/local/share/fonts", // local shared - "/usr/share/fonts", // system - "/usr/X11R6/lib/X11/fonts" // X - }; - } -} diff --git a/src/java/org/apache/fop/fonts/autodetect/WindowsFontDirFinder.java b/src/java/org/apache/fop/fonts/autodetect/WindowsFontDirFinder.java deleted file mode 100644 index bd506d9ed..000000000 --- a/src/java/org/apache/fop/fonts/autodetect/WindowsFontDirFinder.java +++ /dev/null @@ -1,120 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.autodetect; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.List; - -import org.apache.commons.io.IOUtils; - -/** - * FontFinder for native Windows platforms - */ -public class WindowsFontDirFinder implements FontDirFinder { - - /** - * Attempts to read windir environment variable on windows - * (disclaimer: This is a bit dirty but seems to work nicely) - */ - private String getWinDir(String osName) throws IOException { - Process process = null; - Runtime runtime = Runtime.getRuntime(); - if (osName.startsWith("Windows 9")) { - process = runtime.exec("command.com /c echo %windir%"); - } else { - process = runtime.exec("cmd.exe /c echo %windir%"); - } - InputStreamReader isr = null; - BufferedReader bufferedReader = null; - String dir = ""; - try { - isr = new InputStreamReader(process.getInputStream()); - bufferedReader = new BufferedReader(isr); - dir = bufferedReader.readLine(); - } finally { - IOUtils.closeQuietly(bufferedReader); - IOUtils.closeQuietly(isr); - } - return dir; - } - - /** - * {@inheritDoc} - * @return a list of detected font files - */ - public List<File> find() { - List<File> fontDirList = new java.util.ArrayList<File>(); - String windir = null; - try { - windir = System.getProperty("env.windir"); - } catch (SecurityException e) { - // should continue if this fails - } - String osName = System.getProperty("os.name"); - if (windir == null) { - try { - windir = getWinDir(osName); - } catch (IOException e) { - // should continue if this fails - } - } - File osFontsDir = null; - File psFontsDir = null; - if (windir != null) { - // remove any trailing '/' - if (windir.endsWith("/")) { - windir = windir.substring(0, windir.length() - 1); - } - osFontsDir = new File(windir + File.separator + "FONTS"); - if (osFontsDir.exists() && osFontsDir.canRead()) { - fontDirList.add(osFontsDir); - } - psFontsDir = new File(windir.substring(0, 2) + File.separator + "PSFONTS"); - if (psFontsDir.exists() && psFontsDir.canRead()) { - fontDirList.add(psFontsDir); - } - } else { - String windowsDirName = osName.endsWith("NT") ? "WINNT" : "WINDOWS"; - // look for true type font folder - for (char driveLetter = 'C'; driveLetter <= 'E'; driveLetter++) { - osFontsDir = new File( - driveLetter + ":" - + File.separator + windowsDirName - + File.separator + "FONTS"); - if (osFontsDir.exists() && osFontsDir.canRead()) { - fontDirList.add(osFontsDir); - break; - } - } - // look for type 1 font folder - for (char driveLetter = 'C'; driveLetter <= 'E'; driveLetter++) { - psFontsDir = new File(driveLetter + ":" + File.separator + "PSFONTS"); - if (psFontsDir.exists() && psFontsDir.canRead()) { - fontDirList.add(psFontsDir); - break; - } - } - } - return fontDirList; - } -} diff --git a/src/java/org/apache/fop/fonts/autodetect/package.html b/src/java/org/apache/fop/fonts/autodetect/package.html deleted file mode 100644 index 0a29acbb1..000000000 --- a/src/java/org/apache/fop/fonts/autodetect/package.html +++ /dev/null @@ -1,23 +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. ---> -<!-- $Id: $ --> -<HTML> -<TITLE>org.apache.fop.fonts.autodetect Package</TITLE> -<BODY> -<P>A collection of classes that aid in the autodetection of installed system fonts.</P> -</BODY> -</HTML> diff --git a/src/java/org/apache/fop/fonts/base14/Base14FontCollection.java b/src/java/org/apache/fop/fonts/base14/Base14FontCollection.java deleted file mode 100644 index ac01c9850..000000000 --- a/src/java/org/apache/fop/fonts/base14/Base14FontCollection.java +++ /dev/null @@ -1,149 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.base14; - -import org.apache.fop.fonts.Font; -import org.apache.fop.fonts.FontCollection; -import org.apache.fop.fonts.FontInfo; - -/** - * Sets up Base 14 fonts - */ -public class Base14FontCollection implements FontCollection { - - private boolean kerning; - - /** - * Main constructor - * - * @param kerning set to true when font kerning is enabled - */ - public Base14FontCollection(boolean kerning) { - this.kerning = kerning; - } - - /** - * {@inheritDoc} - */ - public int setup(int start, FontInfo fontInfo) { - fontInfo.addMetrics("F1", new Helvetica(kerning)); - fontInfo.addMetrics("F2", new HelveticaOblique(kerning)); - fontInfo.addMetrics("F3", new HelveticaBold(kerning)); - fontInfo.addMetrics("F4", new HelveticaBoldOblique(kerning)); - fontInfo.addMetrics("F5", new TimesRoman(kerning)); - fontInfo.addMetrics("F6", new TimesItalic(kerning)); - fontInfo.addMetrics("F7", new TimesBold(kerning)); - fontInfo.addMetrics("F8", new TimesBoldItalic(kerning)); - fontInfo.addMetrics("F9", new Courier(kerning)); - fontInfo.addMetrics("F10", new CourierOblique(kerning)); - fontInfo.addMetrics("F11", new CourierBold(kerning)); - fontInfo.addMetrics("F12", new CourierBoldOblique(kerning)); - fontInfo.addMetrics("F13", new Symbol()); - fontInfo.addMetrics("F14", new ZapfDingbats()); - - // Custom type 1 fonts step 1/2 - // fontInfo.addMetrics("F15", new OMEP()); - // fontInfo.addMetrics("F16", new GaramondLightCondensed()); - // fontInfo.addMetrics("F17", new BauerBodoniBoldItalic()); - - /* any is treated as serif */ - fontInfo.addFontProperties("F5", "any", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "any", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "any", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F7", "any", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "any", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "any", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - - fontInfo.addFontProperties("F1", "sans-serif", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F2", "sans-serif", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F2", "sans-serif", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F3", "sans-serif", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F4", "sans-serif", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F4", "sans-serif", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F1", "SansSerif", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F2", "SansSerif", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F2", "SansSerif", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F3", "SansSerif", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F4", "SansSerif", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F4", "SansSerif", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F5", "serif", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "serif", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "serif", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F7", "serif", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "serif", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "serif", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F9", "monospace", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F10", "monospace", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F10", "monospace", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F11", "monospace", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F12", "monospace", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F12", "monospace", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F9", "Monospaced", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F10", "Monospaced", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F10", "Monospaced", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F11", "Monospaced", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F12", "Monospaced", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F12", "Monospaced", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - - fontInfo.addFontProperties("F1", "Helvetica", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F2", "Helvetica", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F2", "Helvetica", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F3", "Helvetica", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F4", "Helvetica", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F4", "Helvetica", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F5", "Times", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "Times", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "Times", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F7", "Times", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "Times", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "Times", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F9", "Courier", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F10", "Courier", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F10", "Courier", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F11", "Courier", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F12", "Courier", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F12", "Courier", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F13", "Symbol", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F14", "ZapfDingbats", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - - // Custom type 1 fonts step 2/2 - // fontInfo.addFontProperties("F15", "OMEP", "normal", FontInfo.NORMAL); - // fontInfo.addFontProperties("F16", "Garamond-LightCondensed", "normal", FontInfo.NORMAL); - // fontInfo.addFontProperties("F17", "BauerBodoni", "italic", FontInfo.BOLD); - - /* for compatibility with PassiveTex */ - fontInfo.addFontProperties("F5", "Times-Roman", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "Times-Roman", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "Times-Roman", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F7", "Times-Roman", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "Times-Roman", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "Times-Roman", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F5", "Times Roman", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "Times Roman", Font.STYLE_OBLIQUE, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F6", "Times Roman", Font.STYLE_ITALIC, Font.WEIGHT_NORMAL); - fontInfo.addFontProperties("F7", "Times Roman", Font.STYLE_NORMAL, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "Times Roman", Font.STYLE_OBLIQUE, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F8", "Times Roman", Font.STYLE_ITALIC, Font.WEIGHT_BOLD); - fontInfo.addFontProperties("F9", "Computer-Modern-Typewriter", - Font.STYLE_NORMAL, Font.WEIGHT_NORMAL); - - return 15; - } -} diff --git a/src/java/org/apache/fop/fonts/base14/package.html b/src/java/org/apache/fop/fonts/base14/package.html deleted file mode 100644 index 90c58d555..000000000 --- a/src/java/org/apache/fop/fonts/base14/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<HTML> -<TITLE>org.apache.fop.fonts.base14 Package</TITLE> -<BODY> -<P>Base 14 fonts used for PDF and PostScript. Generated entirely from XML files.</P> -</BODY> -</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/fonts/cff/CFFDataReader.java b/src/java/org/apache/fop/fonts/cff/CFFDataReader.java deleted file mode 100644 index 3ce63a2a4..000000000 --- a/src/java/org/apache/fop/fonts/cff/CFFDataReader.java +++ /dev/null @@ -1,929 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.cff; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.apache.fontbox.cff.CFFDataInput; -import org.apache.fontbox.cff.CFFOperator; - -import org.apache.fop.fonts.truetype.FontFileReader; -import org.apache.fop.fonts.truetype.OTFFile; - -/** - * A class to read the CFF data from an OTF CFF font file. - */ -public class CFFDataReader { - private CFFDataInput cffData; - - private byte[] header; - private CFFIndexData nameIndex; - private CFFIndexData topDICTIndex; - private CFFIndexData stringIndex; - private CFFIndexData charStringIndex; - private CFFIndexData globalIndexSubr; - private CFFIndexData localIndexSubr; - private CustomEncoding encoding; - private FDSelect fdSelect; - private List<FontDict> fdFonts; - - private static final int DOUBLE_BYTE_OPERATOR = 12; - private static final int NUM_STANDARD_STRINGS = 391; - - /** Commonly used parsed dictionaries */ - private LinkedHashMap<String, DICTEntry> topDict; - - public CFFDataReader() { - - } - - /** - * Constructor for the CFF data reader which accepts the CFF byte data - * as an argument. - * @param cffDataArray A byte array which holds the CFF data - */ - public CFFDataReader(byte[] cffDataArray) throws IOException { - cffData = new CFFDataInput(cffDataArray); - readCFFData(); - } - - /** - * Constructor for the CFF data reader which accepts a FontFileReader object - * which points to the original font file as an argument. - * @param fontFile The font file as represented by a FontFileReader object - */ - public CFFDataReader(FontFileReader fontFile) throws IOException { - cffData = new CFFDataInput(OTFFile.getCFFData(fontFile)); - readCFFData(); - } - - private void readCFFData() throws IOException { - header = readHeader(); - nameIndex = readIndex(); - topDICTIndex = readIndex(); - topDict = parseDictData(topDICTIndex.getData()); - stringIndex = readIndex(); - globalIndexSubr = readIndex(); - charStringIndex = readCharStringIndex(); - encoding = readEncoding(); - fdSelect = readFDSelect(); - localIndexSubr = readLocalIndexSubrs(); - fdFonts = parseCIDData(); - } - - public Map<String, DICTEntry> getPrivateDict(DICTEntry privateEntry) throws IOException { - return parseDictData(getPrivateDictBytes(privateEntry)); - } - - public byte[] getPrivateDictBytes(DICTEntry privateEntry) throws IOException { - int privateLength = privateEntry.getOperands().get(0).intValue(); - int privateOffset = privateEntry.getOperands().get(1).intValue(); - return getCFFOffsetBytes(privateOffset, privateLength); - } - - /** - * Retrieves a number of bytes from the CFF data stream - * @param offset The offset of the bytes to retrieve - * @param length The number of bytes to retrieve - * @return Returns a byte array of requested bytes - * @throws IOException Throws an IO Exception if an error occurs - */ - private byte[] getCFFOffsetBytes(int offset, int length) throws IOException { - cffData.setPosition(offset); - return cffData.readBytes(length); - } - - /** - * Parses the dictionary data and returns a map of objects for each entry - * @param dictData The data for the dictionary data - * @return Returns a map of type DICTEntry identified by the operand name - * @throws IOException Throws an IO Exception if an error occurs - */ - public LinkedHashMap<String, DICTEntry> parseDictData(byte[] dictData) throws IOException { - LinkedHashMap<String, DICTEntry> dictEntries = new LinkedHashMap<String, DICTEntry>(); - List<Number> operands = new ArrayList<Number>(); - List<Integer> operandLengths = new ArrayList<Integer>(); - int lastOperandLength = 0; - for (int i = 0; i < dictData.length; i++) { - int readByte = dictData[i] & 0xFF; - if (readByte < 28) { - int[] operator = new int[(readByte == DOUBLE_BYTE_OPERATOR) ? 2 : 1]; - if (readByte == DOUBLE_BYTE_OPERATOR) { - operator[0] = dictData[i]; - operator[1] = dictData[i + 1]; - i++; - } else { - operator[0] = dictData[i]; - } - String operatorName = ""; - CFFOperator tempOp = null; - if (operator.length > 1) { - tempOp = CFFOperator.getOperator(new CFFOperator.Key(operator[0], operator[1])); - } else { - tempOp = CFFOperator.getOperator(new CFFOperator.Key(operator[0])); - } - if (tempOp != null) { - operatorName = tempOp.getName(); - } - DICTEntry newEntry = new DICTEntry(); - newEntry.setOperator(operator); - newEntry.setOperands(new ArrayList<Number>(operands)); - newEntry.setOperatorName(operatorName); - newEntry.setOffset(i - lastOperandLength); - newEntry.setOperandLength(lastOperandLength); - newEntry.setOperandLengths(new ArrayList<Integer>(operandLengths)); - byte[] byteData = new byte[lastOperandLength + operator.length]; - System.arraycopy(dictData, i - operator.length - (lastOperandLength - 1), - byteData, 0, operator.length + lastOperandLength); - newEntry.setByteData(byteData); - dictEntries.put(operatorName, newEntry); - operands.clear(); - operandLengths.clear(); - lastOperandLength = 0; - } else { - if (readByte >= 32 && readByte <= 246) { - operands.add(readByte - 139); - lastOperandLength += 1; - operandLengths.add(1); - } else if (readByte >= 247 && readByte <= 250) { - operands.add((readByte - 247) * 256 + (dictData[i + 1] & 0xFF) + 108); - lastOperandLength += 2; - operandLengths.add(2); - i++; - } else if (readByte >= 251 && readByte <= 254) { - operands.add(-(readByte - 251) * 256 - (dictData[i + 1] & 0xFF) - 108); - lastOperandLength += 2; - operandLengths.add(2); - i++; - } else if (readByte == 28) { - operands.add((dictData[i + 1] & 0xFF) << 8 | (dictData[i + 2] & 0xFF)); - lastOperandLength += 3; - operandLengths.add(3); - i += 2; - } else if (readByte == 29) { - operands.add((dictData[i + 1] & 0xFF) << 24 | (dictData[i + 2] & 0xFF) << 16 - | (dictData[i + 3] & 0xFF) << 8 | (dictData[i + 4] & 0xFF)); - lastOperandLength += 5; - operandLengths.add(5); - i += 4; - } else if (readByte == 30) { - boolean terminatorFound = false; - StringBuilder realNumber = new StringBuilder(); - int byteCount = 1; - do { - byte nibblesByte = dictData[++i]; - byteCount++; - terminatorFound = readNibble(realNumber, (nibblesByte >> 4) & 0x0F); - if (!terminatorFound) { - terminatorFound = readNibble(realNumber, nibblesByte & 0x0F); - } - } while (!terminatorFound); - operands.add(Double.valueOf(realNumber.toString())); - lastOperandLength += byteCount; - operandLengths.add(byteCount); - } - } - } - return dictEntries; - } - - private boolean readNibble(StringBuilder realNumber, int nibble) { - if (nibble <= 0x9) { - realNumber.append(nibble); - } else { - switch (nibble) { - case 0xa: realNumber.append("."); break; - case 0xb: realNumber.append("E"); break; - case 0xc: realNumber.append("E-"); break; - case 0xd: break; - case 0xe: realNumber.append("-"); break; - case 0xf: return true; - default: throw new AssertionError("Unexpected nibble value"); - } - } - return false; - } - - /** - * A class containing data for a dictionary entry - */ - public static class DICTEntry { - private int[] operator; - private List<Number> operands; - private List<Integer> operandLengths; - private String operatorName; - private int offset; - private int operandLength; - private byte[] data = new byte[0]; - - public void setOperator(int[] operator) { - this.operator = operator; - } - - public int[] getOperator() { - return this.operator; - } - - public void setOperands(List<Number> operands) { - this.operands = operands; - } - - public List<Number> getOperands() { - return this.operands; - } - - public void setOperatorName(String operatorName) { - this.operatorName = operatorName; - } - - public String getOperatorName() { - return this.operatorName; - } - - public void setOffset(int offset) { - this.offset = offset; - } - - public int getOffset() { - return this.offset; - } - - public void setOperandLength(int operandLength) { - this.operandLength = operandLength; - } - - public int getOperandLength() { - return this.operandLength; - } - - public void setByteData(byte[] data) { - this.data = data.clone(); - } - - public byte[] getByteData() { - return data.clone(); - } - - public void setOperandLengths(List<Integer> operandLengths) { - this.operandLengths = operandLengths; - } - - public List<Integer> getOperandLengths() { - return operandLengths; - } - } - - private byte[] readHeader() throws IOException { - //Read known header - byte[] fixedHeader = cffData.readBytes(4); - int hdrSize = (fixedHeader[2] & 0xFF); - byte[] extra = cffData.readBytes(hdrSize - 4); - byte[] header = new byte[hdrSize]; - for (int i = 0; i < fixedHeader.length; i++) { - header[i] = fixedHeader[i]; - } - for (int i = 4; i < extra.length; i++) { - header[i] = extra[i - 4]; - } - return header; - } - - /** - * Reads a CFF index object are the specified offset position - * @param offset The position of the index object to read - * @return Returns an object representing the index - * @throws IOException Throws an IO Exception if an error occurs - */ - public CFFIndexData readIndex(int offset) throws IOException { - cffData.setPosition(offset); - return readIndex(); - } - - private CFFIndexData readIndex() throws IOException { - return readIndex(cffData); - } - - /** - * Reads an index from the current position of the CFFDataInput object - * @param input The object holding the CFF byte data - * @return Returns an object representing the index - * @throws IOException Throws an IO Exception if an error occurs - */ - public CFFIndexData readIndex(CFFDataInput input) throws IOException { - CFFIndexData nameIndex = new CFFIndexData(); - if (input != null) { - int origPos = input.getPosition(); - nameIndex.parseIndexHeader(input); - int tableSize = input.getPosition() - origPos; - nameIndex.setByteData(input.getPosition() - tableSize, tableSize); - } - return nameIndex; - } - - /** - * Retrieves the SID for the given GID object - * @param charsetOffset The offset of the charset data - * @param GID The GID for which to retrieve the SID - * @return Returns the SID as an integer - */ - public int getSIDFromGID(int charsetOffset, int gid) throws IOException { - if (gid == 0) { - return 0; - } - cffData.setPosition(charsetOffset); - int charsetFormat = cffData.readCard8(); - switch (charsetFormat) { - case 0: //Adjust for .notdef character - cffData.setPosition(cffData.getPosition() + (--gid * 2)); - return cffData.readSID(); - case 1: return getSIDFromGIDFormat(gid, 1); - case 2: return getSIDFromGIDFormat(gid, 2); - default: return 0; - } - } - - private int getSIDFromGIDFormat(int gid, int format) throws IOException { - int glyphCount = 0; - while (true) { - int oldGlyphCount = glyphCount; - int start = cffData.readSID(); - glyphCount += ((format == 1) ? cffData.readCard8() : cffData.readCard16()) + 1; - if (gid <= glyphCount) { - return start + (gid - oldGlyphCount) - 1; - } - } - } - - public byte[] getHeader() { - return header.clone(); - } - - public CFFIndexData getNameIndex() { - return nameIndex; - } - - public CFFIndexData getTopDictIndex() { - return topDICTIndex; - } - - public LinkedHashMap<String, DICTEntry> getTopDictEntries() { - return topDict; - } - - public CFFIndexData getStringIndex() { - return stringIndex; - } - - public CFFIndexData getGlobalIndexSubr() { - return globalIndexSubr; - } - - public CFFIndexData getLocalIndexSubr() { - return localIndexSubr; - } - - public CFFIndexData getCharStringIndex() { - return charStringIndex; - } - - public CFFDataInput getCFFData() { - return cffData; - } - - public CustomEncoding getEncoding() { - return encoding; - } - - public FDSelect getFDSelect() { - return fdSelect; - } - - public List<FontDict> getFDFonts() { - return fdFonts; - } - - public CFFDataInput getLocalSubrsForGlyph(int glyph) throws IOException { - //Subsets are currently written using a Format0 FDSelect - FDSelect fontDictionary = getFDSelect(); - if (fontDictionary instanceof Format0FDSelect) { - Format0FDSelect fdSelect = (Format0FDSelect)fontDictionary; - int found = fdSelect.getFDIndexes()[glyph]; - FontDict font = getFDFonts().get(found); - byte[] localSubrData = font.getLocalSubrData().getByteData(); - if (localSubrData != null) { - return new CFFDataInput(localSubrData); - } else { - return null; - } - } else if (fontDictionary instanceof Format3FDSelect) { - Format3FDSelect fdSelect = (Format3FDSelect)fontDictionary; - int index = 0; - for (int first : fdSelect.getRanges().keySet()) { - if (first > glyph) { - break; - } - index++; - } - FontDict font = getFDFonts().get(index); - byte[] localSubrsData = font.getLocalSubrData().getByteData(); - if (localSubrsData != null) { - return new CFFDataInput(localSubrsData); - } else { - return null; - } - } - return null; - } - - /** - * Parses the char string index from the CFF byte data - * @param offset The offset to the char string index - * @return Returns the char string index object - * @throws IOException Throws an IO Exception if an error occurs - */ - public CFFIndexData readCharStringIndex() throws IOException { - int offset = topDict.get("CharStrings").getOperands().get(0).intValue(); - cffData.setPosition(offset); - return readIndex(); - } - - private CustomEncoding readEncoding() throws IOException { - CustomEncoding foundEncoding = null; - if (topDict.get("Encoding") != null) { - int offset = topDict.get("Encoding").getOperands().get(0).intValue(); - if (offset != 0 && offset != 1) { - //No need to set the offset as we are reading the data sequentially. - int format = cffData.readCard8(); - int numEntries = cffData.readCard8(); - switch (format) { - case 0: - foundEncoding = readFormat0Encoding(format, numEntries); - break; - case 1: - foundEncoding = readFormat1Encoding(format, numEntries); - break; - default: break; - } - } - } - return foundEncoding; - } - - private Format0Encoding readFormat0Encoding(int format, int numEntries) - throws IOException { - Format0Encoding newEncoding = new Format0Encoding(); - newEncoding.setFormat(format); - newEncoding.setNumEntries(numEntries); - int[] codes = new int[numEntries]; - for (int i = 0; i < numEntries; i++) { - codes[i] = cffData.readCard8(); - } - newEncoding.setCodes(codes); - return newEncoding; - } - - private Format1Encoding readFormat1Encoding(int format, int numEntries) - throws IOException { - Format1Encoding newEncoding = new Format1Encoding(); - newEncoding.setFormat(format); - newEncoding.setNumEntries(numEntries); - LinkedHashMap<Integer, Integer> ranges = new LinkedHashMap<Integer, Integer>(); - for (int i = 0; i < numEntries; i++) { - int first = cffData.readCard8(); - int left = cffData.readCard8(); - ranges.put(first, left); - } - newEncoding.setRanges(ranges); - return newEncoding; - } - - private FDSelect readFDSelect() throws IOException { - FDSelect fdSelect = null; - DICTEntry fdSelectEntry = topDict.get("FDSelect"); - if (fdSelectEntry != null) { - int fdOffset = fdSelectEntry.getOperands().get(0).intValue(); - cffData.setPosition(fdOffset); - int format = cffData.readCard8(); - switch (format) { - case 0: - fdSelect = readFormat0FDSelect(); - break; - case 3: - fdSelect = readFormat3FDSelect(); - break; - default: - } - } - return fdSelect; - } - - private Format0FDSelect readFormat0FDSelect() throws IOException { - Format0FDSelect newFDs = new Format0FDSelect(); - newFDs.setFormat(0); - int glyphCount = charStringIndex.getNumObjects(); - int[] fds = new int[glyphCount]; - for (int i = 0; i < glyphCount; i++) { - fds[i] = cffData.readCard8(); - } - newFDs.setFDIndexes(fds); - return newFDs; - } - - private Format3FDSelect readFormat3FDSelect() throws IOException { - Format3FDSelect newFDs = new Format3FDSelect(); - newFDs.setFormat(3); - int rangeCount = cffData.readCard16(); - newFDs.setRangeCount(rangeCount); - LinkedHashMap<Integer, Integer> ranges = new LinkedHashMap<Integer, Integer>(); - for (int i = 0; i < rangeCount; i++) { - int first = cffData.readCard16(); - int fd = cffData.readCard8(); - ranges.put(first, fd); - } - newFDs.setRanges(ranges); - newFDs.setSentinelGID(cffData.readCard16()); - return newFDs; - } - - private List<FontDict> parseCIDData() throws IOException { - ArrayList<FontDict> fdFonts = new ArrayList<FontDict>(); - if (topDict.get("ROS") != null) { - DICTEntry fdArray = topDict.get("FDArray"); - if (fdArray != null) { - int fdIndex = fdArray.getOperands().get(0).intValue(); - CFFIndexData fontDicts = readIndex(fdIndex); - for (int i = 0; i < fontDicts.getNumObjects(); i++) { - FontDict newFontDict = new FontDict(); - - byte[] fdData = fontDicts.getValue(i); - LinkedHashMap<String, DICTEntry> fdEntries = parseDictData(fdData); - newFontDict.setByteData(fontDicts.getValuePosition(i), fontDicts.getValueLength(i)); - DICTEntry fontFDEntry = fdEntries.get("FontName"); - if (fontFDEntry != null) { - newFontDict.setFontName(getString(fontFDEntry.getOperands().get(0).intValue())); - } - DICTEntry privateFDEntry = fdEntries.get("Private"); - if (privateFDEntry != null) { - newFontDict = setFDData(privateFDEntry, newFontDict); - } - - fdFonts.add(newFontDict); - } - } - } - return fdFonts; - } - - private FontDict setFDData(DICTEntry privateFDEntry, FontDict newFontDict) throws IOException { - int privateFDLength = privateFDEntry.getOperands().get(0).intValue(); - int privateFDOffset = privateFDEntry.getOperands().get(1).intValue(); - cffData.setPosition(privateFDOffset); - byte[] privateDict = cffData.readBytes(privateFDLength); - newFontDict.setPrivateDictData(privateFDOffset, privateFDLength); - LinkedHashMap<String, DICTEntry> privateEntries = parseDictData(privateDict); - DICTEntry subroutines = privateEntries.get("Subrs"); - if (subroutines != null) { - CFFIndexData localSubrs = readIndex(privateFDOffset - + subroutines.getOperands().get(0).intValue()); - newFontDict.setLocalSubrData(localSubrs); - } else { - newFontDict.setLocalSubrData(new CFFIndexData()); - } - return newFontDict; - } - - private String getString(int sid) throws IOException { - return new String(stringIndex.getValue(sid - NUM_STANDARD_STRINGS)); - } - - private CFFIndexData readLocalIndexSubrs() throws IOException { - CFFIndexData localSubrs = null; - DICTEntry privateEntry = topDict.get("Private"); - if (privateEntry != null) { - int length = privateEntry.getOperands().get(0).intValue(); - int offset = privateEntry.getOperands().get(1).intValue(); - cffData.setPosition(offset); - byte[] privateData = cffData.readBytes(length); - LinkedHashMap<String, DICTEntry> privateDict = parseDictData(privateData); - DICTEntry localSubrsEntry = privateDict.get("Subrs"); - if (localSubrsEntry != null) { - int localOffset = offset + localSubrsEntry.getOperands().get(0).intValue(); - cffData.setPosition(localOffset); - localSubrs = readIndex(); - } - } - return localSubrs; - } - - /** - * Parent class which provides the ability to retrieve byte data from - * a sub-table. - */ - public class CFFSubTable { - private DataLocation dataLocation = new DataLocation(); - - public void setByteData(int position, int length) { - dataLocation = new DataLocation(position, length); - } - - public byte[] getByteData() throws IOException { - int oldPos = cffData.getPosition(); - try { - cffData.setPosition(dataLocation.getDataPosition()); - return cffData.readBytes(dataLocation.getDataLength()); - } finally { - cffData.setPosition(oldPos); - } - } - } - - /** - * An object used to hold index data from the CFF data - */ - public class CFFIndexData extends CFFSubTable { - private int numObjects; - private int offSize; - private int[] offsets = new int[0]; - private DataLocation dataLocation = new DataLocation(); - - public void setNumObjects(int numObjects) { - this.numObjects = numObjects; - } - - public int getNumObjects() { - return this.numObjects; - } - - public void setOffSize(int offSize) { - this.offSize = offSize; - } - - public int getOffSize() { - return this.offSize; - } - - public void setOffsets(int[] offsets) { - this.offsets = offsets.clone(); - } - - public int[] getOffsets() { - return offsets.clone(); - } - - public void setData(int position, int length) { - dataLocation = new DataLocation(position, length); - } - - public byte[] getData() throws IOException { - int origPos = cffData.getPosition(); - try { - cffData.setPosition(dataLocation.getDataPosition()); - return cffData.readBytes(dataLocation.getDataLength()); - } finally { - cffData.setPosition(origPos); - } - } - - /** - * Parses index data from an index object found within the CFF byte data - * @param cffData A byte array containing the CFF data - * @throws IOException Throws an IO Exception if an error occurs - */ - public void parseIndexHeader(CFFDataInput cffData) throws IOException { - setNumObjects(cffData.readCard16()); - setOffSize(cffData.readOffSize()); - int[] offsets = new int[getNumObjects() + 1]; - byte[] bytes; - //Fills the offsets array - for (int i = 0; i <= getNumObjects(); i++) { - switch (getOffSize()) { - case 1: - offsets[i] = cffData.readCard8(); - break; - case 2: - offsets[i] = cffData.readCard16(); - break; - case 3: - bytes = cffData.readBytes(3); - offsets[i] = ((bytes[0] & 0xFF) << 16) + ((bytes[1] & 0xFF) << 8) + (bytes[2] & 0xFF); - break; - case 4: - bytes = cffData.readBytes(4); - offsets[i] = ((bytes[0] & 0xFF) << 24) + ((bytes[1] & 0xFF) << 16) - + ((bytes[2] & 0xFF) << 8) + (bytes[3] & 0xFF); - break; - default: continue; - } - } - setOffsets(offsets); - int position = cffData.getPosition(); - int dataSize = offsets[offsets.length - 1] - offsets[0]; - - cffData.setPosition(cffData.getPosition() + dataSize); - setData(position, dataSize); - } - - /** - * Retrieves data from the index data - * @param index The index position of the data to retrieve - * @return Returns the byte data for the given index - * @throws IOException Throws an IO Exception if an error occurs - */ - public byte[] getValue(int index) throws IOException { - int oldPos = cffData.getPosition(); - try { - cffData.setPosition(dataLocation.getDataPosition() + (offsets[index] - 1)); - return cffData.readBytes(offsets[index + 1] - offsets[index]); - } finally { - cffData.setPosition(oldPos); - } - } - - public int getValuePosition(int index) { - return dataLocation.getDataPosition() + (offsets[index] - 1); - } - - public int getValueLength(int index) { - return offsets[index + 1] - offsets[index]; - } - } - - public abstract class CustomEncoding { - private int format; - private int numEntries; - - public void setFormat(int format) { - this.format = format; - } - - public int getFormat() { - return format; - } - - public void setNumEntries(int numEntries) { - this.numEntries = numEntries; - } - - public int getNumEntries() { - return numEntries; - } - } - - public class Format0Encoding extends CustomEncoding { - private int[] codes = new int[0]; - - public void setCodes(int[] codes) { - this.codes = codes.clone(); - } - - public int[] getCodes() { - return codes.clone(); - } - } - - public class Format1Encoding extends CustomEncoding { - private LinkedHashMap<Integer, Integer> ranges; - - public void setRanges(LinkedHashMap<Integer, Integer> ranges) { - this.ranges = ranges; - } - - public LinkedHashMap<Integer, Integer> getRanges() { - return ranges; - } - } - - public class FDSelect { - private int format; - - public void setFormat(int format) { - this.format = format; - } - - public int getFormat() { - return format; - } - } - - public class Format0FDSelect extends FDSelect { - private int[] fds = new int[0]; - - public void setFDIndexes(int[] fds) { - this.fds = fds.clone(); - } - - public int[] getFDIndexes() { - return fds.clone(); - } - } - - public class Format3FDSelect extends FDSelect { - private int rangeCount; - private LinkedHashMap<Integer, Integer> ranges; - private int sentinelGID; - - public void setRangeCount(int rangeCount) { - this.rangeCount = rangeCount; - } - - public int getRangeCount() { - return rangeCount; - } - - public void setRanges(LinkedHashMap<Integer, Integer> ranges) { - this.ranges = ranges; - } - - public LinkedHashMap<Integer, Integer> getRanges() { - return ranges; - } - - public void setSentinelGID(int sentinelGID) { - this.sentinelGID = sentinelGID; - } - - public int getSentinelGID() { - return sentinelGID; - } - } - - public class FontDict extends CFFSubTable { - private String fontName; - private DataLocation dataLocation = new DataLocation(); - private CFFIndexData localSubrData; - - public void setFontName(String groupName) { - this.fontName = groupName; - } - - public String getFontName() { - return fontName; - } - - public void setPrivateDictData(int position, int length) { - dataLocation = new DataLocation(position, length); - } - - public byte[] getPrivateDictData() throws IOException { - int origPos = cffData.getPosition(); - try { - cffData.setPosition(dataLocation.getDataPosition()); - return cffData.readBytes(dataLocation.getDataLength()); - } finally { - cffData.setPosition(origPos); - } - } - - public void setLocalSubrData(CFFIndexData localSubrData) { - this.localSubrData = localSubrData; - } - - public CFFIndexData getLocalSubrData() { - return localSubrData; - } - } - - private static class DataLocation { - private int dataPosition; - private int dataLength; - - public DataLocation() { - dataPosition = 0; - dataLength = 0; - } - - public DataLocation(int position, int length) { - this.dataPosition = position; - this.dataLength = length; - } - - public int getDataPosition() { - return dataPosition; - } - - public int getDataLength() { - return dataLength; - } - } -} diff --git a/src/java/org/apache/fop/fonts/package.html b/src/java/org/apache/fop/fonts/package.html deleted file mode 100644 index fee0bf827..000000000 --- a/src/java/org/apache/fop/fonts/package.html +++ /dev/null @@ -1,23 +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. ---> -<!-- $Id: package.html 643433 2008-04-01 15:08:24Z acumiskey $ --> -<HTML> -<TITLE>org.apache.fop.fonts Package</TITLE> -<BODY> -<P>Classes for font handling. Subpackages contain command line applications for font metrics generation, font parsing classes etc.</P> -</BODY> -</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/fonts/substitute/AttributeValue.java b/src/java/org/apache/fop/fonts/substitute/AttributeValue.java deleted file mode 100644 index bfe888d3c..000000000 --- a/src/java/org/apache/fop/fonts/substitute/AttributeValue.java +++ /dev/null @@ -1,65 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.substitute; - -import java.util.StringTokenizer; - -/** - * Encapsulates a font attribute value - */ -public class AttributeValue extends java.util.ArrayList { - - private static final long serialVersionUID = 748610847500940557L; - - /** - * Returns an <code>AttributeValue</code> object holding the - * value of the specified <code>String</code>. - * - * @param valuesString the value to be parsed - * @return an <code>AttributeValue</code> object holding the value - * represented by the string argument. - */ - public static AttributeValue valueOf(String valuesString) { - AttributeValue attribute = new AttributeValue(); - StringTokenizer stringTokenizer = new StringTokenizer(valuesString, ","); - if (stringTokenizer.countTokens() > 1) { - while (stringTokenizer.hasMoreTokens()) { - String token = stringTokenizer.nextToken().trim(); - AttributeValue tokenAttribute = AttributeValue.valueOf(token); - attribute.addAll(tokenAttribute); - } - } else { - String token = stringTokenizer.nextToken().trim(); - Object value = null; - try { - value = Integer.valueOf(token); - } catch (NumberFormatException ex) { - value = FontWeightRange.valueOf(token); - if (value == null) { - value = token; - } - } - if (value != null) { - attribute.add(value); - } - } - return attribute; - } -} diff --git a/src/java/org/apache/fop/fonts/substitute/FontQualifier.java b/src/java/org/apache/fop/fonts/substitute/FontQualifier.java deleted file mode 100644 index 8e9213e9d..000000000 --- a/src/java/org/apache/fop/fonts/substitute/FontQualifier.java +++ /dev/null @@ -1,306 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.substitute; - -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.fonts.Font; -import org.apache.fop.fonts.FontInfo; -import org.apache.fop.fonts.FontTriplet; -import org.apache.fop.fonts.FontUtil; - -/** - * Encapsulates a font substitution qualifier - */ -public class FontQualifier { - - /** logger instance */ - private static Log log = LogFactory.getLog(FontQualifier.class); - - /** font family attribute value */ - private AttributeValue fontFamilyAttributeValue; - - /** font style attribute value */ - private AttributeValue fontStyleAttributeValue; - - /** font weight attribute value */ - private AttributeValue fontWeightAttributeValue; - - /** - * Default constructor - */ - public FontQualifier() { - } - - /** - * Sets the font family - * @param fontFamily the font family - */ - public void setFontFamily(String fontFamily) { - AttributeValue fontFamilyAttribute = AttributeValue.valueOf(fontFamily); - if (fontFamilyAttribute == null) { - log.error("Invalid font-family value '" + fontFamily + "'"); - return; - } - this.fontFamilyAttributeValue = fontFamilyAttribute; - } - - /** - * Sets the font style - * @param fontStyle the font style - */ - public void setFontStyle(String fontStyle) { - AttributeValue fontStyleAttribute = AttributeValue.valueOf(fontStyle); - if (fontStyleAttribute != null) { - this.fontStyleAttributeValue = fontStyleAttribute; - } - } - - /** - * Sets the font weight - * @param fontWeight the font weight - */ - public void setFontWeight(String fontWeight) { - AttributeValue fontWeightAttribute = AttributeValue.valueOf(fontWeight); - if (fontWeightAttribute != null) { - for (Iterator it = fontWeightAttribute.iterator(); it.hasNext();) { - Object weightObj = it.next(); - if (weightObj instanceof String) { - String weightString = ((String)weightObj).trim(); - try { - FontUtil.parseCSS2FontWeight(weightString); - } catch (IllegalArgumentException ex) { - log.error("Invalid font-weight value '" + weightString + "'"); - return; - } - } - } - this.fontWeightAttributeValue = fontWeightAttribute; - } - } - - /** - * @return the font family attribute - */ - public AttributeValue getFontFamily() { - return this.fontFamilyAttributeValue; - } - - /** - * @return the font style attribute - */ - public AttributeValue getFontStyle() { - if (fontStyleAttributeValue == null) { - return AttributeValue.valueOf(Font.STYLE_NORMAL); - } - return this.fontStyleAttributeValue; - } - - /** - * @return the font weight attribute - */ - public AttributeValue getFontWeight() { - if (fontWeightAttributeValue == null) { - return AttributeValue.valueOf(Integer.toString(Font.WEIGHT_NORMAL)); - } - return this.fontWeightAttributeValue; - } - - /** - * @return true if this rule has a font weight - */ - public boolean hasFontWeight() { - return this.fontWeightAttributeValue != null; - } - - /** - * @return true if this rule has a font style - */ - public boolean hasFontStyle() { - return this.fontStyleAttributeValue != null; - } - - /** - * Returns a list of matching font triplet found in a given font info - * - * @param fontInfo the font info - * @return a list of matching font triplets - */ - protected List/*<FontTriplet>*/ match(FontInfo fontInfo) { - AttributeValue fontFamilyValue = getFontFamily(); - AttributeValue weightValue = getFontWeight(); - AttributeValue styleValue = getFontStyle(); - - List/*<FontTriplet>*/ matchingTriplets = new java.util.ArrayList/*<FontTriplet>*/(); - - // try to find matching destination font triplet - for (Iterator attrIt = fontFamilyValue.iterator(); attrIt.hasNext();) { - String fontFamilyString = (String)attrIt.next(); - Map/*<FontTriplet>*/ triplets = (Map/*<FontTriplet>*/)fontInfo.getFontTriplets(); - if (triplets != null) { - Set/*<FontTriplet>*/ tripletSet = triplets.keySet(); - for (Iterator/*<FontTriplet>*/ tripletIt = tripletSet.iterator(); - tripletIt.hasNext();) { - FontTriplet triplet = (FontTriplet)tripletIt.next(); - String fontName = triplet.getName(); - - // matched font family name - if (fontFamilyString.toLowerCase().equals(fontName.toLowerCase())) { - - // try and match font weight - boolean weightMatched = false; - int fontWeight = triplet.getWeight(); - for (Iterator weightIt = weightValue.iterator(); weightIt.hasNext();) { - Object weightObj = weightIt.next(); - if (weightObj instanceof FontWeightRange) { - FontWeightRange intRange = (FontWeightRange)weightObj; - if (intRange.isWithinRange(fontWeight)) { - weightMatched = true; - } - } else if (weightObj instanceof String) { - String fontWeightString = (String)weightObj; - int fontWeightValue = FontUtil.parseCSS2FontWeight( - fontWeightString); - if (fontWeightValue == fontWeight) { - weightMatched = true; - } - } else if (weightObj instanceof Integer) { - Integer fontWeightInteger = (Integer)weightObj; - int fontWeightValue = fontWeightInteger.intValue(); - if (fontWeightValue == fontWeight) { - weightMatched = true; - } - } - } - - // try and match font style - boolean styleMatched = false; - String fontStyleString = triplet.getStyle(); - for (Iterator styleIt = styleValue.iterator(); styleIt.hasNext();) { - String style = (String)styleIt.next(); - if (fontStyleString.equals(style)) { - styleMatched = true; - } - } - - if (weightMatched && styleMatched) { - matchingTriplets.add(triplet); - } - } - } - } - } - return matchingTriplets; - } - - /** - * Returns the highest priority matching font triplet found in a given font info - * @param fontInfo the font info - * @return the highest priority matching font triplet - */ - protected FontTriplet bestMatch(FontInfo fontInfo) { - List/*<FontTriplet>*/ matchingTriplets = match(fontInfo); - FontTriplet bestTriplet = null; - if (matchingTriplets.size() == 1) { - bestTriplet = (FontTriplet)matchingTriplets.get(0); - } else { - for (Iterator iterator = matchingTriplets.iterator(); iterator.hasNext();) { - FontTriplet triplet = (FontTriplet)iterator.next(); - if (bestTriplet == null) { - bestTriplet = triplet; - } else { - int priority = triplet.getPriority(); - if (priority < bestTriplet.getPriority()) { - bestTriplet = triplet; - } - } - } - } - return bestTriplet; - } - - /** - * @return a list of font triplets matching this qualifier - */ - public List/*<FontTriplet>*/ getTriplets() { - List/*<FontTriplet>*/ triplets = new java.util.ArrayList/*<FontTriplet>*/(); - - AttributeValue fontFamilyValue = getFontFamily(); - for (Iterator fontFamilyIt = fontFamilyValue.iterator(); fontFamilyIt.hasNext();) { - String name = (String)fontFamilyIt.next(); - - AttributeValue styleValue = getFontStyle(); - for (Iterator styleIt = styleValue.iterator(); styleIt.hasNext();) { - String style = (String)styleIt.next(); - - AttributeValue weightValue = getFontWeight(); - for (Iterator weightIt = weightValue.iterator(); weightIt.hasNext();) { - Object weightObj = weightIt.next(); - - if (weightObj instanceof FontWeightRange) { - FontWeightRange fontWeightRange = (FontWeightRange)weightObj; - int[] weightRange = fontWeightRange.toArray(); - for (int i = 0; i < weightRange.length; i++) { - triplets.add(new FontTriplet(name, style, weightRange[i])); - } - } else if (weightObj instanceof String) { - String weightString = (String)weightObj; - int weight = FontUtil.parseCSS2FontWeight(weightString); - triplets.add(new FontTriplet(name, style, weight)); - } else if (weightObj instanceof Integer) { - Integer weightInteger = (Integer)weightObj; - int weight = weightInteger.intValue(); - triplets.add(new FontTriplet(name, style, weight)); - } - } - } - } - return triplets; - } - - /** - * {@inheritDoc} - */ - public String toString() { - String str = ""; - if (fontFamilyAttributeValue != null) { - str += "font-family=" + fontFamilyAttributeValue; - } - if (fontStyleAttributeValue != null) { - if (str.length() > 0) { - str += ", "; - } - str += "font-style=" + fontStyleAttributeValue; - } - if (fontWeightAttributeValue != null) { - if (str.length() > 0) { - str += ", "; - } - str += "font-weight=" + fontWeightAttributeValue; - } - return str; - } -} diff --git a/src/java/org/apache/fop/fonts/substitute/FontSubstitution.java b/src/java/org/apache/fop/fonts/substitute/FontSubstitution.java deleted file mode 100644 index 7725fc147..000000000 --- a/src/java/org/apache/fop/fonts/substitute/FontSubstitution.java +++ /dev/null @@ -1,61 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.substitute; - -/** - * Encapsulates a pair of substitution qualifiers - */ -public class FontSubstitution { - - private FontQualifier fromQualifier; - private FontQualifier toQualifier; - - /** - * Main constructor - * - * @param fromQualifier the substitution from qualifier - * @param toQualifier the substitution to qualifier - */ - public FontSubstitution(FontQualifier fromQualifier, FontQualifier toQualifier) { - this.fromQualifier = fromQualifier; - this.toQualifier = toQualifier; - } - - /** - * @return the substitution from qualifier - */ - public FontQualifier getFromQualifier() { - return fromQualifier; - } - - /** - * @return the substitution to qualifier - */ - public FontQualifier getToQualifier() { - return toQualifier; - } - - /** - * {@inheritDoc} - */ - public String toString() { - return "from=" + fromQualifier + ", to=" + toQualifier; - } -} diff --git a/src/java/org/apache/fop/fonts/substitute/FontSubstitutions.java b/src/java/org/apache/fop/fonts/substitute/FontSubstitutions.java deleted file mode 100644 index e96459577..000000000 --- a/src/java/org/apache/fop/fonts/substitute/FontSubstitutions.java +++ /dev/null @@ -1,67 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.substitute; - -import java.util.Iterator; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.fonts.FontInfo; -import org.apache.fop.fonts.FontTriplet; - -/** - * Font substitutions - */ -public class FontSubstitutions extends java.util.ArrayList/*<Substitutions>*/ { - - private static final long serialVersionUID = -9173104935431899722L; - - /** logging instance */ - protected static final Log log = LogFactory.getLog(FontSubstitutions.class); - - /** - * Adjusts a given fontInfo using this font substitution catalog - * @param fontInfo font info - */ - public void adjustFontInfo(FontInfo fontInfo) { - for (Iterator/*<FontSubstitution>*/ subsIt = super.iterator(); subsIt.hasNext();) { - FontSubstitution substitution = (FontSubstitution)subsIt.next(); - - // find the best matching font triplet - FontQualifier toQualifier = substitution.getToQualifier(); - FontTriplet fontTriplet = toQualifier.bestMatch(fontInfo); - if (fontTriplet == null) { - log.error("Unable to match font substitution for destination qualifier " - + toQualifier); - continue; - } - String internalFontKey = fontInfo.getInternalFontKey(fontTriplet); - - FontQualifier fromQualifier = substitution.getFromQualifier(); - List/*<FontTriplet>*/ tripletList = fromQualifier.getTriplets(); - for (Iterator tripletit = tripletList.iterator(); tripletit.hasNext();) { - FontTriplet triplet = (FontTriplet) tripletit.next(); - fontInfo.addFontProperties(internalFontKey, triplet); - } - } - } -} diff --git a/src/java/org/apache/fop/fonts/substitute/FontSubstitutionsConfigurator.java b/src/java/org/apache/fop/fonts/substitute/FontSubstitutionsConfigurator.java deleted file mode 100644 index fb60473fc..000000000 --- a/src/java/org/apache/fop/fonts/substitute/FontSubstitutionsConfigurator.java +++ /dev/null @@ -1,84 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.substitute; - -import org.apache.avalon.framework.configuration.Configuration; - -import org.apache.fop.apps.FOPException; - -/** - * Configures a font substitution catalog - */ -public class FontSubstitutionsConfigurator { - - private Configuration cfg; - - /** - * Main constructor - * - * @param cfg a configuration - */ - public FontSubstitutionsConfigurator(Configuration cfg) { - this.cfg = cfg; - } - - private static FontQualifier getQualfierFromConfiguration(Configuration cfg) - throws FOPException { - String fontFamily = cfg.getAttribute("font-family", null); - if (fontFamily == null) { - throw new FOPException("substitution qualifier must have a font-family"); - } - FontQualifier qualifier = new FontQualifier(); - qualifier.setFontFamily(fontFamily); - String fontWeight = cfg.getAttribute("font-weight", null); - if (fontWeight != null) { - qualifier.setFontWeight(fontWeight); - } - String fontStyle = cfg.getAttribute("font-style", null); - if (fontStyle != null) { - qualifier.setFontStyle(fontStyle); - } - return qualifier; - } - - /** - * Configures a font substitution catalog - * - * @param substitutions font substitutions - * @throws FOPException if something's wrong with the config data - */ - public void configure(FontSubstitutions substitutions) throws FOPException { - Configuration[] substitutionCfgs = cfg.getChildren("substitution"); - for (int i = 0; i < substitutionCfgs.length; i++) { - Configuration fromCfg = substitutionCfgs[i].getChild("from", false); - if (fromCfg == null) { - throw new FOPException("'substitution' element without child 'from' element"); - } - Configuration toCfg = substitutionCfgs[i].getChild("to", false); - if (fromCfg == null) { - throw new FOPException("'substitution' element without child 'to' element"); - } - FontQualifier fromQualifier = getQualfierFromConfiguration(fromCfg); - FontQualifier toQualifier = getQualfierFromConfiguration(toCfg); - FontSubstitution substitution = new FontSubstitution(fromQualifier, toQualifier); - substitutions.add(substitution); - } - } -} diff --git a/src/java/org/apache/fop/fonts/substitute/FontWeightRange.java b/src/java/org/apache/fop/fonts/substitute/FontWeightRange.java deleted file mode 100644 index 34e04eb67..000000000 --- a/src/java/org/apache/fop/fonts/substitute/FontWeightRange.java +++ /dev/null @@ -1,114 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.substitute; - -import java.util.StringTokenizer; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Encapsulates a range of font weight values - */ -public class FontWeightRange { - - /** logging instance */ - protected static final Log log = LogFactory.getLog("org.apache.fop.render.fonts"); - - /** - * Returns an <code>FontWeightRange</code> object holding the - * range values of the specified <code>String</code>. - * - * @param weightRangeString the value range string - * @return an <code>FontWeightRange</code> object holding the value ranges - */ - public static FontWeightRange valueOf(String weightRangeString) { - StringTokenizer rangeToken = new StringTokenizer(weightRangeString, ".."); - FontWeightRange weightRange = null; - if (rangeToken.countTokens() == 2) { - String weightString = rangeToken.nextToken().trim(); - try { - int start = Integer.parseInt(weightString); - if (start % 100 != 0) { - log.error("font-weight start range is not a multiple of 100"); - } - int end = Integer.parseInt(rangeToken.nextToken()); - if (end % 100 != 0) { - log.error("font-weight end range is not a multiple of 100"); - } - if (start <= end) { - weightRange = new FontWeightRange(start, end); - } else { - log.error("font-weight start range is greater than end range"); - } - } catch (NumberFormatException e) { - log.error("invalid font-weight value " + weightString); - } - } - return weightRange; - } - - /** the start range */ - private int start; - - /** the end range */ - private int end; - - /** - * Main constructor - * @param start the start value range - * @param end the end value range - */ - public FontWeightRange(int start, int end) { - this.start = start; - this.end = end; - } - - /** - * Returns true if the given integer value is within this integer range - * @param value the integer value - * @return true if the given integer value is within this integer range - */ - public boolean isWithinRange(int value) { - return (value >= start && value <= end); - } - - /** - * {@inheritDoc} - */ - public String toString() { - return start + ".." + end; - } - - /** - * @return an integer array containing the weight ranges - */ - public int[] toArray() { - int cnt = 0; - for (int i = start; i <= end; i += 100) { - cnt++; - } - int[] range = new int[cnt]; - for (int i = 0; i < cnt; i++) { - range[i] = start + (i * 100); - } - return range; - } -} diff --git a/src/java/org/apache/fop/fonts/substitute/package.html b/src/java/org/apache/fop/fonts/substitute/package.html deleted file mode 100644 index c144ca1f8..000000000 --- a/src/java/org/apache/fop/fonts/substitute/package.html +++ /dev/null @@ -1,23 +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. ---> -<!-- $Id$ --> -<HTML> -<TITLE>org.apache.fop.fonts.substitute Package</TITLE> -<BODY> -<P>Font substitution facilities.</P> -</BODY> -</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/fonts/truetype/FontFileReader.java b/src/java/org/apache/fop/fonts/truetype/FontFileReader.java deleted file mode 100644 index 790e885bc..000000000 --- a/src/java/org/apache/fop/fonts/truetype/FontFileReader.java +++ /dev/null @@ -1,325 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.io.IOUtils; - -/** - * Reads a TrueType font file into a byte array and - * provides file like functions for array access. - */ -public class FontFileReader { - - private final int fsize; // file size - private int current; // current position in file - private final byte[] file; - - /** - * Constructor - * - * @param in InputStream to read from - * @throws IOException In case of an I/O problem - */ - public FontFileReader(InputStream in) throws IOException { - this.file = IOUtils.toByteArray(in); - this.fsize = this.file.length; - this.current = 0; - } - - - /** - * Set current file position to offset - * - * @param offset The new offset to set - * @throws IOException In case of an I/O problem - */ - public void seekSet(long offset) throws IOException { - if (offset > fsize || offset < 0) { - throw new java.io.EOFException("Reached EOF, file size=" + fsize - + " offset=" + offset); - } - current = (int)offset; - } - - /** - * Skip a given number of bytes. - * - * @param add The number of bytes to advance - * @throws IOException In case of an I/O problem - */ - public void skip(long add) throws IOException { - seekSet(current + add); - } - - /** - * Returns current file position. - * - * @return int The current position. - */ - public int getCurrentPos() { - return current; - } - - /** - * Returns the size of the file. - * - * @return int The filesize - */ - public int getFileSize() { - return fsize; - } - - /** - * Read 1 byte. - * - * @return One byte - * @throws IOException If EOF is reached - */ - private byte read() throws IOException { - if (current >= fsize) { - throw new java.io.EOFException("Reached EOF, file size=" + fsize); - } - - final byte ret = file[current++]; - return ret; - } - - /** - * Read 1 signed byte. - * - * @return One byte - * @throws IOException If EOF is reached - */ - public final byte readTTFByte() throws IOException { - return read(); - } - - /** - * Read 1 unsigned byte. - * - * @return One unsigned byte - * @throws IOException If EOF is reached - */ - public final int readTTFUByte() throws IOException { - final byte buf = read(); - - if (buf < 0) { - return (256 + buf); - } else { - return buf; - } - } - - /** - * Read 2 bytes signed. - * - * @return One signed short - * @throws IOException If EOF is reached - */ - public final short readTTFShort() throws IOException { - final int ret = (readTTFUByte() << 8) + readTTFUByte(); - final short sret = (short)ret; - return sret; - } - - /** - * Read 2 bytes unsigned. - * - * @return One unsigned short - * @throws IOException If EOF is reached - */ - public final int readTTFUShort() throws IOException { - final int ret = (readTTFUByte() << 8) + readTTFUByte(); - return ret; - } - - /** - * Write a USHort at a given position. - * - * @param pos The absolute position to write to - * @param val The value to write - * @throws IOException If EOF is reached - */ - public final void writeTTFUShort(long pos, int val) throws IOException { - if ((pos + 2) > fsize) { - throw new java.io.EOFException("Reached EOF"); - } - final byte b1 = (byte)((val >> 8) & 0xff); - final byte b2 = (byte)(val & 0xff); - final int fileIndex = (int) pos; - file[fileIndex] = b1; - file[fileIndex + 1] = b2; - } - - /** - * Read 2 bytes signed at position pos without changing current position. - * - * @param pos The absolute position to read from - * @return One signed short - * @throws IOException If EOF is reached - */ - public final short readTTFShort(long pos) throws IOException { - final long cp = getCurrentPos(); - seekSet(pos); - final short ret = readTTFShort(); - seekSet(cp); - return ret; - } - - /** - * Read 2 bytes unsigned at position pos without changing current position. - * - * @param pos The absolute position to read from - * @return One unsigned short - * @throws IOException If EOF is reached - */ - public final int readTTFUShort(long pos) throws IOException { - long cp = getCurrentPos(); - seekSet(pos); - int ret = readTTFUShort(); - seekSet(cp); - return ret; - } - - /** - * Read 4 bytes. - * - * @return One signed integer - * @throws IOException If EOF is reached - */ - public final int readTTFLong() throws IOException { - long ret = readTTFUByte(); // << 8; - ret = (ret << 8) + readTTFUByte(); - ret = (ret << 8) + readTTFUByte(); - ret = (ret << 8) + readTTFUByte(); - - return (int)ret; - } - - /** - * Read 4 bytes. - * - * @return One unsigned integer - * @throws IOException If EOF is reached - */ - public final long readTTFULong() throws IOException { - long ret = readTTFUByte(); - ret = (ret << 8) + readTTFUByte(); - ret = (ret << 8) + readTTFUByte(); - ret = (ret << 8) + readTTFUByte(); - - return ret; - } - - /** - * Read a NUL terminated ISO-8859-1 string. - * - * @return A String - * @throws IOException If EOF is reached - */ - public final String readTTFString() throws IOException { - int i = current; - while (file[i++] != 0) { - if (i >= fsize) { - throw new java.io.EOFException("Reached EOF, file size=" - + fsize); - } - } - - byte[] tmp = new byte[i - current - 1]; - System.arraycopy(file, current, tmp, 0, i - current - 1); - return new String(tmp, "ISO-8859-1"); - } - - - /** - * Read an ISO-8859-1 string of len bytes. - * - * @param len The length of the string to read - * @return A String - * @throws IOException If EOF is reached - */ - public final String readTTFString(int len) throws IOException { - if ((len + current) > fsize) { - throw new java.io.EOFException("Reached EOF, file size=" + fsize); - } - - byte[] tmp = new byte[len]; - System.arraycopy(file, current, tmp, 0, len); - current += len; - final String encoding; - if ((tmp.length > 0) && (tmp[0] == 0)) { - encoding = "UTF-16BE"; - } else { - encoding = "ISO-8859-1"; - } - return new String(tmp, encoding); - } - - /** - * Read an ISO-8859-1 string of len bytes. - * - * @param len The length of the string to read - * @param encodingID the string encoding id (presently ignored; always uses UTF-16BE) - * @return A String - * @throws IOException If EOF is reached - */ - public final String readTTFString(int len, int encodingID) throws IOException { - if ((len + current) > fsize) { - throw new java.io.EOFException("Reached EOF, file size=" + fsize); - } - - byte[] tmp = new byte[len]; - System.arraycopy(file, current, tmp, 0, len); - current += len; - final String encoding; - encoding = "UTF-16BE"; //Use this for all known encoding IDs for now - return new String(tmp, encoding); - } - - /** - * Return a copy of the internal array - * - * @param offset The absolute offset to start reading from - * @param length The number of bytes to read - * @return An array of bytes - * @throws IOException if out of bounds - */ - public byte[] getBytes(int offset, - int length) throws IOException { - if ((offset + length) > fsize) { - throw new java.io.IOException("Reached EOF"); - } - - byte[] ret = new byte[length]; - System.arraycopy(file, offset, ret, 0, length); - return ret; - } - /** - * Returns the full byte array representation of the file. - * @return byte array. - */ - public byte[] getAllBytes() { - return file; - } -} diff --git a/src/java/org/apache/fop/fonts/truetype/GlyfTable.java b/src/java/org/apache/fop/fonts/truetype/GlyfTable.java deleted file mode 100644 index 6ad479a0e..000000000 --- a/src/java/org/apache/fop/fonts/truetype/GlyfTable.java +++ /dev/null @@ -1,231 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.io.IOException; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; - -/** - * This "glyf" table in a TrueType font file contains information that describes the glyphs. This - * class is responsible for creating a subset of the "glyf" table given a set of glyph indices. - */ -public class GlyfTable { - - private final OFMtxEntry[] mtxTab; - - private final long tableOffset; - - private final Set<Long> remappedComposites; - - protected final Map<Integer, Integer> subset; - - private final FontFileReader in; - - /** All the composite glyphs that appear in the subset. */ - private Set<Integer> compositeGlyphs = new TreeSet<Integer>(); - - /** All the glyphs that are composed, but do not appear in the subset. */ - protected Set<Integer> composedGlyphs = new TreeSet<Integer>(); - - public GlyfTable(FontFileReader in, OFMtxEntry[] metrics, OFDirTabEntry dirTableEntry, - Map<Integer, Integer> glyphs) throws IOException { - mtxTab = metrics; - tableOffset = dirTableEntry.getOffset(); - remappedComposites = new HashSet<Long>(); - this.subset = glyphs; - this.in = in; - } - - private static enum GlyfFlags { - - ARG_1_AND_2_ARE_WORDS(4, 2), - ARGS_ARE_XY_VALUES, - ROUND_XY_TO_GRID, - WE_HAVE_A_SCALE(2), - RESERVED, - MORE_COMPONENTS, - WE_HAVE_AN_X_AND_Y_SCALE(4), - WE_HAVE_A_TWO_BY_TWO(8), - WE_HAVE_INSTRUCTIONS, - USE_MY_METRICS, - OVERLAP_COMPOUND, - SCALED_COMPONENT_OFFSET, - UNSCALED_COMPONENT_OFFSET; - - private final int bitMask; - private final int argsCountIfSet; - private final int argsCountIfNotSet; - - private GlyfFlags(int argsCountIfSet, int argsCountIfNotSet) { - this.bitMask = 1 << this.ordinal(); - this.argsCountIfSet = argsCountIfSet; - this.argsCountIfNotSet = argsCountIfNotSet; - } - - private GlyfFlags(int argsCountIfSet) { - this(argsCountIfSet, 0); - } - - private GlyfFlags() { - this(0, 0); - } - - /** - * Calculates, from the given flags, the offset to the next glyph index. - * - * @param flags the glyph data flags - * @return offset to the next glyph if any, or 0 - */ - static int getOffsetToNextComposedGlyf(int flags) { - int offset = 0; - for (GlyfFlags flag : GlyfFlags.values()) { - offset += (flags & flag.bitMask) > 0 ? flag.argsCountIfSet : flag.argsCountIfNotSet; - } - return offset; - } - - /** - * Checks the given flags to see if there is another composed glyph. - * - * @param flags the glyph data flags - * @return true if there is another composed glyph, otherwise false. - */ - static boolean hasMoreComposites(int flags) { - return (flags & MORE_COMPONENTS.bitMask) > 0; - } - } - - /** - * Populates the map of subset glyphs with all the glyphs that compose the glyphs in the subset. - * This also re-maps the indices of composed glyphs to their new index in the subset font. - * - * @throws IOException an I/O error - */ - protected void populateGlyphsWithComposites() throws IOException { - for (int indexInOriginal : subset.keySet()) { - scanGlyphsRecursively(indexInOriginal); - } - - addAllComposedGlyphsToSubset(); - - for (int compositeGlyph : compositeGlyphs) { - long offset = tableOffset + mtxTab[compositeGlyph].getOffset() + 10; - if (!remappedComposites.contains(offset)) { - remapComposite(offset); - } - } - } - - /** - * Scans each glyph for any composed glyphs. This populates <code>compositeGlyphs</code> with - * all the composite glyphs being used in the subset. This also populates <code>newGlyphs</code> - * with any new glyphs that are composed and do not appear in the subset of glyphs. - * - * For example the double quote mark (") is often composed of two apostrophes ('), if an - * apostrophe doesn't appear in the glyphs in the subset, it will be included and will be added - * to newGlyphs. - * - * @param indexInOriginal the index of the glyph to test from the original font - * @throws IOException an I/O error - */ - private void scanGlyphsRecursively(int indexInOriginal) throws IOException { - if (!subset.containsKey(indexInOriginal)) { - composedGlyphs.add(indexInOriginal); - } - - if (isComposite(indexInOriginal)) { - compositeGlyphs.add(indexInOriginal); - Set<Integer> composedGlyphs = retrieveComposedGlyphs(indexInOriginal); - for (Integer composedGlyph : composedGlyphs) { - scanGlyphsRecursively(composedGlyph); - } - } - } - - /** - * Adds to the subset, all the glyphs that are composed by a glyph, but do not appear themselves - * in the subset. - */ - protected void addAllComposedGlyphsToSubset() { - int newIndex = subset.size(); - for (int composedGlyph : composedGlyphs) { - subset.put(composedGlyph, newIndex++); - } - } - - /** - * Re-maps the index of composed glyphs in the original font to the index of the same glyph in - * the subset font. - * - * @param glyphOffset the offset of the composite glyph - * @throws IOException an I/O error - */ - private void remapComposite(long glyphOffset) throws IOException { - long currentGlyphOffset = glyphOffset; - - remappedComposites.add(currentGlyphOffset); - - int flags = 0; - do { - flags = in.readTTFUShort(currentGlyphOffset); - int glyphIndex = in.readTTFUShort(currentGlyphOffset + 2); - Integer indexInSubset = subset.get(glyphIndex); - assert indexInSubset != null; - /* - * TODO: this should not be done here!! We're writing to the stream we're reading from, - * this is asking for trouble! What should happen is when the glyph data is copied from - * subset, the remapping should be done there. So the original stream is left untouched. - */ - in.writeTTFUShort(currentGlyphOffset + 2, indexInSubset); - - currentGlyphOffset += 4 + GlyfFlags.getOffsetToNextComposedGlyf(flags); - } while (GlyfFlags.hasMoreComposites(flags)); - } - - public boolean isComposite(int indexInOriginal) throws IOException { - int numberOfContours = in.readTTFShort(tableOffset + mtxTab[indexInOriginal].getOffset()); - return numberOfContours < 0; - } - - /** - * Reads a composite glyph at a given index and retrieves all the glyph indices of contingent - * composed glyphs. - * - * @param indexInOriginal the glyph index of the composite glyph - * @return the set of glyph indices this glyph composes - * @throws IOException an I/O error - */ - public Set<Integer> retrieveComposedGlyphs(int indexInOriginal) - throws IOException { - Set<Integer> composedGlyphs = new HashSet<Integer>(); - long offset = tableOffset + mtxTab[indexInOriginal].getOffset() + 10; - int flags = 0; - do { - flags = in.readTTFUShort(offset); - composedGlyphs.add(in.readTTFUShort(offset + 2)); - offset += 4 + GlyfFlags.getOffsetToNextComposedGlyf(flags); - } while (GlyfFlags.hasMoreComposites(flags)); - - return composedGlyphs; - } -} diff --git a/src/java/org/apache/fop/fonts/truetype/OFDirTabEntry.java b/src/java/org/apache/fop/fonts/truetype/OFDirTabEntry.java deleted file mode 100644 index 34e7fba14..000000000 --- a/src/java/org/apache/fop/fonts/truetype/OFDirTabEntry.java +++ /dev/null @@ -1,117 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.Arrays; - - -/** - * This class represents an entry to a TrueType font's Dir Tab. - */ -public class OFDirTabEntry { - - private byte[] tag = new byte[4]; - private long checksum; - private long offset; - private long length; - - public OFDirTabEntry() { - } - - public OFDirTabEntry(long offset, long length) { - this.offset = offset; - this.length = length; - } - - /** - * Read Dir Tab. - * @param in font file reader - * @return tag name - * @throws IOException upon I/O exception - */ - public String read(FontFileReader in) throws IOException { - tag[0] = in.readTTFByte(); - tag[1] = in.readTTFByte(); - tag[2] = in.readTTFByte(); - tag[3] = in.readTTFByte(); - - checksum = in.readTTFLong(); - offset = in.readTTFULong(); - length = in.readTTFULong(); - - return getTagString(); - } - - - @Override - public String toString() { - return "Read dir tab [" + Arrays.toString(tag) + "]" - + " offset: " + offset - + " length: " + length - + " name: " + getTagString(); - } - - /** - * Returns the checksum. - * @return int - */ - public long getChecksum() { - return checksum; - } - - /** - * Returns the length. - * @return long - */ - public long getLength() { - return length; - } - - /** - * Returns the offset. - * @return long - */ - public long getOffset() { - return offset; - } - - /** - * Returns the tag bytes. - * @return byte[] - */ - public byte[] getTag() { - return tag; - } - - /** - * Returns the tag bytes. - * @return byte[] - */ - public String getTagString() { - try { - return new String(tag, "ISO-8859-1"); - } catch (UnsupportedEncodingException e) { - return this.toString(); // Should never happen. - } - } - -} diff --git a/src/java/org/apache/fop/fonts/truetype/OFFontLoader.java b/src/java/org/apache/fop/fonts/truetype/OFFontLoader.java deleted file mode 100644 index 7c8774933..000000000 --- a/src/java/org/apache/fop/fonts/truetype/OFFontLoader.java +++ /dev/null @@ -1,271 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.awt.Rectangle; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.io.IOUtils; - -import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.fonts.CIDFontType; -import org.apache.fop.fonts.CMapSegment; -import org.apache.fop.fonts.EmbeddingMode; -import org.apache.fop.fonts.EncodingMode; -import org.apache.fop.fonts.FontLoader; -import org.apache.fop.fonts.FontType; -import org.apache.fop.fonts.MultiByteFont; -import org.apache.fop.fonts.NamedCharacter; -import org.apache.fop.fonts.SingleByteFont; -import org.apache.fop.fonts.truetype.OpenFont.PostScriptVersion; -import org.apache.fop.util.HexEncoder; - -/** - * Loads a TrueType font into memory directly from the original font file. - */ -public class OFFontLoader extends FontLoader { - - private MultiByteFont multiFont; - private SingleByteFont singleFont; - private final String subFontName; - private EncodingMode encodingMode; - private EmbeddingMode embeddingMode; - - /** - * Default constructor - * @param fontFileURI the URI representing the font file - * @param resourceResolver the resource resolver for font URI resolution - */ - public OFFontLoader(URI fontFileURI, InternalResourceResolver resourceResolver) { - this(fontFileURI, null, true, EmbeddingMode.AUTO, EncodingMode.AUTO, true, true, resourceResolver); - } - - /** - * Additional constructor for TrueType Collections. - * @param fontFileURI the URI representing the font file - * @param subFontName the sub-fontname of a font in a TrueType Collection (or null for normal - * TrueType fonts) - * @param embedded indicates whether the font is embedded or referenced - * @param embeddingMode the embedding mode of the font - * @param encodingMode the requested encoding mode - * @param useKerning true to enable loading kerning info if available, false to disable - * @param useAdvanced true to enable loading advanced info if available, false to disable - * @param resolver the FontResolver for font URI resolution - */ - public OFFontLoader(URI fontFileURI, String subFontName, boolean embedded, - EmbeddingMode embeddingMode, EncodingMode encodingMode, boolean useKerning, - boolean useAdvanced, InternalResourceResolver resolver) { - super(fontFileURI, embedded, useKerning, useAdvanced, resolver); - this.subFontName = subFontName; - this.encodingMode = encodingMode; - this.embeddingMode = embeddingMode; - if (this.encodingMode == EncodingMode.AUTO) { - this.encodingMode = EncodingMode.CID; //Default to CID mode for TrueType - } - if (this.embeddingMode == EmbeddingMode.AUTO) { - this.embeddingMode = EmbeddingMode.SUBSET; - } - } - - /** {@inheritDoc} */ - protected void read() throws IOException { - read(this.subFontName); - } - - /** - * Reads a TrueType font. - * @param ttcFontName the TrueType sub-font name of TrueType Collection (may be null for - * normal TrueType fonts) - * @throws IOException if an I/O error occurs - */ - private void read(String ttcFontName) throws IOException { - InputStream in = resourceResolver.getResource(this.fontFileURI); - try { - FontFileReader reader = new FontFileReader(in); - String header = readHeader(reader); - boolean isCFF = header.equals("OTTO"); - OpenFont otf = (isCFF) ? new OTFFile() : new TTFFile(useKerning, useAdvanced); - boolean supported = otf.readFont(reader, header, ttcFontName); - if (!supported) { - throw new IOException("The font does not have a Unicode cmap table: " + fontFileURI); - } - buildFont(otf, ttcFontName); - loaded = true; - } finally { - IOUtils.closeQuietly(in); - } - } - - public static String readHeader(FontFileReader fontFile) throws IOException { - if (fontFile != null) { - fontFile.seekSet(0); - return fontFile.readTTFString(4); // TTF_FIXED_SIZE (4 bytes) - } - return null; - } - - private void buildFont(OpenFont otf, String ttcFontName) { - boolean isCid = this.embedded; - if (this.encodingMode == EncodingMode.SINGLE_BYTE) { - isCid = false; - } - - if (isCid) { - multiFont = new MultiByteFont(resourceResolver, embeddingMode); - multiFont.setIsOTFFile(otf instanceof OTFFile); - returnFont = multiFont; - multiFont.setTTCName(ttcFontName); - } else { - singleFont = new SingleByteFont(resourceResolver, embeddingMode); - returnFont = singleFont; - } - - returnFont.setFontURI(fontFileURI); - returnFont.setFontName(otf.getPostScriptName()); - returnFont.setFullName(otf.getFullName()); - returnFont.setFamilyNames(otf.getFamilyNames()); - returnFont.setFontSubFamilyName(otf.getSubFamilyName()); - returnFont.setCapHeight(otf.getCapHeight()); - returnFont.setXHeight(otf.getXHeight()); - returnFont.setAscender(otf.getLowerCaseAscent()); - returnFont.setDescender(otf.getLowerCaseDescent()); - returnFont.setFontBBox(otf.getFontBBox()); - returnFont.setUnderlinePosition(otf.getUnderlinePosition() - otf.getUnderlineThickness() / 2); - returnFont.setUnderlineThickness(otf.getUnderlineThickness()); - returnFont.setStrikeoutPosition(otf.getStrikeoutPosition() - otf.getStrikeoutThickness() / 2); - returnFont.setStrikeoutThickness(otf.getStrikeoutThickness()); - returnFont.setFlags(otf.getFlags()); - returnFont.setStemV(Integer.parseInt(otf.getStemV())); //not used for TTF - returnFont.setItalicAngle(Integer.parseInt(otf.getItalicAngle())); - returnFont.setMissingWidth(0); - returnFont.setWeight(otf.getWeightClass()); - returnFont.setEmbeddingMode(this.embeddingMode); - if (isCid) { - if (otf instanceof OTFFile) { - multiFont.setCIDType(CIDFontType.CIDTYPE0); - } else { - multiFont.setCIDType(CIDFontType.CIDTYPE2); - } - multiFont.setWidthArray(otf.getWidths()); - multiFont.setBBoxArray(otf.getBoundingBoxes()); - } else { - singleFont.setFontType(FontType.TRUETYPE); - singleFont.setEncoding(otf.getCharSetName()); - returnFont.setFirstChar(otf.getFirstChar()); - returnFont.setLastChar(otf.getLastChar()); - singleFont.setTrueTypePostScriptVersion(otf.getPostScriptVersion()); - copyGlyphMetricsSingleByte(otf); - } - returnFont.setCMap(getCMap(otf)); - - if (otf.getKerning() != null && useKerning) { - copyKerning(otf, isCid); - } - if (useAdvanced) { - copyAdvanced(otf); - } - if (this.embedded) { - if (otf.isEmbeddable()) { - returnFont.setEmbedURI(this.fontFileURI); - } else { - String msg = "The font " + this.fontFileURI + " is not embeddable due to a" - + " licensing restriction."; - throw new RuntimeException(msg); - } - } - } - - private CMapSegment[] getCMap(OpenFont otf) { - CMapSegment[] array = new CMapSegment[otf.getCMaps().size()]; - return otf.getCMaps().toArray(array); - } - - private void copyGlyphMetricsSingleByte(OpenFont otf) { - int[] wx = otf.getWidths(); - Rectangle[] bboxes = otf.getBoundingBoxes(); - for (int i = singleFont.getFirstChar(); i <= singleFont.getLastChar(); i++) { - singleFont.setWidth(i, otf.getCharWidth(i)); - int[] bbox = otf.getBBox(i); - singleFont.setBoundingBox(i, - new Rectangle(bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1])); - } - - for (CMapSegment segment : otf.getCMaps()) { - if (segment.getUnicodeStart() < 0xFFFE) { - for (char u = (char)segment.getUnicodeStart(); u <= segment.getUnicodeEnd(); u++) { - int codePoint = singleFont.getEncoding().mapChar(u); - if (codePoint <= 0) { - int glyphIndex = segment.getGlyphStartIndex() + u - segment.getUnicodeStart(); - String glyphName = otf.getGlyphName(glyphIndex); - if (glyphName.length() == 0 && otf.getPostScriptVersion() != PostScriptVersion.V2) { - glyphName = "u" + HexEncoder.encode(u); - } - if (glyphName.length() > 0) { - String unicode = Character.toString(u); - NamedCharacter nc = new NamedCharacter(glyphName, unicode); - singleFont.addUnencodedCharacter(nc, wx[glyphIndex], bboxes[glyphIndex]); - } - } - } - } - } - } - - /** - * Copy kerning information. - */ - private void copyKerning(OpenFont otf, boolean isCid) { - - // Get kerning - Set<Integer> kerningSet; - if (isCid) { - kerningSet = otf.getKerning().keySet(); - } else { - kerningSet = otf.getAnsiKerning().keySet(); - } - - for (Integer kpx1 : kerningSet) { - Map<Integer, Integer> h2; - if (isCid) { - h2 = otf.getKerning().get(kpx1); - } else { - h2 = otf.getAnsiKerning().get(kpx1); - } - returnFont.putKerningEntry(kpx1, h2); - } - } - - /** - * Copy advanced typographic information. - */ - private void copyAdvanced(OpenFont otf) { - if (returnFont instanceof MultiByteFont) { - MultiByteFont mbf = (MultiByteFont) returnFont; - mbf.setGDEF(otf.getGDEF()); - mbf.setGSUB(otf.getGSUB()); - mbf.setGPOS(otf.getGPOS()); - } - } - -} diff --git a/src/java/org/apache/fop/fonts/truetype/OFMtxEntry.java b/src/java/org/apache/fop/fonts/truetype/OFMtxEntry.java deleted file mode 100644 index b52f03849..000000000 --- a/src/java/org/apache/fop/fonts/truetype/OFMtxEntry.java +++ /dev/null @@ -1,195 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.util.List; - -/** - * This class represents a TrueType Mtx Entry. - */ -public class OFMtxEntry { - - private int wx; - private int lsb; - private String name = ""; - private int index; - private List unicodeIndex = new java.util.ArrayList(); - private int[] boundingBox = new int[4]; - private long offset; - private byte found; - - /** - * Returns a String representation of this object. - * - * @param t TTFFile to use for unit conversion - * @return String String representation - */ - public String toString(TTFFile t) { - return "Glyph " + name + " index: " + getIndexAsString() + " bbox [" - + t.convertTTFUnit2PDFUnit(boundingBox[0]) + " " - + t.convertTTFUnit2PDFUnit(boundingBox[1]) + " " - + t.convertTTFUnit2PDFUnit(boundingBox[2]) + " " - + t.convertTTFUnit2PDFUnit(boundingBox[3]) + "] wx: " - + t.convertTTFUnit2PDFUnit(wx); - } - - /** - * Returns the boundingBox. - * @return int[] - */ - public int[] getBoundingBox() { - return boundingBox; - } - - /** - * Sets the boundingBox. - * @param boundingBox The boundingBox to set - */ - public void setBoundingBox(int[] boundingBox) { - this.boundingBox = boundingBox; - } - - /** - * Returns the found. - * @return byte - */ - public byte getFound() { - return found; - } - - /** - * Returns the index. - * @return int - */ - public int getIndex() { - return index; - } - - /** - * Determines whether this index represents a reserved character. - * @return True if it is reserved - */ - public boolean isIndexReserved() { - return (getIndex() >= 32768) && (getIndex() <= 65535); - } - - /** - * Returns a String representation of the index taking into account if - * the index is in the reserved range. - * @return index as String - */ - public String getIndexAsString() { - if (isIndexReserved()) { - return Integer.toString(getIndex()) + " (reserved)"; - } else { - return Integer.toString(getIndex()); - } - } - - /** - * Returns the lsb. - * @return int - */ - public int getLsb() { - return lsb; - } - - /** - * Returns the name. - * @return String - */ - public String getName() { - return name; - } - - /** - * Returns the offset. - * @return long - */ - public long getOffset() { - return offset; - } - - /** - * Returns the unicodeIndex. - * @return List - */ - public List getUnicodeIndex() { - return unicodeIndex; - } - - /** - * Returns the wx. - * @return int - */ - public int getWx() { - return wx; - } - - /** - * Sets the found. - * @param found The found to set - */ - public void setFound(byte found) { - this.found = found; - } - - /** - * Sets the index. - * @param index The index to set - */ - public void setIndex(int index) { - this.index = index; - } - - /** - * Sets the lsb. - * @param lsb The lsb to set - */ - public void setLsb(int lsb) { - this.lsb = lsb; - } - - /** - * Sets the name. - * @param name The name to set - */ - public void setName(String name) { - this.name = name; - } - - /** - * Sets the offset. - * @param offset The offset to set - */ - public void setOffset(long offset) { - this.offset = offset; - } - - /** - * Sets the wx. - * @param wx The wx to set - */ - public void setWx(int wx) { - this.wx = wx; - } - - -} diff --git a/src/java/org/apache/fop/fonts/truetype/OFTableName.java b/src/java/org/apache/fop/fonts/truetype/OFTableName.java deleted file mode 100644 index f6264129a..000000000 --- a/src/java/org/apache/fop/fonts/truetype/OFTableName.java +++ /dev/null @@ -1,169 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - - -/** - * Represents table names as found in a TrueType font's Table Directory. - * TrueType fonts may have custom tables so we cannot use an enum. - */ -public final class OFTableName { - - /** The first table in a TrueType font file containing metadata about other tables. */ - public static final OFTableName TABLE_DIRECTORY = new OFTableName("tableDirectory"); - - /** Baseline data */ - public static final OFTableName BASE = new OFTableName("BASE"); - - /** CFF data/ */ - public static final OFTableName CFF = new OFTableName("CFF "); - - /** Embedded bitmap data. */ - public static final OFTableName EBDT = new OFTableName("EBDT"); - - /** Embedded bitmap location data. */ - public static final OFTableName EBLC = new OFTableName("EBLC"); - - /** Embedded bitmap scaling data. */ - public static final OFTableName EBSC = new OFTableName("EBSC"); - - /** A FontForge specific table. */ - public static final OFTableName FFTM = new OFTableName("FFTM"); - - /** Divides glyphs into various classes that make using the GPOS/GSUB tables easier. */ - public static final OFTableName GDEF = new OFTableName("GDEF"); - - /** Provides kerning information, mark-to-base, etc. for opentype fonts. */ - public static final OFTableName GPOS = new OFTableName("GPOS"); - - /** Provides ligature information, swash, etc. for opentype fonts. */ - public static final OFTableName GSUB = new OFTableName("GSUB"); - - /** Linear threshold table. */ - public static final OFTableName LTSH = new OFTableName("LTSH"); - - /** OS/2 and Windows specific metrics. */ - public static final OFTableName OS2 = new OFTableName("OS/2"); - - /** PCL 5 data. */ - public static final OFTableName PCLT = new OFTableName("PCLT"); - - /** Vertical Device Metrics table. */ - public static final OFTableName VDMX = new OFTableName("VDMX"); - - /** Character to glyph mapping. */ - public static final OFTableName CMAP = new OFTableName("cmap"); - - /** Control Value Table. */ - public static final OFTableName CVT = new OFTableName("cvt "); - - /** Font program. */ - public static final OFTableName FPGM = new OFTableName("fpgm"); - - /** Grid-fitting and scan conversion procedure (grayscale). */ - public static final OFTableName GASP = new OFTableName("gasp"); - - /** Glyph data. */ - public static final OFTableName GLYF = new OFTableName("glyf"); - - /** Horizontal device metrics. */ - public static final OFTableName HDMX = new OFTableName("hdmx"); - - /** Font header. */ - public static final OFTableName HEAD = new OFTableName("head"); - - /** Horizontal header. */ - public static final OFTableName HHEA = new OFTableName("hhea"); - - /** Horizontal metrics. */ - public static final OFTableName HMTX = new OFTableName("hmtx"); - - /** Kerning. */ - public static final OFTableName KERN = new OFTableName("kern"); - - /** Index to location. */ - public static final OFTableName LOCA = new OFTableName("loca"); - - /** Maximum profile. */ - public static final OFTableName MAXP = new OFTableName("maxp"); - - /** Naming table. */ - public static final OFTableName NAME = new OFTableName("name"); - - /** PostScript information. */ - public static final OFTableName POST = new OFTableName("post"); - - /** CVT Program. */ - public static final OFTableName PREP = new OFTableName("prep"); - - /** Vertical Metrics header. */ - public static final OFTableName VHEA = new OFTableName("vhea"); - - /** Vertical Metrics. */ - public static final OFTableName VMTX = new OFTableName("vmtx"); - - private final String name; - - private OFTableName(String name) { - this.name = name; - } - - /** - * Returns the name of the table as it should be in the Directory Table. - */ - public String getName() { - return name; - } - - /** - * Returns an instance of this class corresponding to the given string representation. - * @param tableName table name as in the Table Directory - * @return TTFTableName - */ - public static OFTableName getValue(String tableName) { - if (tableName != null) { - return new OFTableName(tableName); - } - throw new IllegalArgumentException("A TrueType font table name must not be null"); - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof OFTableName)) { - return false; - } - OFTableName to = (OFTableName) o; - return this.name.equals(to.getName()); - } - - @Override - public String toString() { - return name; - } - -} diff --git a/src/java/org/apache/fop/fonts/truetype/OTFFile.java b/src/java/org/apache/fop/fonts/truetype/OTFFile.java deleted file mode 100644 index 1ac7a565e..000000000 --- a/src/java/org/apache/fop/fonts/truetype/OTFFile.java +++ /dev/null @@ -1,175 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.apache.fontbox.cff.CFFDataInput; -import org.apache.fontbox.cff.CFFFont; -import org.apache.fontbox.cff.CFFParser; -import org.apache.fontbox.cff.charset.CFFCharset; - -public class OTFFile extends OpenFont { - - protected CFFFont fileFont; - - public OTFFile() throws IOException { - checkForFontbox(); - } - - private void checkForFontbox() throws IOException { - try { - Class.forName("org.apache.fontbox.cff.CFFFont"); - } catch (ClassNotFoundException ex) { - throw new IOException("The Fontbox jar was not found in the classpath. This is " - + "required for OTF CFF ssupport."); - } - } - - @Override - protected void updateBBoxAndOffset() throws IOException { - List<Mapping> gidMappings = getGIDMappings(fileFont); - Map<Integer, String> sidNames = constructNameMap(gidMappings); - UnicodeMapping[] mappings = unicodeMappings.toArray(new UnicodeMapping[unicodeMappings.size()]); - for (int i = 0; i < mappings.length; i++) { - int glyphIdx = mappings[i].getGlyphIndex(); - Mapping m = gidMappings.get(glyphIdx); - String name = sidNames.get(m.getSID()); - mtxTab[glyphIdx].setName(name); - } - } - - private List<Mapping> getGIDMappings(CFFFont font) { - List<Mapping> gidMappings = new ArrayList<Mapping>(); - Mapping notdef = new Mapping(); - gidMappings.add(notdef); - for (CFFCharset.Entry entry : font.getCharset().getEntries()) { - String name = entry.getName(); - byte[] bytes = font.getCharStringsDict().get(name); - if (bytes == null) { - continue; - } - Mapping mapping = new Mapping(); - mapping.setSID(entry.getSID()); - mapping.setName(name); - mapping.setBytes(bytes); - gidMappings.add(mapping); - } - return gidMappings; - } - - private Map<Integer, String> constructNameMap(Collection<Mapping> mappings) { - Map<Integer, String> sidNames = new HashMap<Integer, String>(); - Iterator<Mapping> it = mappings.iterator(); - while (it.hasNext()) { - Mapping mapping = it.next(); - sidNames.put(mapping.getSID(), mapping.getName()); - } - return sidNames; - } - - private static class Mapping { - private int sid; - private String name; - private byte[] bytes; - - public void setSID(int sid) { - this.sid = sid; - } - - public int getSID() { - return sid; - } - - public void setName(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void setBytes(byte[] bytes) { - this.bytes = bytes; - } - - public byte[] getBytes() { - return bytes; - } - } - - - @Override - protected void initializeFont(FontFileReader in) throws IOException { - fontFile = in; - fontFile.seekSet(0); - CFFParser parser = new CFFParser(); - fileFont = parser.parse(in.getAllBytes()).get(0); - } - - protected void readName() throws IOException { - Object familyName = fileFont.getProperty("FamilyName"); - if (familyName != null && !familyName.equals("")) { - familyNames.add(familyName.toString()); - fullName = familyName.toString(); - } else { - fullName = fileFont.getName(); - familyNames.add(fullName); - } - } - - /** - * Reads the CFFData from a given font file - * @param fontFile The font file being read - * @return The byte data found in the CFF table - */ - public static byte[] getCFFData(FontFileReader fontFile) throws IOException { - byte[] cff = fontFile.getAllBytes(); - CFFDataInput input = new CFFDataInput(fontFile.getAllBytes()); - input.readBytes(4); //OTTO - short numTables = input.readShort(); - input.readShort(); //searchRange - input.readShort(); //entrySelector - input.readShort(); //rangeShift - - for (int q = 0; q < numTables; q++) { - String tagName = new String(input.readBytes(4)); - readLong(input); //Checksum - long offset = readLong(input); - long length = readLong(input); - if (tagName.equals("CFF ")) { - cff = new byte[(int)length]; - System.arraycopy(fontFile.getAllBytes(), (int)offset, cff, 0, cff.length); - break; - } - } - return cff; - } - - private static long readLong(CFFDataInput input) throws IOException { - return (input.readCard16() << 16) | input.readCard16(); - } -} diff --git a/src/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java b/src/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java deleted file mode 100644 index 2c083add2..000000000 --- a/src/java/org/apache/fop/fonts/truetype/OTFSubSetFile.java +++ /dev/null @@ -1,1129 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.apache.fontbox.cff.CFFStandardString; -import org.apache.fontbox.cff.encoding.CFFEncoding; - -import org.apache.fop.fonts.MultiByteFont; -import org.apache.fop.fonts.cff.CFFDataReader; -import org.apache.fop.fonts.cff.CFFDataReader.CFFIndexData; -import org.apache.fop.fonts.cff.CFFDataReader.DICTEntry; -import org.apache.fop.fonts.cff.CFFDataReader.FDSelect; -import org.apache.fop.fonts.cff.CFFDataReader.FontDict; -import org.apache.fop.fonts.cff.CFFDataReader.Format0FDSelect; -import org.apache.fop.fonts.cff.CFFDataReader.Format3FDSelect; - -/** - * Reads an OpenType CFF file and generates a subset - * The OpenType specification can be found at the Microsoft - * Typography site: http://www.microsoft.com/typography/otspec/ - */ -public class OTFSubSetFile extends OTFFile { - - protected byte[] output; - protected int currentPos; - private int realSize; - - /** A map containing each glyph to be included in the subset - * with their existing and new GID's **/ - protected LinkedHashMap<Integer, Integer> subsetGlyphs = new LinkedHashMap<Integer, Integer>(); - - /** A map of the new GID to SID used to construct the charset table **/ - protected LinkedHashMap<Integer, Integer> gidToSID; - - protected CFFIndexData localIndexSubr; - protected CFFIndexData globalIndexSubr; - - /** List of subroutines to write to the local / global indexes in the subset font **/ - protected List<byte[]> subsetLocalIndexSubr; - protected List<byte[]> subsetGlobalIndexSubr; - - /** For fonts which have an FDSelect or ROS flag in Top Dict, this is used to store the - * local subroutine indexes for each group as opposed to the above subsetLocalIndexSubr */ - private ArrayList<List<byte[]>> fdSubrs; - - /** The subset FD Select table used to store the mappings between glyphs and their - * associated FDFont object which point to a private dict and local subroutines. */ - private LinkedHashMap<Integer, FDIndexReference> subsetFDSelect; - - /** A list of unique subroutines from the global / local subroutine indexes */ - protected List<Integer> localUniques; - protected List<Integer> globalUniques; - - /** A store of the number of subroutines each global / local subroutine will store **/ - protected int subsetLocalSubrCount; - protected int subsetGlobalSubrCount; - - /** A list of char string data for each glyph to be stored in the subset font **/ - protected List<byte[]> subsetCharStringsIndex; - - /** The embedded name to change in the name table **/ - protected String embeddedName; - - /** An array used to hold the string index data for the subset font **/ - protected List<byte[]> stringIndexData = new ArrayList<byte[]>(); - - /** The CFF reader object used to read data and offsets from the original font file */ - protected CFFDataReader cffReader; - - /** The class used to represent this font **/ - private MultiByteFont mbFont; - - /** The number of standard strings in CFF **/ - public static final int NUM_STANDARD_STRINGS = 391; - /** The operator used to identify a local subroutine reference */ - private static final int LOCAL_SUBROUTINE = 10; - /** The operator used to identify a global subroutine reference */ - private static final int GLOBAL_SUBROUTINE = 29; - - public OTFSubSetFile() throws IOException { - super(); - } - - public void readFont(FontFileReader in, String embeddedName, String header, - MultiByteFont mbFont) throws IOException { - this.mbFont = mbFont; - readFont(in, embeddedName, header, mbFont.getUsedGlyphs()); - } - - /** - * Reads and creates a subset of the font. - * - * @param in FontFileReader to read from - * @param name Name to be checked for in the font file - * @param header The header of the font file - * @param glyphs Map of glyphs (glyphs has old index as (Integer) key and - * new index as (Integer) value) - * @throws IOException in case of an I/O problem - */ - void readFont(FontFileReader in, String embeddedName, String header, - Map<Integer, Integer> usedGlyphs) throws IOException { - fontFile = in; - - currentPos = 0; - realSize = 0; - - this.embeddedName = embeddedName; - - //Sort by the new GID and store in a LinkedHashMap - subsetGlyphs = sortByValue(usedGlyphs); - - output = new byte[in.getFileSize()]; - - initializeFont(in); - - cffReader = new CFFDataReader(fontFile); - - //Create the CIDFontType0C data - createCFF(); - } - - private LinkedHashMap<Integer, Integer> sortByValue(Map<Integer, Integer> map) { - List<Entry<Integer, Integer>> list = new ArrayList<Entry<Integer, Integer>>(map.entrySet()); - Collections.sort(list, new Comparator<Entry<Integer, Integer>>() { - public int compare(Entry<Integer, Integer> o1, Entry<Integer, Integer> o2) { - return ((Comparable<Integer>) o1.getValue()).compareTo(o2.getValue()); - } - }); - - LinkedHashMap<Integer, Integer> result = new LinkedHashMap<Integer, Integer>(); - for (Entry<Integer, Integer> entry : list) { - result.put(entry.getKey(), entry.getValue()); - } - return result; - } - - protected void createCFF() throws IOException { - //Header - writeBytes(cffReader.getHeader()); - - //Name Index - writeIndex(Arrays.asList(embeddedName.getBytes())); - - //Keep offset of the topDICT so it can be updated once all data has been written - int topDictOffset = currentPos; - //Top DICT Index and Data - byte[] topDictIndex = cffReader.getTopDictIndex().getByteData(); - int offSize = topDictIndex[2]; - writeBytes(topDictIndex, 0, 3 + (offSize * 2)); - int topDictDataOffset = currentPos; - writeTopDICT(); - - //Create the char string index data and related local / global subroutines - if (cffReader.getFDSelect() == null) { - createCharStringData(); - } else { - createCharStringDataCID(); - } - - //If it is a CID-Keyed font, store each FD font and add each SID - List<Integer> fontNameSIDs = null; - List<Integer> subsetFDFonts = null; - if (cffReader.getFDSelect() != null) { - subsetFDFonts = getUsedFDFonts(); - fontNameSIDs = storeFDStrings(subsetFDFonts); - } - - //String index - writeStringIndex(); - - //Global subroutine index - writeIndex(subsetGlobalIndexSubr); - - //Encoding - int encodingOffset = currentPos; - writeEncoding(fileFont.getEncoding()); - - //Charset table - int charsetOffset = currentPos; - writeCharsetTable(cffReader.getFDSelect() != null); - - //FDSelect table - int fdSelectOffset = currentPos; - if (cffReader.getFDSelect() != null) { - writeFDSelect(); - } - - //Char Strings Index - int charStringOffset = currentPos; - writeIndex(subsetCharStringsIndex); - - if (cffReader.getFDSelect() == null) { - //Keep offset to modify later with the local subroutine index offset - int privateDictOffset = currentPos; - writePrivateDict(); - - //Local subroutine index - int localIndexOffset = currentPos; - writeIndex(subsetLocalIndexSubr); - - //Update the offsets - updateOffsets(topDictOffset, charsetOffset, charStringOffset, privateDictOffset, - localIndexOffset, encodingOffset); - } else { - List<Integer> privateDictOffsets = writeCIDDictsAndSubrs(subsetFDFonts); - int fdArrayOffset = writeFDArray(subsetFDFonts, privateDictOffsets, fontNameSIDs); - - updateCIDOffsets(topDictDataOffset, fdArrayOffset, fdSelectOffset, charsetOffset, - charStringOffset, encodingOffset); - } - } - - protected List<Integer> storeFDStrings(List<Integer> uniqueNewRefs) throws IOException { - ArrayList<Integer> fontNameSIDs = new ArrayList<Integer>(); - List<FontDict> fdFonts = cffReader.getFDFonts(); - for (int i = 0; i < uniqueNewRefs.size(); i++) { - FontDict fdFont = fdFonts.get(uniqueNewRefs.get(i)); - byte[] fdFontByteData = fdFont.getByteData(); - Map<String, DICTEntry> fdFontDict = cffReader.parseDictData(fdFontByteData); - fontNameSIDs.add(stringIndexData.size() + NUM_STANDARD_STRINGS); - stringIndexData.add(cffReader.getStringIndex().getValue(fdFontDict.get("FontName") - .getOperands().get(0).intValue() - NUM_STANDARD_STRINGS)); - } - return fontNameSIDs; - } - - protected void writeBytes(byte[] out) { - for (int i = 0; i < out.length; i++) { - writeByte(out[i]); - } - } - - protected void writeBytes(byte[] out, int offset, int length) { - for (int i = offset; i < offset + length; i++) { - output[currentPos++] = out[i]; - realSize++; - } - } - - private void writeEncoding(CFFEncoding encoding) throws IOException { - LinkedHashMap<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); - DICTEntry encodingEntry = topDICT.get("Encoding"); - if (encodingEntry != null && encodingEntry.getOperands().get(0).intValue() != 0 - && encodingEntry.getOperands().get(0).intValue() != 1) { - writeByte(0); - writeByte(gidToSID.size()); - for (int gid : gidToSID.keySet()) { - int code = encoding.getCode(gidToSID.get(gid)); - writeByte(code); - } - } - } - - protected void writeTopDICT() throws IOException { - LinkedHashMap<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); - List<String> topDictStringEntries = Arrays.asList("version", "Notice", "Copyright", - "FullName", "FamilyName", "Weight", "PostScript"); - for (Map.Entry<String, DICTEntry> dictEntry : topDICT.entrySet()) { - String dictKey = dictEntry.getKey(); - DICTEntry entry = dictEntry.getValue(); - //If the value is an SID, update the reference but keep the size the same - if (dictKey.equals("ROS")) { - writeROSEntry(entry); - } else if (dictKey.equals("CIDCount")) { - writeCIDCount(entry); - } else if (topDictStringEntries.contains(dictKey)) { - writeTopDictStringEntry(entry); - } else { - writeBytes(entry.getByteData()); - } - } - } - - private void writeROSEntry(DICTEntry dictEntry) throws IOException { - int sidA = dictEntry.getOperands().get(0).intValue(); - if (sidA > 390) { - stringIndexData.add(cffReader.getStringIndex().getValue(sidA - NUM_STANDARD_STRINGS)); - } - int sidAStringIndex = stringIndexData.size() + 390; - int sidB = dictEntry.getOperands().get(1).intValue(); - if (sidB > 390) { - stringIndexData.add("Identity".getBytes()); - } - int sidBStringIndex = stringIndexData.size() + 390; - byte[] cidEntryByteData = dictEntry.getByteData(); - cidEntryByteData = updateOffset(cidEntryByteData, 0, dictEntry.getOperandLengths().get(0), - sidAStringIndex); - cidEntryByteData = updateOffset(cidEntryByteData, dictEntry.getOperandLengths().get(0), - dictEntry.getOperandLengths().get(1), sidBStringIndex); - cidEntryByteData = updateOffset(cidEntryByteData, dictEntry.getOperandLengths().get(0) - + dictEntry.getOperandLengths().get(1), dictEntry.getOperandLengths().get(2), 139); - writeBytes(cidEntryByteData); - } - - protected void writeCIDCount(DICTEntry dictEntry) throws IOException { - byte[] cidCountByteData = dictEntry.getByteData(); - cidCountByteData = updateOffset(cidCountByteData, 0, dictEntry.getOperandLengths().get(0), - subsetGlyphs.size()); - writeBytes(cidCountByteData); - } - - private void writeTopDictStringEntry(DICTEntry dictEntry) throws IOException { - int sid = dictEntry.getOperands().get(0).intValue(); - if (sid > 391) { - stringIndexData.add(cffReader.getStringIndex().getValue(sid - 391)); - } - - byte[] newDictEntry = createNewRef(stringIndexData.size() + 390, dictEntry.getOperator(), - dictEntry.getOperandLength()); - writeBytes(newDictEntry); - } - - private void writeStringIndex() throws IOException { - Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); - int charsetOffset = topDICT.get("charset").getOperands().get(0).intValue(); - - gidToSID = new LinkedHashMap<Integer, Integer>(); - - for (int gid : subsetGlyphs.keySet()) { - int sid = cffReader.getSIDFromGID(charsetOffset, gid); - //Check whether the SID falls into the standard string set - if (sid < NUM_STANDARD_STRINGS) { - gidToSID.put(subsetGlyphs.get(gid), sid); - if (mbFont != null) { - mbFont.mapUsedGlyphName(subsetGlyphs.get(gid), - CFFStandardString.getName(sid)); - } - } else { - int index = sid - NUM_STANDARD_STRINGS; - if (index <= cffReader.getStringIndex().getNumObjects()) { - if (mbFont != null) { - mbFont.mapUsedGlyphName(subsetGlyphs.get(gid), - new String(cffReader.getStringIndex().getValue(index))); - } - gidToSID.put(subsetGlyphs.get(gid), stringIndexData.size() + 391); - stringIndexData.add(cffReader.getStringIndex().getValue(index)); - } else { - if (mbFont != null) { - mbFont.mapUsedGlyphName(subsetGlyphs.get(gid), ".notdef"); - } - gidToSID.put(subsetGlyphs.get(gid), index); - } - } - } - //Write the String Index - writeIndex(stringIndexData); - } - - protected void createCharStringDataCID() throws IOException { - CFFIndexData charStringsIndex = cffReader.getCharStringIndex(); - - FDSelect fontDictionary = cffReader.getFDSelect(); - if (fontDictionary instanceof Format0FDSelect) { - throw new UnsupportedOperationException("OTF CFF CID Format0 currently not implemented"); - } else if (fontDictionary instanceof Format3FDSelect) { - Format3FDSelect fdSelect = (Format3FDSelect)fontDictionary; - Map<Integer, Integer> subsetGroups = new HashMap<Integer, Integer>(); - - List<Integer> uniqueGroups = new ArrayList<Integer>(); - for (int gid : subsetGlyphs.keySet()) { - Set<Integer> rangeKeys = fdSelect.getRanges().keySet(); - Integer[] ranges = rangeKeys.toArray(new Integer[rangeKeys.size()]); - for (int i = 0; i < ranges.length; i++) { - int nextRange = -1; - if (i < ranges.length - 1) { - nextRange = ranges[i + 1]; - } else { - nextRange = fdSelect.getSentinelGID(); - } - if (gid >= ranges[i] && gid < nextRange) { - subsetGroups.put(gid, fdSelect.getRanges().get(ranges[i])); - if (!uniqueGroups.contains(fdSelect.getRanges().get(ranges[i]))) { - uniqueGroups.add(fdSelect.getRanges().get(ranges[i])); - } - } - } - } - - //Prepare resources - globalIndexSubr = cffReader.getGlobalIndexSubr(); - - //Create the new char string index - subsetCharStringsIndex = new ArrayList<byte[]>(); - - globalUniques = new ArrayList<Integer>(); - - subsetFDSelect = new LinkedHashMap<Integer, FDIndexReference>(); - - List<List<Integer>> foundLocalUniques = new ArrayList<List<Integer>>(); - for (int i = 0; i < uniqueGroups.size(); i++) { - foundLocalUniques.add(new ArrayList<Integer>()); - } - for (int gid : subsetGlyphs.keySet()) { - int group = subsetGroups.get(gid); - localIndexSubr = cffReader.getFDFonts().get(group).getLocalSubrData(); - localUniques = foundLocalUniques.get(uniqueGroups.indexOf(subsetGroups.get(gid))); - - FDIndexReference newFDReference = new FDIndexReference( - uniqueGroups.indexOf(subsetGroups.get(gid)), subsetGroups.get(gid)); - subsetFDSelect.put(subsetGlyphs.get(gid), newFDReference); - byte[] data = charStringsIndex.getValue(gid); - preScanForSubsetIndexSize(data); - } - - //Create the two lists which are to store the local and global subroutines - subsetGlobalIndexSubr = new ArrayList<byte[]>(); - - fdSubrs = new ArrayList<List<byte[]>>(); - subsetGlobalSubrCount = globalUniques.size(); - globalUniques.clear(); - localUniques = null; - - for (int l = 0; l < foundLocalUniques.size(); l++) { - fdSubrs.add(new ArrayList<byte[]>()); - } - List<List<Integer>> foundLocalUniquesB = new ArrayList<List<Integer>>(); - for (int k = 0; k < uniqueGroups.size(); k++) { - foundLocalUniquesB.add(new ArrayList<Integer>()); - } - for (Integer gid : subsetGlyphs.keySet()) { - int group = subsetGroups.get(gid); - localIndexSubr = cffReader.getFDFonts().get(group).getLocalSubrData(); - localUniques = foundLocalUniquesB.get(subsetFDSelect.get(subsetGlyphs.get(gid)).getNewFDIndex()); - byte[] data = charStringsIndex.getValue(gid); - subsetLocalIndexSubr = fdSubrs.get(subsetFDSelect.get(subsetGlyphs.get(gid)).getNewFDIndex()); - subsetLocalSubrCount = foundLocalUniques.get(subsetFDSelect.get(subsetGlyphs.get(gid)) - .getNewFDIndex()).size(); - data = readCharStringData(data, subsetLocalSubrCount); - subsetCharStringsIndex.add(data); - } - } - } - - protected void writeFDSelect() { - writeByte(0); //Format - for (Integer gid : subsetFDSelect.keySet()) { - writeByte(subsetFDSelect.get(gid).getNewFDIndex()); - } - } - - protected List<Integer> getUsedFDFonts() { - List<Integer> uniqueNewRefs = new ArrayList<Integer>(); - for (int gid : subsetFDSelect.keySet()) { - int fdIndex = subsetFDSelect.get(gid).getOldFDIndex(); - if (!uniqueNewRefs.contains(fdIndex)) { - uniqueNewRefs.add(fdIndex); - } - } - return uniqueNewRefs; - } - - protected List<Integer> writeCIDDictsAndSubrs(List<Integer> uniqueNewRefs) - throws IOException { - List<Integer> privateDictOffsets = new ArrayList<Integer>(); - List<FontDict> fdFonts = cffReader.getFDFonts(); - for (int i = 0; i < uniqueNewRefs.size(); i++) { - FontDict curFDFont = fdFonts.get(uniqueNewRefs.get(i)); - HashMap<String, DICTEntry> fdPrivateDict = cffReader.parseDictData( - curFDFont.getPrivateDictData()); - int privateDictOffset = currentPos; - privateDictOffsets.add(privateDictOffset); - byte[] fdPrivateDictByteData = curFDFont.getPrivateDictData(); - if (fdPrivateDict.get("Subrs") != null) { - int encodingValue = 0; - if (fdPrivateDict.get("Subrs").getOperandLength() == 1) { - encodingValue = 139; - } - fdPrivateDictByteData = updateOffset(fdPrivateDictByteData, fdPrivateDict.get("Subrs").getOffset(), - fdPrivateDict.get("Subrs").getOperandLength(), - fdPrivateDictByteData.length + encodingValue); - } - writeBytes(fdPrivateDictByteData); - writeIndex(fdSubrs.get(i)); - } - return privateDictOffsets; - } - - protected int writeFDArray(List<Integer> uniqueNewRefs, List<Integer> privateDictOffsets, - List<Integer> fontNameSIDs) - throws IOException { - int offset = currentPos; - List<FontDict> fdFonts = cffReader.getFDFonts(); - - writeCard16(uniqueNewRefs.size()); - writeByte(1); //Offset size - writeByte(1); //First offset - - int count = 1; - for (int i = 0; i < uniqueNewRefs.size(); i++) { - FontDict fdFont = fdFonts.get(uniqueNewRefs.get(i)); - count += fdFont.getByteData().length; - writeByte(count); - } - - for (int i = 0; i < uniqueNewRefs.size(); i++) { - FontDict fdFont = fdFonts.get(uniqueNewRefs.get(i)); - byte[] fdFontByteData = fdFont.getByteData(); - Map<String, DICTEntry> fdFontDict = cffReader.parseDictData(fdFontByteData); - //Update the SID to the FontName - fdFontByteData = updateOffset(fdFontByteData, fdFontDict.get("FontName").getOffset() - 1, - fdFontDict.get("FontName").getOperandLengths().get(0), - fontNameSIDs.get(i)); - //Update the Private dict reference - fdFontByteData = updateOffset(fdFontByteData, fdFontDict.get("Private").getOffset() - + fdFontDict.get("Private").getOperandLengths().get(0), - fdFontDict.get("Private").getOperandLengths().get(1), - privateDictOffsets.get(i)); - writeBytes(fdFontByteData); - } - return offset; - } - - private class FDIndexReference { - private int newFDIndex; - private int oldFDIndex; - - public FDIndexReference(int newFDIndex, int oldFDIndex) { - this.newFDIndex = newFDIndex; - this.oldFDIndex = oldFDIndex; - } - - public int getNewFDIndex() { - return newFDIndex; - } - - public int getOldFDIndex() { - return oldFDIndex; - } - } - - private void createCharStringData() throws IOException { - Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); - - CFFIndexData charStringsIndex = cffReader.getCharStringIndex(); - - DICTEntry privateEntry = topDICT.get("Private"); - if (privateEntry != null) { - int privateOffset = privateEntry.getOperands().get(1).intValue(); - Map<String, DICTEntry> privateDICT = cffReader.getPrivateDict(privateEntry); - - if (privateDICT.get("Subrs") != null) { - int localSubrOffset = privateOffset + privateDICT.get("Subrs").getOperands().get(0).intValue(); - localIndexSubr = cffReader.readIndex(localSubrOffset); - } else { - localIndexSubr = cffReader.readIndex(null); - } - } - - globalIndexSubr = cffReader.getGlobalIndexSubr(); - - //Create the two lists which are to store the local and global subroutines - subsetLocalIndexSubr = new ArrayList<byte[]>(); - subsetGlobalIndexSubr = new ArrayList<byte[]>(); - - //Create the new char string index - subsetCharStringsIndex = new ArrayList<byte[]>(); - - localUniques = new ArrayList<Integer>(); - globalUniques = new ArrayList<Integer>(); - - for (int gid : subsetGlyphs.keySet()) { - byte[] data = charStringsIndex.getValue(gid); - preScanForSubsetIndexSize(data); - } - - //Store the size of each subset index and clear the unique arrays - subsetLocalSubrCount = localUniques.size(); - subsetGlobalSubrCount = globalUniques.size(); - localUniques.clear(); - globalUniques.clear(); - - for (int gid : subsetGlyphs.keySet()) { - byte[] data = charStringsIndex.getValue(gid); - //Retrieve modified char string data and fill local / global subroutine arrays - data = readCharStringData(data, subsetLocalSubrCount); - subsetCharStringsIndex.add(data); - } - } - - private void preScanForSubsetIndexSize(byte[] data) throws IOException { - boolean hasLocalSubroutines = localIndexSubr != null && localIndexSubr.getNumObjects() > 0; - boolean hasGlobalSubroutines = globalIndexSubr != null && globalIndexSubr.getNumObjects() > 0; - BytesNumber operand = new BytesNumber(-1, -1); - for (int dataPos = 0; dataPos < data.length; dataPos++) { - int b0 = data[dataPos] & 0xff; - if (b0 == LOCAL_SUBROUTINE && hasLocalSubroutines) { - int subrNumber = getSubrNumber(localIndexSubr.getNumObjects(), operand.getNumber()); - - if (!localUniques.contains(subrNumber) && subrNumber < localIndexSubr.getNumObjects()) { - localUniques.add(subrNumber); - byte[] subr = localIndexSubr.getValue(subrNumber); - preScanForSubsetIndexSize(subr); - } - operand.clearNumber(); - } else if (b0 == GLOBAL_SUBROUTINE && hasGlobalSubroutines) { - int subrNumber = getSubrNumber(globalIndexSubr.getNumObjects(), operand.getNumber()); - - if (!globalUniques.contains(subrNumber) && subrNumber < globalIndexSubr.getNumObjects()) { - globalUniques.add(subrNumber); - byte[] subr = globalIndexSubr.getValue(subrNumber); - preScanForSubsetIndexSize(subr); - } - operand.clearNumber(); - } else if ((b0 >= 0 && b0 <= 27) || (b0 >= 29 && b0 <= 31)) { - operand.clearNumber(); - if (b0 == 19 || b0 == 20) { - dataPos += 1; - } - } else if (b0 == 28 || (b0 >= 32 && b0 <= 255)) { - operand = readNumber(b0, data, dataPos); - dataPos += operand.getNumBytes() - 1; - } - } - } - - private int getSubrNumber(int numSubroutines, int operand) { - int bias = getBias(numSubroutines); - return bias + operand; - } - - private byte[] readCharStringData(byte[] data, int subsetLocalSubrCount) throws IOException { - boolean hasLocalSubroutines = localIndexSubr != null && localIndexSubr.getNumObjects() > 0; - boolean hasGlobalSubroutines = globalIndexSubr != null && globalIndexSubr.getNumObjects() > 0; - BytesNumber operand = new BytesNumber(-1, -1); - for (int dataPos = 0; dataPos < data.length; dataPos++) { - int b0 = data[dataPos] & 0xff; - if (b0 == 10 && hasLocalSubroutines) { - int subrNumber = getSubrNumber(localIndexSubr.getNumObjects(), operand.getNumber()); - - int newRef = getNewRefForReference(subrNumber, localUniques, localIndexSubr, subsetLocalIndexSubr, - subsetLocalSubrCount); - - if (newRef != -1) { - byte[] newData = constructNewRefData(dataPos, data, operand, subsetLocalSubrCount, - newRef, new int[] {10}); - dataPos -= data.length - newData.length; - data = newData; - } - - operand.clearNumber(); - } else if (b0 == 29 && hasGlobalSubroutines) { - int subrNumber = getSubrNumber(globalIndexSubr.getNumObjects(), operand.getNumber()); - - int newRef = getNewRefForReference(subrNumber, globalUniques, globalIndexSubr, subsetGlobalIndexSubr, - subsetGlobalSubrCount); - - if (newRef != -1) { - byte[] newData = constructNewRefData(dataPos, data, operand, subsetGlobalSubrCount, - newRef, new int[] {29}); - dataPos -= (data.length - newData.length); - data = newData; - } - - operand.clearNumber(); - } else if ((b0 >= 0 && b0 <= 27) || (b0 >= 29 && b0 <= 31)) { - operand.clearNumber(); - if (b0 == 19) { - dataPos += 1; - } - } else if (b0 == 28 || (b0 >= 32 && b0 <= 255)) { - operand = readNumber(b0, data, dataPos); - dataPos += operand.getNumBytes() - 1; - } - } - - //Return the data with the modified references to our arrays - return data; - } - - private int getNewRefForReference(int subrNumber, List<Integer> uniquesArray, - CFFIndexData indexSubr, List<byte[]> subsetIndexSubr, int subrCount) throws IOException { - int newRef = -1; - if (!uniquesArray.contains(subrNumber)) { - if (subrNumber < indexSubr.getNumObjects()) { - byte[] subr = indexSubr.getValue(subrNumber); - subr = readCharStringData(subr, subrCount); - if (!uniquesArray.contains(subrNumber)) { - uniquesArray.add(subrNumber); - subsetIndexSubr.add(subr); - newRef = subsetIndexSubr.size() - 1; - } else { - newRef = uniquesArray.indexOf(subrNumber); - } - } - } else { - newRef = uniquesArray.indexOf(subrNumber); - } - return newRef; - } - - private int getBias(int subrCount) { - if (subrCount < 1240) { - return 107; - } else if (subrCount < 33900) { - return 1131; - } else { - return 32768; - } - } - - private byte[] constructNewRefData(int curDataPos, byte[] currentData, BytesNumber operand, - int fullSubsetIndexSize, int curSubsetIndexSize, int[] operatorCode) { - //Create the new array with the modified reference - byte[] newData; - int startRef = curDataPos - operand.getNumBytes(); - int length = operand.getNumBytes() + 1; - byte[] preBytes = new byte[startRef]; - System.arraycopy(currentData, 0, preBytes, 0, startRef); - int newBias = getBias(fullSubsetIndexSize); - int newRef = curSubsetIndexSize - newBias; - byte[] newRefBytes = createNewRef(newRef, operatorCode, -1); - newData = concatArray(preBytes, newRefBytes); - byte[] postBytes = new byte[currentData.length - (startRef + length)]; - System.arraycopy(currentData, startRef + length, postBytes, 0, - currentData.length - (startRef + length)); - return concatArray(newData, postBytes); - } - - public static byte[] createNewRef(int newRef, int[] operatorCode, int forceLength) { - byte[] newRefBytes; - int sizeOfOperator = operatorCode.length; - if ((forceLength == -1 && newRef <= 107) || forceLength == 1) { - newRefBytes = new byte[1 + sizeOfOperator]; - //The index values are 0 indexed - newRefBytes[0] = (byte)(newRef + 139); - for (int i = 0; i < operatorCode.length; i++) { - newRefBytes[1 + i] = (byte)operatorCode[i]; - } - } else if ((forceLength == -1 && newRef <= 1131) || forceLength == 2) { - newRefBytes = new byte[2 + sizeOfOperator]; - if (newRef <= 363) { - newRefBytes[0] = (byte)247; - } else if (newRef <= 619) { - newRefBytes[0] = (byte)248; - } else if (newRef <= 875) { - newRefBytes[0] = (byte)249; - } else { - newRefBytes[0] = (byte)250; - } - newRefBytes[1] = (byte)(newRef - 108); - for (int i = 0; i < operatorCode.length; i++) { - newRefBytes[2 + i] = (byte)operatorCode[i]; - } - } else if ((forceLength == -1 && newRef <= 32767) || forceLength == 3) { - newRefBytes = new byte[3 + sizeOfOperator]; - newRefBytes[0] = 28; - newRefBytes[1] = (byte)(newRef >> 8); - newRefBytes[2] = (byte)newRef; - for (int i = 0; i < operatorCode.length; i++) { - newRefBytes[3 + i] = (byte)operatorCode[i]; - } - } else { - newRefBytes = new byte[5 + sizeOfOperator]; - newRefBytes[0] = 29; - newRefBytes[1] = (byte)(newRef >> 24); - newRefBytes[2] = (byte)(newRef >> 16); - newRefBytes[3] = (byte)(newRef >> 8); - newRefBytes[4] = (byte)newRef; - for (int i = 0; i < operatorCode.length; i++) { - newRefBytes[5 + i] = (byte)operatorCode[i]; - } - } - return newRefBytes; - } - - public static byte[] concatArray(byte[] a, byte[] b) { - int aLen = a.length; - int bLen = b.length; - byte[] c = new byte[aLen + bLen]; - System.arraycopy(a, 0, c, 0, aLen); - System.arraycopy(b, 0, c, aLen, bLen); - return c; - } - - protected int writeIndex(List<byte[]> dataArray) { - int hdrTotal = 3; - //2 byte number of items - this.writeCard16(dataArray.size()); - //Offset Size: 1 byte = 256, 2 bytes = 65536 etc. - int totLength = 0; - for (int i = 0; i < dataArray.size(); i++) { - totLength += dataArray.get(i).length; - } - int offSize = 1; - if (totLength <= (1 << 8)) { - offSize = 1; - } else if (totLength <= (1 << 16)) { - offSize = 2; - } else if (totLength <= (1 << 24)) { - offSize = 3; - } else { - offSize = 4; - } - this.writeByte(offSize); - //Count the first offset 1 - hdrTotal += offSize; - int total = 0; - for (int i = 0; i < dataArray.size(); i++) { - hdrTotal += offSize; - int length = dataArray.get(i).length; - switch (offSize) { - case 1: - if (i == 0) { - writeByte(1); - } - total += length; - writeByte(total + 1); - break; - case 2: - if (i == 0) { - writeCard16(1); - } - total += length; - writeCard16(total + 1); - break; - case 3: - if (i == 0) { - writeThreeByteNumber(1); - } - total += length; - writeThreeByteNumber(total + 1); - break; - case 4: - if (i == 0) { - writeULong(1); - } - total += length; - writeULong(total + 1); - break; - default: - throw new AssertionError("Offset Size was not an expected value."); - } - } - for (int i = 0; i < dataArray.size(); i++) { - writeBytes(dataArray.get(i)); - } - return hdrTotal + total; - } - - private BytesNumber readNumber(int b0, byte[] input, int curPos) throws IOException { - if (b0 == 28) { - int b1 = input[curPos + 1] & 0xff; - int b2 = input[curPos + 2] & 0xff; - return new BytesNumber(Integer.valueOf((short) (b1 << 8 | b2)), 3); - } else if (b0 >= 32 && b0 <= 246) { - return new BytesNumber(Integer.valueOf(b0 - 139), 1); - } else if (b0 >= 247 && b0 <= 250) { - int b1 = input[curPos + 1] & 0xff; - return new BytesNumber(Integer.valueOf((b0 - 247) * 256 + b1 + 108), 2); - } else if (b0 >= 251 && b0 <= 254) { - int b1 = input[curPos + 1] & 0xff; - return new BytesNumber(Integer.valueOf(-(b0 - 251) * 256 - b1 - 108), 2); - } else if (b0 == 255) { - int b1 = input[curPos + 1] & 0xff; - int b2 = input[curPos + 2] & 0xff; - return new BytesNumber(Integer.valueOf((short)(b1 << 8 | b2)), 5); - } else { - throw new IllegalArgumentException(); - } - } - - /** - * A class used to store the last number operand and also it's size in bytes - */ - static class BytesNumber { - private int number; - private int numBytes; - - public BytesNumber(int number, int numBytes) { - this.number = number; - this.numBytes = numBytes; - } - - public int getNumber() { - return this.number; - } - - public int getNumBytes() { - return this.numBytes; - } - - public void clearNumber() { - this.number = -1; - this.numBytes = -1; - } - - public String toString() { - return Integer.toString(number); - } - - @Override - public boolean equals(Object entry) { - assert entry instanceof BytesNumber; - BytesNumber bnEntry = (BytesNumber)entry; - return this.number == bnEntry.getNumber() - && this.numBytes == bnEntry.getNumBytes(); - } - - @Override - public int hashCode() { - int hash = 1; - hash = hash * 17 + number; - hash = hash * 31 + numBytes; - return hash; - } - } - - private void writeCharsetTable(boolean cidFont) throws IOException { - writeByte(0); - for (int gid : gidToSID.keySet()) { - if (cidFont && gid == 0) { - continue; - } - writeCard16((cidFont) ? gid : gidToSID.get(gid)); - } - } - - protected void writePrivateDict() throws IOException { - Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); - - DICTEntry privateEntry = topDICT.get("Private"); - if (privateEntry != null) { - writeBytes(cffReader.getPrivateDictBytes(privateEntry)); - } - } - - protected void updateOffsets(int topDictOffset, int charsetOffset, int charStringOffset, - int privateDictOffset, int localIndexOffset, int encodingOffset) - throws IOException { - Map<String, DICTEntry> topDICT = cffReader.getTopDictEntries(); - Map<String, DICTEntry> privateDICT = null; - - DICTEntry privateEntry = topDICT.get("Private"); - if (privateEntry != null) { - privateDICT = cffReader.getPrivateDict(privateEntry); - } - - int dataPos = 3 + (cffReader.getTopDictIndex().getOffSize() - * cffReader.getTopDictIndex().getOffsets().length); - int dataTopDictOffset = topDictOffset + dataPos; - - updateFixedOffsets(topDICT, dataTopDictOffset, charsetOffset, charStringOffset, encodingOffset); - - if (privateDICT != null) { - //Private index offset in the top dict - int oldPrivateOffset = dataTopDictOffset + privateEntry.getOffset(); - output = updateOffset(output, oldPrivateOffset + privateEntry.getOperandLengths().get(0), - privateEntry.getOperandLengths().get(1), privateDictOffset); - - //Update the local subroutine index offset in the private dict - DICTEntry subroutines = privateDICT.get("Subrs"); - if (subroutines != null) { - int oldLocalSubrOffset = privateDictOffset + subroutines.getOffset(); - //Value needs to be converted to -139 etc. - int encodeValue = 0; - if (subroutines.getOperandLength() == 1) { - encodeValue = 139; - } - output = updateOffset(output, oldLocalSubrOffset, subroutines.getOperandLength(), - (localIndexOffset - privateDictOffset) + encodeValue); - } - } - } - - protected void updateFixedOffsets(Map<String, DICTEntry> topDICT, int dataTopDictOffset, - int charsetOffset, int charStringOffset, int encodingOffset) { - //Charset offset in the top dict - DICTEntry charset = topDICT.get("charset"); - int oldCharsetOffset = dataTopDictOffset + charset.getOffset(); - output = updateOffset(output, oldCharsetOffset, charset.getOperandLength(), charsetOffset); - - //Char string index offset in the private dict - DICTEntry charString = topDICT.get("CharStrings"); - int oldCharStringOffset = dataTopDictOffset + charString.getOffset(); - output = updateOffset(output, oldCharStringOffset, charString.getOperandLength(), charStringOffset); - - DICTEntry encodingEntry = topDICT.get("Encoding"); - if (encodingEntry != null && encodingEntry.getOperands().get(0).intValue() != 0 - && encodingEntry.getOperands().get(0).intValue() != 1) { - int oldEncodingOffset = dataTopDictOffset + encodingEntry.getOffset(); - output = updateOffset(output, oldEncodingOffset, encodingEntry.getOperandLength(), encodingOffset); - } - } - - protected void updateCIDOffsets(int topDictDataOffset, int fdArrayOffset, int fdSelectOffset, - int charsetOffset, int charStringOffset, int encodingOffset) { - LinkedHashMap<String, DICTEntry> topDict = cffReader.getTopDictEntries(); - - DICTEntry fdArrayEntry = topDict.get("FDArray"); - if (fdArrayEntry != null) { - output = updateOffset(output, topDictDataOffset + fdArrayEntry.getOffset() - 1, - fdArrayEntry.getOperandLength(), fdArrayOffset); - } - - DICTEntry fdSelect = topDict.get("FDSelect"); - if (fdSelect != null) { - output = updateOffset(output, topDictDataOffset + fdSelect.getOffset() - 1, - fdSelect.getOperandLength(), fdSelectOffset); - } - - updateFixedOffsets(topDict, topDictDataOffset, charsetOffset, charStringOffset, encodingOffset); - } - - protected byte[] updateOffset(byte[] out, int position, int length, int replacement) { - switch (length) { - case 1: - out[position] = (byte)(replacement & 0xFF); - break; - case 2: - if (replacement <= 363) { - out[position] = (byte)247; - } else if (replacement <= 619) { - out[position] = (byte)248; - } else if (replacement <= 875) { - out[position] = (byte)249; - } else { - out[position] = (byte)250; - } - out[position + 1] = (byte)(replacement - 108); - break; - case 3: - out[position] = (byte)28; - out[position + 1] = (byte)((replacement >> 8) & 0xFF); - out[position + 2] = (byte)(replacement & 0xFF); - break; - case 5: - out[position] = (byte)29; - out[position + 1] = (byte)((replacement >> 24) & 0xFF); - out[position + 2] = (byte)((replacement >> 16) & 0xFF); - out[position + 3] = (byte)((replacement >> 8) & 0xFF); - out[position + 4] = (byte)(replacement & 0xFF); - break; - default: - } - return out; - } - - /** - * Appends a byte to the output array, - * updates currentPost but not realSize - */ - protected void writeByte(int b) { - output[currentPos++] = (byte)b; - realSize++; - } - - /** - * Appends a USHORT to the output array, - * updates currentPost but not realSize - */ - protected void writeCard16(int s) { - byte b1 = (byte)((s >> 8) & 0xff); - byte b2 = (byte)(s & 0xff); - writeByte(b1); - writeByte(b2); - } - - private void writeThreeByteNumber(int s) { - byte b1 = (byte)((s >> 16) & 0xFF); - byte b2 = (byte)((s >> 8) & 0xFF); - byte b3 = (byte)(s & 0xFF); - writeByte(b1); - writeByte(b2); - writeByte(b3); - } - - /** - * Appends a ULONG to the output array, - * at the given position - */ - private void writeULong(int s) { - byte b1 = (byte)((s >> 24) & 0xff); - byte b2 = (byte)((s >> 16) & 0xff); - byte b3 = (byte)((s >> 8) & 0xff); - byte b4 = (byte)(s & 0xff); - writeByte(b1); - writeByte(b2); - writeByte(b3); - writeByte(b4); - } - - /** - * Returns a subset of the fonts (readFont() MUST be called first in order to create the - * subset). - * @return byte array - */ - public byte[] getFontSubset() { - byte[] ret = new byte[realSize]; - System.arraycopy(output, 0, ret, 0, realSize); - return ret; - } - - /** - * Returns the parsed CFF data for the original font. - * @return The CFFDataReader contaiing the parsed data - */ - public CFFDataReader getCFFReader() { - return cffReader; - } -} diff --git a/src/java/org/apache/fop/fonts/truetype/OpenFont.java b/src/java/org/apache/fop/fonts/truetype/OpenFont.java deleted file mode 100644 index e94f31bb1..000000000 --- a/src/java/org/apache/fop/fonts/truetype/OpenFont.java +++ /dev/null @@ -1,2006 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.awt.Rectangle; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.BitSet; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.xmlgraphics.fonts.Glyphs; - -import org.apache.fop.complexscripts.fonts.AdvancedTypographicTableFormatException; -import org.apache.fop.complexscripts.fonts.GlyphDefinitionTable; -import org.apache.fop.complexscripts.fonts.GlyphPositioningTable; -import org.apache.fop.complexscripts.fonts.GlyphSubstitutionTable; -import org.apache.fop.complexscripts.fonts.OTFAdvancedTypographicTableReader; -import org.apache.fop.fonts.CMapSegment; -import org.apache.fop.fonts.FontUtil; -import org.apache.fop.fonts.MultiByteFont; - -public abstract class OpenFont { - - static final byte NTABS = 24; - static final int MAX_CHAR_CODE = 255; - static final int ENC_BUF_SIZE = 1024; - - private static final String[] MAC_GLYPH_ORDERING = { - /* 0x000 */ - ".notdef", ".null", "nonmarkingreturn", "space", - "exclam", "quotedbl", "numbersign", "dollar", - "percent", "ampersand", "quotesingle", "parenleft", - "parenright", "asterisk", "plus", "comma", - /* 0x010 */ - "hyphen", "period", "slash", "zero", - "one", "two", "three", "four", - "five", "six", "seven", "eight", - "nine", "colon", "semicolon", "less", - /* 0x020 */ - "equal", "greater", "question", "at", - "A", "B", "C", "D", - "E", "F", "G", "H", - "I", "J", "K", "L", - /* 0x030 */ - "M", "N", "O", "P", - "Q", "R", "S", "T", - "U", "V", "W", "X", - "Y", "Z", "bracketleft", "backslash", - /* 0x040 */ - "bracketright", "asciicircum", "underscore", "grave", - "a", "b", "c", "d", - "e", "f", "g", "h", - "i", "j", "k", "l", - /* 0x050 */ - "m", "n", "o", "p", - "q", "r", "s", "t", - "u", "v", "w", "x", - "y", "z", "braceleft", "bar", - /* 0x060 */ - "braceright", "asciitilde", "Adieresis", "Aring", - "Ccedilla", "Eacute", "Ntilde", "Odieresis", - "Udieresis", "aacute", "agrave", "acircumflex", - "adieresis", "atilde", "aring", "ccedilla", - /* 0x070 */ - "eacute", "egrave", "ecircumflex", "edieresis", - "iacute", "igrave", "icircumflex", "idieresis", - "ntilde", "oacute", "ograve", "ocircumflex", - "odieresis", "otilde", "uacute", "ugrave", - /* 0x080 */ - "ucircumflex", "udieresis", "dagger", "degree", - "cent", "sterling", "section", "bullet", - "paragraph", "germandbls", "registered", "copyright", - "trademark", "acute", "dieresis", "notequal", - /* 0x090 */ - "AE", "Oslash", "infinity", "plusminus", - "lessequal", "greaterequal", "yen", "mu", - "partialdiff", "summation", "product", "pi", - "integral", "ordfeminine", "ordmasculine", "Omega", - /* 0x0A0 */ - "ae", "oslash", "questiondown", "exclamdown", - "logicalnot", "radical", "florin", "approxequal", - "Delta", "guillemotleft", "guillemotright", "ellipsis", - "nonbreakingspace", "Agrave", "Atilde", "Otilde", - /* 0x0B0 */ - "OE", "oe", "endash", "emdash", - "quotedblleft", "quotedblright", "quoteleft", "quoteright", - "divide", "lozenge", "ydieresis", "Ydieresis", - "fraction", "currency", "guilsinglleft", "guilsinglright", - /* 0x0C0 */ - "fi", "fl", "daggerdbl", "periodcentered", - "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", - "Ecircumflex", "Aacute", "Edieresis", "Egrave", - "Iacute", "Icircumflex", "Idieresis", "Igrave", - /* 0x0D0 */ - "Oacute", "Ocircumflex", "apple", "Ograve", - "Uacute", "Ucircumflex", "Ugrave", "dotlessi", - "circumflex", "tilde", "macron", "breve", - "dotaccent", "ring", "cedilla", "hungarumlaut", - /* 0x0E0 */ - "ogonek", "caron", "Lslash", "lslash", - "Scaron", "scaron", "Zcaron", "zcaron", - "brokenbar", "Eth", "eth", "Yacute", - "yacute", "Thorn", "thorn", "minus", - /* 0x0F0 */ - "multiply", "onesuperior", "twosuperior", "threesuperior", - "onehalf", "onequarter", "threequarters", "franc", - "Gbreve", "gbreve", "Idotaccent", "Scedilla", - "scedilla", "Cacute", "cacute", "Ccaron", - /* 0x100 */ - "ccaron", "dcroat" - }; - - /** The FontFileReader used to read this TrueType font. */ - protected FontFileReader fontFile; - - /** Set to true to get even more debug output than with level DEBUG */ - public static final boolean TRACE_ENABLED = false; - - private static final String ENCODING = "WinAnsiEncoding"; // Default encoding - - private static final short FIRST_CHAR = 0; - - protected boolean useKerning; - private boolean isEmbeddable = true; - private boolean hasSerifs = true; - /** - * Table directory - */ - protected Map<OFTableName, OFDirTabEntry> dirTabs; - - private Map<Integer, Map<Integer, Integer>> kerningTab; // for CIDs - private Map<Integer, Map<Integer, Integer>> ansiKerningTab; // For winAnsiEncoding - private List<CMapSegment> cmaps; - protected List<UnicodeMapping> unicodeMappings; - - private int upem; // unitsPerEm from "head" table - protected int nhmtx; // Number of horizontal metrics - private PostScriptVersion postScriptVersion; - protected int locaFormat; - /** - * Offset to last loca - */ - protected long lastLoca; - protected int numberOfGlyphs; // Number of glyphs in font (read from "maxp" table) - - /** - * Contains glyph data - */ - protected OFMtxEntry[] mtxTab; // Contains glyph data - - protected String postScriptName = ""; - protected String fullName = ""; - protected String notice = ""; - protected final Set<String> familyNames = new HashSet<String>(); - protected String subFamilyName = ""; - protected boolean cid = true; - - private long italicAngle; - private long isFixedPitch; - private int fontBBox1; - private int fontBBox2; - private int fontBBox3; - private int fontBBox4; - private int capHeight; - private int os2CapHeight; - private int underlinePosition; - private int underlineThickness; - private int strikeoutPosition; - private int strikeoutThickness; - private int xHeight; - private int os2xHeight; - //Effective ascender/descender - private int ascender; - private int descender; - //Ascender/descender from hhea table - private int hheaAscender; - private int hheaDescender; - //Ascender/descender from OS/2 table - private int os2Ascender; - private int os2Descender; - private int usWeightClass; - - private short lastChar; - - private int[] ansiWidth; - private Map<Integer, List<Integer>> ansiIndex; - - // internal mapping of glyph indexes to unicode indexes - // used for quick mappings in this class - private final Map<Integer, Integer> glyphToUnicodeMap = new HashMap<Integer, Integer>(); - private final Map<Integer, Integer> unicodeToGlyphMap = new HashMap<Integer, Integer>(); - - private boolean isCFF; - - // advanced typographic table support - protected boolean useAdvanced; - protected OTFAdvancedTypographicTableReader advancedTableReader; - - /** - * Version of the PostScript table (<q>post</q>) contained in this font. - */ - public static enum PostScriptVersion { - /** PostScript table version 1.0. */ - V1, - /** PostScript table version 2.0. */ - V2, - /** PostScript table version 3.0. */ - V3, - /** Unknown version of the PostScript table. */ - UNKNOWN; - } - - /** - * logging instance - */ - protected Log log = LogFactory.getLog(TTFFile.class); - - public OpenFont() { - this(true, false); - } - - /** - * Constructor - * @param useKerning true if kerning data should be loaded - * @param useAdvanced true if advanced typographic tables should be loaded - */ - public OpenFont(boolean useKerning, boolean useAdvanced) { - this.useKerning = useKerning; - this.useAdvanced = useAdvanced; - } - - /** - * Key-value helper class. - */ - static final class UnicodeMapping implements Comparable { - - private final int unicodeIndex; - private final int glyphIndex; - - UnicodeMapping(OpenFont font, int glyphIndex, int unicodeIndex) { - this.unicodeIndex = unicodeIndex; - this.glyphIndex = glyphIndex; - font.glyphToUnicodeMap.put(new Integer(glyphIndex), new Integer(unicodeIndex)); - font.unicodeToGlyphMap.put(new Integer(unicodeIndex), new Integer(glyphIndex)); - } - - /** - * Returns the glyphIndex. - * @return the glyph index - */ - public int getGlyphIndex() { - return glyphIndex; - } - - /** - * Returns the unicodeIndex. - * @return the Unicode index - */ - public int getUnicodeIndex() { - return unicodeIndex; - } - - - /** {@inheritDoc} */ - public int hashCode() { - int hc = unicodeIndex; - hc = 19 * hc + (hc ^ glyphIndex); - return hc; - } - - /** {@inheritDoc} */ - public boolean equals(Object o) { - if (o instanceof UnicodeMapping) { - UnicodeMapping m = (UnicodeMapping) o; - if (unicodeIndex != m.unicodeIndex) { - return false; - } else { - return (glyphIndex == m.glyphIndex); - } - } else { - return false; - } - } - - /** {@inheritDoc} */ - public int compareTo(Object o) { - if (o instanceof UnicodeMapping) { - UnicodeMapping m = (UnicodeMapping) o; - if (unicodeIndex > m.unicodeIndex) { - return 1; - } else if (unicodeIndex < m.unicodeIndex) { - return -1; - } else { - return 0; - } - } else { - return -1; - } - } - } - - /** - * Obtain directory table entry. - * @param name (tag) of entry - * @return a directory table entry or null if none found - */ - public OFDirTabEntry getDirectoryEntry(OFTableName name) { - return dirTabs.get(name); - } - - /** - * Position inputstream to position indicated - * in the dirtab offset + offset - * @param in font file reader - * @param tableName (tag) of table - * @param offset from start of table - * @return true if seek succeeded - * @throws IOException if I/O exception occurs during seek - */ - public boolean seekTab(FontFileReader in, OFTableName tableName, - long offset) throws IOException { - OFDirTabEntry dt = dirTabs.get(tableName); - if (dt == null) { - log.info("Dirtab " + tableName.getName() + " not found."); - return false; - } else { - in.seekSet(dt.getOffset() + offset); - } - return true; - } - - /** - * Convert from truetype unit to pdf unit based on the - * unitsPerEm field in the "head" table - * @param n truetype unit - * @return pdf unit - */ - public int convertTTFUnit2PDFUnit(int n) { - int ret; - if (n < 0) { - long rest1 = n % upem; - long storrest = 1000 * rest1; - long ledd2 = (storrest != 0 ? rest1 / storrest : 0); - ret = -((-1000 * n) / upem - (int)ledd2); - } else { - ret = (n / upem) * 1000 + ((n % upem) * 1000) / upem; - } - - return ret; - } - - /** - * Read the cmap table, - * return false if the table is not present or only unsupported - * tables are present. Currently only unicode cmaps are supported. - * Set the unicodeIndex in the TTFMtxEntries and fills in the - * cmaps vector. - */ - protected boolean readCMAP() throws IOException { - - unicodeMappings = new ArrayList<OpenFont.UnicodeMapping>(); - - if (!seekTab(fontFile, OFTableName.CMAP, 2)) { - return true; - } - int numCMap = fontFile.readTTFUShort(); // Number of cmap subtables - long cmapUniOffset = 0; - long symbolMapOffset = 0; - - if (log.isDebugEnabled()) { - log.debug(numCMap + " cmap tables"); - } - - //Read offset for all tables. We are only interested in the unicode table - for (int i = 0; i < numCMap; i++) { - int cmapPID = fontFile.readTTFUShort(); - int cmapEID = fontFile.readTTFUShort(); - long cmapOffset = fontFile.readTTFLong(); - - if (log.isDebugEnabled()) { - log.debug("Platform ID: " + cmapPID + " Encoding: " + cmapEID); - } - - if (cmapPID == 3 && cmapEID == 1) { - cmapUniOffset = cmapOffset; - } - if (cmapPID == 3 && cmapEID == 0) { - symbolMapOffset = cmapOffset; - } - } - - if (cmapUniOffset > 0) { - return readUnicodeCmap(cmapUniOffset, 1); - } else if (symbolMapOffset > 0) { - return readUnicodeCmap(symbolMapOffset, 0); - } else { - log.fatal("Unsupported TrueType font: No Unicode or Symbol cmap table" - + " not present. Aborting"); - return false; - } - } - - private boolean readUnicodeCmap(long cmapUniOffset, int encodingID) - throws IOException { - //Read CMAP table and correct mtxTab.index - int mtxPtr = 0; - - // Read unicode cmap - seekTab(fontFile, OFTableName.CMAP, cmapUniOffset); - int cmapFormat = fontFile.readTTFUShort(); - /*int cmap_length =*/ fontFile.readTTFUShort(); //skip cmap length - - if (log.isDebugEnabled()) { - log.debug("CMAP format: " + cmapFormat); - } - - if (cmapFormat == 4) { - fontFile.skip(2); // Skip version number - int cmapSegCountX2 = fontFile.readTTFUShort(); - int cmapSearchRange = fontFile.readTTFUShort(); - int cmapEntrySelector = fontFile.readTTFUShort(); - int cmapRangeShift = fontFile.readTTFUShort(); - - if (log.isDebugEnabled()) { - log.debug("segCountX2 : " + cmapSegCountX2); - log.debug("searchRange : " + cmapSearchRange); - log.debug("entrySelector: " + cmapEntrySelector); - log.debug("rangeShift : " + cmapRangeShift); - } - - - int[] cmapEndCounts = new int[cmapSegCountX2 / 2]; - int[] cmapStartCounts = new int[cmapSegCountX2 / 2]; - int[] cmapDeltas = new int[cmapSegCountX2 / 2]; - int[] cmapRangeOffsets = new int[cmapSegCountX2 / 2]; - - for (int i = 0; i < (cmapSegCountX2 / 2); i++) { - cmapEndCounts[i] = fontFile.readTTFUShort(); - } - - fontFile.skip(2); // Skip reservedPad - - for (int i = 0; i < (cmapSegCountX2 / 2); i++) { - cmapStartCounts[i] = fontFile.readTTFUShort(); - } - - for (int i = 0; i < (cmapSegCountX2 / 2); i++) { - cmapDeltas[i] = fontFile.readTTFShort(); - } - - //int startRangeOffset = in.getCurrentPos(); - - for (int i = 0; i < (cmapSegCountX2 / 2); i++) { - cmapRangeOffsets[i] = fontFile.readTTFUShort(); - } - - int glyphIdArrayOffset = fontFile.getCurrentPos(); - - BitSet eightBitGlyphs = new BitSet(256); - - // Insert the unicode id for the glyphs in mtxTab - // and fill in the cmaps ArrayList - for (int i = 0; i < cmapStartCounts.length; i++) { - - if (log.isTraceEnabled()) { - log.trace(i + ": " + cmapStartCounts[i] - + " - " + cmapEndCounts[i]); - } - if (log.isDebugEnabled()) { - if (isInPrivateUseArea(cmapStartCounts[i], cmapEndCounts[i])) { - log.debug("Font contains glyphs in the Unicode private use area: " - + Integer.toHexString(cmapStartCounts[i]) + " - " - + Integer.toHexString(cmapEndCounts[i])); - } - } - - for (int j = cmapStartCounts[i]; j <= cmapEndCounts[i]; j++) { - - // Update lastChar - if (j < 256 && j > lastChar) { - lastChar = (short)j; - } - - if (j < 256) { - eightBitGlyphs.set(j); - } - - if (mtxPtr < mtxTab.length) { - int glyphIdx; - // the last character 65535 = .notdef - // may have a range offset - if (cmapRangeOffsets[i] != 0 && j != 65535) { - int glyphOffset = glyphIdArrayOffset - + ((cmapRangeOffsets[i] / 2) - + (j - cmapStartCounts[i]) - + (i) - - cmapSegCountX2 / 2) * 2; - fontFile.seekSet(glyphOffset); - glyphIdx = (fontFile.readTTFUShort() + cmapDeltas[i]) - & 0xffff; - //mtxTab[glyphIdx].setName(mtxTab[glyphIdx].getName() + " - "+(char)j); - unicodeMappings.add(new UnicodeMapping(this, glyphIdx, j)); - mtxTab[glyphIdx].getUnicodeIndex().add(new Integer(j)); - - if (encodingID == 0 && j >= 0xF020 && j <= 0xF0FF) { - //Experimental: Mapping 0xF020-0xF0FF to 0x0020-0x00FF - //Tested with Wingdings and Symbol TTF fonts which map their - //glyphs in the region 0xF020-0xF0FF. - int mapped = j - 0xF000; - if (!eightBitGlyphs.get(mapped)) { - //Only map if Unicode code point hasn't been mapped before - unicodeMappings.add(new UnicodeMapping(this, glyphIdx, mapped)); - mtxTab[glyphIdx].getUnicodeIndex().add(new Integer(mapped)); - } - } - - // Also add winAnsiWidth - List<Integer> v = ansiIndex.get(new Integer(j)); - if (v != null) { - for (Integer aIdx : v) { - ansiWidth[aIdx.intValue()] - = mtxTab[glyphIdx].getWx(); - - if (log.isTraceEnabled()) { - log.trace("Added width " - + mtxTab[glyphIdx].getWx() - + " uni: " + j - + " ansi: " + aIdx.intValue()); - } - } - } - - if (log.isTraceEnabled()) { - log.trace("Idx: " - + glyphIdx - + " Delta: " + cmapDeltas[i] - + " Unicode: " + j - + " name: " + mtxTab[glyphIdx].getName()); - } - } else { - glyphIdx = (j + cmapDeltas[i]) & 0xffff; - - if (glyphIdx < mtxTab.length) { - mtxTab[glyphIdx].getUnicodeIndex().add(new Integer(j)); - } else { - log.debug("Glyph " + glyphIdx - + " out of range: " - + mtxTab.length); - } - - unicodeMappings.add(new UnicodeMapping(this, glyphIdx, j)); - if (glyphIdx < mtxTab.length) { - mtxTab[glyphIdx].getUnicodeIndex().add(new Integer(j)); - } else { - log.debug("Glyph " + glyphIdx - + " out of range: " - + mtxTab.length); - } - - // Also add winAnsiWidth - List<Integer> v = ansiIndex.get(new Integer(j)); - if (v != null) { - for (Integer aIdx : v) { - ansiWidth[aIdx.intValue()] = mtxTab[glyphIdx].getWx(); - } - } - - //getLogger().debug("IIdx: " + - // mtxPtr + - // " Delta: " + cmap_deltas[i] + - // " Unicode: " + j + - // " name: " + - // mtxTab[(j+cmap_deltas[i]) & 0xffff].name); - - } - if (glyphIdx < mtxTab.length) { - if (mtxTab[glyphIdx].getUnicodeIndex().size() < 2) { - mtxPtr++; - } - } - } - } - } - } else { - log.error("Cmap format not supported: " + cmapFormat); - return false; - } - return true; - } - - private boolean isInPrivateUseArea(int start, int end) { - return (isInPrivateUseArea(start) || isInPrivateUseArea(end)); - } - - private boolean isInPrivateUseArea(int unicode) { - return (unicode >= 0xE000 && unicode <= 0xF8FF); - } - - /** - * - * @return mmtx data - */ - public List<OFMtxEntry> getMtx() { - return Collections.unmodifiableList(Arrays.asList(mtxTab)); - } - - /** - * Print first char/last char - */ - /* not used - private void printMaxMin() { - int min = 255; - int max = 0; - for (int i = 0; i < mtxTab.length; i++) { - if (mtxTab[i].getIndex() < min) { - min = mtxTab[i].getIndex(); - } - if (mtxTab[i].getIndex() > max) { - max = mtxTab[i].getIndex(); - } - } - log.info("Min: " + min); - log.info("Max: " + max); - } - */ - - - /** - * Reads the font using a FontFileReader. - * - * @param in The FontFileReader to use - * @throws IOException In case of an I/O problem - */ - public void readFont(FontFileReader in, String header) throws IOException { - readFont(in, header, (String)null); - } - - /** - * initialize the ansiWidths array (for winAnsiEncoding) - * and fill with the missingwidth - */ - protected void initAnsiWidths() { - ansiWidth = new int[256]; - for (int i = 0; i < 256; i++) { - ansiWidth[i] = mtxTab[0].getWx(); - } - - // Create an index hash to the ansiWidth - // Can't just index the winAnsiEncoding when inserting widths - // same char (eg bullet) is repeated more than one place - ansiIndex = new HashMap<Integer, List<Integer>>(); - for (int i = 32; i < Glyphs.WINANSI_ENCODING.length; i++) { - Integer ansi = new Integer(i); - Integer uni = new Integer(Glyphs.WINANSI_ENCODING[i]); - - List<Integer> v = ansiIndex.get(uni); - if (v == null) { - v = new ArrayList<Integer>(); - ansiIndex.put(uni, v); - } - v.add(ansi); - } - } - - /** - * Read the font data. - * If the fontfile is a TrueType Collection (.ttc file) - * the name of the font to read data for must be supplied, - * else the name is ignored. - * - * @param in The FontFileReader to use - * @param name The name of the font - * @return boolean Returns true if the font is valid - * @throws IOException In case of an I/O problem - */ - public boolean readFont(FontFileReader in, String header, String name) throws IOException { - initializeFont(in); - /* - * Check if TrueType collection, and that the name - * exists in the collection - */ - if (!checkTTC(header, name)) { - if (name == null) { - throw new IllegalArgumentException( - "For TrueType collection you must specify which font " - + "to select (-ttcname)"); - } else { - throw new IOException( - "Name does not exist in the TrueType collection: " + name); - } - } - - readDirTabs(); - readFontHeader(); - getNumGlyphs(); - if (log.isDebugEnabled()) { - log.debug("Number of glyphs in font: " + numberOfGlyphs); - } - readHorizontalHeader(); - readHorizontalMetrics(); - initAnsiWidths(); - readPostScript(); - readOS2(); - determineAscDesc(); - - readName(); - boolean pcltFound = readPCLT(); - // Read cmap table and fill in ansiwidths - boolean valid = readCMAP(); - if (!valid) { - return false; - } - - // Create cmaps for bfentries - createCMaps(); - updateBBoxAndOffset(); - - if (useKerning) { - readKerning(); - } - handleCharacterSpacing(in); - - guessVerticalMetricsFromGlyphBBox(); - return true; - } - - /** - * Reads a font. - * - * @param in FontFileReader to read from - * @param name Name to be checked for in the font file - * @param glyphs Map of glyphs (glyphs has old index as (Integer) key and - * new index as (Integer) value) - * @throws IOException in case of an I/O problem - */ - public void readFont(FontFileReader in, String header, MultiByteFont mbfont) throws IOException { - readFont(in, header, mbfont.getTTCName()); - } - - protected abstract void updateBBoxAndOffset() throws IOException; - - protected abstract void readName() throws IOException; - - protected abstract void initializeFont(FontFileReader in) throws IOException; - - protected void handleCharacterSpacing(FontFileReader in) throws IOException { - // Read advanced typographic tables. - if (useAdvanced) { - try { - OTFAdvancedTypographicTableReader atr - = new OTFAdvancedTypographicTableReader(this, in); - atr.readAll(); - this.advancedTableReader = atr; - } catch (AdvancedTypographicTableFormatException e) { - log.warn( - "Encountered format constraint violation in advanced (typographic) table (AT) " - + "in font '" + getFullName() + "', ignoring AT data: " - + e.getMessage() - ); - } - } - - } - - protected void createCMaps() { - cmaps = new ArrayList<CMapSegment>(); - int unicodeStart; - int glyphStart; - int unicodeEnd; - if (unicodeMappings.isEmpty()) { - return; - } - Iterator<UnicodeMapping> e = unicodeMappings.iterator(); - UnicodeMapping um = e.next(); - UnicodeMapping lastMapping = um; - - unicodeStart = um.getUnicodeIndex(); - glyphStart = um.getGlyphIndex(); - - while (e.hasNext()) { - um = e.next(); - if (((lastMapping.getUnicodeIndex() + 1) != um.getUnicodeIndex()) - || ((lastMapping.getGlyphIndex() + 1) != um.getGlyphIndex())) { - unicodeEnd = lastMapping.getUnicodeIndex(); - cmaps.add(new CMapSegment(unicodeStart, unicodeEnd, glyphStart)); - unicodeStart = um.getUnicodeIndex(); - glyphStart = um.getGlyphIndex(); - } - lastMapping = um; - } - - unicodeEnd = lastMapping.getUnicodeIndex(); - cmaps.add(new CMapSegment(unicodeStart, unicodeEnd, glyphStart)); - } - - /** - * Returns the PostScript name of the font. - * @return String The PostScript name - */ - public String getPostScriptName() { - if (postScriptName.length() == 0) { - return FontUtil.stripWhiteSpace(getFullName()); - } else { - return postScriptName; - } - } - - PostScriptVersion getPostScriptVersion() { - return postScriptVersion; - } - - /** - * Returns the font family names of the font. - * @return Set The family names (a Set of Strings) - */ - public Set<String> getFamilyNames() { - return familyNames; - } - - /** - * Returns the font sub family name of the font. - * @return String The sub family name - */ - public String getSubFamilyName() { - return subFamilyName; - } - - /** - * Returns the full name of the font. - * @return String The full name - */ - public String getFullName() { - return fullName; - } - - /** - * Returns the name of the character set used. - * @return String The caracter set - */ - public String getCharSetName() { - return ENCODING; - } - - /** - * Returns the CapHeight attribute of the font. - * @return int The CapHeight - */ - public int getCapHeight() { - return convertTTFUnit2PDFUnit(capHeight); - } - - /** - * Returns the XHeight attribute of the font. - * @return int The XHeight - */ - public int getXHeight() { - return convertTTFUnit2PDFUnit(xHeight); - } - - /** - * Returns the number of bytes necessary to pad the currentPosition so that a table begins - * on a 4-byte boundary. - * @param currentPosition the position to pad. - * @return int the number of bytes to pad. - */ - protected int getPadSize(int currentPosition) { - int padSize = 4 - (currentPosition % 4); - return padSize < 4 ? padSize : 0; - } - - /** - * Returns the Flags attribute of the font. - * @return int The Flags - */ - public int getFlags() { - int flags = 32; // Use Adobe Standard charset - if (italicAngle != 0) { - flags |= 64; - } - if (isFixedPitch != 0) { - flags |= 2; - } - if (hasSerifs) { - flags |= 1; - } - return flags; - } - - /** - * Returns the weight class of this font. Valid values are 100, 200....,800, 900. - * @return the weight class value (or 0 if there was no OS/2 table in the font) - */ - public int getWeightClass() { - return this.usWeightClass; - } - - /** - * Returns the StemV attribute of the font. - * @return String The StemV - */ - public String getStemV() { - return "0"; - } - - /** - * Returns the ItalicAngle attribute of the font. - * @return String The ItalicAngle - */ - public String getItalicAngle() { - String ia = Short.toString((short)(italicAngle / 0x10000)); - - // This is the correct italic angle, however only int italic - // angles are supported at the moment so this is commented out. - /* - * if ((italicAngle % 0x10000) > 0 ) - * ia=ia+(comma+Short.toString((short)((short)((italicAngle % 0x10000)*1000)/0x10000))); - */ - return ia; - } - - /** - * @return int[] The font bbox - */ - public int[] getFontBBox() { - final int[] fbb = new int[4]; - fbb[0] = convertTTFUnit2PDFUnit(fontBBox1); - fbb[1] = convertTTFUnit2PDFUnit(fontBBox2); - fbb[2] = convertTTFUnit2PDFUnit(fontBBox3); - fbb[3] = convertTTFUnit2PDFUnit(fontBBox4); - - return fbb; - } - - /** - * Returns the original bounding box values from the HEAD table - * @return An array of bounding box values - */ - public int[] getBBoxRaw() { - int[] bbox = {fontBBox1, fontBBox2, fontBBox3, fontBBox4}; - return bbox; - } - - /** - * Returns the LowerCaseAscent attribute of the font. - * @return int The LowerCaseAscent - */ - public int getLowerCaseAscent() { - return convertTTFUnit2PDFUnit(ascender); - } - - /** - * Returns the LowerCaseDescent attribute of the font. - * @return int The LowerCaseDescent - */ - public int getLowerCaseDescent() { - return convertTTFUnit2PDFUnit(descender); - } - - /** - * Returns the index of the last character, but this is for WinAnsiEncoding - * only, so the last char is < 256. - * @return short Index of the last character (<256) - */ - public short getLastChar() { - return lastChar; - } - - /** - * Returns the index of the first character. - * @return short Index of the first character - */ - public short getFirstChar() { - return FIRST_CHAR; - } - - /** - * Returns an array of character widths. - * @return int[] The character widths - */ - public int[] getWidths() { - int[] wx = new int[mtxTab.length]; - for (int i = 0; i < wx.length; i++) { - wx[i] = convertTTFUnit2PDFUnit(mtxTab[i].getWx()); - } - return wx; - } - - public Rectangle[] getBoundingBoxes() { - Rectangle[] boundingBoxes = new Rectangle[mtxTab.length]; - for (int i = 0; i < boundingBoxes.length; i++) { - int[] boundingBox = mtxTab[i].getBoundingBox(); - boundingBoxes[i] = new Rectangle( - convertTTFUnit2PDFUnit(boundingBox[0]), - convertTTFUnit2PDFUnit(boundingBox[1]), - convertTTFUnit2PDFUnit(boundingBox[2] - boundingBox[0]), - convertTTFUnit2PDFUnit(boundingBox[3] - boundingBox[1])); - } - return boundingBoxes; - } - - /** - * Returns an array (xMin, yMin, xMax, yMax) for a glyph. - * - * @param glyphIndex the index of the glyph - * @return int[] Array defining bounding box. - */ - public int[] getBBox(int glyphIndex) { - int[] bboxInTTFUnits = mtxTab[glyphIndex].getBoundingBox(); - int[] bbox = new int[4]; - for (int i = 0; i < 4; i++) { - bbox[i] = convertTTFUnit2PDFUnit(bboxInTTFUnits[i]); - } - return bbox; - } - - /** - * Returns the width of a given character. - * @param idx Index of the character - * @return int Standard width - */ - public int getCharWidth(int idx) { - return convertTTFUnit2PDFUnit(ansiWidth[idx]); - } - - /** - * Returns the width of a given character in raw units - * @param idx Index of the character - * @return int Width in it's raw form stored in the font - */ - public int getCharWidthRaw(int idx) { - if (ansiWidth != null) { - return ansiWidth[idx]; - } - return -1; - } - - /** - * Returns the kerning table. - * @return Map The kerning table - */ - public Map<Integer, Map<Integer, Integer>> getKerning() { - return kerningTab; - } - - /** - * Returns the ANSI kerning table. - * @return Map The ANSI kerning table - */ - public Map<Integer, Map<Integer, Integer>> getAnsiKerning() { - return ansiKerningTab; - } - - public int getUnderlinePosition() { - return convertTTFUnit2PDFUnit(underlinePosition); - } - - public int getUnderlineThickness() { - return convertTTFUnit2PDFUnit(underlineThickness); - } - - public int getStrikeoutPosition() { - return convertTTFUnit2PDFUnit(strikeoutPosition); - } - - public int getStrikeoutThickness() { - return convertTTFUnit2PDFUnit(strikeoutThickness); - } - - /** - * Indicates if the font may be embedded. - * @return boolean True if it may be embedded - */ - public boolean isEmbeddable() { - return isEmbeddable; - } - - /** - * Indicates whether or not the font is an OpenType - * CFF font (rather than a TrueType font). - * @return true if the font is in OpenType CFF format. - */ - public boolean isCFF() { - return this.isCFF; - } - - /** - * Read Table Directory from the current position in the - * FontFileReader and fill the global HashMap dirTabs - * with the table name (String) as key and a TTFDirTabEntry - * as value. - * @throws IOException in case of an I/O problem - */ - protected void readDirTabs() throws IOException { - int sfntVersion = fontFile.readTTFLong(); // TTF_FIXED_SIZE (4 bytes) - switch (sfntVersion) { - case 0x10000: - log.debug("sfnt version: OpenType 1.0"); - break; - case 0x4F54544F: //"OTTO" - this.isCFF = true; - log.debug("sfnt version: OpenType with CFF data"); - break; - case 0x74727565: //"true" - log.debug("sfnt version: Apple TrueType"); - break; - case 0x74797031: //"typ1" - log.debug("sfnt version: Apple Type 1 housed in sfnt wrapper"); - break; - default: - log.debug("Unknown sfnt version: " + Integer.toHexString(sfntVersion)); - break; - } - int ntabs = fontFile.readTTFUShort(); - fontFile.skip(6); // 3xTTF_USHORT_SIZE - - dirTabs = new HashMap<OFTableName, OFDirTabEntry>(); - OFDirTabEntry[] pd = new OFDirTabEntry[ntabs]; - log.debug("Reading " + ntabs + " dir tables"); - - for (int i = 0; i < ntabs; i++) { - pd[i] = new OFDirTabEntry(); - String tableName = pd[i].read(fontFile); - dirTabs.put(OFTableName.getValue(tableName), pd[i]); - } - dirTabs.put(OFTableName.TABLE_DIRECTORY, - new OFDirTabEntry(0L, fontFile.getCurrentPos())); - log.debug("dir tables: " + dirTabs.keySet()); - } - - /** - * Read the "head" table, this reads the bounding box and - * sets the upem (unitsPerEM) variable - * @throws IOException in case of an I/O problem - */ - protected void readFontHeader() throws IOException { - seekTab(fontFile, OFTableName.HEAD, 2 * 4 + 2 * 4); - int flags = fontFile.readTTFUShort(); - if (log.isDebugEnabled()) { - log.debug("flags: " + flags + " - " + Integer.toString(flags, 2)); - } - upem = fontFile.readTTFUShort(); - if (log.isDebugEnabled()) { - log.debug("unit per em: " + upem); - } - - fontFile.skip(16); - - fontBBox1 = fontFile.readTTFShort(); - fontBBox2 = fontFile.readTTFShort(); - fontBBox3 = fontFile.readTTFShort(); - fontBBox4 = fontFile.readTTFShort(); - if (log.isDebugEnabled()) { - log.debug("font bbox: xMin=" + fontBBox1 - + " yMin=" + fontBBox2 - + " xMax=" + fontBBox3 - + " yMax=" + fontBBox4); - } - - fontFile.skip(2 + 2 + 2); - - locaFormat = fontFile.readTTFShort(); - } - - /** - * Read the number of glyphs from the "maxp" table - * @throws IOException in case of an I/O problem - */ - protected void getNumGlyphs() throws IOException { - seekTab(fontFile, OFTableName.MAXP, 4); - numberOfGlyphs = fontFile.readTTFUShort(); - } - - - /** - * Read the "hhea" table to find the ascender and descender and - * size of "hmtx" table, as a fixed size font might have only - * one width. - * @throws IOException in case of an I/O problem - */ - protected void readHorizontalHeader() - throws IOException { - seekTab(fontFile, OFTableName.HHEA, 4); - hheaAscender = fontFile.readTTFShort(); - hheaDescender = fontFile.readTTFShort(); - - fontFile.skip(2 + 2 + 3 * 2 + 8 * 2); - nhmtx = fontFile.readTTFUShort(); - - if (log.isDebugEnabled()) { - log.debug("hhea.Ascender: " + formatUnitsForDebug(hheaAscender)); - log.debug("hhea.Descender: " + formatUnitsForDebug(hheaDescender)); - log.debug("Number of horizontal metrics: " + nhmtx); - } - } - - /** - * Read "hmtx" table and put the horizontal metrics - * in the mtxTab array. If the number of metrics is less - * than the number of glyphs (eg fixed size fonts), extend - * the mtxTab array and fill in the missing widths - * @throws IOException in case of an I/O problem - */ - protected void readHorizontalMetrics() - throws IOException { - seekTab(fontFile, OFTableName.HMTX, 0); - - int mtxSize = Math.max(numberOfGlyphs, nhmtx); - mtxTab = new OFMtxEntry[mtxSize]; - - if (log.isTraceEnabled()) { - log.trace("*** Widths array: \n"); - } - for (int i = 0; i < mtxSize; i++) { - mtxTab[i] = new OFMtxEntry(); - } - for (int i = 0; i < nhmtx; i++) { - mtxTab[i].setWx(fontFile.readTTFUShort()); - mtxTab[i].setLsb(fontFile.readTTFUShort()); - - if (log.isTraceEnabled()) { - log.trace(" width[" + i + "] = " - + convertTTFUnit2PDFUnit(mtxTab[i].getWx()) + ";"); - } - } - - if (cid && nhmtx < mtxSize) { - // Fill in the missing widths - int lastWidth = mtxTab[nhmtx - 1].getWx(); - for (int i = nhmtx; i < mtxSize; i++) { - mtxTab[i].setWx(lastWidth); - mtxTab[i].setLsb(fontFile.readTTFUShort()); - } - } - } - - - /** - * Read the "post" table - * containing the PostScript names of the glyphs. - */ - protected void readPostScript() throws IOException { - seekTab(fontFile, OFTableName.POST, 0); - int postFormat = fontFile.readTTFLong(); - italicAngle = fontFile.readTTFULong(); - underlinePosition = fontFile.readTTFShort(); - underlineThickness = fontFile.readTTFShort(); - isFixedPitch = fontFile.readTTFULong(); - - //Skip memory usage values - fontFile.skip(4 * 4); - - log.debug("PostScript format: 0x" + Integer.toHexString(postFormat)); - switch (postFormat) { - case 0x00010000: - log.debug("PostScript format 1"); - postScriptVersion = PostScriptVersion.V1; - for (int i = 0; i < MAC_GLYPH_ORDERING.length; i++) { - mtxTab[i].setName(MAC_GLYPH_ORDERING[i]); - } - break; - case 0x00020000: - log.debug("PostScript format 2"); - postScriptVersion = PostScriptVersion.V2; - int numGlyphStrings = 257; - - // Read Number of Glyphs - int l = fontFile.readTTFUShort(); - - // Read indexes - for (int i = 0; i < l; i++) { - mtxTab[i].setIndex(fontFile.readTTFUShort()); - - if (mtxTab[i].getIndex() > numGlyphStrings) { - numGlyphStrings = mtxTab[i].getIndex(); - } - - if (log.isTraceEnabled()) { - log.trace("PostScript index: " + mtxTab[i].getIndexAsString()); - } - } - - // firstChar=minIndex; - String[] psGlyphsBuffer = new String[numGlyphStrings - 257]; - if (log.isDebugEnabled()) { - log.debug("Reading " + numGlyphStrings - + " glyphnames, that are not in the standard Macintosh" - + " set. Total number of glyphs=" + l); - } - for (int i = 0; i < psGlyphsBuffer.length; i++) { - psGlyphsBuffer[i] = fontFile.readTTFString(fontFile.readTTFUByte()); - } - - //Set glyph names - for (int i = 0; i < l; i++) { - if (mtxTab[i].getIndex() < MAC_GLYPH_ORDERING.length) { - mtxTab[i].setName(MAC_GLYPH_ORDERING[mtxTab[i].getIndex()]); - } else { - if (!mtxTab[i].isIndexReserved()) { - int k = mtxTab[i].getIndex() - MAC_GLYPH_ORDERING.length; - - if (log.isTraceEnabled()) { - log.trace(k + " i=" + i + " mtx=" + mtxTab.length - + " ps=" + psGlyphsBuffer.length); - } - - mtxTab[i].setName(psGlyphsBuffer[k]); - } - } - } - - break; - case 0x00030000: - // PostScript format 3 contains no glyph names - log.debug("PostScript format 3"); - postScriptVersion = PostScriptVersion.V3; - break; - default: - log.error("Unknown PostScript format: " + postFormat); - postScriptVersion = PostScriptVersion.UNKNOWN; - } - } - - - /** - * Read the "OS/2" table - */ - protected void readOS2() throws IOException { - // Check if font is embeddable - OFDirTabEntry os2Entry = dirTabs.get(OFTableName.OS2); - if (os2Entry != null) { - seekTab(fontFile, OFTableName.OS2, 0); - int version = fontFile.readTTFUShort(); - if (log.isDebugEnabled()) { - log.debug("OS/2 table: version=" + version - + ", offset=" + os2Entry.getOffset() + ", len=" + os2Entry.getLength()); - } - fontFile.skip(2); //xAvgCharWidth - this.usWeightClass = fontFile.readTTFUShort(); - - // usWidthClass - fontFile.skip(2); - - int fsType = fontFile.readTTFUShort(); - if (fsType == 2) { - isEmbeddable = false; - } else { - isEmbeddable = true; - } - fontFile.skip(8 * 2); - strikeoutThickness = fontFile.readTTFShort(); - strikeoutPosition = fontFile.readTTFShort(); - fontFile.skip(2); - fontFile.skip(10); //panose array - fontFile.skip(4 * 4); //unicode ranges - fontFile.skip(4); - fontFile.skip(3 * 2); - int v; - os2Ascender = fontFile.readTTFShort(); //sTypoAscender - os2Descender = fontFile.readTTFShort(); //sTypoDescender - if (log.isDebugEnabled()) { - log.debug("sTypoAscender: " + os2Ascender - + " -> internal " + convertTTFUnit2PDFUnit(os2Ascender)); - log.debug("sTypoDescender: " + os2Descender - + " -> internal " + convertTTFUnit2PDFUnit(os2Descender)); - } - v = fontFile.readTTFShort(); //sTypoLineGap - if (log.isDebugEnabled()) { - log.debug("sTypoLineGap: " + v); - } - v = fontFile.readTTFUShort(); //usWinAscent - if (log.isDebugEnabled()) { - log.debug("usWinAscent: " + formatUnitsForDebug(v)); - } - v = fontFile.readTTFUShort(); //usWinDescent - if (log.isDebugEnabled()) { - log.debug("usWinDescent: " + formatUnitsForDebug(v)); - } - - //version 1 OS/2 table might end here - if (os2Entry.getLength() >= 78 + (2 * 4) + (2 * 2)) { - fontFile.skip(2 * 4); - this.os2xHeight = fontFile.readTTFShort(); //sxHeight - this.os2CapHeight = fontFile.readTTFShort(); //sCapHeight - if (log.isDebugEnabled()) { - log.debug("sxHeight: " + this.os2xHeight); - log.debug("sCapHeight: " + this.os2CapHeight); - } - } - - } else { - isEmbeddable = true; - } - } - - /** - * Read the "PCLT" table to find xHeight and capHeight. - * @throws IOException In case of a I/O problem - */ - protected boolean readPCLT() throws IOException { - OFDirTabEntry dirTab = dirTabs.get(OFTableName.PCLT); - if (dirTab != null) { - fontFile.seekSet(dirTab.getOffset() + 4 + 4 + 2); - xHeight = fontFile.readTTFUShort(); - log.debug("xHeight from PCLT: " + formatUnitsForDebug(xHeight)); - fontFile.skip(2 * 2); - capHeight = fontFile.readTTFUShort(); - log.debug("capHeight from PCLT: " + formatUnitsForDebug(capHeight)); - fontFile.skip(2 + 16 + 8 + 6 + 1 + 1); - - int serifStyle = fontFile.readTTFUByte(); - serifStyle = serifStyle >> 6; - serifStyle = serifStyle & 3; - if (serifStyle == 1) { - hasSerifs = false; - } else { - hasSerifs = true; - } - return true; - } else { - return false; - } - } - - /** - * Determines the right source for the ascender and descender values. The problem here is - * that the interpretation of these values is not the same for every font. There doesn't seem - * to be a uniform definition of an ascender and a descender. In some fonts - * the hhea values are defined after the Apple interpretation, but not in every font. The - * same problem is in the OS/2 table. FOP needs the ascender and descender to determine the - * baseline so we need values which add up more or less to the "em box". However, due to - * accent modifiers a character can grow beyond the em box. - */ - protected void determineAscDesc() { - int hheaBoxHeight = hheaAscender - hheaDescender; - int os2BoxHeight = os2Ascender - os2Descender; - if (os2Ascender > 0 && os2BoxHeight <= upem) { - ascender = os2Ascender; - descender = os2Descender; - } else if (hheaAscender > 0 && hheaBoxHeight <= upem) { - ascender = hheaAscender; - descender = hheaDescender; - } else { - if (os2Ascender > 0) { - //Fall back to info from OS/2 if possible - ascender = os2Ascender; - descender = os2Descender; - } else { - ascender = hheaAscender; - descender = hheaDescender; - } - } - - if (log.isDebugEnabled()) { - log.debug("Font box height: " + (ascender - descender)); - if (ascender - descender > upem) { - log.debug("Ascender and descender together are larger than the em box."); - } - } - } - - protected void guessVerticalMetricsFromGlyphBBox() { - // Approximate capHeight from height of "H" - // It's most unlikely that a font misses the PCLT table - // This also assumes that postscriptnames exists ("H") - // Should look it up in the cmap (that wouldn't help - // for charsets without H anyway...) - // Same for xHeight with the letter "x" - int localCapHeight = 0; - int localXHeight = 0; - int localAscender = 0; - int localDescender = 0; - for (int i = 0; i < mtxTab.length; i++) { - if ("H".equals(mtxTab[i].getName())) { - localCapHeight = mtxTab[i].getBoundingBox()[3]; - } else if ("x".equals(mtxTab[i].getName())) { - localXHeight = mtxTab[i].getBoundingBox()[3]; - } else if ("d".equals(mtxTab[i].getName())) { - localAscender = mtxTab[i].getBoundingBox()[3]; - } else if ("p".equals(mtxTab[i].getName())) { - localDescender = mtxTab[i].getBoundingBox()[1]; - } else { - // OpenType Fonts with a version 3.0 "post" table don't have glyph names. - // Use Unicode indices instead. - List unicodeIndex = mtxTab[i].getUnicodeIndex(); - if (unicodeIndex.size() > 0) { - //Only the first index is used - char ch = (char)((Integer)unicodeIndex.get(0)).intValue(); - if (ch == 'H') { - localCapHeight = mtxTab[i].getBoundingBox()[3]; - } else if (ch == 'x') { - localXHeight = mtxTab[i].getBoundingBox()[3]; - } else if (ch == 'd') { - localAscender = mtxTab[i].getBoundingBox()[3]; - } else if (ch == 'p') { - localDescender = mtxTab[i].getBoundingBox()[1]; - } - } - } - } - if (log.isDebugEnabled()) { - log.debug("Ascender from glyph 'd': " + formatUnitsForDebug(localAscender)); - log.debug("Descender from glyph 'p': " + formatUnitsForDebug(localDescender)); - } - if (ascender - descender > upem) { - log.debug("Replacing specified ascender/descender with derived values to get values" - + " which fit in the em box."); - ascender = localAscender; - descender = localDescender; - } - - if (log.isDebugEnabled()) { - log.debug("xHeight from glyph 'x': " + formatUnitsForDebug(localXHeight)); - log.debug("CapHeight from glyph 'H': " + formatUnitsForDebug(localCapHeight)); - } - if (capHeight == 0) { - capHeight = localCapHeight; - if (capHeight == 0) { - capHeight = os2CapHeight; - } - if (capHeight == 0) { - log.debug("capHeight value could not be determined." - + " The font may not work as expected."); - } - } - if (xHeight == 0) { - xHeight = localXHeight; - if (xHeight == 0) { - xHeight = os2xHeight; - } - if (xHeight == 0) { - log.debug("xHeight value could not be determined." - + " The font may not work as expected."); - } - } - } - - /** - * Read the kerning table, create a table for both CIDs and - * winAnsiEncoding. - * @throws IOException In case of a I/O problem - */ - protected void readKerning() throws IOException { - // Read kerning - kerningTab = new HashMap<Integer, Map<Integer, Integer>>(); - ansiKerningTab = new HashMap<Integer, Map<Integer, Integer>>(); - OFDirTabEntry dirTab = dirTabs.get(OFTableName.KERN); - if (dirTab != null) { - seekTab(fontFile, OFTableName.KERN, 2); - for (int n = fontFile.readTTFUShort(); n > 0; n--) { - fontFile.skip(2 * 2); - int k = fontFile.readTTFUShort(); - if (!((k & 1) != 0) || (k & 2) != 0 || (k & 4) != 0) { - return; - } - if ((k >> 8) != 0) { - continue; - } - - k = fontFile.readTTFUShort(); - fontFile.skip(3 * 2); - while (k-- > 0) { - int i = fontFile.readTTFUShort(); - int j = fontFile.readTTFUShort(); - int kpx = fontFile.readTTFShort(); - if (kpx != 0) { - // CID kerning table entry, using unicode indexes - final Integer iObj = glyphToUnicode(i); - final Integer u2 = glyphToUnicode(j); - if (iObj == null) { - // happens for many fonts (Ubuntu font set), - // stray entries in the kerning table?? - log.debug("Ignoring kerning pair because no Unicode index was" - + " found for the first glyph " + i); - } else if (u2 == null) { - log.debug("Ignoring kerning pair because Unicode index was" - + " found for the second glyph " + i); - } else { - Map<Integer, Integer> adjTab = kerningTab.get(iObj); - if (adjTab == null) { - adjTab = new HashMap<Integer, Integer>(); - } - adjTab.put(u2, new Integer(convertTTFUnit2PDFUnit(kpx))); - kerningTab.put(iObj, adjTab); - } - } - } - } - - // Create winAnsiEncoded kerning table from kerningTab - // (could probably be simplified, for now we remap back to CID indexes and - // then to winAnsi) - - for (Map.Entry<Integer, Map<Integer, Integer>> e1 : kerningTab.entrySet()) { - Integer unicodeKey1 = e1.getKey(); - Integer cidKey1 = unicodeToGlyph(unicodeKey1); - Map<Integer, Integer> akpx = new HashMap<Integer, Integer>(); - Map<Integer, Integer> ckpx = e1.getValue(); - - for (Map.Entry<Integer, Integer> e : ckpx.entrySet()) { - Integer unicodeKey2 = e.getKey(); - Integer cidKey2 = unicodeToGlyph(unicodeKey2.intValue()); - Integer kern = e.getValue(); - - Iterator uniMap = mtxTab[cidKey2.intValue()].getUnicodeIndex().listIterator(); - while (uniMap.hasNext()) { - Integer unicodeKey = (Integer)uniMap.next(); - Integer[] ansiKeys = unicodeToWinAnsi(unicodeKey.intValue()); - for (int u = 0; u < ansiKeys.length; u++) { - akpx.put(ansiKeys[u], kern); - } - } - } - - if (akpx.size() > 0) { - Iterator uniMap = mtxTab[cidKey1.intValue()].getUnicodeIndex().listIterator(); - while (uniMap.hasNext()) { - Integer unicodeKey = (Integer)uniMap.next(); - Integer[] ansiKeys = unicodeToWinAnsi(unicodeKey.intValue()); - for (int u = 0; u < ansiKeys.length; u++) { - ansiKerningTab.put(ansiKeys[u], akpx); - } - } - } - } - } - } - - /** - * Streams a font. - * @param ttfOut The interface for streaming TrueType tables. - * @exception IOException file write error - */ - public void stream(TTFOutputStream ttfOut) throws IOException { - SortedSet<Map.Entry<OFTableName, OFDirTabEntry>> sortedDirTabs = sortDirTabMap(dirTabs); - byte[] file = fontFile.getAllBytes(); - TTFTableOutputStream tableOut = ttfOut.getTableOutputStream(); - TTFGlyphOutputStream glyphOut = ttfOut.getGlyphOutputStream(); - ttfOut.startFontStream(); - for (Map.Entry<OFTableName, OFDirTabEntry> entry : sortedDirTabs) { - int offset = (int) entry.getValue().getOffset(); - int paddedLength = (int) entry.getValue().getLength(); - paddedLength += getPadSize(offset + paddedLength); - if (entry.getKey().equals(OFTableName.GLYF)) { - streamGlyf(glyphOut, file, offset, paddedLength); - } else { - tableOut.streamTable(file, offset, paddedLength); - } - } - ttfOut.endFontStream(); - } - - private void streamGlyf(TTFGlyphOutputStream glyphOut, byte[] fontFile, int tableOffset, - int tableLength) throws IOException { - //Stream all but the last glyph - int glyphStart = 0; - int glyphEnd = 0; - glyphOut.startGlyphStream(); - for (int i = 0; i < mtxTab.length - 1; i++) { - glyphStart = (int) mtxTab[i].getOffset() + tableOffset; - glyphEnd = (int) mtxTab[i + 1].getOffset() + tableOffset; - glyphOut.streamGlyph(fontFile, glyphStart, glyphEnd - glyphStart); - } - glyphOut.streamGlyph(fontFile, glyphEnd, (tableOffset + tableLength) - glyphEnd); - glyphOut.endGlyphStream(); - } - - /** - * Returns the order in which the tables in a TrueType font should be written to file. - * @param directoryTabs the map that is to be sorted. - * @return TTFTablesNames[] an array of table names sorted in the order they should appear in - * the TTF file. - */ - SortedSet<Map.Entry<OFTableName, OFDirTabEntry>> - sortDirTabMap(Map<OFTableName, OFDirTabEntry> directoryTabs) { - SortedSet<Map.Entry<OFTableName, OFDirTabEntry>> sortedSet - = new TreeSet<Map.Entry<OFTableName, OFDirTabEntry>>( - new Comparator<Map.Entry<OFTableName, OFDirTabEntry>>() { - - public int compare(Entry<OFTableName, OFDirTabEntry> o1, - Entry<OFTableName, OFDirTabEntry> o2) { - return (int) (o1.getValue().getOffset() - o2.getValue().getOffset()); - } - }); - // @SuppressFBWarnings("DMI_ENTRY_SETS_MAY_REUSE_ENTRY_OBJECTS") - sortedSet.addAll(directoryTabs.entrySet()); - return sortedSet; - } - - /** - * Returns this font's character to glyph mapping. - * - * @return the font's cmap - */ - public List<CMapSegment> getCMaps() { - return cmaps; - } - - /** - * Check if this is a TrueType collection and that the given - * name exists in the collection. - * If it does, set offset in fontfile to the beginning of - * the Table Directory for that font. - * @param name The name to check - * @return True if not collection or font name present, false otherwise - * @throws IOException In case of an I/O problem - */ - protected final boolean checkTTC(String tag, String name) throws IOException { - if ("ttcf".equals(tag)) { - // This is a TrueType Collection - fontFile.skip(4); - - // Read directory offsets - int numDirectories = (int)fontFile.readTTFULong(); - // int numDirectories=in.readTTFUShort(); - long[] dirOffsets = new long[numDirectories]; - for (int i = 0; i < numDirectories; i++) { - dirOffsets[i] = fontFile.readTTFULong(); - } - - log.info("This is a TrueType collection file with " - + numDirectories + " fonts"); - log.info("Containing the following fonts: "); - // Read all the directories and name tables to check - // If the font exists - this is a bit ugly, but... - boolean found = false; - - // Iterate through all name tables even if font - // Is found, just to show all the names - long dirTabOffset = 0; - for (int i = 0; (i < numDirectories); i++) { - fontFile.seekSet(dirOffsets[i]); - readDirTabs(); - - readName(); - - if (fullName.equals(name)) { - found = true; - dirTabOffset = dirOffsets[i]; - log.info(fullName + " <-- selected"); - } else { - log.info(fullName); - } - - // Reset names - notice = ""; - fullName = ""; - familyNames.clear(); - postScriptName = ""; - subFamilyName = ""; - } - - fontFile.seekSet(dirTabOffset); - return found; - } else { - fontFile.seekSet(0); - return true; - } - } - - /** - * Return TTC font names - * @param in FontFileReader to read from - * @return True if not collection or font name present, false otherwise - * @throws IOException In case of an I/O problem - */ - public final List<String> getTTCnames(FontFileReader in) throws IOException { - this.fontFile = in; - - List<String> fontNames = new ArrayList<String>(); - String tag = in.readTTFString(4); - - if ("ttcf".equals(tag)) { - // This is a TrueType Collection - in.skip(4); - - // Read directory offsets - int numDirectories = (int)in.readTTFULong(); - long[] dirOffsets = new long[numDirectories]; - for (int i = 0; i < numDirectories; i++) { - dirOffsets[i] = in.readTTFULong(); - } - - log.info("This is a TrueType collection file with " - + numDirectories + " fonts"); - log.info("Containing the following fonts: "); - - for (int i = 0; (i < numDirectories); i++) { - in.seekSet(dirOffsets[i]); - readDirTabs(); - - readName(); - - log.info(fullName); - fontNames.add(fullName); - - // Reset names - notice = ""; - fullName = ""; - familyNames.clear(); - postScriptName = ""; - subFamilyName = ""; - } - - in.seekSet(0); - return fontNames; - } else { - log.error("Not a TTC!"); - return null; - } - } - - /* - * Helper classes, they are not very efficient, but that really - * doesn't matter... - */ - private Integer[] unicodeToWinAnsi(int unicode) { - List<Integer> ret = new ArrayList<Integer>(); - for (int i = 32; i < Glyphs.WINANSI_ENCODING.length; i++) { - if (unicode == Glyphs.WINANSI_ENCODING[i]) { - ret.add(new Integer(i)); - } - } - return ret.toArray(new Integer[ret.size()]); - } - - /** - * Dumps a few informational values to System.out. - */ - public void printStuff() { - System.out.println("Font name: " + postScriptName); - System.out.println("Full name: " + fullName); - System.out.println("Family name: " + familyNames); - System.out.println("Subfamily name: " + subFamilyName); - System.out.println("Notice: " + notice); - System.out.println("xHeight: " + convertTTFUnit2PDFUnit(xHeight)); - System.out.println("capheight: " + convertTTFUnit2PDFUnit(capHeight)); - - int italic = (int)(italicAngle >> 16); - System.out.println("Italic: " + italic); - System.out.print("ItalicAngle: " + (short)(italicAngle / 0x10000)); - if ((italicAngle % 0x10000) > 0) { - System.out.print("." - + (short)((italicAngle % 0x10000) * 1000) - / 0x10000); - } - System.out.println(); - System.out.println("Ascender: " + convertTTFUnit2PDFUnit(ascender)); - System.out.println("Descender: " + convertTTFUnit2PDFUnit(descender)); - System.out.println("FontBBox: [" + convertTTFUnit2PDFUnit(fontBBox1) - + " " + convertTTFUnit2PDFUnit(fontBBox2) + " " - + convertTTFUnit2PDFUnit(fontBBox3) + " " - + convertTTFUnit2PDFUnit(fontBBox4) + "]"); - } - - private String formatUnitsForDebug(int units) { - return units + " -> " + convertTTFUnit2PDFUnit(units) + " internal units"; - } - - /** - * Map a glyph index to the corresponding unicode code point - * - * @param glyphIndex - * @return unicode code point - */ - private Integer glyphToUnicode(int glyphIndex) { - return glyphToUnicodeMap.get(new Integer(glyphIndex)); - } - - /** - * Map a unicode code point to the corresponding glyph index - * - * @param unicodeIndex unicode code point - * @return glyph index - */ - private Integer unicodeToGlyph(int unicodeIndex) throws IOException { - final Integer result - = unicodeToGlyphMap.get(new Integer(unicodeIndex)); - if (result == null) { - throw new IOException( - "Glyph index not found for unicode value " + unicodeIndex); - } - return result; - } - - String getGlyphName(int glyphIndex) { - return mtxTab[glyphIndex].getName(); - } - - /** - * Determine if advanced (typographic) table is present. - * @return true if advanced (typographic) table is present - */ - public boolean hasAdvancedTable() { - if (advancedTableReader != null) { - return advancedTableReader.hasAdvancedTable(); - } else { - return false; - } - } - - /** - * Returns the GDEF table or null if none present. - * @return the GDEF table - */ - public GlyphDefinitionTable getGDEF() { - if (advancedTableReader != null) { - return advancedTableReader.getGDEF(); - } else { - return null; - } - } - - /** - * Returns the GSUB table or null if none present. - * @return the GSUB table - */ - public GlyphSubstitutionTable getGSUB() { - if (advancedTableReader != null) { - return advancedTableReader.getGSUB(); - } else { - return null; - } - } - - /** - * Returns the GPOS table or null if none present. - * @return the GPOS table - */ - public GlyphPositioningTable getGPOS() { - if (advancedTableReader != null) { - return advancedTableReader.getGPOS(); - } else { - return null; - } - } - - /** - * Static main method to get info about a TrueType font. - * @param args The command line arguments - */ - public static void main(String[] args) { - InputStream stream = null; - try { - boolean useKerning = true; - boolean useAdvanced = true; - - stream = new FileInputStream(args[0]); - FontFileReader reader = new FontFileReader(stream); - - String name = null; - if (args.length >= 2) { - name = args[1]; - } - - String header = OFFontLoader.readHeader(reader); - boolean isCFF = header.equals("OTTO"); - OpenFont otfFile = (isCFF) ? new OTFFile() : new TTFFile(useKerning, useAdvanced); - otfFile.readFont(reader, header, name); - otfFile.printStuff(); - - } catch (IOException ioe) { - System.err.println("Problem reading font: " + ioe.toString()); - ioe.printStackTrace(System.err); - } finally { - IOUtils.closeQuietly(stream); - } - } - - public String getCopyrightNotice() { - return notice; - } -} diff --git a/src/java/org/apache/fop/fonts/truetype/TTFFile.java b/src/java/org/apache/fop/fonts/truetype/TTFFile.java deleted file mode 100644 index 4b0e3d628..000000000 --- a/src/java/org/apache/fop/fonts/truetype/TTFFile.java +++ /dev/null @@ -1,203 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.io.IOException; - -/** - * Reads a TrueType file or a TrueType Collection. - * The TrueType spec can be found at the Microsoft. - * Typography site: http://www.microsoft.com/truetype/ - */ -public class TTFFile extends OpenFont { - - public TTFFile() { - this(true, false); - } - - /** - * Constructor - * @param useKerning true if kerning data should be loaded - * @param useAdvanced true if advanced typographic tables should be loaded - */ - public TTFFile(boolean useKerning, boolean useAdvanced) { - super(useKerning, useAdvanced); - } - - /** - * Read the "name" table. - * @throws IOException In case of a I/O problem - */ - protected void readName() throws IOException { - seekTab(fontFile, OFTableName.NAME, 2); - int i = fontFile.getCurrentPos(); - int n = fontFile.readTTFUShort(); - int j = fontFile.readTTFUShort() + i - 2; - i += 2 * 2; - - while (n-- > 0) { - // getLogger().debug("Iteration: " + n); - fontFile.seekSet(i); - final int platformID = fontFile.readTTFUShort(); - final int encodingID = fontFile.readTTFUShort(); - final int languageID = fontFile.readTTFUShort(); - - int k = fontFile.readTTFUShort(); - int l = fontFile.readTTFUShort(); - - if (((platformID == 1 || platformID == 3) - && (encodingID == 0 || encodingID == 1))) { - fontFile.seekSet(j + fontFile.readTTFUShort()); - String txt; - if (platformID == 3) { - txt = fontFile.readTTFString(l, encodingID); - } else { - txt = fontFile.readTTFString(l); - } - - if (log.isDebugEnabled()) { - log.debug(platformID + " " - + encodingID + " " - + languageID + " " - + k + " " + txt); - } - switch (k) { - case 0: - if (notice.length() == 0) { - notice = txt; - } - break; - case 1: //Font Family Name - case 16: //Preferred Family - familyNames.add(txt); - break; - case 2: - if (subFamilyName.length() == 0) { - subFamilyName = txt; - } - break; - case 4: - if (fullName.length() == 0 || (platformID == 3 && languageID == 1033)) { - fullName = txt; - } - break; - case 6: - if (postScriptName.length() == 0) { - postScriptName = txt; - } - break; - default: - break; - } - } - i += 6 * 2; - } - } - - /** - * Read the "glyf" table to find the bounding boxes. - * @throws IOException In case of a I/O problem - */ - private void readGlyf() throws IOException { - OFDirTabEntry dirTab = dirTabs.get(OFTableName.GLYF); - if (dirTab == null) { - throw new IOException("glyf table not found, cannot continue"); - } - for (int i = 0; i < (numberOfGlyphs - 1); i++) { - if (mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) { - fontFile.seekSet(dirTab.getOffset() + mtxTab[i].getOffset()); - fontFile.skip(2); - final int[] bbox = { - fontFile.readTTFShort(), - fontFile.readTTFShort(), - fontFile.readTTFShort(), - fontFile.readTTFShort()}; - mtxTab[i].setBoundingBox(bbox); - } else { - mtxTab[i].setBoundingBox(mtxTab[0].getBoundingBox()); - } - } - - long n = (dirTabs.get(OFTableName.GLYF)).getOffset(); - for (int i = 0; i < numberOfGlyphs; i++) { - if ((i + 1) >= mtxTab.length - || mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) { - fontFile.seekSet(n + mtxTab[i].getOffset()); - fontFile.skip(2); - final int[] bbox = { - fontFile.readTTFShort(), - fontFile.readTTFShort(), - fontFile.readTTFShort(), - fontFile.readTTFShort()}; - mtxTab[i].setBoundingBox(bbox); - } else { - /**@todo Verify that this is correct, looks like a copy/paste bug (jm)*/ - final int bbox0 = mtxTab[0].getBoundingBox()[0]; - final int[] bbox = {bbox0, bbox0, bbox0, bbox0}; - mtxTab[i].setBoundingBox(bbox); - /* Original code - mtxTab[i].bbox[0] = mtxTab[0].bbox[0]; - mtxTab[i].bbox[1] = mtxTab[0].bbox[0]; - mtxTab[i].bbox[2] = mtxTab[0].bbox[0]; - mtxTab[i].bbox[3] = mtxTab[0].bbox[0]; */ - } - if (log.isTraceEnabled()) { - log.trace(mtxTab[i].toString(this)); - } - } - } - - @Override - protected void updateBBoxAndOffset() throws IOException { - readIndexToLocation(); - readGlyf(); - } - - /** - * Read the "loca" table. - * @throws IOException In case of a I/O problem - */ - protected final void readIndexToLocation() - throws IOException { - if (!seekTab(fontFile, OFTableName.LOCA, 0)) { - throw new IOException("'loca' table not found, happens when the font file doesn't" - + " contain TrueType outlines (trying to read an OpenType CFF font maybe?)"); - } - for (int i = 0; i < numberOfGlyphs; i++) { - mtxTab[i].setOffset(locaFormat == 1 ? fontFile.readTTFULong() - : (fontFile.readTTFUShort() << 1)); - } - lastLoca = (locaFormat == 1 ? fontFile.readTTFULong() - : (fontFile.readTTFUShort() << 1)); - } - - /** - * Gets the last location of the glyf table - * @return The last location as a long - */ - public long getLastGlyfLocation() { - return lastLoca; - } - - @Override - protected void initializeFont(FontFileReader in) throws IOException { - fontFile = in; - } -} diff --git a/src/java/org/apache/fop/fonts/truetype/TTFGlyphOutputStream.java b/src/java/org/apache/fop/fonts/truetype/TTFGlyphOutputStream.java deleted file mode 100644 index 313d5836d..000000000 --- a/src/java/org/apache/fop/fonts/truetype/TTFGlyphOutputStream.java +++ /dev/null @@ -1,48 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.io.IOException; - -/** - * An interface for writing individual glyphs from the glyf table of a TrueType font to an output stream. - */ -public interface TTFGlyphOutputStream { - - /** - * Begins the streaming of glyphs. - */ - void startGlyphStream() throws IOException; - - /** - * Streams an individual glyph from the given byte array. - * - * @param glyphData the source of the glyph data to stream from - * @param offset the position in the glyph data where the glyph starts - * @param size the size of the glyph data in bytes - */ - void streamGlyph(byte[] glyphData, int offset, int size) throws IOException; - - /** - * Ends the streaming of glyphs. - */ - void endGlyphStream() throws IOException; - -} diff --git a/src/java/org/apache/fop/fonts/truetype/TTFOutputStream.java b/src/java/org/apache/fop/fonts/truetype/TTFOutputStream.java deleted file mode 100644 index 09b5b6f50..000000000 --- a/src/java/org/apache/fop/fonts/truetype/TTFOutputStream.java +++ /dev/null @@ -1,49 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.io.IOException; - -/** - * An interface for writing a TrueType font to an output stream. - */ -public interface TTFOutputStream { - - /** - * Starts writing the font. - */ - void startFontStream() throws IOException; - - /** - * Returns an object for streaming TrueType tables. - */ - TTFTableOutputStream getTableOutputStream(); - - /** - * Returns an object for streaming TrueType glyphs in the glyf table. - */ - TTFGlyphOutputStream getGlyphOutputStream(); - - /** - * Ends writing the font. - */ - void endFontStream() throws IOException; - -} diff --git a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java b/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java deleted file mode 100644 index 6d2d68672..000000000 --- a/src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java +++ /dev/null @@ -1,714 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.SortedSet; - - -/** - * Reads a TrueType file and generates a subset - * that can be used to embed a TrueType CID font. - * TrueType tables needed for embedded CID fonts are: - * "head", "hhea", "loca", "maxp", "cvt ", "prep", "glyf", "hmtx" and "fpgm". - * The TrueType spec can be found at the Microsoft - * Typography site: http://www.microsoft.com/truetype/ - */ -public class TTFSubSetFile extends TTFFile { - - protected byte[] output; - protected int realSize; - protected int currentPos; - - /* - * Offsets in name table to be filled out by table. - * The offsets are to the checkSum field - */ - protected Map<OFTableName, Integer> offsets = new HashMap<OFTableName, Integer>(); - - private int checkSumAdjustmentOffset; - protected int locaOffset; - - /** Stores the glyph offsets so that we can end strings at glyph boundaries */ - protected int[] glyphOffsets; - - /** - * Default Constructor - */ - public TTFSubSetFile() { - } - - /** - * Constructor - * @param useKerning true if kerning data should be loaded - * @param useAdvanced true if advanced typographic tables should be loaded - */ - public TTFSubSetFile(boolean useKerning, boolean useAdvanced) { - super(useKerning, useAdvanced); - } - - /** The dir tab entries in the new subset font. */ - protected Map<OFTableName, OFDirTabEntry> newDirTabs - = new HashMap<OFTableName, OFDirTabEntry>(); - - private int determineTableCount() { - int numTables = 4; //4 req'd tables: head,hhea,hmtx,maxp - if (isCFF()) { - throw new UnsupportedOperationException( - "OpenType fonts with CFF glyphs are not supported"); - } else { - numTables += 5; //5 req'd tables: glyf,loca,post,name,OS/2 - if (hasCvt()) { - numTables++; - } - if (hasFpgm()) { - numTables++; - } - if (hasPrep()) { - numTables++; - } - if (!cid) { - numTables++; //cmap - } - } - return numTables; - } - - /** - * Create the directory table - */ - protected void createDirectory() { - int numTables = determineTableCount(); - // Create the TrueType header - writeByte((byte)0); - writeByte((byte)1); - writeByte((byte)0); - writeByte((byte)0); - realSize += 4; - - writeUShort(numTables); - realSize += 2; - - // Create searchRange, entrySelector and rangeShift - int maxPow = maxPow2(numTables); - int searchRange = (int) Math.pow(2, maxPow) * 16; - writeUShort(searchRange); - realSize += 2; - - writeUShort(maxPow); - realSize += 2; - - writeUShort((numTables * 16) - searchRange); - realSize += 2; - // Create space for the table entries (these must be in ASCII alphabetical order[A-Z] then[a-z]) - writeTableName(OFTableName.OS2); - if (!cid) { - writeTableName(OFTableName.CMAP); - } - if (hasCvt()) { - writeTableName(OFTableName.CVT); - } - if (hasFpgm()) { - writeTableName(OFTableName.FPGM); - } - writeTableName(OFTableName.GLYF); - writeTableName(OFTableName.HEAD); - writeTableName(OFTableName.HHEA); - writeTableName(OFTableName.HMTX); - writeTableName(OFTableName.LOCA); - writeTableName(OFTableName.MAXP); - writeTableName(OFTableName.NAME); - writeTableName(OFTableName.POST); - if (hasPrep()) { - writeTableName(OFTableName.PREP); - } - newDirTabs.put(OFTableName.TABLE_DIRECTORY, new OFDirTabEntry(0, currentPos)); - } - - private void writeTableName(OFTableName tableName) { - writeString(tableName.getName()); - offsets.put(tableName, currentPos); - currentPos += 12; - realSize += 16; - } - - - private boolean hasCvt() { - return dirTabs.containsKey(OFTableName.CVT); - } - - private boolean hasFpgm() { - return dirTabs.containsKey(OFTableName.FPGM); - } - - private boolean hasPrep() { - return dirTabs.containsKey(OFTableName.PREP); - } - - /** - * Create an empty loca table without updating checksum - */ - protected void createLoca(int size) throws IOException { - pad4(); - locaOffset = currentPos; - int dirTableOffset = offsets.get(OFTableName.LOCA); - writeULong(dirTableOffset + 4, currentPos); - writeULong(dirTableOffset + 8, size * 4 + 4); - currentPos += size * 4 + 4; - realSize += size * 4 + 4; - } - - private boolean copyTable(FontFileReader in, OFTableName tableName) throws IOException { - OFDirTabEntry entry = dirTabs.get(tableName); - if (entry != null) { - pad4(); - seekTab(in, tableName, 0); - writeBytes(in.getBytes((int) entry.getOffset(), (int) entry.getLength())); - - updateCheckSum(currentPos, (int) entry.getLength(), tableName); - currentPos += (int) entry.getLength(); - realSize += (int) entry.getLength(); - return true; - } else { - return false; - } - } - - /** - * Copy the cvt table as is from original font to subset font - */ - protected boolean createCvt(FontFileReader in) throws IOException { - return copyTable(in, OFTableName.CVT); - } - - /** - * Copy the fpgm table as is from original font to subset font - */ - protected boolean createFpgm(FontFileReader in) throws IOException { - return copyTable(in, OFTableName.FPGM); - } - - /** - * Copy the name table as is from the original. - */ - protected boolean createName(FontFileReader in) throws IOException { - return copyTable(in, OFTableName.NAME); - } - - /** - * Copy the OS/2 table as is from the original. - */ - protected boolean createOS2(FontFileReader in) throws IOException { - return copyTable(in, OFTableName.OS2); - } - - /** - * Copy the maxp table as is from original font to subset font - * and set num glyphs to size - */ - protected void createMaxp(FontFileReader in, int size) throws IOException { - OFTableName maxp = OFTableName.MAXP; - OFDirTabEntry entry = dirTabs.get(maxp); - if (entry != null) { - pad4(); - seekTab(in, maxp, 0); - writeBytes(in.getBytes((int) entry.getOffset(), (int) entry.getLength())); - writeUShort(currentPos + 4, size); - - updateCheckSum(currentPos, (int)entry.getLength(), maxp); - currentPos += (int)entry.getLength(); - realSize += (int)entry.getLength(); - } else { - throw new IOException("Can't find maxp table"); - } - } - - protected void createPost(FontFileReader in) throws IOException { - OFTableName post = OFTableName.POST; - OFDirTabEntry entry = dirTabs.get(post); - if (entry != null) { - pad4(); - seekTab(in, post, 0); - int newTableSize = 32; // This is the post table size with glyphs truncated - byte[] newPostTable = new byte[newTableSize]; - // We only want the first 28 bytes (truncate the glyph names); - System.arraycopy(in.getBytes((int) entry.getOffset(), newTableSize), - 0, newPostTable, 0, newTableSize); - // set the post table to Format 3.0 - newPostTable[1] = 0x03; - writeBytes(newPostTable); - updateCheckSum(currentPos, newTableSize, post); - currentPos += newTableSize; - realSize += newTableSize; - } else { -// throw new IOException("Can't find post table"); - } - } - - - /** - * Copy the prep table as is from original font to subset font - */ - protected boolean createPrep(FontFileReader in) throws IOException { - return copyTable(in, OFTableName.PREP); - } - - - /** - * Copy the hhea table as is from original font to subset font - * and fill in size of hmtx table - */ - protected void createHhea(FontFileReader in, int size) throws IOException { - OFDirTabEntry entry = dirTabs.get(OFTableName.HHEA); - if (entry != null) { - pad4(); - seekTab(in, OFTableName.HHEA, 0); - writeBytes(in.getBytes((int) entry.getOffset(), (int) entry.getLength())); - writeUShort((int) entry.getLength() + currentPos - 2, size); - - updateCheckSum(currentPos, (int) entry.getLength(), OFTableName.HHEA); - currentPos += (int) entry.getLength(); - realSize += (int) entry.getLength(); - } else { - throw new IOException("Can't find hhea table"); - } - } - - - /** - * Copy the head table as is from original font to subset font - * and set indexToLocaFormat to long and set - * checkSumAdjustment to 0, store offset to checkSumAdjustment - * in checkSumAdjustmentOffset - */ - protected void createHead(FontFileReader in) throws IOException { - OFTableName head = OFTableName.HEAD; - OFDirTabEntry entry = dirTabs.get(head); - if (entry != null) { - pad4(); - seekTab(in, head, 0); - writeBytes(in.getBytes((int) entry.getOffset(), (int) entry.getLength())); - - checkSumAdjustmentOffset = currentPos + 8; - output[currentPos + 8] = 0; // Set checkSumAdjustment to 0 - output[currentPos + 9] = 0; - output[currentPos + 10] = 0; - output[currentPos + 11] = 0; - output[currentPos + 50] = 0; // long locaformat - if (cid) { - output[currentPos + 51] = 1; // long locaformat - } - updateCheckSum(currentPos, (int)entry.getLength(), head); - currentPos += (int)entry.getLength(); - realSize += (int)entry.getLength(); - } else { - throw new IOException("Can't find head table"); - } - } - - - /** - * Create the glyf table and fill in loca table - */ - private void createGlyf(FontFileReader in, - Map<Integer, Integer> glyphs) throws IOException { - OFTableName glyf = OFTableName.GLYF; - OFDirTabEntry entry = dirTabs.get(glyf); - int size = 0; - int startPos = 0; - int endOffset = 0; // Store this as the last loca - if (entry != null) { - pad4(); - startPos = currentPos; - - /* Loca table must be in order by glyph index, so build - * an array first and then write the glyph info and - * location offset. - */ - int[] origIndexes = buildSubsetIndexToOrigIndexMap(glyphs); - glyphOffsets = new int[origIndexes.length]; - - for (int i = 0; i < origIndexes.length; i++) { - int nextOffset = 0; - int origGlyphIndex = origIndexes[i]; - if (origGlyphIndex >= (mtxTab.length - 1)) { - nextOffset = (int)lastLoca; - } else { - nextOffset = (int)mtxTab[origGlyphIndex + 1].getOffset(); - } - int glyphOffset = (int)mtxTab[origGlyphIndex].getOffset(); - int glyphLength = nextOffset - glyphOffset; - - byte[] glyphData = in.getBytes( - (int)entry.getOffset() + glyphOffset, - glyphLength); - int endOffset1 = endOffset; - // Copy glyph - writeBytes(glyphData); - - - // Update loca table - writeULong(locaOffset + i * 4, currentPos - startPos); - if ((currentPos - startPos + glyphLength) > endOffset1) { - endOffset1 = (currentPos - startPos + glyphLength); - } - - // Store the glyph boundary positions relative to the start of the font - glyphOffsets[i] = currentPos; - currentPos += glyphLength; - realSize += glyphLength; - - - endOffset = endOffset1; - } - - - size = currentPos - startPos; - - currentPos += 12; - realSize += 12; - updateCheckSum(startPos, size + 12, glyf); - - // Update loca checksum and last loca index - writeULong(locaOffset + glyphs.size() * 4, endOffset); - int locaSize = glyphs.size() * 4 + 4; - int checksum = getCheckSum(output, locaOffset, locaSize); - writeULong(offsets.get(OFTableName.LOCA), checksum); - int padSize = (locaOffset + locaSize) % 4; - newDirTabs.put(OFTableName.LOCA, - new OFDirTabEntry(locaOffset, locaSize + padSize)); - } else { - throw new IOException("Can't find glyf table"); - } - } - - protected int[] buildSubsetIndexToOrigIndexMap(Map<Integer, Integer> glyphs) { - int[] origIndexes = new int[glyphs.size()]; - for (Map.Entry<Integer, Integer> glyph : glyphs.entrySet()) { - int origIndex = glyph.getKey(); - int subsetIndex = glyph.getValue(); - if (origIndexes.length > subsetIndex) { - origIndexes[subsetIndex] = origIndex; - } - } - return origIndexes; - } - - /** - * Create the hmtx table by copying metrics from original - * font to subset font. The glyphs Map contains an - * Integer key and Integer value that maps the original - * metric (key) to the subset metric (value) - */ - protected void createHmtx(FontFileReader in, - Map<Integer, Integer> glyphs) throws IOException { - OFTableName hmtx = OFTableName.HMTX; - OFDirTabEntry entry = dirTabs.get(hmtx); - - int longHorMetricSize = glyphs.size() * 2; - int leftSideBearingSize = glyphs.size() * 2; - int hmtxSize = longHorMetricSize + leftSideBearingSize; - - if (entry != null) { - pad4(); - //int offset = (int)entry.offset; - for (Map.Entry<Integer, Integer> glyph : glyphs.entrySet()) { - Integer origIndex = glyph.getKey(); - Integer subsetIndex = glyph.getValue(); - - writeUShort(currentPos + subsetIndex.intValue() * 4, - mtxTab[origIndex.intValue()].getWx()); - writeUShort(currentPos + subsetIndex.intValue() * 4 + 2, - mtxTab[origIndex.intValue()].getLsb()); - } - - updateCheckSum(currentPos, hmtxSize, hmtx); - currentPos += hmtxSize; - realSize += hmtxSize; - } else { - throw new IOException("Can't find hmtx table"); - } - } - - /** - * Reads a font and creates a subset of the font. - * - * @param in FontFileReader to read from - * @param name Name to be checked for in the font file - * @param glyphs Map of glyphs (glyphs has old index as (Integer) key and - * new index as (Integer) value) - * @throws IOException in case of an I/O problem - */ - public void readFont(FontFileReader in, String name, String header, - Map<Integer, Integer> glyphs) throws IOException { - fontFile = in; - //Check if TrueType collection, and that the name exists in the collection - if (!checkTTC(header, name)) { - throw new IOException("Failed to read font"); - } - - //Copy the Map as we're going to modify it - Map<Integer, Integer> subsetGlyphs = new HashMap<Integer, Integer>(glyphs); - - output = new byte[in.getFileSize()]; - - readDirTabs(); - readFontHeader(); - getNumGlyphs(); - readHorizontalHeader(); - readHorizontalMetrics(); - readIndexToLocation(); - - scanGlyphs(in, subsetGlyphs); - - createDirectory(); // Create the TrueType header and directory - - boolean optionalTableFound; - optionalTableFound = createCvt(in); // copy the cvt table - if (!optionalTableFound) { - // cvt is optional (used in TrueType fonts only) - log.debug("TrueType: ctv table not present. Skipped."); - } - - optionalTableFound = createFpgm(in); // copy fpgm table - if (!optionalTableFound) { - // fpgm is optional (used in TrueType fonts only) - log.debug("TrueType: fpgm table not present. Skipped."); - } - createLoca(subsetGlyphs.size()); // create empty loca table - createGlyf(in, subsetGlyphs); //create glyf table and update loca table - - createOS2(in); // copy the OS/2 table - createHead(in); - createHhea(in, subsetGlyphs.size()); // Create the hhea table - createHmtx(in, subsetGlyphs); // Create hmtx table - createMaxp(in, subsetGlyphs.size()); // copy the maxp table - createName(in); // copy the name table - createPost(in); // copy the post table - - optionalTableFound = createPrep(in); // copy prep table - if (!optionalTableFound) { - // prep is optional (used in TrueType fonts only) - log.debug("TrueType: prep table not present. Skipped."); - } - - pad4(); - createCheckSumAdjustment(); - } - - /** - * Returns a subset of the fonts (readFont() MUST be called first in order to create the - * subset). - * @return byte array - */ - public byte[] getFontSubset() { - byte[] ret = new byte[realSize]; - System.arraycopy(output, 0, ret, 0, realSize); - return ret; - } - - private void handleGlyphSubset(TTFGlyphOutputStream glyphOut) throws IOException { - glyphOut.startGlyphStream(); - // Stream all but the last glyph - for (int i = 0; i < glyphOffsets.length - 1; i++) { - glyphOut.streamGlyph(output, glyphOffsets[i], - glyphOffsets[i + 1] - glyphOffsets[i]); - } - // Stream the last glyph - OFDirTabEntry glyf = newDirTabs.get(OFTableName.GLYF); - long lastGlyphLength = glyf.getLength() - - (glyphOffsets[glyphOffsets.length - 1] - glyf.getOffset()); - glyphOut.streamGlyph(output, glyphOffsets[glyphOffsets.length - 1], - (int) lastGlyphLength); - glyphOut.endGlyphStream(); - } - - @Override - public void stream(TTFOutputStream ttfOut) throws IOException { - SortedSet<Map.Entry<OFTableName, OFDirTabEntry>> sortedDirTabs - = sortDirTabMap(newDirTabs); - TTFTableOutputStream tableOut = ttfOut.getTableOutputStream(); - TTFGlyphOutputStream glyphOut = ttfOut.getGlyphOutputStream(); - - ttfOut.startFontStream(); - for (Map.Entry<OFTableName, OFDirTabEntry> entry : sortedDirTabs) { - if (entry.getKey().equals(OFTableName.GLYF)) { - handleGlyphSubset(glyphOut); - } else { - tableOut.streamTable(output, (int) entry.getValue().getOffset(), - (int) entry.getValue().getLength()); - } - } - ttfOut.endFontStream(); - } - - protected void scanGlyphs(FontFileReader in, Map<Integer, Integer> subsetGlyphs) - throws IOException { - OFDirTabEntry glyfTableInfo = dirTabs.get(OFTableName.GLYF); - if (glyfTableInfo == null) { - throw new IOException("Glyf table could not be found"); - } - - GlyfTable glyfTable = new GlyfTable(in, mtxTab, glyfTableInfo, subsetGlyphs); - glyfTable.populateGlyphsWithComposites(); - } - - /** - * writes a ISO-8859-1 string at the currentPosition - * updates currentPosition but not realSize - * @return number of bytes written - */ - private int writeString(String str) { - int length = 0; - try { - byte[] buf = str.getBytes("ISO-8859-1"); - writeBytes(buf); - length = buf.length; - currentPos += length; - } catch (java.io.UnsupportedEncodingException e) { - // This should never happen! - } - - return length; - } - - /** - * Appends a byte to the output array, - * updates currentPost but not realSize - */ - private void writeByte(byte b) { - output[currentPos++] = b; - } - - protected void writeBytes(byte[] b) { - if (b.length + currentPos > output.length) { - byte[] newoutput = new byte[output.length * 2]; - System.arraycopy(output, 0, newoutput, 0, output.length); - output = newoutput; - } - System.arraycopy(b, 0, output, currentPos, b.length); - } - - /** - * Appends a USHORT to the output array, - * updates currentPost but not realSize - */ - protected void writeUShort(int s) { - byte b1 = (byte)((s >> 8) & 0xff); - byte b2 = (byte)(s & 0xff); - writeByte(b1); - writeByte(b2); - } - - /** - * Appends a USHORT to the output array, - * at the given position without changing currentPos - */ - protected void writeUShort(int pos, int s) { - byte b1 = (byte)((s >> 8) & 0xff); - byte b2 = (byte)(s & 0xff); - output[pos] = b1; - output[pos + 1] = b2; - } - - - /** - * Appends a ULONG to the output array, - * at the given position without changing currentPos - */ - protected void writeULong(int pos, int s) { - byte b1 = (byte)((s >> 24) & 0xff); - byte b2 = (byte)((s >> 16) & 0xff); - byte b3 = (byte)((s >> 8) & 0xff); - byte b4 = (byte)(s & 0xff); - output[pos] = b1; - output[pos + 1] = b2; - output[pos + 2] = b3; - output[pos + 3] = b4; - } - - /** - * Create a padding in the fontfile to align - * on a 4-byte boundary - */ - protected void pad4() { - int padSize = getPadSize(currentPos); - if (padSize < 4) { - for (int i = 0; i < padSize; i++) { - output[currentPos++] = 0; - realSize++; - } - } - } - - /** - * Returns the maximum power of 2 <= max - */ - private int maxPow2(int max) { - int i = 0; - while (Math.pow(2, i) <= max) { - i++; - } - - return (i - 1); - } - - - protected void updateCheckSum(int tableStart, int tableSize, OFTableName tableName) { - int checksum = getCheckSum(output, tableStart, tableSize); - int offset = offsets.get(tableName); - int padSize = getPadSize(tableStart + tableSize); - newDirTabs.put(tableName, new OFDirTabEntry(tableStart, tableSize + padSize)); - writeULong(offset, checksum); - writeULong(offset + 4, tableStart); - writeULong(offset + 8, tableSize); - } - - protected static int getCheckSum(byte[] data, int start, int size) { - // All the tables here are aligned on four byte boundaries - // Add remainder to size if it's not a multiple of 4 - int remainder = size % 4; - if (remainder != 0) { - size += remainder; - } - - long sum = 0; - - for (int i = 0; i < size; i += 4) { - long l = 0; - for (int j = 0; j < 4; j++) { - l <<= 8; - if (data.length > (start + i + j)) { - l |= data[start + i + j] & 0xff; - } - } - sum += l; - } - return (int) sum; - } - - protected void createCheckSumAdjustment() { - long sum = getCheckSum(output, 0, realSize); - int checksum = (int)(0xb1b0afba - sum); - writeULong(checkSumAdjustmentOffset, checksum); - } -} diff --git a/src/java/org/apache/fop/fonts/truetype/TTFTableOutputStream.java b/src/java/org/apache/fop/fonts/truetype/TTFTableOutputStream.java deleted file mode 100644 index d0d2007f5..000000000 --- a/src/java/org/apache/fop/fonts/truetype/TTFTableOutputStream.java +++ /dev/null @@ -1,37 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.truetype; - -import java.io.IOException; - -/** - * An interface for writing a TrueType table to an output stream. - */ -public interface TTFTableOutputStream { - - /** - * Streams a table from the given byte array. - * - * @param ttfData the source of the table to stream from - * @param offset the position in the byte array where the table starts - * @param size the size of the table in bytes - */ - void streamTable(byte[] ttfData, int offset, int size) throws IOException; -} diff --git a/src/java/org/apache/fop/fonts/truetype/package.html b/src/java/org/apache/fop/fonts/truetype/package.html deleted file mode 100644 index 6517f9889..000000000 --- a/src/java/org/apache/fop/fonts/truetype/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<HTML> -<TITLE>org.apache.fop.fonts.truetype Package</TITLE> -<BODY> -<P>Classes for TrueType fonts.</P> -</BODY> -</HTML>
\ No newline at end of file diff --git a/src/java/org/apache/fop/fonts/type1/AFMCharMetrics.java b/src/java/org/apache/fop/fonts/type1/AFMCharMetrics.java deleted file mode 100644 index 8d9f4238b..000000000 --- a/src/java/org/apache/fop/fonts/type1/AFMCharMetrics.java +++ /dev/null @@ -1,167 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.type1; - -import java.awt.Rectangle; - -import org.apache.fop.fonts.NamedCharacter; - - -/** - * Holds the metrics of a single character from an AFM file. - */ -public class AFMCharMetrics { - - private int charCode = -1; - private NamedCharacter character; - private double widthX; - private double widthY; - private Rectangle bBox; - - /** - * Returns the character code. - * @return the charCode (-1 if not part of the encoding) - */ - public int getCharCode() { - return charCode; - } - - /** - * Indicates whether the character has a character code, i.e. is part of the default encoding. - * @return true if there is a character code. - */ - public boolean hasCharCode() { - return charCode >= 0; - } - - /** - * Sets the character code. - * @param charCode the charCode to set - */ - public void setCharCode(int charCode) { - this.charCode = charCode; - } - - /** - * Returns the named character represented by this instance. - * @return the named character (or null if no named character is associated) - */ - public NamedCharacter getCharacter() { - return this.character; - } - - /** - * Sets the named character represented by this instance. - * @param ch the named character - */ - public void setCharacter(NamedCharacter ch) { - this.character = ch; - } - - /** - * Sets the named character represented by this instance. - * @param charName the character name (as defined in the Adobe glyph list) - * @param unicodeSequence the Unicode sequence - */ - public void setCharacter(String charName, String unicodeSequence) { - setCharacter(new NamedCharacter(charName, unicodeSequence)); - } - - /** - * Returns the Unicode sequence for this character. - * @return the Unicode characters - * (or null if no such Unicode sequence exists for this character) - */ - public String getUnicodeSequence() { - return (getCharacter() != null ? getCharacter().getUnicodeSequence() : null); - } - - /** - * Returns the PostScript character name. - * @return the charName (or null if no character name is associated) - */ - public String getCharName() { - return (getCharacter() != null ? getCharacter().getName() : null); - } - - /** - * Returns the progression dimension in x-direction. - * @return the widthX - */ - public double getWidthX() { - return widthX; - } - - /** - * Sets the progression dimension in x-direction - * @param widthX the widthX to set - */ - public void setWidthX(double widthX) { - this.widthX = widthX; - } - - /** - * Returns the progression dimension in y-direction. - * @return the widthY - */ - public double getWidthY() { - return widthY; - } - - /** - * Sets the progression dimension in y-direction - * @param widthY the widthY to set - */ - public void setWidthY(double widthY) { - this.widthY = widthY; - } - - /** - * Returns the character's bounding box. - * @return the bounding box (or null if it isn't available) - */ - public Rectangle getBBox() { - return bBox; - } - - /** - * Sets the character's bounding box. - * @param box the bounding box - */ - public void setBBox(Rectangle box) { - bBox = box; - } - - /** {@inheritDoc} */ - public String toString() { - StringBuffer sb = new StringBuffer("AFM Char: "); - sb.append(getCharCode()); - sb.append(" ("); - if (getUnicodeSequence() != null) { - for (int i = 0, c = getUnicodeSequence().length(); i < c; i++) { - sb.append("0x").append(Integer.toHexString(getUnicodeSequence().charAt(i))); - sb.append(", "); - } - } - sb.append(getCharName()).append(')'); - return sb.toString(); - } - -} diff --git a/src/java/org/apache/fop/fonts/type1/AFMFile.java b/src/java/org/apache/fop/fonts/type1/AFMFile.java deleted file mode 100644 index 2aa718ea0..000000000 --- a/src/java/org/apache/fop/fonts/type1/AFMFile.java +++ /dev/null @@ -1,505 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.type1; - -import java.awt.geom.Dimension2D; -import java.awt.geom.RectangularShape; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.xmlgraphics.java2d.Dimension2DDouble; - -import org.apache.fop.fonts.NamedCharacter; -import org.apache.fop.fonts.SingleByteEncoding; - -/** - * Represents the contents of a Type 1 AFM font metrics file. - */ -public class AFMFile { - - /** logging instance */ - private static final Log LOG = LogFactory.getLog(AFMFile.class); - - private String fontName; - private String fullName; - private String familyName; - - private String weight; - private RectangularShape fontBBox; - - private String encodingScheme; - private String characterSet; - - private Number capHeight; - private Number xHeight; - private Number ascender; - private Number descender; - private Number stdHW; - private Number stdVW; - - private AFMWritingDirectionMetrics[] writingDirectionMetrics - = new AFMWritingDirectionMetrics[3]; - - private List<AFMCharMetrics> charMetrics = new java.util.ArrayList<AFMCharMetrics>(); - private Map<String, AFMCharMetrics> charNameToMetrics - = new java.util.HashMap<String, AFMCharMetrics>(); - private int firstChar = -1; - private int lastChar = -1; - - private Map<String, Map<String, Dimension2D>> kerningMap; - - /** - * Default constructor. - */ - public AFMFile() { - //nop - } - - /** - * Returns the FontName value. - * @return the font name - */ - public String getFontName() { - return fontName; - } - - /** - * Sets the FontName value. - * @param fontName the font name to set - */ - public void setFontName(String fontName) { - this.fontName = fontName; - } - - /** - * Returns the FullName value. - * @return the full name of the font - */ - public String getFullName() { - return fullName; - } - - /** - * Sets the FullName value. - * @param fullName the full name to set - */ - public void setFullName(String fullName) { - this.fullName = fullName; - } - - /** - * Returns the FamilyName value. - * @return the family name of the font - */ - public String getFamilyName() { - return familyName; - } - - /** - * Sets the FamilyName value. - * @param familyName the family name to set - */ - public void setFamilyName(String familyName) { - this.familyName = familyName; - } - - /** - * Returns the Weight value. - * @return the weight - */ - public String getWeight() { - return weight; - } - - /** - * Sets the Weight value. - * @param weight the weight to set - */ - public void setWeight(String weight) { - this.weight = weight; - } - - /** - * Returns the FontBBox value. - * @return the font's bounding box - */ - public RectangularShape getFontBBox() { - return fontBBox; - } - - /** - * Returns the FontBBox value as integer array. - * @return the font's bounding box - */ - public int[] getFontBBoxAsIntArray() { - RectangularShape rect = getFontBBox(); - return new int[] { - (int)Math.floor(rect.getMinX()), (int)Math.floor(rect.getMinY()), - (int)Math.ceil(rect.getMaxX()), (int)Math.ceil(rect.getMaxY())}; - } - - /** - * Sets the FontBBox value. - * @param fontBBox the fontBBox to set - */ - public void setFontBBox(RectangularShape fontBBox) { - this.fontBBox = fontBBox; - } - - /** - * Returns the EncodingScheme value. - * @return the encoding scheme - */ - public String getEncodingScheme() { - return encodingScheme; - } - - /** - * Sets the EncodingScheme value - * @param encodingScheme the encodingScheme to set - */ - public void setEncodingScheme(String encodingScheme) { - this.encodingScheme = encodingScheme; - } - - /** - * Returns the CharacterSet value. - * @return the characterSet - */ - public String getCharacterSet() { - return characterSet; - } - - /** - * Sets the CharacterSet value. - * @param characterSet the characterSet to set - */ - public void setCharacterSet(String characterSet) { - this.characterSet = characterSet; - } - - /** - * Returns the CapHeight value. - * @return the capHeight - */ - public Number getCapHeight() { - return capHeight; - } - - /** - * Sets the CapHeight value. - * @param capHeight the capHeight to set - */ - public void setCapHeight(Number capHeight) { - this.capHeight = capHeight; - } - - /** - * Returns the XHeight value. - * @return the xHeight - */ - public Number getXHeight() { - return xHeight; - } - - /** - * Sets the XHeight value. - * @param height the xHeight to set - */ - public void setXHeight(Number height) { - xHeight = height; - } - - /** - * Returns the Ascender value. - * @return the ascender - */ - public Number getAscender() { - return ascender; - } - - /** - * Sets the Ascender value. - * @param ascender the ascender to set - */ - public void setAscender(Number ascender) { - this.ascender = ascender; - } - - /** - * Returns the Descender value. - * @return the descender - */ - public Number getDescender() { - return descender; - } - - /** - * Sets the Descender value. - * @param descender the descender to set - */ - public void setDescender(Number descender) { - this.descender = descender; - } - - /** - * Returns the StdHW value. - * @return the descender - */ - public Number getStdHW() { - return stdHW; - } - - /** - * Sets the StdHW value. - * @param stdHW the StdHW to set - */ - public void setStdHW(Number stdHW) { - this.stdHW = stdHW; - } - - /** - * Returns the StdVW value. - * @return the descender - */ - public Number getStdVW() { - return stdVW; - } - - /** - * Sets the StdVW value. - * @param stdVW the StdVW to set - */ - public void setStdVW(Number stdVW) { - this.stdVW = stdVW; - } - - /** - * Gets writing direction metrics. - * @param index the writing direction (0, 1 or 2) - * @return the writing direction metrics - */ - public AFMWritingDirectionMetrics getWritingDirectionMetrics(int index) { - return this.writingDirectionMetrics[index]; - } - - /** - * Sets writing direction metrics. - * @param index the writing direction (0, 1 or 2) - * @param metrics the writing direction metrics - */ - public void setWritingDirectionMetrics(int index, AFMWritingDirectionMetrics metrics) { - this.writingDirectionMetrics[index] = metrics; - } - - /** - * Adds new character metrics. - * @param metrics the character metrics - */ - public void addCharMetrics(AFMCharMetrics metrics) { - String name = metrics.getCharName(); - if (metrics.getUnicodeSequence() == null && name.equals(".notdef")) { - //Ignore as no Unicode assignment is possible - return; - } - this.charMetrics.add(metrics); - if (name != null) { - this.charNameToMetrics.put(name, metrics); - } - int idx = metrics.getCharCode(); - if (idx >= 0) { //Only if the character is part of the encoding - if (firstChar < 0 || idx < firstChar) { - firstChar = idx; - } - if (lastChar < 0 || idx > lastChar) { - lastChar = idx; - } - } - } - - /** - * Returns the number of character available for this font. - * @return the number of character - */ - public int getCharCount() { - return this.charMetrics.size(); - } - - /** - * Returns the first character index in the encoding that has a glyph. - * @return the first character index with a glyph - */ - public int getFirstChar() { - return this.firstChar; - } - - /** - * Returns the last character index in the encoding that has a glyph. - * @return the last character index with a glyph - */ - public int getLastChar() { - return this.lastChar; - } - - /** - * Returns the character metrics associated with the character name. - * @param name the character name - * @return the character metrics or null if there's no such character - */ - public AFMCharMetrics getChar(String name) { - return this.charNameToMetrics.get(name); - } - - /** - * Returns the list of AFMCharMetrics instances representing all the available characters. - * @return a List of AFMCharMetrics instances - */ - public List<AFMCharMetrics> getCharMetrics() { - return Collections.unmodifiableList(this.charMetrics); - } - - /** - * Adds a X-kerning entry. - * @param name1 the name of the first character - * @param name2 the name of the second character - * @param kx kerning value in x-direction - */ - public void addXKerning(String name1, String name2, double kx) { - if (this.kerningMap == null) { - this.kerningMap = new java.util.HashMap<String, Map<String, Dimension2D>>(); - } - Map<String, Dimension2D> entries = this.kerningMap.get(name1); - if (entries == null) { - entries = new java.util.HashMap<String, Dimension2D>(); - this.kerningMap.put(name1, entries); - } - entries.put(name2, new Dimension2DDouble(kx, 0)); - } - - /** - * Indicates whether the font has kerning information. - * @return true if there is kerning information - */ - public boolean hasKerning() { - return this.kerningMap != null; - } - - /** - * Creates and returns a kerning map for writing mode 0 (ltr) with character codes. - * @return the kerning map or null if there is no kerning information. - */ - public Map<Integer, Map<Integer, Integer>> createXKerningMapEncoded() { - if (!hasKerning()) { - return null; - } - Map<Integer, Map<Integer, Integer>> m - = new java.util.HashMap<Integer, Map<Integer, Integer>>(); - for (Map.Entry<String, Map<String, Dimension2D>> entryFrom : this.kerningMap.entrySet()) { - String name1 = entryFrom.getKey(); - AFMCharMetrics chm1 = getChar(name1); - if (chm1 == null || !chm1.hasCharCode()) { - continue; - } - Map<Integer, Integer> container = null; - Map<String, Dimension2D> entriesTo = entryFrom.getValue(); - for (Map.Entry<String, Dimension2D> entryTo : entriesTo.entrySet()) { - String name2 = entryTo.getKey(); - AFMCharMetrics chm2 = getChar(name2); - if (chm2 == null || !chm2.hasCharCode()) { - continue; - } - if (container == null) { - Integer k1 = Integer.valueOf(chm1.getCharCode()); - container = m.get(k1); - if (container == null) { - container = new java.util.HashMap<Integer, Integer>(); - m.put(k1, container); - } - } - Dimension2D dim = entryTo.getValue(); - container.put(Integer.valueOf(chm2.getCharCode()), - Integer.valueOf((int)Math.round(dim.getWidth()))); - } - } - return m; - } - - /** - * The character codes in an AFM cannot always be trusted to be the same values as in the - * font's primary encoding. Therefore, we provide a way to override this primary encoding. - * @param encoding the encoding to replace the one given in the AFM - */ - public void overridePrimaryEncoding(SingleByteEncoding encoding) { - if (LOG.isDebugEnabled()) { - LOG.debug("Overriding primary encoding of " + getFontName() + " with: " + encoding); - } - AFMCharMetrics[] mapped = new AFMCharMetrics[256]; - for (AFMCharMetrics cm : this.charMetrics) { - NamedCharacter nc = cm.getCharacter(); - if (nc.hasSingleUnicodeValue()) { - int codePoint = encoding.mapChar(nc.getSingleUnicodeValue()); - if (codePoint > 0) { - if (mapped[codePoint] != null) { - if (LOG.isDebugEnabled()) { - AFMCharMetrics other = mapped[codePoint]; - String msg = "Not mapping character " + nc + " to code point " - + codePoint + " (" + Integer.toHexString(codePoint) + ") in " - + encoding + ". " - + other + " has already been assigned that code point."; - if (other.getUnicodeSequence() - .equals(nc.getUnicodeSequence())) { - msg += " This is a specialized glyph for the" - + " same Unicode character."; - //TODO should these be mapped to a private Unicode area to make - //them accessible? - } else { - msg += " This is a similar character."; - } - if (cm.getWidthX() != other.getWidthX()) { - msg += " They have differing widths: " - + cm.getWidthX() + " vs. " + other.getWidthX(); - } - LOG.debug(msg); - } - } else { - cm.setCharCode(codePoint); - mapped[codePoint] = cm; - } - } else { - cm.setCharCode(-1); - } - } else { - //No Unicode equivalent - cm.setCharCode(-1); - } - } - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return "AFM: " + getFullName(); - } - -} diff --git a/src/java/org/apache/fop/fonts/type1/AFMParser.java b/src/java/org/apache/fop/fonts/type1/AFMParser.java deleted file mode 100644 index ecc9196ed..000000000 --- a/src/java/org/apache/fop/fonts/type1/AFMParser.java +++ /dev/null @@ -1,597 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.type1; - -import java.awt.Rectangle; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; -import java.util.Stack; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.fonts.NamedCharacter; - -/** - * Parses the contents of a Type 1 AFM font metrics file into an object structure ({@link AFMFile}). - */ -public class AFMParser { - - private static Log log = LogFactory.getLog(AFMParser.class); - - private static final String START_FONT_METRICS = "StartFontMetrics"; - //private static final String END_FONT_METRICS = "EndFontMetrics"; - private static final String FONT_NAME = "FontName"; - private static final String FULL_NAME = "FullName"; - private static final String FAMILY_NAME = "FamilyName"; - private static final String WEIGHT = "Weight"; - private static final String FONT_BBOX = "FontBBox"; - private static final String ENCODING_SCHEME = "EncodingScheme"; - private static final String CHARACTER_SET = "CharacterSet"; - private static final String IS_BASE_FONT = "IsBaseFont"; - private static final String IS_CID_FONT = "IsCIDFont"; - private static final String CAP_HEIGHT = "CapHeight"; - private static final String X_HEIGHT = "XHeight"; - private static final String ASCENDER = "Ascender"; - private static final String DESCENDER = "Descender"; - private static final String STDHW = "StdHW"; - private static final String STDVW = "StdVW"; - private static final String UNDERLINE_POSITION = "UnderlinePosition"; - private static final String UNDERLINE_THICKNESS = "UnderlineThickness"; - private static final String ITALIC_ANGLE = "ItalicAngle"; - private static final String IS_FIXED_PITCH = "IsFixedPitch"; - private static final String START_DIRECTION = "StartDirection"; - private static final String END_DIRECTION = "EndDirection"; - private static final String START_CHAR_METRICS = "StartCharMetrics"; - private static final String END_CHAR_METRICS = "EndCharMetrics"; - private static final String C = "C"; - private static final String CH = "CH"; - private static final String WX = "WX"; - private static final String W0X = "W0X"; - private static final String W1X = "W1X"; - private static final String WY = "WY"; - private static final String W0Y = "W0Y"; - private static final String W1Y = "W1Y"; - private static final String W = "W"; - private static final String W0 = "W0"; - private static final String W1 = "W1"; - private static final String N = "N"; - private static final String B = "B"; - private static final String START_TRACK_KERN = "StartTrackKern"; - private static final String END_TRACK_KERN = "EndTrackKern"; - //private static final String START_KERN_PAIRS = "StartKernPairs"; - //private static final String START_KERN_PAIRS0 = "StartKernPairs0"; - private static final String START_KERN_PAIRS1 = "StartKernPairs1"; - //private static final String END_KERN_PAIRS = "EndKernPairs"; - private static final String START_COMPOSITES = "StartComposites"; - private static final String START_COMP_FONT_METRICS = "StartCompFontMetrics"; - - private static final String KP = "KP"; - private static final String KPH = "KPH"; - private static final String KPX = "KPX"; - private static final String KPY = "KPY"; - - private static final int PARSE_NORMAL = 0; - private static final int PARSE_CHAR_METRICS = 1; - - private static final Map<String, ValueHandler> VALUE_PARSERS; - private static final Map<String, Integer> PARSE_MODE_CHANGES; - - static { - VALUE_PARSERS = new HashMap<String, ValueHandler>(); - VALUE_PARSERS.put(START_FONT_METRICS, new StartFontMetrics()); - VALUE_PARSERS.put(FONT_NAME, new StringSetter(FONT_NAME)); - VALUE_PARSERS.put(FULL_NAME, new StringSetter(FULL_NAME)); - VALUE_PARSERS.put(FAMILY_NAME, new StringSetter(FAMILY_NAME)); - VALUE_PARSERS.put(WEIGHT, new StringSetter(WEIGHT)); - VALUE_PARSERS.put(ENCODING_SCHEME, new StringSetter(ENCODING_SCHEME)); - VALUE_PARSERS.put(FONT_BBOX, new FontBBox()); - VALUE_PARSERS.put(CHARACTER_SET, new StringSetter(CHARACTER_SET)); - VALUE_PARSERS.put(IS_BASE_FONT, new IsBaseFont()); - VALUE_PARSERS.put(IS_CID_FONT, new IsCIDFont()); - VALUE_PARSERS.put(CAP_HEIGHT, new NumberSetter(CAP_HEIGHT)); - VALUE_PARSERS.put(X_HEIGHT, new NumberSetter(X_HEIGHT)); - VALUE_PARSERS.put(ASCENDER, new NumberSetter(ASCENDER)); - VALUE_PARSERS.put(DESCENDER, new NumberSetter(DESCENDER)); - VALUE_PARSERS.put(STDHW, new NumberSetter(STDHW)); - VALUE_PARSERS.put(STDVW, new NumberSetter(STDVW)); - VALUE_PARSERS.put(START_DIRECTION, new StartDirection()); - VALUE_PARSERS.put(END_DIRECTION, new EndDirection()); - VALUE_PARSERS.put(UNDERLINE_POSITION, new WritingDirNumberSetter(UNDERLINE_POSITION)); - VALUE_PARSERS.put(UNDERLINE_THICKNESS, new WritingDirNumberSetter(UNDERLINE_THICKNESS)); - VALUE_PARSERS.put(ITALIC_ANGLE, new WritingDirDoubleSetter(ITALIC_ANGLE)); - VALUE_PARSERS.put(IS_FIXED_PITCH, new WritingDirBooleanSetter(IS_FIXED_PITCH)); - VALUE_PARSERS.put(C, new IntegerSetter("CharCode")); - VALUE_PARSERS.put(CH, new NotImplementedYet(CH)); - VALUE_PARSERS.put(WX, new DoubleSetter("WidthX")); - VALUE_PARSERS.put(W0X, new DoubleSetter("WidthX")); - VALUE_PARSERS.put(W1X, new NotImplementedYet(W1X)); - VALUE_PARSERS.put(WY, new DoubleSetter("WidthY")); - VALUE_PARSERS.put(W0Y, new DoubleSetter("WidthY")); - VALUE_PARSERS.put(W1Y, new NotImplementedYet(W1Y)); - VALUE_PARSERS.put(W, new NotImplementedYet(W)); - VALUE_PARSERS.put(W0, new NotImplementedYet(W0)); - VALUE_PARSERS.put(W1, new NotImplementedYet(W1)); - VALUE_PARSERS.put(N, new NamedCharacterSetter("Character")); - VALUE_PARSERS.put(B, new CharBBox()); - VALUE_PARSERS.put(START_TRACK_KERN, new NotImplementedYet(START_TRACK_KERN)); - VALUE_PARSERS.put(START_KERN_PAIRS1, new NotImplementedYet(START_KERN_PAIRS1)); - VALUE_PARSERS.put(START_COMPOSITES, new NotImplementedYet(START_COMPOSITES)); - VALUE_PARSERS.put(START_COMP_FONT_METRICS, new NotImplementedYet(START_COMP_FONT_METRICS)); - VALUE_PARSERS.put(KP, new NotImplementedYet(KP)); - VALUE_PARSERS.put(KPH, new NotImplementedYet(KPH)); - VALUE_PARSERS.put(KPX, new KPXHandler()); - VALUE_PARSERS.put(KPY, new NotImplementedYet(KPY)); - - PARSE_MODE_CHANGES = new HashMap<String, Integer>(); - PARSE_MODE_CHANGES.put(START_CHAR_METRICS, new Integer(PARSE_CHAR_METRICS)); - PARSE_MODE_CHANGES.put(END_CHAR_METRICS, new Integer(PARSE_NORMAL)); - } - - /** - * Main constructor. - */ - public AFMParser() { - } - - /** - * Parses an AFM file from a stream. - * @param in the stream to read from - * @param afmFileName the name of the AFM file - * @return the parsed AFM file - * @throws IOException if an I/O error occurs - */ - public AFMFile parse(InputStream in, String afmFileName) throws IOException { - Reader reader = new java.io.InputStreamReader(in, "US-ASCII"); - try { - return parse(new BufferedReader(reader), afmFileName); - } finally { - IOUtils.closeQuietly(reader); - } - } - - /** - * Parses an AFM file from a BufferedReader. - * @param reader the BufferedReader instance to read from - * @param afmFileName the name of the AFM file - * @return the parsed AFM file - * @throws IOException if an I/O error occurs - */ - public AFMFile parse(BufferedReader reader, String afmFileName) throws IOException { - Stack<Object> stack = new Stack<Object>(); - int parseMode = PARSE_NORMAL; - while (true) { - String line = reader.readLine(); - if (line == null) { - break; - } - String key = null; - switch (parseMode) { - case PARSE_NORMAL: - key = parseLine(line, stack); - break; - case PARSE_CHAR_METRICS: - key = parseCharMetrics(line, stack, afmFileName); - break; - default: - throw new IllegalStateException("Invalid parse mode"); - } - Integer newParseMode = PARSE_MODE_CHANGES.get(key); - if (newParseMode != null) { - parseMode = newParseMode.intValue(); - } - } - return (AFMFile)stack.pop(); - } - - private String parseLine(String line, Stack<Object> stack) throws IOException { - int startpos = 0; - //Find key - startpos = skipToNonWhiteSpace(line, startpos); - int endpos = skipToWhiteSpace(line, startpos); - String key = line.substring(startpos, endpos); - - //Parse value - startpos = skipToNonWhiteSpace(line, endpos); - ValueHandler vp = VALUE_PARSERS.get(key); - if (vp != null) { - vp.parse(line, startpos, stack); - } - return key; - } - - private String parseCharMetrics(String line, Stack<Object> stack, String afmFileName) - throws IOException { - String trimmedLine = line.trim(); - if (END_CHAR_METRICS.equals(trimmedLine)) { - return trimmedLine; - } - AFMFile afm = (AFMFile) stack.peek(); - String encoding = afm.getEncodingScheme(); - CharMetricsHandler charMetricsHandler = CharMetricsHandler.getHandler(VALUE_PARSERS, - encoding); - AFMCharMetrics chm = charMetricsHandler.parse(trimmedLine, stack, afmFileName); - afm.addCharMetrics(chm); - return null; - } - - private static int skipToNonWhiteSpace(String line, int startpos) { - int pos = startpos; - while (pos < line.length() && isWhitespace(line.charAt(pos))) { - pos++; - } - return pos; - } - - private static int skipToWhiteSpace(String line, int startpos) { - int pos = startpos; - while (pos < line.length() && !isWhitespace(line.charAt(pos))) { - pos++; - } - return pos; - } - - private static boolean isWhitespace(char ch) { - return ch == ' ' - || ch == '\t'; - } - - // ---------------- Value Handlers --------------------------- - - interface ValueHandler { - void parse(String line, int startpos, Stack<Object> stack) throws IOException; - } - - private abstract static class AbstractValueHandler implements ValueHandler { - - protected int findValue(String line, int startpos) { - return skipToWhiteSpace(line, startpos); - } - - protected String getStringValue(String line, int startpos) { - return line.substring(startpos); - } - - protected Number getNumberValue(String line, int startpos) { - try { - return new Integer(getIntegerValue(line, startpos)); - } catch (NumberFormatException nfe) { - return new Double(getDoubleValue(line, startpos)); - } - } - - protected int getIntegerValue(String line, int startpos) { - int endpos = findValue(line, startpos); - return Integer.parseInt(line.substring(startpos, endpos)); - } - - protected double getDoubleValue(String line, int startpos) { - int endpos = findValue(line, startpos); - return Double.parseDouble(line.substring(startpos, endpos)); - } - - protected Boolean getBooleanValue(String line, int startpos) { - return Boolean.valueOf(getStringValue(line, startpos)); - } - - } - - private static class StartFontMetrics extends AbstractValueHandler { - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - int endpos = findValue(line, startpos); - double version = Double.parseDouble(line.substring(startpos, endpos)); - if (version < 2) { - throw new IOException( - "AFM version must be at least 2.0 but it is " + version + "!"); - } - AFMFile afm = new AFMFile(); - stack.push(afm); - } - } - - private abstract static class BeanSetter extends AbstractValueHandler { - protected String method; - - public BeanSetter(String variable) { - this.method = "set" + variable; - } - - protected void setValue(Object target, Class<?> argType, Object value) { - Class<?> c = target.getClass(); - - try { - Method mth = c.getMethod(method, argType); - mth.invoke(target, value); - } catch (NoSuchMethodException e) { - throw new RuntimeException("Bean error: " + e.getMessage(), e); - } catch (IllegalAccessException e) { - throw new RuntimeException("Bean error: " + e.getMessage(), e); - } catch (InvocationTargetException e) { - throw new RuntimeException("Bean error: " + e.getMessage(), e); - } - } - } - - private static class StringSetter extends BeanSetter { - - public StringSetter(String variable) { - super(variable); - } - - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - String s = getStringValue(line, startpos); - Object obj = stack.peek(); - setValue(obj, String.class, s); - } - } - - private static class NamedCharacterSetter extends BeanSetter { - - public NamedCharacterSetter(String variable) { - super(variable); - } - - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - NamedCharacter ch = new NamedCharacter(getStringValue(line, startpos)); - Object obj = stack.peek(); - setValue(obj, NamedCharacter.class, ch); - } - } - - private static class NumberSetter extends BeanSetter { - public NumberSetter(String variable) { - super(variable); - } - - protected Object getContextObject(Stack<Object> stack) { - return stack.peek(); - } - - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - Number num = getNumberValue(line, startpos); - setValue(getContextObject(stack), Number.class, num); - } - } - - private static class IntegerSetter extends NumberSetter { - public IntegerSetter(String variable) { - super(variable); - } - - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - int value = getIntegerValue(line, startpos); - setValue(getContextObject(stack), int.class, new Integer(value)); - } - } - - private static class DoubleSetter extends NumberSetter { - public DoubleSetter(String variable) { - super(variable); - } - - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - double value = getDoubleValue(line, startpos); - setValue(getContextObject(stack), double.class, new Double(value)); - } - } - - private static class WritingDirNumberSetter extends NumberSetter { - - public WritingDirNumberSetter(String variable) { - super(variable); - } - - protected Object getContextObject(Stack<Object> stack) { - if (stack.peek() instanceof AFMWritingDirectionMetrics) { - return (AFMWritingDirectionMetrics)stack.peek(); - } else { - AFMFile afm = (AFMFile)stack.peek(); - AFMWritingDirectionMetrics wdm = afm.getWritingDirectionMetrics(0); - if (wdm == null) { - wdm = new AFMWritingDirectionMetrics(); - afm.setWritingDirectionMetrics(0, wdm); - } - return wdm; - } - } - - } - - private static class WritingDirDoubleSetter extends WritingDirNumberSetter { - - public WritingDirDoubleSetter(String variable) { - super(variable); - } - - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - double value = getDoubleValue(line, startpos); - setValue(getContextObject(stack), double.class, new Double(value)); - } - } - - private static class BooleanSetter extends AbstractValueHandler { - private String method; - - public BooleanSetter(String variable) { - this.method = "set" + variable.substring(2); //Cut "Is" in front - } - - protected Object getContextObject(Stack<Object> stack) { - return (AFMFile)stack.peek(); - } - - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - Boolean b = getBooleanValue(line, startpos); - - Object target = getContextObject(stack); - Class<?> c = target.getClass(); - try { - Method mth = c.getMethod(method, boolean.class); - mth.invoke(target, b); - } catch (NoSuchMethodException e) { - throw new RuntimeException("Bean error: " + e.getMessage(), e); - } catch (IllegalAccessException e) { - throw new RuntimeException("Bean error: " + e.getMessage(), e); - } catch (InvocationTargetException e) { - throw new RuntimeException("Bean error: " + e.getMessage(), e); - } - } - } - - private static class WritingDirBooleanSetter extends BooleanSetter { - - public WritingDirBooleanSetter(String variable) { - super(variable); - } - - protected Object getContextObject(Stack<Object> stack) { - if (stack.peek() instanceof AFMWritingDirectionMetrics) { - return (AFMWritingDirectionMetrics)stack.peek(); - } else { - AFMFile afm = (AFMFile)stack.peek(); - AFMWritingDirectionMetrics wdm = afm.getWritingDirectionMetrics(0); - if (wdm == null) { - wdm = new AFMWritingDirectionMetrics(); - afm.setWritingDirectionMetrics(0, wdm); - } - return wdm; - } - } - - } - - private static class FontBBox extends AbstractValueHandler { - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - Rectangle rect = parseBBox(line, startpos); - - AFMFile afm = (AFMFile)stack.peek(); - afm.setFontBBox(rect); - } - - protected Rectangle parseBBox(String line, int startpos) { - Rectangle rect = new Rectangle(); - int endpos; - - endpos = findValue(line, startpos); - rect.x = Integer.parseInt(line.substring(startpos, endpos)); - startpos = skipToNonWhiteSpace(line, endpos); - - endpos = findValue(line, startpos); - rect.y = Integer.parseInt(line.substring(startpos, endpos)); - startpos = skipToNonWhiteSpace(line, endpos); - - endpos = findValue(line, startpos); - int v = Integer.parseInt(line.substring(startpos, endpos)); - rect.width = v - rect.x; - startpos = skipToNonWhiteSpace(line, endpos); - - endpos = findValue(line, startpos); - v = Integer.parseInt(line.substring(startpos, endpos)); - rect.height = v - rect.y; - startpos = skipToNonWhiteSpace(line, endpos); - return rect; - } - } - - private static class CharBBox extends FontBBox { - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - Rectangle rect = parseBBox(line, startpos); - - AFMCharMetrics metrics = (AFMCharMetrics)stack.peek(); - metrics.setBBox(rect); - } - } - - private static class IsBaseFont extends AbstractValueHandler { - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - if (getBooleanValue(line, startpos).booleanValue()) { - throw new IOException("Only base fonts are currently supported!"); - } - } - } - - private static class IsCIDFont extends AbstractValueHandler { - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - if (getBooleanValue(line, startpos).booleanValue()) { - throw new IOException("CID fonts are currently not supported!"); - } - } - } - - private static class NotImplementedYet extends AbstractValueHandler { - private String key; - - public NotImplementedYet(String key) { - this.key = key; - } - - public void parse(String line, int startpos, Stack stack) throws IOException { - log.warn("Support for '" + key + "' has not been implemented, yet!" - + " Some font data in the AFM file will be ignored."); - } - } - - private static class StartDirection extends AbstractValueHandler { - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - int index = getIntegerValue(line, startpos); - AFMWritingDirectionMetrics wdm = new AFMWritingDirectionMetrics(); - AFMFile afm = (AFMFile)stack.peek(); - afm.setWritingDirectionMetrics(index, wdm); - stack.push(wdm); - } - } - - private static class EndDirection extends AbstractValueHandler { - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - if (!(stack.pop() instanceof AFMWritingDirectionMetrics)) { - throw new IOException("AFM format error: nesting incorrect"); - } - } - } - - private static class KPXHandler extends AbstractValueHandler { - public void parse(String line, int startpos, Stack<Object> stack) throws IOException { - AFMFile afm = (AFMFile)stack.peek(); - int endpos; - - endpos = findValue(line, startpos); - String name1 = line.substring(startpos, endpos); - startpos = skipToNonWhiteSpace(line, endpos); - - endpos = findValue(line, startpos); - String name2 = line.substring(startpos, endpos); - startpos = skipToNonWhiteSpace(line, endpos); - - endpos = findValue(line, startpos); - double kx = Double.parseDouble(line.substring(startpos, endpos)); - startpos = skipToNonWhiteSpace(line, endpos); - - afm.addXKerning(name1, name2, kx); - } - } - -} diff --git a/src/java/org/apache/fop/fonts/type1/AFMWritingDirectionMetrics.java b/src/java/org/apache/fop/fonts/type1/AFMWritingDirectionMetrics.java deleted file mode 100644 index 07d522bd9..000000000 --- a/src/java/org/apache/fop/fonts/type1/AFMWritingDirectionMetrics.java +++ /dev/null @@ -1,96 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.type1; - -/** - * Represents a writing direction metrics section from an AFM file. - */ -public class AFMWritingDirectionMetrics { - - private Number underlinePosition; - private Number underlineThickness; - private double italicAngle; - private boolean isFixedPitch; - - /** - * Returns the UnderlinePosition value. - * @return the underlinePosition - */ - public Number getUnderlinePosition() { - return underlinePosition; - } - - /** - * Sets the UnderlinePosition value. - * @param underlinePosition the underlinePosition to set - */ - public void setUnderlinePosition(Number underlinePosition) { - this.underlinePosition = underlinePosition; - } - - /** - * Returns the UnderlineThickness value. - * @return the underlineThickness - */ - public Number getUnderlineThickness() { - return underlineThickness; - } - - /** - * Sets the UnderlineThickness value. - * @param underlineThickness the underlineThickness to set - */ - public void setUnderlineThickness(Number underlineThickness) { - this.underlineThickness = underlineThickness; - } - - /** - * Returns the ItalicAngle value. - * @return the italicAngle - */ - public double getItalicAngle() { - return italicAngle; - } - - /** - * Sets the ItalicAngle value. - * @param italicAngle the italicAngle to set - */ - public void setItalicAngle(double italicAngle) { - this.italicAngle = italicAngle; - } - - /** - * Returns the IsFixedPitch value. - * @return the isFixedPitch - */ - public boolean isFixedPitch() { - return isFixedPitch; - } - - /** - * Set the IsFixedPitch value. - * @param value the isFixedPitch to set - */ - public void setFixedPitch(boolean value) { - this.isFixedPitch = value; - } - -} diff --git a/src/java/org/apache/fop/fonts/type1/AdobeStandardEncoding.java b/src/java/org/apache/fop/fonts/type1/AdobeStandardEncoding.java deleted file mode 100644 index d3d5a969d..000000000 --- a/src/java/org/apache/fop/fonts/type1/AdobeStandardEncoding.java +++ /dev/null @@ -1,419 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.type1; - -import java.util.HashMap; -import java.util.Map; - -/** - * Enumerates the {@linkplain http://unicode.org/Public/MAPPINGS/VENDORS/ADOBE/stdenc.txt} for - * characters found in a Type1 font. - */ -public enum AdobeStandardEncoding { - /** space character */ - space(0x0020, 0x20, "SPACE", "space"), - /** space character */ - space_nobreak(0x00A0, 0x20, "NO-BREAK SPACE", "space"), - /** exclamation mark */ - exclam(0x0021, 0x21, "EXCLAMATION MARK", "exclam"), - /** quotation mark */ - quotedbl(0x0022, 0x22, "QUOTATION MARK", "quotedbl"), - /** number sign */ - numersign(0x0023, 0x23, "NUMBER SIGN", "numbersign"), - /** dollar character */ - dollar(0x0024, 0x24, "DOLLAR SIGN", "dollar"), - /** percent character */ - percent(0x0025, 0x25, "PERCENT SIGN", "percent"), - /** ampersand character */ - ampersand(0x0026, 0x26, "AMPERSAND", "ampersand"), - /** right single quotation mark */ - quoteright(0x2019, 0x27, "RIGHT SINGLE QUOTATION MARK", "quoteright"), - /** left parenthesis character */ - parenleft(0x0028, 0x28, "LEFT PARENTHESIS", "parenleft"), - /** right parenthesis character */ - parenright(0x0029, 0x29, "RIGHT PARENTHESIS", "parenright"), - /** asterisk character */ - asterisk(0x002A, 0x2A, "ASTERISK", "asterisk"), - /** plus sign */ - plus(0x002B, 0x2B, "PLUS SIGN", "plus"), - /** comma character */ - comma(0x002C, 0x2C, "COMMA", "comma"), - /** hyphen-minus character */ - hyphen(0x002D, 0x2D, "HYPHEN-MINUS", "hyphen"), - /** soft-hyphen character */ - hyphen_soft(0x00AD, 0x2D, "SOFT HYPHEN", "hyphen"), - /** period character */ - period(0x002E, 0x2E, "FULL STOP", "period"), - /** slash character */ - slash(0x002F, 0x2F, "SOLIDUS", "slash"), - /** zero character */ - zero(0x0030, 0x30, "DIGIT ZERO", "zero"), - /** one character */ - one(0x0031, 0x31, "DIGIT ONE", "one"), - /** two character */ - two(0x0032, 0x32, "DIGIT TWO", "two"), - /** three character */ - three(0x0033, 0x33, "DIGIT THREE", "three"), - /** four character */ - four(0x0034, 0x34, "DIGIT FOUR", "four"), - /** five character */ - five(0x0035, 0x35, "DIGIT FIVE", "five"), - /** six character */ - six(0x0036, 0x36, "DIGIT SIX", "six"), - /** seven character */ - seven(0x0037, 0x37, "DIGIT SEVEN", "seven"), - /** eight character */ - eight(0x0038, 0x38, "DIGIT EIGHT", "eight"), - /** nine character */ - nine(0x0039, 0x39, "DIGIT NINE", "nine"), - /** colon character */ - colon(0x003A, 0x3A, "COLON", "colon"), - /** semi-colon character */ - semicolon(0x003B, 0x3B, "SEMICOLON", "semicolon"), - /** less character */ - less(0x003C, 0x3C, "LESS-THAN SIGN", "less"), - /** equal character */ - equal(0x003D, 0x3D, "EQUALS SIGN", "equal"), - /** greater character */ - greater(0x003E, 0x3E, "GREATER-THAN SIGN", "greater"), - /** question character */ - question(0x003F, 0x3F, "QUESTION MARK", "question"), - /** at character */ - at(0x0040, 0x40, "COMMERCIAL AT", "at"), - /** A character */ - A(0x0041, 0x41, "LATIN CAPITAL LETTER A", "A"), - /** B character */ - B(0x0042, 0x42, "LATIN CAPITAL LETTER B", "B"), - /** C character */ - C(0x0043, 0x43, "LATIN CAPITAL LETTER C", "C"), - /** D character */ - D(0x0044, 0x44, "LATIN CAPITAL LETTER D", "D"), - /** E character */ - E(0x0045, 0x45, "LATIN CAPITAL LETTER E", "E"), - /** F character */ - F(0x0046, 0x46, "LATIN CAPITAL LETTER F", "F"), - /** G character */ - G(0x0047, 0x47, "LATIN CAPITAL LETTER G", "G"), - /** H character */ - H(0x0048, 0x48, "LATIN CAPITAL LETTER H", "H"), - /** I character */ - I(0x0049, 0x49, "LATIN CAPITAL LETTER I", "I"), - /** J character */ - J(0x004A, 0x4A, "LATIN CAPITAL LETTER J", "J"), - /** K character */ - K(0x004B, 0x4B, "LATIN CAPITAL LETTER K", "K"), - /** L character */ - L(0x004C, 0x4C, "LATIN CAPITAL LETTER L", "L"), - /** M character */ - M(0x004D, 0x4D, "LATIN CAPITAL LETTER M", "M"), - /** N character */ - N(0x004E, 0x4E, "LATIN CAPITAL LETTER N", "N"), - /** O character */ - O(0x004F, 0x4F, "LATIN CAPITAL LETTER O", "O"), - /** P character */ - P(0x0050, 0x50, "LATIN CAPITAL LETTER P", "P"), - /** Q character */ - Q(0x0051, 0x51, "LATIN CAPITAL LETTER Q", "Q"), - /** R character */ - R(0x0052, 0x52, "LATIN CAPITAL LETTER R", "R"), - /** S character */ - S(0x0053, 0x53, "LATIN CAPITAL LETTER S", "S"), - /** T character */ - T(0x0054, 0x54, "LATIN CAPITAL LETTER T", "T"), - /** U character */ - U(0x0055, 0x55, "LATIN CAPITAL LETTER U", "U"), - /** V character */ - V(0x0056, 0x56, "LATIN CAPITAL LETTER V", "V"), - /** W character */ - W(0x0057, 0x57, "LATIN CAPITAL LETTER W", "W"), - /** X character */ - X(0x0058, 0x58, "LATIN CAPITAL LETTER X", "X"), - /** Y character */ - Y(0x0059, 0x59, "LATIN CAPITAL LETTER Y", "Y"), - /** Z character */ - Z(0x005A, 0x5A, "LATIN CAPITAL LETTER Z", "Z"), - /** left bracket character */ - bracketleft(0x005B, 0x5B, "LEFT SQUARE BRACKET", "bracketleft"), - /** back slash character */ - backslash(0x005C, 0x5C, "REVERSE SOLIDUS", "backslash"), - /** bracket right character */ - bracketright(0x005D, 0x5D, "RIGHT SQUARE BRACKET", "bracketright"), - /** circumflex character */ - asciicircum(0x005E, 0x5E, "CIRCUMFLEX ACCENT", "asciicircum"), - /** under score character */ - underscore(0x005F, 0x5F, "LOW LINE", "underscore"), - /** left single quotation character */ - quoteleft(0x2018, 0x60, "LEFT SINGLE QUOTATION MARK", "quoteleft"), - /** a character */ - a(0x0061, 0x61, "LATIN SMALL LETTER A", "a"), - /** b character */ - b(0x0062, 0x62, "LATIN SMALL LETTER B", "b"), - /** c character */ - c(0x0063, 0x63, "LATIN SMALL LETTER C", "c"), - /** d character */ - d(0x0064, 0x64, "LATIN SMALL LETTER D", "d"), - /** e character */ - e(0x0065, 0x65, "LATIN SMALL LETTER E", "e"), - /** f character */ - f(0x0066, 0x66, "LATIN SMALL LETTER F", "f"), - /** g character */ - g(0x0067, 0x67, "LATIN SMALL LETTER G", "g"), - /** h character */ - h(0x0068, 0x68, "LATIN SMALL LETTER H", "h"), - /** i character */ - i(0x0069, 0x69, "LATIN SMALL LETTER I", "i"), - /** j character */ - j(0x006A, 0x6A, "LATIN SMALL LETTER J", "j"), - /** k character */ - k(0x006B, 0x6B, "LATIN SMALL LETTER K", "k"), - /** l character */ - l(0x006C, 0x6C, "LATIN SMALL LETTER L", "l"), - /** m character */ - m(0x006D, 0x6D, "LATIN SMALL LETTER M", "m"), - /** n character */ - n(0x006E, 0x6E, "LATIN SMALL LETTER N", "n"), - /** o character */ - o(0x006F, 0x6F, "LATIN SMALL LETTER O", "o"), - /** p character */ - p(0x0070, 0x70, "LATIN SMALL LETTER P", "p"), - /** q character */ - q(0x0071, 0x71, "LATIN SMALL LETTER Q", "q"), - /** r character */ - r(0x0072, 0x72, "LATIN SMALL LETTER R", "r"), - /** s character */ - s(0x0073, 0x73, "LATIN SMALL LETTER S", "s"), - /** t character */ - t(0x0074, 0x74, "LATIN SMALL LETTER T", "t"), - /** u character */ - u(0x0075, 0x75, "LATIN SMALL LETTER U", "u"), - /** v character */ - v(0x0076, 0x76, "LATIN SMALL LETTER V", "v"), - /** w character */ - w(0x0077, 0x77, "LATIN SMALL LETTER W", "w"), - /** x character */ - x(0x0078, 0x78, "LATIN SMALL LETTER X", "x"), - /** y character */ - y(0x0079, 0x79, "LATIN SMALL LETTER Y", "y"), - /** z character */ - z(0x007A, 0x7A, "LATIN SMALL LETTER Z", "z"), - /** left curly bracket character */ - braceleft(0x007B, 0x7B, "LEFT CURLY BRACKET", "braceleft"), - /** vertical line character */ - bar(0x007C, 0x7C, "VERTICAL LINE", "bar"), - /** right curly bracket character */ - braceright(0x007D, 0x7D, "RIGHT CURLY BRACKET", "braceright"), - /** tilde character */ - asciitilde(0x007E, 0x7E, "TILDE", "asciitilde"), - /** inverted exclamation mark */ - exclamdown(0x00A1, 0xA1, "INVERTED EXCLAMATION MARK", "exclamdown"), - /** cent character */ - cent(0x00A2, 0xA2, "CENT SIGN", "cent"), - /** sterling character */ - sterling(0x00A3, 0xA3, "POUND SIGN", "sterling"), - /** fraction slash character */ - fraction(0x2044, 0xA4, "FRACTION SLASH", "fraction"), - /** division slash character */ - fraction_division_slash(0x2215, 0xA4, "DIVISION SLASH", "fraction"), - /** yen character */ - yen(0x00A5, 0xA5, "YEN SIGN", "yen"), - /** florin character */ - florin(0x0192, 0xA6, "LATIN SMALL LETTER F WITH HOOK", "florin"), - /** section sign character */ - section(0x00A7, 0xA7, "SECTION SIGN", "section"), - /** currency sign character */ - currency(0x00A4, 0xA8, "CURRENCY SIGN", "currency"), - /** apostrophe character */ - quotesingle(0x0027, 0xA9, "APOSTROPHE", "quotesingle"), - /** double left quotation mark */ - quotedblleft(0x201C, 0xAA, "LEFT DOUBLE QUOTATION MARK", "quotedblleft"), - /** left-pointing double angle quotation mark */ - guillemotleft(0x00AB, 0xAB, "LEFT-POINTING DOUBLE ANGLE QUOTATION MARK", "guillemotleft"), - /** left-pointing single quotation mark */ - guilsinglleft(0x2039, 0xAC, "SINGLE LEFT-POINTING ANGLE QUOTATION MARK", "guilsinglleft"), - /** right-pointing single quotation mark */ - guilsinglright(0x203A, 0xAD, "SINGLE RIGHT-POINTING ANGLE QUOTATION MARK", "guilsinglright"), - /** fi ligature */ - fi(0xFB01, 0xAE, "LATIN SMALL LIGATURE FI", "fi"), - /** fl ligature */ - fl(0xFB02, 0xAF, "LATIN SMALL LIGATURE FL", "fl"), - /** en-dash character */ - endash(0x2013, 0xB1, "EN DASH", "endash"), - /** dagger character */ - dagger(0x2020, 0xB2, "DAGGER", "dagger"), - /** double dagger character */ - daggerdbl(0x2021, 0xB3, "DOUBLE DAGGER", "daggerdbl"), - /** centered period character */ - periodcentered(0x00B7, 0xB4, "MIDDLE DOT", "periodcentered"), - /** centered period character */ - periodcentered_bullet_operator(0x2219, 0xB4, "BULLET OPERATOR", "periodcentered"), - /** paragraph character */ - paragraph(0x00B6, 0xB6, "PILCROW SIGN", "paragraph"), - /** bullet character */ - bullet(0x2022, 0xB7, "BULLET", "bullet"), - /** single low-9 quotation mark */ - quotesinglbase(0x201A, 0xB8, "SINGLE LOW-9 QUOTATION MARK", "quotesinglbase"), - /** double low-9 quotation mark */ - quotedblbase(0x201E, 0xB9, "DOUBLE LOW-9 QUOTATION MARK", "quotedblbase"), - /** right double quotation mark */ - quotedblright(0x201D, 0xBA, "RIGHT DOUBLE QUOTATION MARK", "quotedblright"), - /** right-pointing double angle quotation mark */ - guillemotright(0x00BB, 0xBB, "RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK", "guillemotright"), - /** horizontal ellipsis character */ - ellipsis(0x2026, 0xBC, "HORIZONTAL ELLIPSIS", "ellipsis"), - /** per-mille character */ - perthousand(0x2030, 0xBD, "PER MILLE SIGN", "perthousand"), - /** inverted question mark */ - questiondown(0x00BF, 0xBF, "INVERTED QUESTION MARK", "questiondown"), - /** grave accent character */ - grave(0x0060, 0xC1, "GRAVE ACCENT", "grave"), - /** acute accent character */ - acute(0x00B4, 0xC2, "ACUTE ACCENT", "acute"), - /** modifier letter circumflex accent character */ - circumflex(0x02C6, 0xC3, "MODIFIER LETTER CIRCUMFLEX ACCENT", "circumflex"), - /** small tilde character */ - tilde(0x02DC, 0xC4, "SMALL TILDE", "tilde"), - /** macron character */ - macron(0x00AF, 0xC5, "MACRON", "macron"), - /** modifier letter macron character */ - macron_modifier_letter(0x02C9, 0xC5, "MODIFIER LETTER MACRON", "macron"), - /** breve character */ - breve(0x02D8, 0xC6, "BREVE", "breve"), - /** dot above character */ - dotaccent(0x02D9, 0xC7, "DOT ABOVE", "dotaccent"), - /** diaeresis character */ - dieresis(0x00A8, 0xC8, "DIAERESIS", "dieresis"), - /** ring above character */ - ring(0x02DA, 0xCA, "RING ABOVE", "ring"), - /** cedilla character */ - cedilla(0x00B8, 0xCB, "CEDILLA", "cedilla"), - /** double acute accent character */ - hungarumlaut(0x02DD, 0xCD, "DOUBLE ACUTE ACCENT", "hungarumlaut"), - /** agonek character */ - ogonek(0x02DB, 0xCE, "OGONEK", "ogonek"), - /** caron character */ - caron(0x02C7, 0xCF, "CARON", "caron"), - /** emdash character */ - emdash(0x2014, 0xD0, "EM DASH", "emdash"), - /** AE (capitalised) character */ - AE(0x00C6, 0xE1, "LATIN CAPITAL LETTER AE", "AE"), - /** femenine ordinal indicator character */ - ordfeminine(0x00AA, 0xE3, "FEMININE ORDINAL INDICATOR", "ordfeminine"), - /** capital letter L with stroke character */ - Lslash(0x0141, 0xE8, "LATIN CAPITAL LETTER L WITH STROKE", "Lslash"), - /** capital letter O with stroke character */ - Oslash(0x00D8, 0xE9, "LATIN CAPITAL LETTER O WITH STROKE", "Oslash"), - /** OE (capitalised) character */ - OE(0x0152, 0xEA, "LATIN CAPITAL LIGATURE OE", "OE"), - /** masculine ordinal indicator character */ - ordmasculine(0x00BA, 0xEB, "MASCULINE ORDINAL INDICATOR", "ordmasculine"), - /** ae (small) character */ - ae(0x00E6, 0xF1, "LATIN SMALL LETTER AE", "ae"), - /** dotless i character */ - dotlessi(0x0131, 0xF5, "LATIN SMALL LETTER DOTLESS I", "dotlessi"), - /** small letter l with stroke character */ - lslash(0x0142, 0xF8, "LATIN SMALL LETTER L WITH STROKE", "lslash"), - /** small letter o with stroke character */ - oslash(0x00F8, 0xF9, "LATIN SMALL LETTER O WITH STROKE", "oslash"), - /** oe (small) character */ - oe(0x0153, 0xFA, "LATIN SMALL LIGATURE OE", "oe"), - /** small letter sharp s character */ - germandbls(0x00DF, 0xFB, "LATIN SMALL LETTER SHARP S", "germandbls"); - - private final int unicodeIndex; - private final int adobeCodePoint; - private final String unicodeName; - private final String adobeName; - - /** The name of the Adobe Standard Encoding as seen in an AFM file. */ - public static final String NAME = "AdobeStandardEncoding"; - - private static final Map<String, AdobeStandardEncoding> CACHE - = new HashMap<String, AdobeStandardEncoding>(); - static { - for (AdobeStandardEncoding encoding : AdobeStandardEncoding.values()) { - CACHE.put(encoding.getAdobeName(), encoding); - } - } - - private AdobeStandardEncoding(int unicodeIndex, int adobeCodePoint, String unicodeName, - String adobeName) { - this.unicodeIndex = unicodeIndex; - this.adobeCodePoint = adobeCodePoint; - this.unicodeName = unicodeName; - this.adobeName = adobeName; - } - - /** - * The Unicode index of this character. - * - * @return the Unicode index - */ - int getUnicodeIndex() { - return unicodeIndex; - } - - /** - * The Adobe code point of this character. - * - * @return the Adobe code point - */ - int getAdobeCodePoint() { - return adobeCodePoint; - } - - /** - * The Unicode name for this character. - * - * @return the Unicode name - */ - String getUnicodeName() { - return unicodeName; - } - - /** - * The Adobe name for this character. - * - * @return the Adobe name - */ - String getAdobeName() { - return adobeName; - } - - /** - * Returns the code point of a Adobe standard encoded character given its name. If the name - * cannot be found, -1 is returned. - * - * @param adobeName the name of the character - * @return the Adobe code point - */ - public static int getAdobeCodePoint(String adobeName) { - AdobeStandardEncoding encoding = CACHE.get(adobeName); - return encoding != null ? encoding.getAdobeCodePoint() : -1; - } - - public static String getCharFromCodePoint(int codePoint) { - for (AdobeStandardEncoding encoding : CACHE.values()) { - if (encoding.getAdobeCodePoint() == codePoint) { - return encoding.getAdobeName(); - } - } - return ""; - } -} diff --git a/src/java/org/apache/fop/fonts/type1/CharMetricsHandler.java b/src/java/org/apache/fop/fonts/type1/CharMetricsHandler.java deleted file mode 100644 index 79753f3f8..000000000 --- a/src/java/org/apache/fop/fonts/type1/CharMetricsHandler.java +++ /dev/null @@ -1,120 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.type1; - -import java.io.IOException; -import java.util.Map; -import java.util.Stack; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.xmlgraphics.fonts.Glyphs; - -import org.apache.fop.fonts.NamedCharacter; -import org.apache.fop.fonts.type1.AFMParser.ValueHandler; - -/** - * A handler that parses the various types of character metrics in an AFM file. - */ -abstract class CharMetricsHandler { - - private static final Log LOG = LogFactory.getLog(CharMetricsHandler.class); - - private static final String WHITE_SPACE = "\\s*"; - private static final String OPERATOR = "([A-Z0-9]{1,3})"; - private static final String OPERANDS = "(.*)"; - - private static final Pattern METRICS_REGEX = Pattern.compile( - WHITE_SPACE + OPERATOR + WHITE_SPACE + OPERANDS + WHITE_SPACE); - private static final Pattern SPLIT_REGEX = Pattern.compile(WHITE_SPACE + ";" + WHITE_SPACE); - - private CharMetricsHandler() { - } - - abstract AFMCharMetrics parse(String line, Stack<Object> stack, String afmFileName) - throws IOException; - - static CharMetricsHandler getHandler(Map<String, ValueHandler> valueParsers, - String line) { - if (line != null && line.contains(AdobeStandardEncoding.NAME)) { - return new AdobeStandardCharMetricsHandler(valueParsers); - } else { - return new DefaultCharMetricsHandler(valueParsers); - } - } - - private static final class DefaultCharMetricsHandler extends CharMetricsHandler { - private final Map<String, ValueHandler> valueParsers; - - - private DefaultCharMetricsHandler(Map<String, ValueHandler> valueParsers) { - this.valueParsers = valueParsers; - } - - AFMCharMetrics parse(String line, Stack<Object> stack, String afmFileName) - throws IOException { - AFMCharMetrics chm = new AFMCharMetrics(); - stack.push(chm); - String[] metrics = SPLIT_REGEX.split(line); - for (String metric : metrics) { - Matcher matcher = METRICS_REGEX.matcher(metric); - if (matcher.matches()) { - String operator = matcher.group(1); - String operands = matcher.group(2); - ValueHandler handler = valueParsers.get(operator); - if (handler != null) { - handler.parse(operands, 0, stack); - } - } - } - stack.pop(); - return chm; - } - } - - private static final class AdobeStandardCharMetricsHandler extends CharMetricsHandler { - private final DefaultCharMetricsHandler defaultHandler; - - private AdobeStandardCharMetricsHandler(Map<String, ValueHandler> valueParsers) { - defaultHandler = new DefaultCharMetricsHandler(valueParsers); - } - - AFMCharMetrics parse(String line, Stack<Object> stack, String afmFileName) - throws IOException { - AFMCharMetrics chm = defaultHandler.parse(line, stack, afmFileName); - NamedCharacter namedChar = chm.getCharacter(); - if (namedChar != null) { - String charName = namedChar.getName(); - int codePoint = AdobeStandardEncoding.getAdobeCodePoint(charName); - if (chm.getCharCode() != codePoint && !Glyphs.NOTDEF.equals(charName)) { - LOG.info(afmFileName + ": named character '" + charName + "'" - + " has an incorrect code point: " + chm.getCharCode() - + ". Changed to " + codePoint); - chm.setCharCode(codePoint); - } - } - return chm; - } - } - -} diff --git a/src/java/org/apache/fop/fonts/type1/PFBData.java b/src/java/org/apache/fop/fonts/type1/PFBData.java deleted file mode 100644 index 05f0ec78f..000000000 --- a/src/java/org/apache/fop/fonts/type1/PFBData.java +++ /dev/null @@ -1,185 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.type1; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Class that represents the contents of a PFB file. - * - * @see PFBParser - */ -public class PFBData { - - /** - * Raw format, no special file structure - */ - public static final int PFB_RAW = 0; - - /** - * PC format - */ - public static final int PFB_PC = 1; - - /** - * MAC Format (unsupported, yet) - */ - public static final int PFB_MAC = 2; - - private int pfbFormat; //One of the PFB_* constants - private byte[] headerSegment; - private byte[] encryptedSegment; - private byte[] trailerSegment; - - - /** - * Sets the PFB format the font was loaded with. - * @param format one of the PFB_* constants - */ - public void setPFBFormat(int format) { - switch (format) { - case PFB_RAW: - case PFB_PC: - this.pfbFormat = format; - break; - case PFB_MAC: - throw new UnsupportedOperationException("Mac format is not yet implemented"); - default: - throw new IllegalArgumentException("Invalid value for PFB format: " + format); - } - } - - - /** - * Returns the format the font was loaded with. - * @return int one of the PFB_* constants - */ - public int getPFBFormat() { - return this.pfbFormat; - } - - /** - * Sets the header segment of the font file. - * @param headerSeg the header segment - */ - public void setHeaderSegment(byte[] headerSeg) { - this.headerSegment = headerSeg; - } - - /** - * Gets the header segment of the font file - * @return Header segment as a byte array - */ - public byte[] getHeaderSegment() { - return this.headerSegment.clone(); - } - - /** - * Sets the encrypted segment of the font file. - * @param encryptedSeg the encrypted segment - */ - public void setEncryptedSegment(byte[] encryptedSeg) { - this.encryptedSegment = encryptedSeg; - } - - /** - * Gets the encrypted segment of the font file - * @return The encrypted segment as a byte array - */ - public byte[] getEncryptedSegment() { - return this.encryptedSegment.clone(); - } - - /** - * Sets the trailer segment of the font file. - * @param trailerSeg the trailer segment - */ - public void setTrailerSegment(byte[] trailerSeg) { - this.trailerSegment = trailerSeg; - } - - /** - * Gets the trailer segment of the font file - * @return The trailer segment as a byte array - */ - public byte[] getTrailerSegment() { - return this.trailerSegment.clone(); - } - - /** - * Returns the full length of the raw font file. - * @return int the raw file length - */ - public int getLength() { - return getLength1() + getLength2() + getLength3(); - } - - - /** - * Returns the Length1 (length of the header segment). - * @return int Length1 - */ - public int getLength1() { - return this.headerSegment.length; - } - - - /** - * Returns the Length2 (length of the encrypted segment). - * @return int Length2 - */ - public int getLength2() { - return this.encryptedSegment.length; - } - - - /** - * Returns the Length3 (length of the trailer segment). - * @return int Length3 - */ - public int getLength3() { - return this.trailerSegment.length; - } - - - /** - * Writes the PFB file in raw format to an OutputStream. - * @param out the OutputStream to write to - * @throws IOException In case of an I/O problem - */ - public void outputAllParts(OutputStream out) throws IOException { - out.write(this.headerSegment); - out.write(this.encryptedSegment); - out.write(this.trailerSegment); - } - - - /** - * {@inheritDoc} - */ - public String toString() { - return "PFB: format=" + getPFBFormat() - + " len1=" + getLength1() - + " len2=" + getLength2() - + " len3=" + getLength3(); - } - -} diff --git a/src/java/org/apache/fop/fonts/type1/PFBParser.java b/src/java/org/apache/fop/fonts/type1/PFBParser.java deleted file mode 100644 index 339a9e141..000000000 --- a/src/java/org/apache/fop/fonts/type1/PFBParser.java +++ /dev/null @@ -1,202 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.type1; - -import java.io.BufferedInputStream; -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.apache.commons.io.IOUtils; - -/** - * This class represents a parser for Adobe Type 1 PFB files. - * - * @see PFBData - */ -public class PFBParser { - - private static final byte[] CURRENTFILE_EEXEC; - private static final byte[] CLEARTOMARK; - - static { - try { - CURRENTFILE_EEXEC = "currentfile eexec".getBytes("US-ASCII"); - CLEARTOMARK = "cleartomark".getBytes("US-ASCII"); - } catch (java.io.UnsupportedEncodingException e) { - throw new RuntimeException("Incompatible VM. It doesn't support the US-ASCII encoding"); - } - } - - - /** - * Parses a PFB file into a PFBData object. - * @param in InputStream to load the PFB file from - * @return PFBData memory representation of the font - * @throws IOException In case of an I/O problem - */ - public PFBData parsePFB(InputStream in) throws IOException { - PFBData pfb = new PFBData(); - BufferedInputStream bin = new BufferedInputStream(in); - DataInputStream din = new DataInputStream(bin); - din.mark(32); - int firstByte = din.readUnsignedByte(); - din.reset(); - if (firstByte == 128) { - pfb.setPFBFormat(PFBData.PFB_PC); - parsePCFormat(pfb, din); - } else { - pfb.setPFBFormat(PFBData.PFB_RAW); - parseRAWFormat(pfb, bin); - } - return pfb; - } - - - private static int swapInteger(final int value) { - return (((value >> 0) & 0xff) << 24) - + (((value >> 8) & 0xff) << 16) - + (((value >> 16) & 0xff) << 8) - + (((value >> 24) & 0xff) << 0); - } - - - private void parsePCFormat(PFBData pfb, DataInputStream din) throws IOException { - int segmentHead; - int segmentType; - - //Read first segment - segmentHead = din.readUnsignedByte(); - if (segmentHead != 128) { - throw new IOException("Invalid file format. Expected ASCII 80hex"); - } - segmentType = din.readUnsignedByte(); //Read - int len1 = swapInteger(din.readInt()); - byte[] headerSegment = new byte[len1]; - din.readFully(headerSegment); - pfb.setHeaderSegment(headerSegment); - - //Read second segment - segmentHead = din.readUnsignedByte(); - if (segmentHead != 128) { - throw new IOException("Invalid file format. Expected ASCII 80hex"); - } - segmentType = din.readUnsignedByte(); - int len2 = swapInteger(din.readInt()); - byte[] encryptedSegment = new byte[len2]; - din.readFully(encryptedSegment); - pfb.setEncryptedSegment(encryptedSegment); - - //Read third segment - segmentHead = din.readUnsignedByte(); - if (segmentHead != 128) { - throw new IOException("Invalid file format. Expected ASCII 80hex"); - } - segmentType = din.readUnsignedByte(); - int len3 = swapInteger(din.readInt()); - byte[] trailerSegment = new byte[len3]; - din.readFully(trailerSegment); - pfb.setTrailerSegment(trailerSegment); - - //Read EOF indicator - segmentHead = din.readUnsignedByte(); - if (segmentHead != 128) { - throw new IOException("Invalid file format. Expected ASCII 80hex"); - } - segmentType = din.readUnsignedByte(); - if (segmentType != 3) { - throw new IOException("Expected segment type 3, but found: " + segmentType); - } - } - - - private static boolean byteCmp(byte[] src, int srcOffset, byte[] cmp) { - for (int i = 0; i < cmp.length; i++) { - // System.out.println("Compare: " + src[srcOffset + i] + " " + cmp[i]); - if (src[srcOffset + i] != cmp[i]) { - return false; - } - } - return true; - } - - private void calcLengths(PFBData pfb, byte[] originalData) { - // Calculate length 1 and 3 - // System.out.println ("Checking font, size = "+originalData.length); - - // Length1 is the size of the initial ascii portion - // search for "currentfile eexec" - // Get the first binary number and search backwards for "eexec" - int len1 = 30; - - // System.out.println("Length1="+len1); - while (!byteCmp(originalData, len1 - CURRENTFILE_EEXEC.length, CURRENTFILE_EEXEC)) { - len1++; - } - - // Skip newline - len1++; - - // Length3 is length of the last portion of the file - int len3 = 0; - len3 -= CLEARTOMARK.length; - while (!byteCmp(originalData, originalData.length + len3, CLEARTOMARK)) { - len3--; - // System.out.println("Len3="+len3); - } - len3 = -len3; - len3++; - // Eat 512 zeroes - int numZeroes = 0; - byte[] ws1 = new byte[]{0x0D}; //CR - byte[] ws2 = new byte[]{0x0A}; //LF - byte[] ws3 = new byte[]{0x30}; //"0" - while ((originalData[originalData.length - len3] == ws1[0] - || originalData[originalData.length - len3] == ws2[0] - || originalData[originalData.length - len3] == ws3[0]) - && numZeroes < 512) { - len3++; - if (originalData[originalData.length - len3] == ws3[0]) { - numZeroes++; - } - } - // System.out.println("Length3="+len3); - - //Create the 3 segments - byte[] buffer = new byte[len1]; - System.arraycopy(originalData, 0, buffer, 0, len1); - pfb.setHeaderSegment(buffer); - - int len2 = originalData.length - len3 - len1; - buffer = new byte[len2]; - System.arraycopy(originalData, len1, buffer, 0, len2); - pfb.setEncryptedSegment(buffer); - - buffer = new byte[len3]; - System.arraycopy(originalData, len1 + len2, buffer, 0, len3); - pfb.setTrailerSegment(buffer); - } - - private void parseRAWFormat(PFBData pfb, BufferedInputStream bin) - throws IOException { - calcLengths(pfb, IOUtils.toByteArray(bin)); - } - -} diff --git a/src/java/org/apache/fop/fonts/type1/PFMFile.java b/src/java/org/apache/fop/fonts/type1/PFMFile.java deleted file mode 100644 index 8856fdb7f..000000000 --- a/src/java/org/apache/fop/fonts/type1/PFMFile.java +++ /dev/null @@ -1,521 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.type1; - -// Java -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.xmlgraphics.fonts.Glyphs; - -/** - * This class represents a PFM file (or parts of it) as a Java object. - */ -public class PFMFile { - - // Header stuff - private String windowsName; - private String postscriptName; - private short dfItalic; - //private int dfWeight; - private short dfCharSet; - private short dfPitchAndFamily; - private int dfAvgWidth; - private int dfMaxWidth; - private int dfMinWidth; - private short dfFirstChar; - private short dfLastChar; - - // Extension stuff - // --- - - // Extend Text Metrics - private int etmCapHeight; - private int etmXHeight; - private int etmLowerCaseAscent; - private int etmLowerCaseDescent; - - // Extent table - private int[] extentTable; - - private Map<Integer, Map<Integer, Integer>> kerningTab = new HashMap<Integer, Map<Integer, Integer>>(); - - /** - * logging instance - */ - protected Log log = LogFactory.getLog(PFMFile.class); - - /** - * Parses a PFM file - * - * @param inStream The stream from which to read the PFM file. - * @throws IOException In case of an I/O problem - */ - public void load(InputStream inStream) throws IOException { - byte[] pfmBytes = IOUtils.toByteArray(inStream); - InputStream bufin = inStream; - bufin = new ByteArrayInputStream(pfmBytes); - PFMInputStream in = new PFMInputStream(bufin); - bufin.mark(512); - short sh1 = in.readByte(); - short sh2 = in.readByte(); - if (sh1 == 128 && sh2 == 1) { - //Found the first section header of a PFB file! - IOUtils.closeQuietly(in); - throw new IOException("Cannot parse PFM file. You probably specified the PFB file" - + " of a Type 1 font as parameter instead of the PFM."); - } - bufin.reset(); - byte[] b = new byte[16]; - if ((bufin.read(b) == b.length) && new String(b, "US-ASCII").equalsIgnoreCase("StartFontMetrics")) { - //Found the header of a AFM file! - IOUtils.closeQuietly(in); - throw new IOException("Cannot parse PFM file. You probably specified the AFM file" - + " of a Type 1 font as parameter instead of the PFM."); - } - bufin.reset(); - final int version = in.readShort(); - if (version != 256) { - log.warn("PFM version expected to be '256' but got '" + version + "'." - + " Please make sure you specify the PFM as parameter" - + " and not the PFB or the AFM."); - } - //final long filesize = in.readInt(); - bufin.reset(); - - loadHeader(in); - loadExtension(in); - } - - /** - * Parses the header of the PFM file. - * - * @param inStream The stream from which to read the PFM file. - * @throws IOException In case of an I/O problem - */ - private void loadHeader(PFMInputStream inStream) throws IOException { - if (inStream.skip(80) != 80) { - throw new IOException("premature EOF when skipping 80 bytes"); - } - dfItalic = inStream.readByte(); - if (inStream.skip(2) != 2) { - throw new IOException("premature EOF when skipping 2 bytes"); - } - inStream.readShort(); // dfWeight = - dfCharSet = inStream.readByte(); - if (inStream.skip(4) != 4) { - throw new IOException("premature EOF when skipping 4 bytes"); - } - dfPitchAndFamily = inStream.readByte(); - dfAvgWidth = inStream.readShort(); - dfMaxWidth = inStream.readShort(); - dfFirstChar = inStream.readByte(); - dfLastChar = inStream.readByte(); - if (inStream.skip(8) != 8) { - throw new IOException("premature EOF when skipping 8 bytes"); - } - long faceOffset = inStream.readInt(); - - inStream.reset(); - if (inStream.skip(faceOffset) != faceOffset) { - throw new IOException("premature EOF when skipping faceOffset bytes"); - } - windowsName = inStream.readString(); - - inStream.reset(); - if (inStream.skip(117) != 117) { - throw new IOException("premature EOF when skipping 117 bytes"); - } - } - - /** - * Parses the extension part of the PFM file. - * - * @param inStream The stream from which to read the PFM file. - */ - private void loadExtension(PFMInputStream inStream) throws IOException { - final int size = inStream.readShort(); - if (size != 30) { - log.warn("Size of extension block was expected to be " - + "30 bytes, but was " + size + " bytes."); - } - final long extMetricsOffset = inStream.readInt(); - final long extentTableOffset = inStream.readInt(); - if (inStream.skip(4) != 4) { //Skip dfOriginTable - throw new IOException("premature EOF when skipping dfOriginTable bytes"); - } - final long kernPairOffset = inStream.readInt(); - if (inStream.skip(4) != 4) { //Skip dfTrackKernTable - throw new IOException("premature EOF when skipping dfTrackKernTable bytes"); - } - long driverInfoOffset = inStream.readInt(); - - if (kernPairOffset > 0) { - inStream.reset(); - if (inStream.skip(kernPairOffset) != kernPairOffset) { - throw new IOException("premature EOF when skipping kernPairOffset bytes"); - } - loadKernPairs(inStream); - } - - inStream.reset(); - if (inStream.skip(driverInfoOffset) != driverInfoOffset) { - throw new IOException("premature EOF when skipping driverInfoOffset bytes"); - } - postscriptName = inStream.readString(); - - if (extMetricsOffset != 0) { - inStream.reset(); - if (inStream.skip(extMetricsOffset) != extMetricsOffset) { - throw new IOException("premature EOF when skipping extMetricsOffset bytes"); - } - loadExtMetrics(inStream); - } - if (extentTableOffset != 0) { - inStream.reset(); - if (inStream.skip(extentTableOffset) != extentTableOffset) { - throw new IOException("premature EOF when skipping extentTableOffset bytes"); - } - loadExtentTable(inStream); - } - - } - - /** - * Parses the kernPairs part of the pfm file - * - * @param inStream The stream from which to read the PFM file. - */ - private void loadKernPairs(PFMInputStream inStream) throws IOException { - int i = inStream.readShort(); - - - if (log.isTraceEnabled()) { - log.trace(i + " kerning pairs"); - } - while (i > 0) { - int g1 = (int) inStream.readByte(); - i--; - - int g2 = (int) inStream.readByte(); - - int adj = inStream.readShort(); - if (adj > 0x8000) { - adj = -(0x10000 - adj); - } - - if (log.isTraceEnabled()) { - log.trace("Char no: (" + g1 + ", " + g2 + ") kern: " + adj); - final String glyph1 = Glyphs.TEX8R_GLYPH_NAMES[g1]; - final String glyph2 = Glyphs.TEX8R_GLYPH_NAMES[g2]; - log.trace("glyphs: " + glyph1 + ", " + glyph2); - } - - Map<Integer, Integer> adjTab = kerningTab.get(Integer.valueOf(g1)); - if (adjTab == null) { - adjTab = new HashMap<Integer, Integer>(); - } - adjTab.put(Integer.valueOf(g2), Integer.valueOf(adj)); - kerningTab.put(Integer.valueOf(g1), adjTab); - } - } - - /** - * Parses the extended metrics part of the PFM file. - * - * @param inStream The stream from which to read the PFM file. - */ - private void loadExtMetrics(PFMInputStream inStream) throws IOException { - final int size = inStream.readShort(); - if (size != 52) { - log.warn("Size of extension block was expected to be " - + "52 bytes, but was " + size + " bytes."); - } - if (inStream.skip(12) != 12) { //Skip etmPointSize, etmOrientation, etmMasterHeight, - //etmMinScale, etmMaxScale, emtMasterUnits - throw new IOException("premature EOF when skipping etmPointSize, ... bytes"); - } - etmCapHeight = inStream.readShort(); - etmXHeight = inStream.readShort(); - etmLowerCaseAscent = inStream.readShort(); - etmLowerCaseDescent = -(inStream.readShort()); - //Ignore the rest of the values - } - - /** - * Parses the extent table of the PFM file. - * - * @param inStream The stream from which to read the PFM file. - */ - private void loadExtentTable(PFMInputStream inStream) throws IOException { - extentTable = new int[dfLastChar - dfFirstChar + 1]; - dfMinWidth = dfMaxWidth; - for (short i = dfFirstChar; i <= dfLastChar; i++) { - extentTable[i - dfFirstChar] = inStream.readShort(); - if (extentTable[i - dfFirstChar] < dfMinWidth) { - dfMinWidth = extentTable[i - dfFirstChar]; - } - } - } - - /** - * Returns the Windows name of the font. - * - * @return The Windows name. - */ - public String getWindowsName() { - return windowsName; - } - - /** - * Return the kerning table. The kerning table is a Map with - * strings with glyphnames as keys, containing Maps as value. - * The value map contains a glyph name string key and an Integer value - * - * @return A Map containing the kerning table - */ - public Map<Integer, Map<Integer, Integer>> getKerning() { - return kerningTab; - } - - /** - * Returns the Postscript name of the font. - * - * @return The Postscript name. - */ - public String getPostscriptName() { - return postscriptName; - } - - /** - * Returns the charset used for the font. - * - * @return The charset (0=WinAnsi). - */ - public short getCharSet() { - return dfCharSet; - } - - /** - * Returns the charset of the font as a string. - * - * @return The name of the charset. - */ - public String getCharSetName() { - //TODO Had to remove the detection for Expert(Subset) encoding. The PFM is not suitable - //for detecting these character sets. We have to parse the AFM for that. - switch (dfCharSet) { - case 0: - return "WinAnsi"; // AKA ISOAdobe - case 2: - if ("Symbol".equals(getPostscriptName())) { - return "Symbol"; - } - break; - case 128: - return "Shift-JIS (Japanese)"; - default: - log.warn("Unknown charset detected (" + dfCharSet - + ", 0x" + Integer.toHexString(dfCharSet) - + "). Trying fallback to WinAnsi."); - } - return "WinAnsi"; - } - - /** - * Returns the number of the character that defines - * the first entry in the widths list. - * - * @return The number of the first character. - */ - public short getFirstChar() { - return dfFirstChar; - } - - /** - * Returns the number of the character that defines - * the last entry in the widths list. - * - * @return The number of the last character. - */ - public short getLastChar() { - return dfLastChar; - } - - /** - * Returns the CapHeight parameter for the font (height of uppercase H). - * - * @return The CapHeight parameter. - */ - public int getCapHeight() { - return etmCapHeight; - } - - /** - * Returns the XHeight parameter for the font (height of lowercase x). - * - * @return The CapHeight parameter. - */ - public int getXHeight() { - return etmXHeight; - } - - /** - * Returns the LowerCaseAscent parameter for the font (height of lowercase d). - * - * @return The LowerCaseAscent parameter. - */ - public int getLowerCaseAscent() { - return etmLowerCaseAscent; - } - - /** - * Returns the LowerCaseDescent parameter for the font (height of lowercase p). - * - * @return The LowerCaseDescent parameter. - */ - public int getLowerCaseDescent() { - return etmLowerCaseDescent; - } - - /** - * Tells whether the font has proportional character spacing. - * - * @return ex. true for Times, false for Courier. - */ - public boolean getIsProportional() { - return ((dfPitchAndFamily & 1) == 1); - } - - /** - * Returns the bounding box for the font. - * Note: this value is just an approximation, - * it does not really exist in the PFM file. - * - * @return The calculated Font BBox. - */ - public int[] getFontBBox() { - int[] bbox = new int[4]; - - // Just guessing.... - if (!getIsProportional() && (dfAvgWidth == dfMaxWidth)) { - bbox[0] = -20; - } else { - bbox[0] = -100; - } - bbox[1] = getLowerCaseDescent() - 5; - bbox[2] = dfMaxWidth + 10; - bbox[3] = getLowerCaseAscent() + 5; - return bbox; - } - - /** - * Indicates whether the font is non-symbolic (Font uses the Adobe standard Latin character - * set or a subset of it). - * @return true if the font is non-symbolic - */ - public boolean isNonSymbolic() { - return (dfCharSet != 2); //!= Symbol fonts - } - - /** - * Returns the characteristics flags for the font as - * needed for a PDF font descriptor (See PDF specs). - * - * @return The characteristics flags. - */ - public int getFlags() { - int flags = 0; - if (!getIsProportional()) { - flags |= 1; //bit 1: FixedPitch - } - if (isNonSymbolic()) { - flags |= 32; //bit 6: Nonsymbolic - } else { - flags |= 4; //bit 3: Symbolic - } - //int serif = dfPitchAndFamily & 0xFFFE; - if ((dfPitchAndFamily & 16) != 0) { - flags |= 2; //bit 2: Serif - } - if ((dfPitchAndFamily & 64) != 0) { - flags |= 8; //bit 4: Script - } - if (dfItalic != 0) { - flags |= 64; //bit 7: Italic - } - return flags; - } - - /** - * Returns the width of the dominant vertical stems of the font. - * Note: this value is just an approximation, - * it does not really exist in the PFM file. - * - * @return The vertical stem width. - */ - public int getStemV() { - // Just guessing.... - if (dfItalic != 0) { - return (int) Math.round(dfMinWidth * 0.25); - } else { - return (int) Math.round(dfMinWidth * 0.6); - } - } - - /** - * Returns the italic angle of the font. - * Note: this value is just an approximation, - * it does not really exist in the PFM file. - * - * @return The italic angle. - */ - public int getItalicAngle() { - if (dfItalic != 0) { - return -16; // Just guessing.... - } else { - return 0; - } - } - - /** - * Returns the width of a character - * - * @param which The number of the character for which the width is requested. - * @return The width of a character. - */ - public int getCharWidth(short which) { - if (extentTable != null) { - return extentTable[which - dfFirstChar]; - } else { - //Fixed-width font (PFM may have no extent table) - //we'll just use the average width - return this.dfAvgWidth; - } - } - -} diff --git a/src/java/org/apache/fop/fonts/type1/PFMInputStream.java b/src/java/org/apache/fop/fonts/type1/PFMInputStream.java deleted file mode 100644 index e8f0cb705..000000000 --- a/src/java/org/apache/fop/fonts/type1/PFMInputStream.java +++ /dev/null @@ -1,113 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.type1; - -import java.io.DataInputStream; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; - -/** - * This is a helper class for reading PFM files. It defines functions for - * extracting specific values out of the stream. - */ -public class PFMInputStream extends java.io.FilterInputStream { - - private final DataInputStream datain; - - /** - * Constructs a PFMInputStream based on an InputStream representing the - * PFM file. - * - * @param in The stream from which to read the PFM file - */ - public PFMInputStream(InputStream in) { - super(in); - datain = new DataInputStream(in); - } - - /** - * Parses a one byte value out of the stream. - * - * @return The value extracted - * @throws IOException In case of an I/O problem - */ - public short readByte() throws IOException { - short s = datain.readByte(); - // Now, we've got to trick Java into forgetting the sign - int s1 = (((s & 0xF0) >>> 4) << 4) + (s & 0x0F); - return (short)s1; - } - - /** - * Parses a two byte value out of the stream. - * - * @return The value extracted - * @throws IOException In case of an I/O problem - */ - public int readShort() throws IOException { - int i = datain.readShort(); - - // Change byte order - int high = (i & 0xFF00) >>> 8; - int low = (i & 0x00FF) << 8; - return low + high; - } - - /** - * Parses a four byte value out of the stream. - * - * @return The value extracted - * @throws IOException In case of an I/O problem - */ - public long readInt() throws IOException { - int i = datain.readInt(); - - // Change byte order - int i1 = (i & 0xFF000000) >>> 24; - int i2 = (i & 0x00FF0000) >>> 8; - int i3 = (i & 0x0000FF00) << 8; - int i4 = (i & 0x000000FF) << 24; - return i1 + i2 + i3 + i4; - } - - /** - * Parses a zero-terminated string out of the stream. - * - * @return The value extracted - * @throws IOException In case of an I/O problem - */ - public String readString() throws IOException { - InputStreamReader reader = new InputStreamReader(in, "ISO-8859-1"); - StringBuffer buf = new StringBuffer(); - - int ch = reader.read(); - while (ch > 0) { - buf.append((char)ch); - ch = reader.read(); - } - if (ch == -1) { - throw new EOFException("Unexpected end of stream reached"); - } - return buf.toString(); - } - -} diff --git a/src/java/org/apache/fop/fonts/type1/PostscriptParser.java b/src/java/org/apache/fop/fonts/type1/PostscriptParser.java deleted file mode 100644 index bc984fecd..000000000 --- a/src/java/org/apache/fop/fonts/type1/PostscriptParser.java +++ /dev/null @@ -1,655 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.type1; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map.Entry; -import java.util.Scanner; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -public class PostscriptParser { - - protected static final Log LOG = LogFactory.getLog(PostscriptParser.class); - /* Patterns used to identify Postscript elements */ - private static final String DICTIONARY = "dict"; - private static final String FIXED_ARRAY = "array"; - private static final String VARIABLE_ARRAY = "["; - private static final String SUBROUTINE = "{"; - /* A list of parsed subroutines so if they are encountered during the parsing - * phase of another element, they can be read and pattern matched. */ - private HashMap<String, PSSubroutine> subroutines = new HashMap<String, PSSubroutine>(); - - /** - * Parses the postscript document and returns a list of elements - * @param segment The byte array containing the postscript data - * @return A list of found Postscript elements - * @throws IOException - */ - public List<PSElement> parse(byte[] segment) throws IOException { - List<PSElement> parsedElements = new ArrayList<PSElement>(); - /* Currently only scan and store the top level element. For deeper - * Postscript parsing you can push and pop elements from a stack */ - PSElement foundElement = null; - String operator = null; - StringBuilder token = new StringBuilder(); - List<String> tokens = new ArrayList<String>(); - int startPoint = -1; - boolean specialDelimiter = false; - boolean lastWasSpecial = false; - for (int i = 0; i < segment.length; i++) { - byte cur = segment[i]; - if (foundElement != null && foundElement.hasMore()) { - foundElement.parse(cur, i); - continue; - } else { - char c = (char)cur; - if (!lastWasSpecial) { - specialDelimiter = (c == '{' || c == '}' || c == '[' || c == ']' - || (!token.toString().equals("") && c == '/')); - boolean isNotBreak = !(c == ' ' || c == '\r' || cur == 15 || cur == 12 - || cur == 10); - if (isNotBreak && !specialDelimiter) { - token.append(c); - continue; - } - } else { - lastWasSpecial = false; - token.append(c); - if (token.toString().equals("/")) { - continue; - } - } - } - try { - boolean setOp = false; - if ((foundElement == null || !foundElement.hasMore()) && token.length() > 1 - && token.charAt(0) == '/' && tokens.size() != 1 || hasEndToken(token.toString())) { - operator = token.toString(); - setOp = true; - if (tokens.size() > 2 && tokens.get(tokens.size() - 1).equals("def")) { - PSVariable newVar = new PSVariable(tokens.get(0), startPoint); - newVar.setValue(tokens.get(1)); - newVar.setEndPoint(i - operator.length()); - parsedElements.add(newVar); - } - tokens.clear(); - startPoint = i - token.length(); - } - if (operator != null) { - if (foundElement instanceof PSSubroutine) { - PSSubroutine sub = (PSSubroutine)foundElement; - subroutines.put(sub.getOperator(), sub); - parsedElements.add(sub); - if (!setOp) { - operator = ""; - } - } else { - if (foundElement != null) { - if (!hasMatch(foundElement.getOperator(), parsedElements)) { - parsedElements.add(foundElement); - } else { - LOG.warn("Duplicate " + foundElement.getOperator() - + " in font file, Ignoring."); - } - } - } - //Compare token against patterns and create an element if matched - foundElement = createElement(operator, token.toString(), startPoint); - } - } finally { - tokens.add(token.toString()); - token = new StringBuilder(); - if (specialDelimiter) { - specialDelimiter = false; - lastWasSpecial = true; - //Retrace special postscript character so it can be processed separately - i--; - } - } - } - return parsedElements; - } - - private boolean hasEndToken(String token) { - return token.equals("currentdict"); - } - - private boolean hasMatch(String operator, List<PSElement> elements) { - for (PSElement element : elements) { - if (element.getOperator().equals(operator)) { - return true; - } - } - return false; - } - - public PSElement createElement(String operator, String elementID, int startPoint) { - if (operator.equals("")) { - return null; - } - if (elementID.equals(FIXED_ARRAY)) { - return new PSFixedArray(operator, startPoint); - } else if (elementID.equals(VARIABLE_ARRAY)) { - return new PSVariableArray(operator, startPoint); - } else if (elementID.equals(SUBROUTINE)) { - return new PSSubroutine(operator, startPoint); - } else if (!operator.equals("/Private") && elementID.equals(DICTIONARY)) { - return new PSDictionary(operator, startPoint); - } - return null; - } - - /** - * A base Postscript element class - */ - public abstract class PSElement { - /* The identifying operator for this element */ - protected String operator; - private List<Byte> token; - /* Determines whether there is any more data to be read whilst parsing */ - protected boolean hasMore = true; - /* The locations of any entries containing binary data (e.g. arrays) */ - protected LinkedHashMap<String, int[]> binaryEntries; - /* The tokens parsed from the current element */ - protected List<String> tokens; - /* Determines whether binary data is currently being read / parsed */ - protected boolean readBinary; - /* The location of the element within the binary data */ - private int startPoint = -1; - protected int endPoint = -1; - /* A flag to determine if unexpected postscript has been found in the element */ - private boolean foundUnexpected; - - public PSElement(String operator, int startPoint) { - this.operator = operator; - this.startPoint = startPoint; - token = new ArrayList<Byte>(); - binaryEntries = new LinkedHashMap<String, int[]>(); - tokens = new ArrayList<String>(); - } - - /** - * Gets the Postscript element operator - * @return The operator returned as a string - */ - public String getOperator() { - return operator; - } - - /** - * The start location of the element within the source binary data - * @return The start location returned as an integer - */ - public int getStartPoint() { - return startPoint; - } - - /** - * The end location of the element within the source binary data - * @return The end location returned as an integer - */ - public int getEndPoint() { - return endPoint; - } - - /** - * Takes over the task of tokenizing the byte data - * @param cur The current byte being read - */ - public void parse(byte cur, int pos) throws UnsupportedEncodingException { - if (!readBinary) { - char c = (char)cur; - boolean specialDelimiter = (c == '{' || c == '}' || c == '[' || c == ']' - || c == '(' || c == ')'); - boolean isNotValidBreak = !(c == ' ' || cur == 15 || cur == 12 || c == '\r' - || c == 10); - if (isNotValidBreak && !specialDelimiter) { - token.add(cur); - } else { - parseToken(pos); - } - if (specialDelimiter) { - token.add(cur); - parseToken(pos); - } - } else { - parseByte(cur, pos); - } - } - - private void parseToken(int pos) throws UnsupportedEncodingException { - byte[] bytesToken = new byte[token.size()]; - for (int i = 0; i < token.size(); i++) { - bytesToken[i] = token.get(i).byteValue(); - } - parseToken(new String(bytesToken, "ASCII"), pos); - token.clear(); - } - - /** - * Passes responsibility for processing the byte stream to the PostScript object - * @param cur The byte currently being read - * @param pos The position of the given byte - */ - public abstract void parseByte(byte cur, int pos); - - /** - * Delegates the parse routine to a sub class - * @param token The token which to parse - */ - public abstract void parseToken(String token, int curPos); - - protected boolean isInteger(String intValue) { - try { - Integer.parseInt(intValue); - return true; - } catch (NumberFormatException ex) { - return false; - } - } - - public LinkedHashMap<String, int[]> getBinaryEntries() { - return binaryEntries; - } - - /** - * Gets the binary entry location of a given index from the array - * @param index The index for which to retrieve the binary data location - * @return - */ - public int[] getBinaryEntryByIndex(int index) { - int count = 0; - for (Entry<String, int[]> entry : binaryEntries.entrySet()) { - if (count == index) { - return entry.getValue(); - } - count++; - } - return new int[0]; - } - - /** - * Determines if more data is still to be parsed for the Postscript element. - * @return Returns true if more data exists - */ - public boolean hasMore() { - return hasMore; - } - - /** - * Sets a value to be true if an expected entry postscript is found in the element. - * An example is where the encoding table may have a series of postscript operators - * altering the state of the array. In this case the only option will be to - * fully embed the font to avoid incorrect encoding in the resulting subset. - * @param foundUnexpected true if unexpected postscript is found. - */ - protected void setFoundUnexpected(boolean foundUnexpected) { - this.foundUnexpected = foundUnexpected; - } - - /** - * Returns whether unexpected postscript has been found in the element - * @return true if unexpected postscript is found - */ - public boolean getFoundUnexpected() { - return this.foundUnexpected; - } - } - - /** - * An object representing a Postscript array with a fixed number of entries - */ - public class PSFixedArray extends PSElement { - - private String entry = ""; - private String token = ""; - private boolean finished; - protected int binaryLength; - /* A list containing each entry and it's contents in the array */ - private HashMap<Integer, String> entries; - private static final String READ_ONLY = "readonly"; - - public PSFixedArray(String operator, int startPoint) { - super(operator, startPoint); - entries = new HashMap<Integer, String>(); - } - - @Override - public void parseToken(String token, int curPos) { - if (!checkForEnd(token) || token.equals("def")) { - hasMore = false; - endPoint = curPos; - return; - } - if (token.equals("dup")) { - if (entry.startsWith("dup")) { - addEntry(entry); - } - entry = ""; - tokens.clear(); - } - if (!token.equals(READ_ONLY)) { - entry += token + " "; - } - if (!token.trim().equals("")) { - tokens.add(token); - } - if (tokens.size() == 4 && tokens.get(0).equals("dup") && isInteger(tokens.get(2))) { - binaryLength = Integer.parseInt(tokens.get(2)); - readBinary = true; - } - } - - private boolean checkForEnd(String checkToken) { - boolean subFound = false; - //Check for a subroutine matching that of an array end definition - PSSubroutine sub = subroutines.get("/" + checkToken); - if (sub != null && sub.getSubroutine().contains("def")) { - subFound = true; - } - if (!finished && (subFound || checkToken.equals("def"))) { - finished = true; - addEntry(entry); - return false; - } else { - return !finished; - } - } - - /** - * Gets a map of array entries identified by index - * @return Returns the map of array entries - */ - public HashMap<Integer, String> getEntries() { - return entries; - } - - private void addEntry(String entry) { - if (!entry.equals("")) { - if (entry.indexOf('/') != -1 && entry.charAt(entry.indexOf('/') - 1) != ' ') { - entry = entry.replace("/", " /"); - } - int entryLen; - do { - entryLen = entry.length(); - entry = entry.replace(" ", " "); - } while (entry.length() != entryLen); - Scanner s = new Scanner(entry).useDelimiter(" "); - boolean valid = false; - do { - s.next(); - if (!s.hasNext()) { - break; - } - int id = s.nextInt(); - entries.put(id, entry); - valid = true; - } while (false); - if (!valid) { - setFoundUnexpected(true); - } - } - } - - @Override - public void parseByte(byte cur, int pos) { - if (binaryLength > 0) { - token += (char)cur; - binaryLength--; - } else { - if (readBinary) { - int bLength = Integer.parseInt(tokens.get(2)); - int start = pos - bLength; - int end = start + bLength; - binaryEntries.put(tokens.get(1), new int[] {start, end}); - token = ""; - readBinary = false; - } else { - tokens.add(token); - parseToken(token, pos); - token = ""; - } - } - } - } - - /** - * An object representing a Postscript array with a variable number of entries - */ - public class PSVariableArray extends PSElement { - private int level; - private List<String> arrayItems; - private String entry = ""; - - public PSVariableArray(String operator, int startPoint) { - super(operator, startPoint); - arrayItems = new ArrayList<String>(); - } - - @Override - public void parseToken(String token, int curPos) { - entry += token + " "; - if (level <= 0 && token.length() > 0 && token.charAt(0) == ']') { - hasMore = false; - endPoint = curPos; - return; - } - /* If the array item is a subroutine, the following keeps track of the current level - * of the tokens being parsed so that it can identify the finish */ - if (token.equals("{")) { - level++; - } else if (token.equals("}")) { - level--; - if (!entry.equals("") && level == 0) { - arrayItems.add(entry); - entry = ""; - } - } - } - - /** - * Gets a list of found array entries within the variable array - * @return Returns the found array elements as a list - */ - public List<String> getEntries() { - return arrayItems; - } - - @Override - public void parseByte(byte cur, int pos) { - //Not currently used - } - } - - /** - * An object representing a Postscript subroutine element - */ - public class PSSubroutine extends PSElement { - private int level = 1; - private String entry = ""; - - public PSSubroutine(String operator, int startPoint) { - super(operator, startPoint); - } - - @Override - public void parseToken(String token, int curPos) { - if (level == 0 && token.length() > 0 && (token.equals("def") || token.equals("ifelse") - || token.charAt(0) == '}')) { - hasMore = false; - endPoint = curPos; - return; - } - if (token.equals("{")) { - level++; - } else if (token.equals("}")) { - level--; - } - entry += token + " "; - } - - /** - * Gets the parsed subroutine element as unmodified string - * @return The subroutine as a string - */ - public String getSubroutine() { - return entry.trim(); - } - - @Override - public void parseByte(byte cur, int pos) { - //Not currently used - } - } - - /** - * An object representing a Postscript dictionary - */ - public class PSDictionary extends PSElement { - /* A list of dictionary entries which they themselves could be variables, - * subroutines and arrays, This is currently left as parsed Strings as there is - * no need to delve deeper for our current purposes. */ - private HashMap<String, String> entries; - private String entry = ""; - private String token = ""; - protected int binaryLength; - - public PSDictionary(String operator, int startPoint) { - super(operator, startPoint); - entries = new HashMap<String, String>(); - } - - @Override - public void parseToken(String token, int curPos) { - if (token.equals("end")) { - addEntry(entry); - hasMore = false; - endPoint = curPos; - return; - } - if (token.startsWith("/")) { - if (entry.trim().startsWith("/")) { - tokens.clear(); - addEntry(entry); - } - entry = ""; - } - if (tokens.size() >= 1 || token.startsWith("/")) { - tokens.add(token); - } - entry += token + " "; - if (tokens.size() == 3 && tokens.get(0).startsWith("/") && !tokens.get(2).equals("def") - && isInteger(tokens.get(1))) { - binaryLength = Integer.parseInt(tokens.get(1)); - readBinary = true; - } - } - - /** - * Gets a map of dictionary entries identified by their name - * @return Returns the dictionary entries as a map - */ - public HashMap<String, String> getEntries() { - return entries; - } - - private void addEntry(String entry) { - Scanner s = new Scanner(entry).useDelimiter(" "); - String id = s.next(); - entries.put(id, entry); - } - - @Override - public void parseByte(byte cur, int pos) { - if (binaryLength > 0) { - binaryLength--; - } else { - if (readBinary) { - int start = pos - Integer.parseInt(tokens.get(1)); - int end = pos; - binaryEntries.put(tokens.get(0), new int[] {start, end}); - readBinary = false; - } else { - tokens.add(token); - parseToken(token, pos); - } - } - } - } - - /** - * An object representing a Postscript variable - */ - public class PSVariable extends PSElement { - - /* The value of the parsed Postscript variable. */ - private String value = ""; - - public PSVariable(String operator, int startPoint) { - super(operator, startPoint); - } - - @Override - public void parseToken(String token, int curPos) { - if (token.equals("def")) { - hasMore = false; - endPoint = curPos; - return; - } - } - - @Override - public void parseByte(byte cur, int pos) { - //Not currently used - } - - /** - * Sets the value of the Postscript variable value - * @param value The value to set - */ - public void setValue(String value) { - this.value = value; - } - - /** - * Gets the value of the Postscript variable - * @return Returns the value as a String - */ - public String getValue() { - return value; - } - - /** - * Sets the end point location of the current Postscript variable. - * @param endPoint The end point location as an integer - */ - public void setEndPoint(int endPoint) { - this.endPoint = endPoint; - } - - } -} diff --git a/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java b/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java deleted file mode 100644 index d364462cc..000000000 --- a/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java +++ /dev/null @@ -1,463 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.type1; - -import java.awt.geom.RectangularShape; -import java.io.IOException; -import java.io.InputStream; -import java.net.URISyntaxException; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.apps.io.InternalResourceResolver; -import org.apache.fop.fonts.CodePointMapping; -import org.apache.fop.fonts.EmbeddingMode; -import org.apache.fop.fonts.FontLoader; -import org.apache.fop.fonts.FontType; -import org.apache.fop.fonts.FontUris; -import org.apache.fop.fonts.SingleByteEncoding; -import org.apache.fop.fonts.SingleByteFont; - -/** - * Loads a Type 1 font into memory directly from the original font file. - */ -public class Type1FontLoader extends FontLoader { - - private static final Log log = LogFactory.getLog(Type1FontLoader.class); - - private SingleByteFont singleFont; - - private EmbeddingMode embeddingMode; - - private final FontUris fontUris; - - /** - * Constructs a new Type 1 font loader. - * @param fontFileURI the URI to the PFB file of a Type 1 font - * @param embedded indicates whether the font is embedded or referenced - * @param useKerning indicates whether to load kerning information if available - * @param resourceResolver the font resolver used to resolve URIs - * @throws IOException In case of an I/O error - */ - public Type1FontLoader(FontUris fontUris, boolean embedded, EmbeddingMode embeddingMode, - boolean useKerning, InternalResourceResolver resourceResolver) throws IOException { - super(fontUris.getEmbed(), embedded, useKerning, true, resourceResolver); - this.embeddingMode = embeddingMode; - this.fontUris = fontUris; - } - - private String getPFMURI(String pfbURI) { - String pfbExt = pfbURI.substring(pfbURI.length() - 3, pfbURI.length()); - String pfmExt = pfbExt.substring(0, 2) - + (Character.isUpperCase(pfbExt.charAt(2)) ? "M" : "m"); - return pfbURI.substring(0, pfbURI.length() - 4) + "." + pfmExt; - } - - private static final String[] AFM_EXTENSIONS = new String[] {".AFM", ".afm", ".Afm"}; - - /** {@inheritDoc} */ - @Override - protected void read() throws IOException { - AFMFile afm = null; - PFMFile pfm = null; - - InputStream afmIn = null; - String fontFileStr = fontFileURI.toASCIIString(); - String partialAfmUri = fontFileStr.substring(0, fontFileStr.length() - 4); - String afmUri = (fontUris.getAfm() != null) ? fontUris.getAfm().toASCIIString() : null; - if (afmUri == null) { - for (String afmExtension : AFM_EXTENSIONS) { - try { - afmUri = partialAfmUri + afmExtension; - afmIn = resourceResolver.getResource(afmUri); - if (afmIn != null) { - break; - } - } catch (IOException ioe) { - // Ignore, AFM probably not available under the URI - } catch (URISyntaxException e) { - // Ignore, AFM probably not available under the URI - } - } - } else { - try { - afmIn = resourceResolver.getResource(afmUri); - } catch (URISyntaxException e) { - throw new IOException(e); - } - } - if (afmIn != null) { - try { - AFMParser afmParser = new AFMParser(); - afm = afmParser.parse(afmIn, afmUri); - } finally { - IOUtils.closeQuietly(afmIn); - } - } - - String pfmUri = (fontUris.getPfm() == null) ? getPFMURI(fontFileStr) : fontUris.getPfm() - .toASCIIString(); - InputStream pfmIn = null; - try { - pfmIn = resourceResolver.getResource(pfmUri); - } catch (IOException ioe) { - // Ignore, PFM probably not available under the URI - } catch (URISyntaxException e) { - // Ignore, PFM probably not available under the URI - } - if (pfmIn != null) { - try { - pfm = new PFMFile(); - pfm.load(pfmIn); - } catch (IOException ioe) { - if (afm == null) { - // Ignore the exception if we have a valid PFM. PFM is only the fallback. - throw ioe; - } - } finally { - IOUtils.closeQuietly(pfmIn); - } - } - - if (afm == null && pfm == null) { - throw new java.io.FileNotFoundException( - "Neither an AFM nor a PFM file was found for " + this.fontFileURI); - } - buildFont(afm, pfm); - this.loaded = true; - } - - private void buildFont(AFMFile afm, PFMFile pfm) { - if (afm == null && pfm == null) { - throw new IllegalArgumentException("Need at least an AFM or a PFM!"); - } - singleFont = new SingleByteFont(resourceResolver, embeddingMode); - singleFont.setFontType(FontType.TYPE1); - if (this.embedded) { - singleFont.setEmbedURI(this.fontFileURI); - } - returnFont = singleFont; - - handleEncoding(afm, pfm); - handleFontName(afm, pfm); - handleMetrics(afm, pfm); - } - - private void handleEncoding(AFMFile afm, PFMFile pfm) { - // Encoding - if (afm != null) { - String encoding = afm.getEncodingScheme(); - singleFont.setUseNativeEncoding(true); - if ("AdobeStandardEncoding".equals(encoding)) { - singleFont.setEncoding(CodePointMapping.STANDARD_ENCODING); - addUnencodedBasedOnEncoding(afm); - } else { - String effEncodingName; - if ("FontSpecific".equals(encoding)) { - effEncodingName = afm.getFontName() + "Encoding"; - } else { - effEncodingName = encoding; - } - if (log.isDebugEnabled()) { - log.debug("Unusual font encoding encountered: " - + encoding + " -> " + effEncodingName); - } - CodePointMapping mapping = buildCustomEncoding(effEncodingName, afm); - singleFont.setEncoding(mapping); - addUnencodedBasedOnAFM(afm); - } - } else { - if (pfm.getCharSet() == 2 && !pfm.getCharSetName().equals("Symbol")) { - int[] table = new int[256]; - String[] charNameMap = new String[256]; - int j = 0; - for (int i = pfm.getFirstChar(); i < pfm.getLastChar(); i++) { - if (j < table.length) { - table[j] = i; - table[j + 1] = i; - j += 2; - } - charNameMap[i] = String.format("x%03o", i); - } - CodePointMapping mapping = new CodePointMapping("custom", table, charNameMap); - singleFont.setEncoding(mapping); - } else if (pfm.getCharSet() >= 0 && pfm.getCharSet() <= 2) { - singleFont.setEncoding(pfm.getCharSetName() + "Encoding"); - } else { - log.warn("The PFM reports an unsupported encoding (" - + pfm.getCharSetName() + "). The font may not work as expected."); - singleFont.setEncoding("WinAnsiEncoding"); // Try fallback, no guarantees! - } - } - } - - private Set<String> toGlyphSet(String[] glyphNames) { - Set<String> glyphSet = new java.util.HashSet<String>(); - for (String name : glyphNames) { - glyphSet.add(name); - } - return glyphSet; - } - - /** - * Adds characters not encoded in the font's primary encoding. This method is used when we - * don't trust the AFM to expose the same encoding as the primary font. - * @param afm the AFM file. - */ - private void addUnencodedBasedOnEncoding(AFMFile afm) { - SingleByteEncoding encoding = singleFont.getEncoding(); - Set<String> glyphNames = toGlyphSet(encoding.getCharNameMap()); - List<AFMCharMetrics> charMetrics = afm.getCharMetrics(); - for (AFMCharMetrics metrics : charMetrics) { - String charName = metrics.getCharName(); - if (charName != null && !glyphNames.contains(charName)) { - addUnencodedCharacter(singleFont, metrics); - } - } - } - - private static void addUnencodedCharacter(SingleByteFont font, AFMCharMetrics metrics) { - font.addUnencodedCharacter(metrics.getCharacter(), - (int) Math.round(metrics.getWidthX()), metrics.getBBox()); - } - - /** - * Adds characters not encoded in the font's primary encoding. This method is used when - * the primary encoding is built based on the character codes in the AFM rather than - * the specified encoding (ex. with symbolic fonts). - * @param afm the AFM file - */ - private void addUnencodedBasedOnAFM(AFMFile afm) { - List charMetrics = afm.getCharMetrics(); - for (int i = 0, c = afm.getCharCount(); i < c; i++) { - AFMCharMetrics metrics = (AFMCharMetrics)charMetrics.get(i); - if (!metrics.hasCharCode() && metrics.getCharacter() != null) { - addUnencodedCharacter(singleFont, metrics); - } - } - } - - private void handleFontName(AFMFile afm, PFMFile pfm) { - // Font name - if (afm != null) { - returnFont.setFontName(afm.getFontName()); // PostScript font name - returnFont.setFullName(afm.getFullName()); - Set<String> names = new HashSet<String>(); - names.add(afm.getFamilyName()); - returnFont.setFamilyNames(names); - } else { - returnFont.setFontName(pfm.getPostscriptName()); - String fullName = pfm.getPostscriptName(); - fullName = fullName.replace('-', ' '); // Hack! Try to emulate full name - returnFont.setFullName(fullName); // emulate afm.getFullName() - Set<String> names = new HashSet<String>(); - names.add(pfm.getWindowsName()); // emulate afm.getFamilyName() - returnFont.setFamilyNames(names); - } - } - - private void handleMetrics(AFMFile afm, PFMFile pfm) { - // Basic metrics - if (afm != null) { - if (afm.getCapHeight() != null) { - returnFont.setCapHeight(afm.getCapHeight().intValue()); - } - if (afm.getXHeight() != null) { - returnFont.setXHeight(afm.getXHeight().intValue()); - } - if (afm.getAscender() != null) { - returnFont.setAscender(afm.getAscender().intValue()); - } - if (afm.getDescender() != null) { - returnFont.setDescender(afm.getDescender().intValue()); - } - - returnFont.setFontBBox(afm.getFontBBoxAsIntArray()); - if (afm.getStdVW() != null) { - returnFont.setStemV(afm.getStdVW().intValue()); - } else { - returnFont.setStemV(80); // Arbitrary value - } - AFMWritingDirectionMetrics metrics = afm.getWritingDirectionMetrics(0); - returnFont.setItalicAngle((int) metrics.getItalicAngle()); - returnFont.setUnderlinePosition(metrics.getUnderlinePosition().intValue()); - returnFont.setUnderlineThickness(metrics.getUnderlineThickness().intValue()); - } else { - returnFont.setFontBBox(pfm.getFontBBox()); - returnFont.setStemV(pfm.getStemV()); - returnFont.setItalicAngle(pfm.getItalicAngle()); - } - if (pfm != null) { - // Sometimes the PFM has these metrics while the AFM doesn't (ex. Symbol) - if (returnFont.getCapHeight() == 0) { - returnFont.setCapHeight(pfm.getCapHeight()); - } - if (returnFont.getXHeight(1) == 0) { - returnFont.setXHeight(pfm.getXHeight()); - } - if (returnFont.getAscender() == 0) { - returnFont.setAscender(pfm.getLowerCaseAscent()); - } - if (returnFont.getDescender() == 0) { - returnFont.setDescender(pfm.getLowerCaseDescent()); - } - } - - // Fallbacks when some crucial font metrics aren't available - // (the following are all optional in AFM, but FontBBox is always available) - if (returnFont.getXHeight(1) == 0) { - int xHeight = 0; - if (afm != null) { - AFMCharMetrics chm = afm.getChar("x"); - if (chm != null) { - RectangularShape rect = chm.getBBox(); - if (rect != null) { - xHeight = (int) Math.round(rect.getMinX()); - } - } - } - if (xHeight == 0) { - xHeight = Math.round(returnFont.getFontBBox()[3] * 0.6f); - } - returnFont.setXHeight(xHeight); - } - if (returnFont.getAscender() == 0) { - int asc = 0; - if (afm != null) { - AFMCharMetrics chm = afm.getChar("d"); - if (chm != null) { - RectangularShape rect = chm.getBBox(); - if (rect != null) { - asc = (int) Math.round(rect.getMinX()); - } - } - } - if (asc == 0) { - asc = Math.round(returnFont.getFontBBox()[3] * 0.9f); - } - returnFont.setAscender(asc); - } - if (returnFont.getDescender() == 0) { - int desc = 0; - if (afm != null) { - AFMCharMetrics chm = afm.getChar("p"); - if (chm != null) { - RectangularShape rect = chm.getBBox(); - if (rect != null) { - desc = (int) Math.round(rect.getMinX()); - } - } - } - if (desc == 0) { - desc = returnFont.getFontBBox()[1]; - } - returnFont.setDescender(desc); - } - if (returnFont.getCapHeight() == 0) { - returnFont.setCapHeight(returnFont.getAscender()); - } - - if (afm != null) { - String charSet = afm.getCharacterSet(); - int flags = 0; - if ("Special".equals(charSet)) { - flags |= 4; // bit 3: Symbolic - } else { - if (singleFont.getEncoding().mapChar('A') == 'A') { - // High likelyhood that the font is non-symbolic - flags |= 32; // bit 6: Nonsymbolic - } else { - flags |= 4; // bit 3: Symbolic - } - } - if (afm.getWritingDirectionMetrics(0).isFixedPitch()) { - flags |= 1; // bit 1: FixedPitch - } - if (afm.getWritingDirectionMetrics(0).getItalicAngle() != 0.0) { - flags |= 64; // bit 7: Italic - } - returnFont.setFlags(flags); - - returnFont.setFirstChar(afm.getFirstChar()); - returnFont.setLastChar(afm.getLastChar()); - for (AFMCharMetrics chm : afm.getCharMetrics()) { - if (chm.hasCharCode()) { - singleFont.setWidth(chm.getCharCode(), (int) Math.round(chm.getWidthX())); - singleFont.setBoundingBox(chm.getCharCode(), chm.getBBox()); - } - } - if (useKerning) { - returnFont.replaceKerningMap(afm.createXKerningMapEncoded()); - } - } else { - returnFont.setFlags(pfm.getFlags()); - returnFont.setFirstChar(pfm.getFirstChar()); - returnFont.setLastChar(pfm.getLastChar()); - for (short i = pfm.getFirstChar(); i <= pfm.getLastChar(); i++) { - singleFont.setWidth(i, pfm.getCharWidth(i)); - } - if (useKerning) { - returnFont.replaceKerningMap(pfm.getKerning()); - } - } - } - - private CodePointMapping buildCustomEncoding(String encodingName, AFMFile afm) { - int mappingCount = 0; - // Just count the first time... - List<AFMCharMetrics> chars = afm.getCharMetrics(); - for (AFMCharMetrics charMetrics : chars) { - if (charMetrics.getCharCode() >= 0) { - mappingCount++; - } - } - // ...and now build the table. - int[] table = new int[mappingCount * 2]; - String[] charNameMap = new String[256]; - int idx = 0; - for (AFMCharMetrics charMetrics : chars) { - if (charMetrics.getCharCode() >= 0) { - charNameMap[charMetrics.getCharCode()] = charMetrics.getCharName(); - String unicodes = charMetrics.getUnicodeSequence(); - if (unicodes == null) { - log.info("No Unicode mapping for glyph: " + charMetrics); - table[idx] = charMetrics.getCharCode(); - idx++; - table[idx] = charMetrics.getCharCode(); - idx++; - } else if (unicodes.length() == 1) { - table[idx] = charMetrics.getCharCode(); - idx++; - table[idx] = unicodes.charAt(0); - idx++; - } else { - log.warn("Multi-character representation of glyph not currently supported: " - + charMetrics); - } - } - } - return new CodePointMapping(encodingName, table, charNameMap); - } -} diff --git a/src/java/org/apache/fop/fonts/type1/Type1SubsetFile.java b/src/java/org/apache/fop/fonts/type1/Type1SubsetFile.java deleted file mode 100644 index 394d5c777..000000000 --- a/src/java/org/apache/fop/fonts/type1/Type1SubsetFile.java +++ /dev/null @@ -1,756 +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. - */ - -/* $Id$ */ - -package org.apache.fop.fonts.type1; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Scanner; -import java.util.Set; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.fop.fonts.SingleByteFont; -import org.apache.fop.fonts.type1.PostscriptParser.PSDictionary; -import org.apache.fop.fonts.type1.PostscriptParser.PSElement; -import org.apache.fop.fonts.type1.PostscriptParser.PSFixedArray; -import org.apache.fop.fonts.type1.PostscriptParser.PSSubroutine; -import org.apache.fop.fonts.type1.PostscriptParser.PSVariable; - -public class Type1SubsetFile { - - protected static final Log LOG = LogFactory.getLog(Type1SubsetFile.class); - /* The subset list of char strings */ - protected HashMap<String, byte[]> subsetCharStrings; - /* The list of character names in the subset font */ - protected List<String> charNames; - /* A list of unique subroutines references */ - protected LinkedHashMap<Integer, byte[]> uniqueSubs; - private SingleByteFont sbfont; - /* New line character */ - protected String eol = "\n"; - /* An option to determine whether the subroutines are subset */ - protected boolean subsetSubroutines = true; - private byte[] fullFont; - //List of parsed Postscript elements - protected List<PSElement> headerSection; - protected List<PSElement> mainSection; - //Determines whether the current font uses standard encoding - protected boolean standardEncoding; - - //Type 1 operators - private static final int OP_SEAC = 6; - private static final int OP_CALLSUBR = 10; - private static final int OP_CALLOTHERSUBR = 16; - - public byte[] createSubset(InputStream in, SingleByteFont sbfont) throws IOException { - fullFont = IOUtils.toByteArray(in); - byte[] subsetFont = createSubset(sbfont, true); - //This should never happen but ensure that subset is shorter than original font - return (subsetFont.length == 0 || subsetFont.length > fullFont.length) - ? fullFont : subsetFont; - } - - /** - * Creates a new subset from the given type 1 font input stream - * @param sbfont The font object containing information such as the - * characters from which to create the subset - * @param subsetSubroutines This option will force the subset to include all - * subroutines. - * @return Returns the subset as a byte array - * @throws IOException - */ - private byte[] createSubset(SingleByteFont sbfont, boolean subsetSubroutines) throws IOException { - this.subsetSubroutines = subsetSubroutines; - InputStream in = new ByteArrayInputStream(fullFont); - //Initialise resources used for the font creation - this.sbfont = sbfont; - PFBParser pfbParser = new PFBParser(); - PFBData pfbData = pfbParser.parsePFB(in); - - PostscriptParser psParser = new PostscriptParser(); - charNames = new ArrayList<String>(); - - //Parse the header section of the font - if (headerSection == null) { - headerSection = psParser.parse(pfbData.getHeaderSegment()); - } - - //Read the encoding section - PSElement encoding = getElement("/Encoding", headerSection); - if (encoding.getFoundUnexpected()) { - //Fully embed the font as we're unable to interpret postscript on arrays - return new byte[0]; - } - List<String> subsetEncodingEntries = readEncoding(encoding); - - //Decode the main section in preparation for parsing - byte[] decoded = BinaryCoder.decodeBytes(pfbData.getEncryptedSegment(), 55665, 4); - - //Initialise the resources used to hold the subset data - uniqueSubs = new LinkedHashMap<Integer, byte[]>(); - subsetCharStrings = new HashMap<String, byte[]>(); - - //Parse the encoded main font section for elements - if (mainSection == null) { - mainSection = psParser.parse(decoded); - } - - //Process and write the main section - PSElement charStrings = getElement("/CharStrings", mainSection); - boolean result = readMainSection(mainSection, decoded, subsetEncodingEntries, charStrings); - if (!result) { - /* This check handles the case where a font uses a postscript method to return a - * subroutine index. As there is currently no java postscript interpreter and writing - * one would be very difficult it prevents us from handling this eventuality. The way - * this issue is being handled is to restart the subset process and include all - * subroutines. */ - uniqueSubs.clear(); - subsetCharStrings.clear(); - charNames.clear(); - return createSubset(sbfont, false); - } - - //Write header section - ByteArrayOutputStream boasHeader = writeHeader(pfbData, encoding); - - ByteArrayOutputStream boasMain = writeMainSection(decoded, mainSection, charStrings); - byte[] mainSectionBytes = boasMain.toByteArray(); - mainSectionBytes = BinaryCoder.encodeBytes(mainSectionBytes, 55665, 4); - boasMain.reset(); - boasMain.write(mainSectionBytes); - - ByteArrayOutputStream baosTrailer = new ByteArrayOutputStream(); - baosTrailer.write(pfbData.getTrailerSegment(), 0, pfbData.getTrailerSegment().length); - - return stitchFont(boasHeader, boasMain, baosTrailer); - } - - protected byte[] stitchFont(ByteArrayOutputStream boasHeader, ByteArrayOutputStream boasMain, - ByteArrayOutputStream boasTrailer) throws IOException { - int headerLength = boasHeader.size(); - int mainLength = boasMain.size(); - - boasMain.write(128); - boasMain.write(1); - updateSectionSize(boasTrailer.size()).writeTo(boasMain); - boasTrailer.write(128); - boasTrailer.write(3); - - boasTrailer.writeTo(boasMain); - - boasHeader.write(128); - boasHeader.write(2); - //You need to encode the main section first before getting it's size!!! - updateSectionSize(mainLength).writeTo(boasHeader); - boasMain.writeTo(boasHeader); - - ByteArrayOutputStream fullFont = new ByteArrayOutputStream(); - fullFont.write(128); - fullFont.write(1); - updateSectionSize(headerLength).writeTo(fullFont); - boasHeader.writeTo(fullFont); - - return fullFont.toByteArray(); - } - - private List<String> readEncoding(PSElement encoding) { - Map<Integer, Integer> usedGlyphs = sbfont.getUsedGlyphs(); - List<Integer> glyphs = new ArrayList<Integer>(usedGlyphs.keySet()); - Collections.sort(glyphs); - List<String> subsetEncodingEntries = new ArrayList<String>(); - //Handle custom encoding - if (encoding instanceof PSFixedArray) { - PSFixedArray encodingArray = (PSFixedArray)encoding; - for (int glyph : glyphs) { - /* Search for matching entries in the original font encoding table to add - * to the subset. As there may be more than one entry for a character (as - * was the case in a font where some glyphs were duplicated), a name search is - * performed and all matching entries are added. */ - List<String> matches = searchEntries(encodingArray.getEntries(), glyph); - /* If no matches are found, create a new entry for the character so - * that it can be added even if it's not in the current encoding. */ - if (matches.size() == 0) { - matches.clear(); - if (glyph == 0) { - matches.add("dup 0 /.notdef put"); - } else { - matches.add(String.format("dup %d /%s put", glyph, - sbfont.getGlyphName(glyph))); - } - } - for (String match : matches) { - subsetEncodingEntries.add(match); - addToCharNames(match); - } - } - //Handle fixed encoding - } else if (encoding instanceof PSVariable) { - if (((PSVariable) encoding).getValue().equals("StandardEncoding")) { - standardEncoding = true; - sbfont.mapUsedGlyphName(0, "/.notdef"); - for (int glyph : glyphs) { - //Retrieve the character name and alternates for the given glyph - String name = sbfont.getGlyphName(glyph); - if (glyph != 0 && name != null && !name.trim().equals("")) { - sbfont.mapUsedGlyphName(glyph, "/" + name); - } - } - } else { - LOG.warn("Only Custom or StandardEncoding is supported when creating a Type 1 subset."); - } - } - return subsetEncodingEntries; - } - - protected List<String> searchEntries(HashMap<Integer, String> encodingEntries, int glyph) { - List<String> matches = new ArrayList<String>(); - for (Entry<Integer, String> entry : encodingEntries.entrySet()) { - String tag = getEntryPart(entry.getValue(), 3); - String name = sbfont.getGlyphName(sbfont.getUsedGlyphs().get(glyph)); - if (name.equals(tag)) { - matches.add(entry.getValue()); - } - } - return matches; - } - - protected ByteArrayOutputStream writeHeader(PFBData pfbData, PSElement encoding) throws IOException { - ByteArrayOutputStream boasHeader = new ByteArrayOutputStream(); - boasHeader.write(pfbData.getHeaderSegment(), 0, encoding.getStartPoint() - 1); - - if (!standardEncoding) { - //Write out the new encoding table for the subset font - String encodingArray = eol + "/Encoding 256 array" + eol - + "0 1 255 {1 index exch /.notdef put } for" + eol; - byte[] encodingDefinition = encodingArray.getBytes("ASCII"); - boasHeader.write(encodingDefinition, 0, encodingDefinition.length); - Set<Entry<Integer, String>> entrySet = sbfont.getUsedGlyphNames().entrySet(); - for (Entry<Integer, String> entry : entrySet) { - String arrayEntry = String.format("dup %d %s put", entry.getKey(), - entry.getValue()); - writeString(arrayEntry + eol, boasHeader); - } - writeString("readonly def" + eol, boasHeader); - } else { - String theEncoding = eol + "/Encoding StandardEncoding def" + eol; - boasHeader.write(theEncoding.getBytes("ASCII")); - } - boasHeader.write(pfbData.getHeaderSegment(), encoding.getEndPoint(), - pfbData.getHeaderSegment().length - encoding.getEndPoint()); - - return boasHeader; - } - - ByteArrayOutputStream updateSectionSize(int size) throws IOException { - //Update the size in the header for the previous section - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - byte[] lowOrderSize = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt( - size).array(); - boas.write(lowOrderSize); - return boas; - } - - private boolean readMainSection(List<PSElement> mainSection, byte[] decoded, - List<String> subsetEncodingEntries, PSElement charStrings) { - subsetEncodingEntries.add(0, "dup 0 /.notdef put"); - /* Reads and parses the charStrings section to subset the charString - * and it's referenced subroutines found in the main section for each glyph. */ - PSDictionary charStringsDict = (PSDictionary)charStrings; - for (String tag : sbfont.getUsedGlyphNames().values()) { - if (!tag.equals("/.notdef")) { - charNames.add(tag); - } - - int[] location = charStringsDict.getBinaryEntries().get(tag); - if (location == null) { - continue; - } - byte[] charStringEntry = getBinaryEntry(location, decoded); - - int skipBytes = 4; - PSElement element = getElement("lenIV", mainSection); - if (element != null && element instanceof PSVariable) { - PSVariable lenIV = (PSVariable)element; - try { - skipBytes = Integer.parseInt(lenIV.getValue()); - } catch (NumberFormatException ex) { - LOG.warn(String.format("Invalid value `%s` for lenIV found in font %s", lenIV.getValue(), - sbfont.getEmbedFileURI().toString())); - } - } - - charStringEntry = BinaryCoder.decodeBytes(charStringEntry, 4330, skipBytes); - PSFixedArray subroutines = (PSFixedArray)getElement("/Subrs", mainSection); - if (subsetSubroutines) { - /* Recursively scan the charString array for subroutines and if found, copy the - * entry to our subset entries and update any references. */ - charStringEntry = createSubsetCharStrings(decoded, charStringEntry, subroutines, - subsetEncodingEntries); - } - if (charStringEntry.length == 0) { - return false; - } - charStringEntry = BinaryCoder.encodeBytes(charStringEntry, 4330, skipBytes); - subsetCharStrings.put(tag, charStringEntry); - } - return true; - } - - private byte[] createSubsetCharStrings(byte[] decoded, byte[] data, PSFixedArray subroutines, - List<String> subsetEncodingEntries) { - List<BytesNumber> operands = new ArrayList<BytesNumber>(); - for (int i = 0; i < data.length; i++) { - int cur = data[i] & 0xFF; - if (cur <= 31) { - int dataLength = data.length; - if (cur == OP_CALLSUBR) { - //Found subroutine. Read subroutine and recursively scan and update references - if (operands.size() == 0) { - continue; - } - if (uniqueSubs.get(operands.get(operands.size() - 1).getNumber()) == null) { - uniqueSubs.put(operands.get(operands.size() - 1).getNumber(), new byte[0]); - data = addSubroutine(subroutines, operands, decoded, subsetEncodingEntries, - data, i, 1, -1, operands.get( - operands.size() - 1).getNumber()); - } else { - data = addSubroutine(subroutines, operands, decoded, subsetEncodingEntries, - data, i, 1, getSubrIndex(operands.get( - operands.size() - 1).getNumber()), operands.get( - operands.size() - 1).getNumber()); - } - } else if (cur == 12) { - int next = data[++i] & 0xFF; - if (next == OP_SEAC) { - /* This charString references two other glyphs which must also be included - * for this character to be displayed properly. */ - int first = operands.get(operands.size() - 2).getNumber(); - int second = operands.get(operands.size() - 1).getNumber(); - String charFirst = AdobeStandardEncoding.getCharFromCodePoint(first); - String charSecond = AdobeStandardEncoding.getCharFromCodePoint(second); - subsetEncodingEntries.add(String.format("dup %d /%s put", - first, charFirst)); - subsetEncodingEntries.add(String.format("dup %d /%s put", - second, charSecond)); - sbfont.mapUsedGlyphName(first, "/" + charFirst); - sbfont.mapUsedGlyphName(second, "/" + charSecond); - } else if (next == OP_CALLOTHERSUBR) { - /* Search for a specific operator chain which results in a referenced - * subroutine being returned from a postscript method. If it's found then - * return null so the subset process can be restarted and all subroutines - * can be included. */ - int[] pattern = {12, 17, 10}; - int count = 0; - boolean matchesPattern = true; - if (data.length > i + 4) { - for (int pos = i + 1; pos < i + 4; pos++) { - if (data[pos] != pattern[count++]) { - matchesPattern = false; - } - } - } - if (matchesPattern) { - return new byte[0]; - } - data = addSubroutine(subroutines, operands, decoded, subsetEncodingEntries, - data, i, 2, -1, operands.get(0).getNumber()); - } - } - if (data.length == 0) { - return new byte[0]; - } - i -= dataLength - data.length; - operands.clear(); - } else if (cur <= 246) { - operands.add(new BytesNumber(cur - 139, 1)); - } else if (cur <= 250) { - operands.add(new BytesNumber((cur - 247) * 256 + (data[i + 1] & 0xFF) + 108, 2)); - i++; - } else if (cur <= 254) { - operands.add(new BytesNumber(-(cur - 251) * 256 - (data[i + 1] & 0xFF) - 108, 2)); - i++; - } else if (cur == 255) { - int b1 = data[i + 1] & 0xFF; - int b2 = data[i + 2] & 0xFF; - int b3 = data[i + 3] & 0xFF; - int b4 = data[i + 4] & 0xFF; - int value = b1 << 24 | b2 << 16 | b3 << 8 | b4; - operands.add(new BytesNumber(value, 5)); - i += 4; - } - } - return data; - } - - private int getSubrIndex(int subID) { - int count = 0; - for (Integer key : uniqueSubs.keySet()) { - if (key == subID) { - return count; - } - count++; - } - return -1; - } - - private byte[] addSubroutine(PSFixedArray subroutines, List<BytesNumber> operands, byte[] decoded, - List<String> subsetEncodingEntries, byte[] data, int i, int opLength, - int existingSubrRef, int subrID) { - if (existingSubrRef == -1) { - int[] subrData = subroutines.getBinaryEntryByIndex(subrID); - byte[] subroutine = getBinaryEntry(subrData, decoded); - subroutine = BinaryCoder.decodeBytes(subroutine, 4330, 4); - subroutine = createSubsetCharStrings(decoded, subroutine, subroutines, - subsetEncodingEntries); - if (subroutine.length == 0) { - return new byte[0]; - } - //Encode data - subroutine = BinaryCoder.encodeBytes(subroutine, 4330, 4); - uniqueSubs.put(subrID, subroutine); - } - int subRef = (existingSubrRef != -1) ? existingSubrRef : uniqueSubs.size() - 1; - data = constructNewRefData(i, data, operands, 1, subRef, opLength); - return data; - } - - protected ByteArrayOutputStream writeMainSection(byte[] decoded, List<PSElement> mainSection, - PSElement charStrings) throws IOException { - ByteArrayOutputStream main = new ByteArrayOutputStream(); - PSElement subrs = getElement("/Subrs", mainSection); - - //Find the ID of the three most commonly subroutines defined in Type 1 fonts - String rd = findVariable(decoded, mainSection, new String[] - {"string currentfile exch readstring pop"}, "RD"); - String nd = findVariable(decoded, mainSection, new String[] - {"def", "noaccess def"}, "noaccess def"); - String np = findVariable(decoded, mainSection, new String[] - {"put", "noaccess put"}, "noaccess put"); - - main.write(decoded, 0, subrs.getStartPoint()); - //Write either the subset or full list of subroutines - if (subsetSubroutines) { - writeString(eol + String.format("/Subrs %d array", uniqueSubs.size()), main); - int count = 0; - for (Entry<Integer, byte[]> entry : uniqueSubs.entrySet()) { - writeString(eol + String.format("dup %d %d %s ", count++, entry.getValue().length, rd), main); - main.write(entry.getValue()); - writeString(" " + np, main); - } - writeString(eol + nd, main); - } else { - int fullSubrsLength = subrs.getEndPoint() - subrs.getStartPoint(); - main.write(decoded, subrs.getStartPoint(), fullSubrsLength); - } - main.write(decoded, subrs.getEndPoint(), charStrings.getStartPoint() - subrs.getEndPoint()); - //Write the subset charString array - writeString(eol + String.format("/CharStrings %d dict dup begin", - subsetCharStrings.size()), main); - for (Entry<String, byte[]> entry : subsetCharStrings.entrySet()) { - writeString(eol + String.format("%s %d %s ", entry.getKey(), - entry.getValue().length, rd), - main); - main.write(entry.getValue()); - writeString(" " + nd, main); - } - writeString(eol + "end", main); - main.write(decoded, charStrings.getEndPoint(), decoded.length - charStrings.getEndPoint()); - - return main; - } - - protected String findVariable(byte[] decoded, List<PSElement> elements, String[] matches, - String fallback) throws UnsupportedEncodingException { - for (PSElement element : elements) { - if (element instanceof PSSubroutine) { - byte[] var = new byte[element.getEndPoint() - element.getStartPoint()]; - System.arraycopy(decoded, element.getStartPoint(), var, 0, element.getEndPoint() - - element.getStartPoint()); - String found = readVariableContents(new String(var, "ASCII")).trim(); - for (String match : matches) { - if (match.equals(found)) { - return element.getOperator().substring(1, element.getOperator().length()); - } - } - } - } - return fallback; - } - - String readVariableContents(String variable) { - int level = 0; - String result = ""; - int start = 0; - int end = 0; - boolean reading = false; - List<Integer> results = new ArrayList<Integer>(); - for (int i = 0; i < variable.length(); i++) { - char curChar = variable.charAt(i); - boolean sectionEnd = false; - if (curChar == '{') { - level++; - sectionEnd = true; - } else if (curChar == '}') { - level--; - sectionEnd = true; - } else if (level == 1) { - if (!reading) { - reading = true; - start = i; - } - end = i; - } - if (sectionEnd && reading) { - results.add(start); - results.add(end); - reading = false; - } - } - for (int i = 0; i < results.size(); i += 2) { - result = result.concat(variable.substring(results.get(i), results.get(i + 1) + 1)); - } - return result; - } - - private void addToCharNames(String encodingEntry) { - int spaceCount = 0; - int lastSpaceIndex = 0; - int charIndex = 0; - String charName = ""; - //Extract the character name from an encoding entry - for (int i = 0; i < encodingEntry.length(); i++) { - boolean isSpace = encodingEntry.charAt(i) == ' '; - if (isSpace) { - spaceCount++; - switch (spaceCount - 1) { - case 1: charIndex = Integer.parseInt(encodingEntry.substring(lastSpaceIndex + 1, - i)); break; - case 2: charName = encodingEntry.substring(lastSpaceIndex + 1, i); break; - default: break; - } - } - if (isSpace) { - lastSpaceIndex = i; - } - } - sbfont.mapUsedGlyphName(charIndex, charName); - } - - protected void writeString(String entry, ByteArrayOutputStream boas) - throws IOException { - byte[] byteEntry = entry.getBytes("ASCII"); - boas.write(byteEntry); - } - - /** - * A class used to store the last number operand and also it's size in bytes - */ - public static final class BytesNumber { - private int number; - private int numBytes; - private String name; - - public BytesNumber(int number, int numBytes) { - this.number = number; - this.numBytes = numBytes; - } - - public int getNumber() { - return this.number; - } - - public int getNumBytes() { - return this.numBytes; - } - - public void setName(String name) { - this.name = name; - } - - public String getName() { - return this.name; - } - } - - private byte[] constructNewRefData(int curDataPos, byte[] currentData, - List<BytesNumber> operands, int opNum, int curSubsetIndexSize, int operatorLength) { - //Create the new array with the modified reference - byte[] newData; - int operandsLenth = getOperandsLength(operands); - int startRef = curDataPos - operandsLenth + getOpPosition(opNum, operands) - + (1 - operatorLength); - byte[] preBytes = new byte[startRef]; - System.arraycopy(currentData, 0, preBytes, 0, startRef); - byte[] newRefBytes = createNewRef(curSubsetIndexSize, -1); - newData = concatArray(preBytes, newRefBytes); - byte[] postBytes = new byte[currentData.length - (startRef - + operands.get(opNum - 1).getNumBytes())]; - System.arraycopy(currentData, startRef + operands.get(opNum - 1).getNumBytes(), postBytes, 0, - currentData.length - (startRef + operands.get(opNum - 1).getNumBytes())); - return concatArray(newData, postBytes); - } - - int getOpPosition(int opNum, List<BytesNumber> operands) { - int byteCount = 0; - for (int i = 0; i < opNum - 1; i++) { - byteCount += operands.get(i).getNumBytes(); - } - return byteCount; - } - - int getOperandsLength(List<BytesNumber> operands) { - int length = 0; - for (BytesNumber number : operands) { - length += number.getNumBytes(); - } - return length; - } - - private byte[] createNewRef(int newRef, int forceLength) { - byte[] newRefBytes; - if ((forceLength == -1 && newRef <= 107) || forceLength == 1) { - newRefBytes = new byte[1]; - newRefBytes[0] = (byte)(newRef + 139); - } else if ((forceLength == -1 && newRef <= 1131) || forceLength == 2) { - newRefBytes = new byte[2]; - if (newRef <= 363) { - newRefBytes[0] = (byte)247; - } else if (newRef <= 619) { - newRefBytes[0] = (byte)248; - } else if (newRef <= 875) { - newRefBytes[0] = (byte)249; - } else { - newRefBytes[0] = (byte)250; - } - newRefBytes[1] = (byte)(newRef - 108); - } else { - newRefBytes = new byte[5]; - newRefBytes[0] = (byte)255; - newRefBytes[1] = (byte)(newRef >> 24); - newRefBytes[2] = (byte)(newRef >> 16); - newRefBytes[3] = (byte)(newRef >> 8); - newRefBytes[4] = (byte)newRef; - } - return newRefBytes; - } - - /** - * Concatenate two byte arrays together - * @param a The first array - * @param b The second array - * @return The concatenated array - */ - byte[] concatArray(byte[] a, byte[] b) { - int aLen = a.length; - int bLen = b.length; - byte[] c = new byte[aLen + bLen]; - System.arraycopy(a, 0, c, 0, aLen); - System.arraycopy(b, 0, c, aLen, bLen); - return c; - } - - /** - * Returns a section of a byte array determined by it's start and - * end position. - * @param position An array containing both the start and end position - * of the section to copy. - * @param decoded The array from which to copy a section of data - * @return Returns the copy of the data section - */ - protected byte[] getBinaryEntry(int[] position, byte[] decoded) { - int start = position[0]; - int finish = position[1]; - byte[] line = new byte[finish - start]; - System.arraycopy(decoded, start, line, 0, finish - start); - return line; - } - - protected String getEntryPart(String entry, int part) { - Scanner s = new Scanner(entry).useDelimiter(" "); - for (int i = 1; i < part; i++) { - s.next(); - } - return s.next(); - } - - protected PSElement getElement(String elementID, List<PSElement> elements) { - for (PSElement element : elements) { - if (element.getOperator().equals(elementID)) { - return element; - } - } - return null; - } - - /** - * A class to encode and decode sections of a type 1 font file. See Adobe - * Type 1 Font Format Section 7.2 for more details. - */ - public static class BinaryCoder { - public static byte[] decodeBytes(byte[] in, int inR, int n) { - byte[] out = new byte[in.length - n]; - int r = inR; - int c1 = 52845; - int c2 = 22719; - for (int i = 0; i < in.length; i++) { - int cypher = in[i] & 0xFF; - int plain = cypher ^ (r >> 8); - if (i >= n) { - out[i - n] = (byte)plain; - } - r = (cypher + r) * c1 + c2 & 0xFFFF; - } - return out; - } - - public static byte[] encodeBytes(byte[] in, int inR, int n) { - byte[] buffer = new byte[in.length + n]; - for (int i = 0; i < n; i++) { - buffer[i] = 0; - } - int r = inR; - int c1 = 52845; - int c2 = 22719; - System.arraycopy(in, 0, buffer, n, buffer.length - n); - byte[] out = new byte[buffer.length]; - for (int i = 0; i < buffer.length; i++) { - int plain = buffer[i] & 0xff; - int cipher = plain ^ r >> 8; - out[i] = (byte) cipher; - r = (cipher + r) * c1 + c2 & 0xffff; - } - return out; - } - } -} diff --git a/src/java/org/apache/fop/fonts/type1/package.html b/src/java/org/apache/fop/fonts/type1/package.html deleted file mode 100644 index 0c492fc4d..000000000 --- a/src/java/org/apache/fop/fonts/type1/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<HTML> -<TITLE>org.apache.fop.fonts.type1 Package</TITLE> -<BODY> -<P>Classes for Adobe Type 1 fonts.</P> -</BODY> -</HTML>
\ No newline at end of file |