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