]>
Commit | Line | Data |
---|---|---|
b75a7d8f | 1 | /* |
b75a7d8f | 2 | * |
57a6839d | 3 | * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved |
b75a7d8f A |
4 | * |
5 | */ | |
6 | ||
7 | #include "LETypes.h" | |
8 | #include "LEFontInstance.h" | |
9 | #include "OpenTypeTables.h" | |
10 | #include "GlyphPositioningTables.h" | |
11 | #include "PairPositioningSubtables.h" | |
12 | #include "ValueRecords.h" | |
13 | #include "GlyphIterator.h" | |
b75a7d8f A |
14 | #include "OpenTypeUtilities.h" |
15 | #include "LESwaps.h" | |
16 | ||
17 | U_NAMESPACE_BEGIN | |
18 | ||
57a6839d | 19 | le_uint32 PairPositioningSubtable::process(const LEReferenceTo<PairPositioningSubtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const |
b75a7d8f A |
20 | { |
21 | switch(SWAPW(subtableFormat)) | |
22 | { | |
23 | case 0: | |
24 | return 0; | |
25 | ||
26 | case 1: | |
27 | { | |
57a6839d | 28 | const LEReferenceTo<PairPositioningFormat1Subtable> subtable(base, success, (const PairPositioningFormat1Subtable *) this); |
b75a7d8f | 29 | |
57a6839d A |
30 | if(LE_SUCCESS(success)) |
31 | return subtable->process(subtable, glyphIterator, fontInstance, success); | |
32 | else | |
33 | return 0; | |
b75a7d8f A |
34 | } |
35 | ||
36 | case 2: | |
37 | { | |
57a6839d | 38 | const LEReferenceTo<PairPositioningFormat2Subtable> subtable(base, success, (const PairPositioningFormat2Subtable *) this); |
b75a7d8f | 39 | |
57a6839d A |
40 | if(LE_SUCCESS(success)) |
41 | return subtable->process(subtable, glyphIterator, fontInstance, success); | |
42 | else | |
43 | return 0; | |
b75a7d8f | 44 | } |
b75a7d8f | 45 | default: |
57a6839d | 46 | return 0; |
b75a7d8f A |
47 | } |
48 | } | |
49 | ||
57a6839d | 50 | le_uint32 PairPositioningFormat1Subtable::process(const LEReferenceTo<PairPositioningFormat1Subtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const |
b75a7d8f A |
51 | { |
52 | LEGlyphID firstGlyph = glyphIterator->getCurrGlyphID(); | |
57a6839d | 53 | le_int32 coverageIndex = getGlyphCoverage(base, firstGlyph, success); |
b75a7d8f A |
54 | GlyphIterator tempIterator(*glyphIterator); |
55 | ||
56 | if (coverageIndex >= 0 && glyphIterator->next()) { | |
57 | Offset pairSetTableOffset = SWAPW(pairSetTableOffsetArray[coverageIndex]); | |
58 | PairSetTable *pairSetTable = (PairSetTable *) ((char *) this + pairSetTableOffset); | |
374ca955 | 59 | le_uint16 pairValueCount = SWAPW(pairSetTable->pairValueCount); |
b75a7d8f A |
60 | le_int16 valueRecord1Size = ValueRecord::getSize(SWAPW(valueFormat1)); |
61 | le_int16 valueRecord2Size = ValueRecord::getSize(SWAPW(valueFormat2)); | |
62 | le_int16 recordSize = sizeof(PairValueRecord) - sizeof(ValueRecord) + valueRecord1Size + valueRecord2Size; | |
63 | LEGlyphID secondGlyph = glyphIterator->getCurrGlyphID(); | |
374ca955 A |
64 | const PairValueRecord *pairValueRecord = NULL; |
65 | ||
66 | if (pairValueCount != 0) { | |
67 | pairValueRecord = findPairValueRecord((TTGlyphID) LE_GET_GLYPH(secondGlyph), pairSetTable->pairValueRecordArray, pairValueCount, recordSize); | |
68 | } | |
b75a7d8f A |
69 | |
70 | if (pairValueRecord == NULL) { | |
71 | return 0; | |
72 | } | |
73 | ||
74 | if (valueFormat1 != 0) { | |
73c04bcf | 75 | pairValueRecord->valueRecord1.adjustPosition(SWAPW(valueFormat1), (char *) this, tempIterator, fontInstance); |
b75a7d8f A |
76 | } |
77 | ||
78 | if (valueFormat2 != 0) { | |
79 | const ValueRecord *valueRecord2 = (const ValueRecord *) ((char *) &pairValueRecord->valueRecord1 + valueRecord1Size); | |
b75a7d8f | 80 | |
73c04bcf | 81 | valueRecord2->adjustPosition(SWAPW(valueFormat2), (char *) this, *glyphIterator, fontInstance); |
b75a7d8f A |
82 | } |
83 | ||
46f4442e A |
84 | // back up glyphIterator so second glyph can be |
85 | // first glyph in the next pair | |
86 | glyphIterator->prev(); | |
87 | return 1; | |
b75a7d8f A |
88 | } |
89 | ||
90 | return 0; | |
91 | } | |
92 | ||
57a6839d | 93 | le_uint32 PairPositioningFormat2Subtable::process(const LEReferenceTo<PairPositioningFormat2Subtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const |
b75a7d8f A |
94 | { |
95 | LEGlyphID firstGlyph = glyphIterator->getCurrGlyphID(); | |
57a6839d | 96 | le_int32 coverageIndex = getGlyphCoverage(base, firstGlyph, success); |
b75a7d8f A |
97 | GlyphIterator tempIterator(*glyphIterator); |
98 | ||
99 | if (coverageIndex >= 0 && glyphIterator->next()) { | |
100 | LEGlyphID secondGlyph = glyphIterator->getCurrGlyphID(); | |
101 | const ClassDefinitionTable *classDef1 = (const ClassDefinitionTable *) ((char *) this + SWAPW(classDef1Offset)); | |
102 | const ClassDefinitionTable *classDef2 = (const ClassDefinitionTable *) ((char *) this + SWAPW(classDef2Offset)); | |
103 | le_int32 class1 = classDef1->getGlyphClass(firstGlyph); | |
104 | le_int32 class2 = classDef2->getGlyphClass(secondGlyph); | |
105 | le_int16 valueRecord1Size = ValueRecord::getSize(SWAPW(valueFormat1)); | |
106 | le_int16 valueRecord2Size = ValueRecord::getSize(SWAPW(valueFormat2)); | |
107 | le_int16 class2RecordSize = valueRecord1Size + valueRecord2Size; | |
108 | le_int16 class1RecordSize = class2RecordSize * SWAPW(class2Count); | |
109 | const Class1Record *class1Record = (const Class1Record *) ((char *) class1RecordArray + (class1RecordSize * class1)); | |
110 | const Class2Record *class2Record = (const Class2Record *) ((char *) class1Record->class2RecordArray + (class2RecordSize * class2)); | |
111 | ||
112 | ||
113 | if (valueFormat1 != 0) { | |
73c04bcf | 114 | class2Record->valueRecord1.adjustPosition(SWAPW(valueFormat1), (char *) this, tempIterator, fontInstance); |
b75a7d8f A |
115 | } |
116 | ||
117 | if (valueFormat2 != 0) { | |
118 | const ValueRecord *valueRecord2 = (const ValueRecord *) ((char *) &class2Record->valueRecord1 + valueRecord1Size); | |
b75a7d8f | 119 | |
73c04bcf | 120 | valueRecord2->adjustPosition(SWAPW(valueFormat2), (const char *) this, *glyphIterator, fontInstance); |
b75a7d8f A |
121 | } |
122 | ||
46f4442e A |
123 | // back up glyphIterator so second glyph can be |
124 | // first glyph in the next pair | |
125 | glyphIterator->prev(); | |
126 | return 1; | |
b75a7d8f A |
127 | } |
128 | ||
129 | return 0; | |
130 | } | |
131 | ||
132 | const PairValueRecord *PairPositioningFormat1Subtable::findPairValueRecord(TTGlyphID glyphID, const PairValueRecord *records, le_uint16 recordCount, le_uint16 recordSize) const | |
133 | { | |
46f4442e A |
134 | #if 1 |
135 | // The OpenType spec. says that the ValueRecord table is | |
136 | // sorted by secondGlyph. Unfortunately, there are fonts | |
137 | // around that have an unsorted ValueRecord table. | |
138 | const PairValueRecord *record = records; | |
139 | ||
140 | for(le_int32 r = 0; r < recordCount; r += 1) { | |
141 | if (SWAPW(record->secondGlyph) == glyphID) { | |
142 | return record; | |
143 | } | |
144 | ||
145 | record = (const PairValueRecord *) ((char *) record + recordSize); | |
146 | } | |
147 | #else | |
b75a7d8f A |
148 | le_uint8 bit = OpenTypeUtilities::highBit(recordCount); |
149 | le_uint16 power = 1 << bit; | |
150 | le_uint16 extra = (recordCount - power) * recordSize; | |
151 | le_uint16 probe = power * recordSize; | |
152 | const PairValueRecord *record = records; | |
153 | const PairValueRecord *trial = (const PairValueRecord *) ((char *) record + extra); | |
154 | ||
155 | if (SWAPW(trial->secondGlyph) <= glyphID) { | |
156 | record = trial; | |
157 | } | |
158 | ||
159 | while (probe > recordSize) { | |
160 | probe >>= 1; | |
161 | trial = (const PairValueRecord *) ((char *) record + probe); | |
162 | ||
163 | if (SWAPW(trial->secondGlyph) <= glyphID) { | |
164 | record = trial; | |
165 | } | |
166 | } | |
167 | ||
168 | if (SWAPW(record->secondGlyph) == glyphID) { | |
169 | return record; | |
170 | } | |
46f4442e | 171 | #endif |
b75a7d8f A |
172 | |
173 | return NULL; | |
174 | } | |
175 | ||
176 | U_NAMESPACE_END |