1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation. Oracle designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Oracle in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 /*
27 *
28 * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
29 *
30 */
31
32 #include "LETypes.h"
33 #include "LEFontInstance.h"
34 #include "OpenTypeTables.h"
35 #include "GlyphPositioningTables.h"
36 #include "PairPositioningSubtables.h"
37 #include "ValueRecords.h"
38 #include "GlyphIterator.h"
39 #include "OpenTypeUtilities.h"
40 #include "LESwaps.h"
41
42 U_NAMESPACE_BEGIN
43
process(const LEReferenceTo<PairPositioningSubtable> & base,GlyphIterator * glyphIterator,const LEFontInstance * fontInstance,LEErrorCode & success) const44 le_uint32 PairPositioningSubtable::process(const LEReferenceTo<PairPositioningSubtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const
45 {
46 if (LE_FAILURE(success)) {
47 return 0;
48 }
49
50 switch(SWAPW(subtableFormat))
51 {
52 case 0:
53 return 0;
54
55 case 1:
56 {
57 const LEReferenceTo<PairPositioningFormat1Subtable> subtable(base, success, (const PairPositioningFormat1Subtable *) this);
58
59 if(LE_SUCCESS(success))
60 return subtable->process(subtable, glyphIterator, fontInstance, success);
61 else
62 return 0;
63 }
64
65 case 2:
66 {
67 const LEReferenceTo<PairPositioningFormat2Subtable> subtable(base, success, (const PairPositioningFormat2Subtable *) this);
68
69 if(LE_SUCCESS(success))
70 return subtable->process(subtable, glyphIterator, fontInstance, success);
71 else
72 return 0;
73 }
74 default:
75 return 0;
76 }
77 }
78
process(const LEReferenceTo<PairPositioningFormat1Subtable> & base,GlyphIterator * glyphIterator,const LEFontInstance * fontInstance,LEErrorCode & success) const79 le_uint32 PairPositioningFormat1Subtable::process(const LEReferenceTo<PairPositioningFormat1Subtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const
80 {
81 if (LE_FAILURE(success)) {
82 return 0;
83 }
84
85 LEGlyphID firstGlyph = glyphIterator->getCurrGlyphID();
86 le_int32 coverageIndex = getGlyphCoverage(base, firstGlyph, success);
87 GlyphIterator tempIterator(*glyphIterator);
88
89 LEReferenceToArrayOf<Offset> pairSetTableOffsetArrayRef(base, success, pairSetTableOffsetArray, SWAPW(pairSetCount));
90
91 if (LE_SUCCESS(success) && coverageIndex >= 0 && glyphIterator->next() && (le_uint32)coverageIndex < pairSetTableOffsetArrayRef.getCount()) {
92 Offset pairSetTableOffset = SWAPW(pairSetTableOffsetArray[coverageIndex]);
93 LEReferenceTo<PairSetTable> pairSetTable(base, success, pairSetTableOffset);
94 if( LE_FAILURE(success) ) return 0;
95 le_uint16 pairValueCount = SWAPW(pairSetTable->pairValueCount);
96 LEReferenceTo<PairValueRecord> pairValueRecordArray(pairSetTable, success, pairSetTable->pairValueRecordArray);
97 if( LE_FAILURE(success) ) return 0;
98 le_int16 valueRecord1Size = ValueRecord::getSize(SWAPW(valueFormat1));
99 le_int16 valueRecord2Size = ValueRecord::getSize(SWAPW(valueFormat2));
100 le_int16 recordSize = sizeof(PairValueRecord) - sizeof(ValueRecord) + valueRecord1Size + valueRecord2Size;
101 LEGlyphID secondGlyph = glyphIterator->getCurrGlyphID();
102 LEReferenceTo<PairValueRecord> pairValueRecord;
103
104 if (pairValueCount != 0) {
105 pairValueRecord = findPairValueRecord((TTGlyphID) LE_GET_GLYPH(secondGlyph), pairValueRecordArray, pairValueCount, recordSize, success);
106 }
107
108 if (pairValueRecord.isEmpty() || LE_FAILURE(success)) {
109 return 0;
110 }
111
112 if (valueFormat1 != 0) {
113 pairValueRecord->valueRecord1.adjustPosition(SWAPW(valueFormat1), base, tempIterator, fontInstance, success);
114 }
115
116 if (valueFormat2 != 0) {
117 LEReferenceTo<ValueRecord> valueRecord2(base, success, ((char *) &pairValueRecord->valueRecord1 + valueRecord1Size));
118 if(LE_SUCCESS(success)) {
119 valueRecord2->adjustPosition(SWAPW(valueFormat2), base, *glyphIterator, fontInstance, success);
120 }
121 }
122
123 // back up glyphIterator so second glyph can be
124 // first glyph in the next pair
125 glyphIterator->prev();
126 return 1;
127 }
128
129 return 0;
130 }
131
process(const LEReferenceTo<PairPositioningFormat2Subtable> & base,GlyphIterator * glyphIterator,const LEFontInstance * fontInstance,LEErrorCode & success) const132 le_uint32 PairPositioningFormat2Subtable::process(const LEReferenceTo<PairPositioningFormat2Subtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const
133 {
134 if (LE_FAILURE(success)) {
135 return 0;
136 }
137
138 LEGlyphID firstGlyph = glyphIterator->getCurrGlyphID();
139 le_int32 coverageIndex = getGlyphCoverage(base, firstGlyph, success);
140
141 if (LE_FAILURE(success)) {
142 return 0;
143 }
144
145 GlyphIterator tempIterator(*glyphIterator);
146
147 if (coverageIndex >= 0 && glyphIterator->next()) {
148 LEGlyphID secondGlyph = glyphIterator->getCurrGlyphID();
149 const LEReferenceTo<ClassDefinitionTable> classDef1(base, success, SWAPW(classDef1Offset));
150 const LEReferenceTo<ClassDefinitionTable> classDef2(base, success, SWAPW(classDef2Offset));
151 le_int32 class1 = classDef1->getGlyphClass(classDef1, firstGlyph, success);
152 le_int32 class2 = classDef2->getGlyphClass(classDef2, secondGlyph, success);
153 le_int16 valueRecord1Size = ValueRecord::getSize(SWAPW(valueFormat1));
154 le_int16 valueRecord2Size = ValueRecord::getSize(SWAPW(valueFormat2));
155 le_int16 class2RecordSize = valueRecord1Size + valueRecord2Size;
156 le_int16 class1RecordSize = class2RecordSize * SWAPW(class2Count);
157 const LEReferenceTo<Class1Record> class1Record(base, success, (const Class1Record *) ((char *) class1RecordArray + (class1RecordSize * class1)));
158 const LEReferenceTo<Class2Record> class2Record(base, success, (const Class2Record *) ((char *) class1Record->class2RecordArray + (class2RecordSize * class2)));
159
160 if( LE_SUCCESS(success) ) {
161 if (valueFormat1 != 0) {
162 class2Record->valueRecord1.adjustPosition(SWAPW(valueFormat1), base, tempIterator, fontInstance, success);
163 }
164 if (valueFormat2 != 0) {
165 const LEReferenceTo<ValueRecord> valueRecord2(base, success, ((char *) &class2Record->valueRecord1) + valueRecord1Size);
166 LEReferenceTo<PairPositioningFormat2Subtable> thisRef(base, success, this);
167 if(LE_SUCCESS(success)) {
168 valueRecord2->adjustPosition(SWAPW(valueFormat2), thisRef, *glyphIterator, fontInstance, success);
169 }
170 }
171 }
172
173 // back up glyphIterator so second glyph can be
174 // first glyph in the next pair
175 glyphIterator->prev();
176 return 1;
177 }
178
179 return 0;
180 }
181
182 LEReferenceTo<PairValueRecord>
findPairValueRecord(TTGlyphID glyphID,LEReferenceTo<PairValueRecord> & records,le_uint16 recordCount,le_uint16 recordSize,LEErrorCode & success) const183 PairPositioningFormat1Subtable::findPairValueRecord(TTGlyphID glyphID, LEReferenceTo<PairValueRecord>& records,
184 le_uint16 recordCount,
185 le_uint16 recordSize, LEErrorCode &success) const
186 {
187 #if 1
188 // The OpenType spec. says that the ValueRecord table is
189 // sorted by secondGlyph. Unfortunately, there are fonts
190 // around that have an unsorted ValueRecord table.
191 LEReferenceTo<PairValueRecord> record(records);
192
193 for(le_int32 r = 0; r < recordCount; r += 1) {
194 if (r > 0) {
195 record.addOffset(recordSize, success);
196 }
197 if(LE_FAILURE(success)) return LEReferenceTo<PairValueRecord>();
198 if (SWAPW(record->secondGlyph) == glyphID) {
199 return record;
200 }
201 }
202 #else
203 #error dead code - not updated.
204 le_uint8 bit = OpenTypeUtilities::highBit(recordCount);
205 le_uint16 power = 1 << bit;
206 le_uint16 extra = (recordCount - power) * recordSize;
207 le_uint16 probe = power * recordSize;
208 const PairValueRecord *record = records;
209 const PairValueRecord *trial = (const PairValueRecord *) ((char *) record + extra);
210
211 if (SWAPW(trial->secondGlyph) <= glyphID) {
212 record = trial;
213 }
214
215 while (probe > recordSize) {
216 probe >>= 1;
217 trial = (const PairValueRecord *) ((char *) record + probe);
218
219 if (SWAPW(trial->secondGlyph) <= glyphID) {
220 record = trial;
221 }
222 }
223
224 if (SWAPW(record->secondGlyph) == glyphID) {
225 return record;
226 }
227 #endif
228
229 return LEReferenceTo<PairValueRecord>();
230 }
231
232 U_NAMESPACE_END
233