| /* |
| * 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(); |
| } |
| } |