/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.awt.font.truetype.tables;
import java.io.IOException;
import org.jnode.awt.font.truetype.TTFFontData;
import org.jnode.awt.font.truetype.TTFInput;
/**
* CMAP Table.
*
* @author Simon Fischer
* @version $Id$
*/
public final class CMapTable extends TTFTable {
private int version;
private EncodingTable encodingTable[];
/**
* @param font
* @param input
*/
CMapTable(TTFFontData font, TTFInput input) {
super(font, input);
}
public int getNrEncodingTables() {
return encodingTable.length;
}
public EncodingTable getEncodingTable(int index) {
return encodingTable[index];
}
public class EncodingTable {
private int platformID;
private int encodingID;
private long offset;
private int format;
private int length;
private int encTblVersion;
private TableFormat tableFormat;
public void readHeader(TTFInput ttf) throws IOException {
platformID = ttf.readUShort();
encodingID = ttf.readUShort();
offset = ttf.readULong();
}
public void readBody(TTFInput ttf) throws IOException {
ttf.seek(offset);
format = ttf.readUShort();
length = ttf.readUShort();
encTblVersion = ttf.readUShort();
switch (format) {
case 0:
tableFormat = new TableFormat0();
break;
case 4:
tableFormat = new TableFormat4();
break;
case 6:
tableFormat = new TableFormat6();
break;
case 2:
break;
default:
System.err.println("Illegal value for encoding table format: " + format);
break;
}
if (tableFormat != null) {
tableFormat.read(ttf);
}
}
public String toString() {
String str =
"[encoding] PID:" + platformID + " EID:" + encodingID + " format:" + format + " v" + encTblVersion +
(tableFormat != null ? tableFormat.toString() : " [no data read]");
return str;
}
/**
* @return The length of the table
*/
public int getLength() {
return this.length;
}
/**
* @return The table format
*/
public TableFormat getTableFormat() {
return this.tableFormat;
}
}
public abstract class TableFormat {
public abstract void read(TTFInput ttf) throws IOException;
public abstract int getGlyphIndex(int character);
}
public class TableFormat0 extends TableFormat {
public int[] glyphIdArray = new int[256];
public void read(TTFInput ttf) throws IOException {
for (int i = 0; i < glyphIdArray.length; i++)
glyphIdArray[i] = ttf.readByte();
}
public String toString() {
String str = "";
for (int i = 0; i < glyphIdArray.length; i++) {
if (i % 16 == 0)
str += "\n " + Integer.toHexString(i / 16) + "x: ";
String number = glyphIdArray[i] + "";
while (number.length() < 3)
number = " " + number;
str += number + " ";
}
return str;
}
public int getGlyphIndex(int character) {
return glyphIdArray[character];
}
}
public class TableFormat4 extends TableFormat {
public int segCount;
public int[] endCount, startCount, idRangeOffset;
public short[] idDelta; // could be int (ushort) as well
public void read(TTFInput ttf) throws IOException {
segCount = ttf.readUShort() / 2;
// dump the next three ushorts to /dev/null as they guy
// who invented them really must have drunk a lot
ttf.readUShort();
ttf.readUShort();
ttf.readUShort();
//endCount = readFFFFTerminatedUShortArray();
endCount = ttf.readUShortArray(segCount);
int reservedPad = ttf.readUShort();
if (reservedPad != 0)
System.err.println("reservedPad not 0, but " + reservedPad + ".");
startCount = ttf.readUShortArray(endCount.length);
// the deltas should be unsigned, but due to
// modulo arithmetic it makes no difference
idDelta = ttf.readShortArray(endCount.length);
idRangeOffset = ttf.readUShortArray(endCount.length);
}
public String toString() {
String str = "\n " + endCount.length + " sections:";
for (int i = 0; i < endCount.length; i++)
str += "\n " + startCount[i] + " to " + endCount[i] + " : " + idDelta[i] + " (" + idRangeOffset[i] +
")";
return str;
}
public int getGlyphIndex(int character) {
return 0;
}
}
public String getTag() {
return "cmap";
}
protected final void readTable(TTFInput ttf) throws IOException {
version = ttf.readUShort();
encodingTable = new EncodingTable[ttf.readUShort()];
for (int i = 0; i < encodingTable.length; i++) {
encodingTable[i] = new EncodingTable();
encodingTable[i].readHeader(ttf);
}
for (int i = 0; i < encodingTable.length; i++) {
encodingTable[i].readBody(ttf);
}
}
public class TableFormat6 extends TableFormat {
public int firstCode = 0, entryCount = 0;
public int[] glyphIdArray;
public void read(TTFInput ttf) throws IOException {
// read first character code of subrange
firstCode = ttf.readUShort();
//read entryCount Number of character codes in subrange.
entryCount = ttf.readUShort();
glyphIdArray = new int[entryCount];
for (int i = 0; i < entryCount; i++)
glyphIdArray[i] = ttf.readUShort();
}
public String toString() {
String str = "";
for (int i = 0; i < glyphIdArray.length; i++) {
if (i % 16 == 0)
str += "\n " + Integer.toHexString(i / 16) + "x: ";
String number = glyphIdArray[i] + "";
while (number.length() < 3)
number = " " + number;
str += number + " ";
}
return str;
}
public int getGlyphIndex(int character) {
if (character < this.firstCode || character > this.firstCode + this.entryCount)
return glyphIdArray[0];
else
return glyphIdArray[character - this.firstCode];
}
}
public String toString() {
String str = super.toString() + " v" + version;
for (int i = 0; i < encodingTable.length; i++)
str += "\n " + encodingTable[i];
return str;
}
}