2 *******************************************************************************
\r
3 * Copyright (C) 1998-2010, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 * Created on Dec 3, 2003
\r
9 *******************************************************************************
\r
11 package com.ibm.icu.dev.tool.layout;
\r
13 import java.util.Vector;
\r
15 import com.ibm.icu.impl.Utility;
\r
17 public class ClassTable implements LookupSubtable
\r
19 static class ClassEntry
\r
21 private int glyphID;
\r
22 private int classID;
\r
24 public ClassEntry(int glyphID, int classID)
\r
26 this.glyphID = glyphID;
\r
27 this.classID = classID;
\r
30 public int getGlyphID()
\r
35 public int getClassID()
\r
40 public int compareTo(ClassEntry that)
\r
42 return this.glyphID - that.glyphID;
\r
46 // Straight insertion sort from Knuth vol. III, pg. 81
\r
48 public static void sort(ClassEntry[] table, Vector unsorted)
\r
50 for (int e = 0; e < table.length; e += 1) {
\r
52 ClassEntry v = (ClassEntry) unsorted.elementAt(e);
\r
54 for (i = e - 1; i >= 0; i -= 1) {
\r
55 if (v.compareTo(table[i]) >= 0) {
\r
59 table[i + 1] = table[i];
\r
66 public static int search(ClassEntry[] table, int glyphID)
\r
68 int log2 = Utility.highBit(table.length);
\r
69 int power = 1 << log2;
\r
70 int extra = table.length - power;
\r
74 if (table[extra].glyphID <= glyphID) {
\r
78 while (probe > (1 << 0)) {
\r
81 if (table[index + probe].glyphID <= glyphID) {
\r
86 if (table[index].glyphID == glyphID) {
\r
94 static class ClassRangeRecord
\r
96 private int startGlyphID;
\r
97 private int endGlyphID;
\r
98 private int classID;
\r
100 public ClassRangeRecord(int startGlyphID, int endGlyphID, int classID)
\r
102 this.startGlyphID = startGlyphID;
\r
103 this.endGlyphID = endGlyphID;
\r
104 this.classID = classID;
\r
107 public void write(OpenTypeTableWriter writer)
\r
109 System.out.print(Utility.hex(startGlyphID, 6));
\r
110 System.out.print(" - ");
\r
111 System.out.print(Utility.hex(endGlyphID, 6));
\r
112 System.out.print(": ");
\r
113 System.out.println(classID);
\r
115 writer.writeData(startGlyphID);
\r
116 writer.writeData(endGlyphID);
\r
117 writer.writeData(classID);
\r
121 private Vector classMap;
\r
122 private ClassEntry[] classTable;
\r
123 private int snapshotSize;
\r
125 public ClassTable()
\r
127 this.classMap = new Vector();
\r
128 this.classTable = null;
\r
129 this.snapshotSize = -1;
\r
133 public void addMapping(int charID, int classID)
\r
135 ClassEntry entry = new ClassEntry(charID, classID);
\r
137 classMap.addElement(entry);
\r
140 public void addMapping(int startCharID, int endCharID, int classID)
\r
142 for (int charID = startCharID; charID <= endCharID; charID += 1) {
\r
143 addMapping(charID, classID);
\r
147 public int getGlyphClassID(int glyphID)
\r
149 int index = ClassEntry.search(classTable, glyphID);
\r
152 return classTable[index].getClassID();
\r
158 public void snapshot()
\r
160 if (snapshotSize != classMap.size()) {
\r
161 snapshotSize = classMap.size();
\r
162 classTable = new ClassEntry[snapshotSize];
\r
164 ClassEntry.sort(classTable, classMap);
\r
168 public void writeClassTable(OpenTypeTableWriter writer)
\r
172 Vector classRanges = new Vector();
\r
173 int startIndex = 0;
\r
175 while (startIndex < classTable.length) {
\r
176 int startID = classTable[startIndex].getGlyphID();
\r
177 int classID = classTable[startIndex].getClassID();
\r
178 int nextID = startID;
\r
179 int endID = startID;
\r
182 for (endIndex = startIndex; endIndex < classTable.length; endIndex += 1) {
\r
183 if (classTable[endIndex].getGlyphID() != nextID ||
\r
184 classTable[endIndex].getClassID() != classID) {
\r
192 if (classID != 0) {
\r
193 ClassRangeRecord range = new ClassRangeRecord(startID, endID, classID);
\r
195 classRanges.addElement(range);
\r
198 startIndex = endIndex;
\r
201 writer.writeData(2); // table format = 2 (class ranges)
\r
202 writer.writeData(classRanges.size()); // class range count
\r
204 for (int i = 0; i < classRanges.size(); i += 1) {
\r
205 ClassRangeRecord range = (ClassRangeRecord) classRanges.elementAt(i);
\r
207 range.write(writer);
\r
211 public void writeLookupSubtable(OpenTypeTableWriter writer)
\r
213 int singleSubstitutionsBase = writer.getOutputIndex();
\r
214 int coverageTableIndex;
\r
218 writer.writeData(2); // format 2: Specified output glyph indices
\r
219 coverageTableIndex = writer.getOutputIndex();
\r
220 writer.writeData(0); // offset to coverage table (fixed later)
\r
221 writer.writeData(classTable.length); // number of glyphIDs in substitution array
\r
223 for (int i = 0; i < classTable.length; i += 1) {
\r
224 writer.writeData(classTable[i].getClassID());
\r
227 writer.fixOffset(coverageTableIndex, singleSubstitutionsBase);
\r
228 writer.writeData(1);
\r
229 writer.writeData(classTable.length);
\r
231 for (int i = 0; i < classTable.length; i += 1) {
\r
232 writer.writeData(classTable[i].getGlyphID());
\r