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