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
42U_NAMESPACE_BEGIN
43
44le_uint32 PairPositioningSubtable::process(const LEReferenceTo<PairPositioningSubtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const
45{
46    switch(SWAPW(subtableFormat))
47    {
48    case 0:
49        return 0;
50
51    case 1:
52    {
53      const LEReferenceTo<PairPositioningFormat1Subtable> subtable(base, success, (const PairPositioningFormat1Subtable *) this);
54
55      if(LE_SUCCESS(success))
56      return subtable->process(subtable, glyphIterator, fontInstance, success);
57      else
58        return 0;
59    }
60
61    case 2:
62    {
63      const LEReferenceTo<PairPositioningFormat2Subtable> subtable(base, success, (const PairPositioningFormat2Subtable *) this);
64
65      if(LE_SUCCESS(success))
66      return subtable->process(subtable, glyphIterator, fontInstance, success);
67      else
68        return 0;
69    }
70    default:
71      return 0;
72    }
73}
74
75le_uint32 PairPositioningFormat1Subtable::process(const LEReferenceTo<PairPositioningFormat1Subtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const
76{
77    LEGlyphID firstGlyph = glyphIterator->getCurrGlyphID();
78    le_int32 coverageIndex = getGlyphCoverage(base, firstGlyph, success);
79    GlyphIterator tempIterator(*glyphIterator);
80
81    LEReferenceToArrayOf<Offset> pairSetTableOffsetArrayRef(base, success, pairSetTableOffsetArray, SWAPW(pairSetCount));
82
83    if (LE_SUCCESS(success) && coverageIndex >= 0 && glyphIterator->next() && (le_uint32)coverageIndex < pairSetTableOffsetArrayRef.getCount()) {
84        Offset pairSetTableOffset = SWAPW(pairSetTableOffsetArray[coverageIndex]);
85        LEReferenceTo<PairSetTable> pairSetTable(base, success, pairSetTableOffset);
86        if( LE_FAILURE(success) ) return 0;
87        le_uint16 pairValueCount = SWAPW(pairSetTable->pairValueCount);
88        LEReferenceTo<PairValueRecord> pairValueRecordArray(pairSetTable, success, pairSetTable->pairValueRecordArray);
89        if( LE_FAILURE(success) ) return 0;
90        le_int16 valueRecord1Size = ValueRecord::getSize(SWAPW(valueFormat1));
91        le_int16 valueRecord2Size = ValueRecord::getSize(SWAPW(valueFormat2));
92        le_int16 recordSize = sizeof(PairValueRecord) - sizeof(ValueRecord) + valueRecord1Size + valueRecord2Size;
93        LEGlyphID secondGlyph = glyphIterator->getCurrGlyphID();
94        LEReferenceTo<PairValueRecord> pairValueRecord;
95
96        if (pairValueCount != 0) {
97          pairValueRecord = findPairValueRecord((TTGlyphID) LE_GET_GLYPH(secondGlyph), pairValueRecordArray, pairValueCount, recordSize, success);
98        }
99
100        if (pairValueRecord.isEmpty() || LE_FAILURE(success)) {
101            return 0;
102        }
103
104        if (valueFormat1 != 0) {
105          pairValueRecord->valueRecord1.adjustPosition(SWAPW(valueFormat1), base, tempIterator, fontInstance, success);
106        }
107
108        if (valueFormat2 != 0) {
109          LEReferenceTo<ValueRecord> valueRecord2(base, success, ((char *) &pairValueRecord->valueRecord1 + valueRecord1Size));
110          if(LE_SUCCESS(success)) {
111            valueRecord2->adjustPosition(SWAPW(valueFormat2), base, *glyphIterator, fontInstance, success);
112          }
113        }
114
115        // back up glyphIterator so second glyph can be
116        // first glyph in the next pair
117        glyphIterator->prev();
118        return 1;
119    }
120
121    return 0;
122}
123
124le_uint32 PairPositioningFormat2Subtable::process(const LEReferenceTo<PairPositioningFormat2Subtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const
125{
126    LEGlyphID firstGlyph = glyphIterator->getCurrGlyphID();
127    le_int32 coverageIndex = getGlyphCoverage(base, firstGlyph, success);
128
129    if (LE_FAILURE(success)) {
130        return 0;
131    }
132
133    GlyphIterator tempIterator(*glyphIterator);
134
135    if (coverageIndex >= 0 && glyphIterator->next()) {
136        LEGlyphID secondGlyph = glyphIterator->getCurrGlyphID();
137        const LEReferenceTo<ClassDefinitionTable> classDef1(base, success, SWAPW(classDef1Offset));
138        const LEReferenceTo<ClassDefinitionTable> classDef2(base, success, SWAPW(classDef2Offset));
139        le_int32 class1 = classDef1->getGlyphClass(classDef1, firstGlyph, success);
140        le_int32 class2 = classDef2->getGlyphClass(classDef2, secondGlyph, success);
141        le_int16 valueRecord1Size = ValueRecord::getSize(SWAPW(valueFormat1));
142        le_int16 valueRecord2Size = ValueRecord::getSize(SWAPW(valueFormat2));
143        le_int16 class2RecordSize = valueRecord1Size + valueRecord2Size;
144        le_int16 class1RecordSize = class2RecordSize * SWAPW(class2Count);
145        const LEReferenceTo<Class1Record> class1Record(base, success, (const Class1Record *) ((char *) class1RecordArray + (class1RecordSize * class1)));
146        const LEReferenceTo<Class2Record> class2Record(base, success, (const Class2Record *) ((char *) class1Record->class2RecordArray + (class2RecordSize * class2)));
147
148        if( LE_SUCCESS(success) ) {
149          if (valueFormat1 != 0) {
150            class2Record->valueRecord1.adjustPosition(SWAPW(valueFormat1), base, tempIterator, fontInstance, success);
151          }
152          if (valueFormat2 != 0) {
153            const LEReferenceTo<ValueRecord> valueRecord2(base, success, ((char *) &class2Record->valueRecord1) + valueRecord1Size);
154            LEReferenceTo<PairPositioningFormat2Subtable> thisRef(base, success, this);
155            if(LE_SUCCESS(success)) {
156              valueRecord2->adjustPosition(SWAPW(valueFormat2), thisRef, *glyphIterator, fontInstance, success);
157            }
158          }
159        }
160
161        // back up glyphIterator so second glyph can be
162        // first glyph in the next pair
163        glyphIterator->prev();
164        return 1;
165    }
166
167    return 0;
168}
169
170LEReferenceTo<PairValueRecord>
171PairPositioningFormat1Subtable::findPairValueRecord(TTGlyphID glyphID, LEReferenceTo<PairValueRecord>& records,
172                                                    le_uint16 recordCount,
173                                                    le_uint16 recordSize, LEErrorCode &success) const
174{
175#if 1
176        // The OpenType spec. says that the ValueRecord table is
177        // sorted by secondGlyph. Unfortunately, there are fonts
178        // around that have an unsorted ValueRecord table.
179        LEReferenceTo<PairValueRecord> record(records);
180
181        for(le_int32 r = 0; r < recordCount; r += 1) {
182          if (r > 0) {
183            record.addOffset(recordSize, success);
184          }
185          if(LE_FAILURE(success)) return LEReferenceTo<PairValueRecord>();
186          if (SWAPW(record->secondGlyph) == glyphID) {
187            return record;
188          }
189        }
190#else
191  #error dead code - not updated.
192    le_uint8 bit = OpenTypeUtilities::highBit(recordCount);
193    le_uint16 power = 1 << bit;
194    le_uint16 extra = (recordCount - power) * recordSize;
195    le_uint16 probe = power * recordSize;
196    const PairValueRecord *record = records;
197    const PairValueRecord *trial = (const PairValueRecord *) ((char *) record + extra);
198
199    if (SWAPW(trial->secondGlyph) <= glyphID) {
200        record = trial;
201    }
202
203    while (probe > recordSize) {
204        probe >>= 1;
205        trial = (const PairValueRecord *) ((char *) record + probe);
206
207        if (SWAPW(trial->secondGlyph) <= glyphID) {
208            record = trial;
209        }
210    }
211
212    if (SWAPW(record->secondGlyph) == glyphID) {
213        return record;
214    }
215#endif
216
217    return LEReferenceTo<PairValueRecord>();
218}
219
220U_NAMESPACE_END
221