aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/fonts/AbstractCodePointMapping.java
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2008-02-16 12:28:48 +0000
committerJeremias Maerki <jeremias@apache.org>2008-02-16 12:28:48 +0000
commit57de10b2fdd6e6f0bbca3aac03bce84d82cfaba3 (patch)
treedb31b6f70693085e182139ccb82345e556fee49b /src/java/org/apache/fop/fonts/AbstractCodePointMapping.java
parent70d511b80f4099730738077cf15dc39a062df89a (diff)
downloadxmlgraphics-fop-57de10b2fdd6e6f0bbca3aac03bce84d82cfaba3.tar.gz
xmlgraphics-fop-57de10b2fdd6e6f0bbca3aac03bce84d82cfaba3.zip
Extracted most of the code in CodePointMapping (generated by XSLT) into a base class for easier maintenance and proper Javadocs.
Deprecated FOP's copy of Glyphs.java. Took a different approach at handling mapping alternatives for single-byte fonts. The AFM now only lists the main character. Substitution is done through Glyphs.java later in CodePointMapping. Fixed a problem in Type1FontLoader where the PFM overrides asc/desc/cap/x even though the AFM provides the values. It showed itself because the URW Symbol font has wrong values in the PFM. Added a note to myself in Type1FontLoader to implement the "Flags" value. The whole thing still seems to work without that part. Added a glyph name list to the CodePointMapping so we can work with the original list from the AFM. Otherwise, various mapping operations to and from resulted in unwanted mappings (because the mappings are not necessarily 1:1) and in the end the PDF received an incorrect Encoding map. Now there's no such problem anymore. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@628280 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop/fonts/AbstractCodePointMapping.java')
-rw-r--r--src/java/org/apache/fop/fonts/AbstractCodePointMapping.java261
1 files changed, 261 insertions, 0 deletions
diff --git a/src/java/org/apache/fop/fonts/AbstractCodePointMapping.java b/src/java/org/apache/fop/fonts/AbstractCodePointMapping.java
new file mode 100644
index 000000000..91d13da85
--- /dev/null
+++ b/src/java/org/apache/fop/fonts/AbstractCodePointMapping.java
@@ -0,0 +1,261 @@
+/*
+ * 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 java.util.Map;
+
+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 {
+
+ private 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
+ private Map fallbackMap; //Here we accumulate all mappings we have found through substitution
+
+ /**
+ * 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;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the encoding's name.
+ * @return the name of the encoding
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Maps a Unicode character to a code point in the encoding.
+ * @param c the Unicode character to map
+ * @return the coid point in the encoding or 0 (=.notdef) if not found
+ */
+ public final char mapChar(char c) {
+ if (c < 256) {
+ char latin1 = latin1Map[c];
+ if (latin1 > 0) {
+ return latin1;
+ }
+ }
+ int bot = 0, top = characters.length - 1;
+ while (top >= bot) {
+ int mid = (bot + top) / 2;
+ char mc = characters[mid];
+
+ if (c == mc) {
+ return codepoints[mid];
+ } else if (c < mc) {
+ top = mid - 1;
+ } else {
+ bot = mid + 1;
+ }
+ }
+
+ //Fallback: using cache
+ synchronized (this) {
+ if (fallbackMap != null) {
+ Character fallback = (Character)fallbackMap.get(new Character(c));
+ if (fallback != null) {
+ return fallback.charValue();
+ }
+ }
+ }
+ //Fallback: find alternatives (slow!)
+ String glyphName = Glyphs.charToGlyphName(c);
+ if (glyphName.length() > 0) {
+ String[] alternatives = Glyphs.getCharNameAlternativesFor(glyphName);
+ if (alternatives != null) {
+ for (int i = 0, ic = alternatives.length; i < ic; i++) {
+ int idx = getCodePointForGlyph(alternatives[i]);
+ if (idx >= 0) {
+ putFallbackCharacter(c, (char)idx);
+ return (char)idx;
+ }
+ }
+ }
+ }
+
+ putFallbackCharacter(c, '\0');
+ return 0;
+ }
+
+ private void putFallbackCharacter(char c, char mapTo) {
+ synchronized (this) {
+ if (this.fallbackMap == null) {
+ this.fallbackMap = new java.util.HashMap();
+ }
+ this.fallbackMap.put(new Character(c), new Character(mapTo));
+ }
+ }
+
+ /**
+ * 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];
+ }
+
+ /**
+ * 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
+ */
+ 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;
+ }
+
+ /**
+ * Returns the array of character names for this encoding.
+ * @return the array of character names
+ * (unmapped code points are represented by a ".notdef" value)
+ */
+ 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} */
+ public String toString() {
+ return getName();
+ }
+}