001: /*
002: *******************************************************************************
003: * Copyright (C) 1998-2005, International Business Machines Corporation and *
004: * others. All Rights Reserved. *
005: *******************************************************************************
006: *
007: * Created on Dec 3, 2003
008: *
009: *******************************************************************************
010: */
011: package com.ibm.icu.dev.tool.layout;
012:
013: import java.util.*;
014:
015: import com.ibm.icu.impl.Utility;
016:
017: public class ClassTable implements LookupSubtable {
018: static class ClassEntry {
019: private int glyphID;
020: private int classID;
021:
022: public ClassEntry(int glyphID, int classID) {
023: this .glyphID = glyphID;
024: this .classID = classID;
025: }
026:
027: public int getGlyphID() {
028: return glyphID;
029: }
030:
031: public int getClassID() {
032: return classID;
033: }
034:
035: public int compareTo(ClassEntry that) {
036: return this .glyphID - that.glyphID;
037: }
038:
039: //
040: // Straight insertion sort from Knuth vol. III, pg. 81
041: //
042: public static void sort(ClassEntry[] table, Vector unsorted) {
043: for (int e = 0; e < table.length; e += 1) {
044: int i;
045: ClassEntry v = (ClassEntry) unsorted.elementAt(e);
046:
047: for (i = e - 1; i >= 0; i -= 1) {
048: if (v.compareTo(table[i]) >= 0) {
049: break;
050: }
051:
052: table[i + 1] = table[i];
053: }
054:
055: table[i + 1] = v;
056: }
057: }
058:
059: public static int search(ClassEntry[] table, int glyphID) {
060: int log2 = Utility.highBit(table.length);
061: int power = 1 << log2;
062: int extra = table.length - power;
063: int probe = power;
064: int index = 0;
065:
066: if (table[extra].glyphID <= glyphID) {
067: index = extra;
068: }
069:
070: while (probe > (1 << 0)) {
071: probe >>= 1;
072:
073: if (table[index + probe].glyphID <= glyphID) {
074: index += probe;
075: }
076: }
077:
078: if (table[index].glyphID == glyphID) {
079: return index;
080: }
081:
082: return -1;
083: }
084: }
085:
086: static class ClassRangeRecord {
087: private int startGlyphID;
088: private int endGlyphID;
089: private int classID;
090:
091: public ClassRangeRecord(int startGlyphID, int endGlyphID,
092: int classID) {
093: this .startGlyphID = startGlyphID;
094: this .endGlyphID = endGlyphID;
095: this .classID = classID;
096: }
097:
098: public void write(OpenTypeTableWriter writer) {
099: System.out.print(Utility.hex(startGlyphID, 6));
100: System.out.print(" - ");
101: System.out.print(Utility.hex(endGlyphID, 6));
102: System.out.print(": ");
103: System.out.println(classID);
104:
105: writer.writeData(startGlyphID);
106: writer.writeData(endGlyphID);
107: writer.writeData(classID);
108: }
109: }
110:
111: private Vector classMap;
112: private ClassEntry[] classTable;
113: private int snapshotSize;
114:
115: public ClassTable() {
116: this .classMap = new Vector();
117: this .classTable = null;
118: this .snapshotSize = -1;
119:
120: }
121:
122: public void addMapping(int charID, int classID) {
123: ClassEntry entry = new ClassEntry(charID, classID);
124:
125: classMap.addElement(entry);
126: }
127:
128: public void addMapping(int startCharID, int endCharID, int classID) {
129: for (int charID = startCharID; charID <= endCharID; charID += 1) {
130: addMapping(charID, classID);
131: }
132: }
133:
134: public int getGlyphClassID(int glyphID) {
135: int index = ClassEntry.search(classTable, glyphID);
136:
137: if (index >= 0) {
138: return classTable[index].getClassID();
139: }
140:
141: return 0;
142: }
143:
144: public void snapshot() {
145: if (snapshotSize != classMap.size()) {
146: snapshotSize = classMap.size();
147: classTable = new ClassEntry[snapshotSize];
148:
149: ClassEntry.sort(classTable, classMap);
150: }
151: }
152:
153: public void writeClassTable(OpenTypeTableWriter writer) {
154: snapshot();
155:
156: Vector classRanges = new Vector();
157: int startIndex = 0;
158:
159: while (startIndex < classTable.length) {
160: int startID = classTable[startIndex].getGlyphID();
161: int classID = classTable[startIndex].getClassID();
162: int nextID = startID;
163: int endID = startID;
164: int endIndex;
165:
166: for (endIndex = startIndex; endIndex < classTable.length; endIndex += 1) {
167: if (classTable[endIndex].getGlyphID() != nextID
168: || classTable[endIndex].getClassID() != classID) {
169: break;
170: }
171:
172: endID = nextID;
173: nextID += 1;
174: }
175:
176: if (classID != 0) {
177: ClassRangeRecord range = new ClassRangeRecord(startID,
178: endID, classID);
179:
180: classRanges.addElement(range);
181: }
182:
183: startIndex = endIndex;
184: }
185:
186: writer.writeData(2); // table format = 2 (class ranges)
187: writer.writeData(classRanges.size()); // class range count
188:
189: for (int i = 0; i < classRanges.size(); i += 1) {
190: ClassRangeRecord range = (ClassRangeRecord) classRanges
191: .elementAt(i);
192:
193: range.write(writer);
194: }
195: }
196:
197: public void writeLookupSubtable(OpenTypeTableWriter writer) {
198: int singleSubstitutionsBase = writer.getOutputIndex();
199: int coverageTableIndex;
200:
201: snapshot();
202:
203: writer.writeData(2); // format 2: Specified output glyph indices
204: coverageTableIndex = writer.getOutputIndex();
205: writer.writeData(0); // offset to coverage table (fixed later)
206: writer.writeData(classTable.length); // number of glyphIDs in substitution array
207:
208: for (int i = 0; i < classTable.length; i += 1) {
209: writer.writeData(classTable[i].getClassID());
210: }
211:
212: writer.fixOffset(coverageTableIndex, singleSubstitutionsBase);
213: writer.writeData(1);
214: writer.writeData(classTable.length);
215:
216: for (int i = 0; i < classTable.length; i += 1) {
217: writer.writeData(classTable[i].getGlyphID());
218: }
219: }
220: }
|