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 * (C) Copyright IBM Corp. and others 1998 - 2013 - All Rights Reserved 28 * 29 */ 30 31 #include "LETypes.h" 32 #include "LayoutTables.h" 33 #include "MorphTables.h" 34 #include "SubtableProcessor2.h" 35 #include "IndicRearrangementProcessor2.h" 36 #include "ContextualGlyphSubstProc2.h" 37 #include "LigatureSubstProc2.h" 38 #include "NonContextualGlyphSubstProc2.h" 39 #include "ContextualGlyphInsertionProc2.h" 40 #include "LEGlyphStorage.h" 41 #include "LESwaps.h" 42 43 U_NAMESPACE_BEGIN 44 45 void MorphTableHeader2::process(const LEReferenceTo<MorphTableHeader2> &base, LEGlyphStorage &glyphStorage, 46 le_int32 typoFlags, LEErrorCode &success) const 47 { 48 if(LE_FAILURE(success)) return; 49 50 le_uint32 chainCount = SWAPL(this->nChains); 51 LEReferenceTo<ChainHeader2> chainHeader(base, success, &chains[0]); 52 /* chainHeader and subtableHeader are implemented as a moving pointer rather than an array dereference 53 * to (slightly) reduce code churn. However, must be careful to preincrement them the 2nd time through. 54 * We don't want to increment them at the end of the loop, as that would attempt to dereference 55 * out of range memory. 56 */ 57 le_uint32 chain; 58 59 for (chain = 0; LE_SUCCESS(success) && (chain < chainCount); chain++) { 60 if (chain>0) { 61 le_uint32 chainLength = SWAPL(chainHeader->chainLength); 62 if (chainLength & 0x03) { // incorrect alignment for 32 bit tables 63 success = LE_MEMORY_ALLOCATION_ERROR; // as good a choice as any 64 return; 65 } 66 chainHeader.addOffset(chainLength, success); // Don't increment the first time 67 } 68 FeatureFlags flag = SWAPL(chainHeader->defaultFlags); 69 le_uint32 nFeatureEntries = SWAPL(chainHeader->nFeatureEntries); 70 le_uint32 nSubtables = SWAPL(chainHeader->nSubtables); 71 LEReferenceTo<MorphSubtableHeader2> subtableHeader(chainHeader, 72 success, (const MorphSubtableHeader2 *)&chainHeader->featureTable[nFeatureEntries]); 73 le_uint32 subtable; 74 if(LE_FAILURE(success)) break; // malformed table 75 76 if (typoFlags != 0) { 77 le_uint32 featureEntry; 78 LEReferenceToArrayOf<FeatureTableEntry> featureTableRef(chainHeader, success, &chainHeader->featureTable[0], nFeatureEntries); 79 if(LE_FAILURE(success)) break; 80 // Feature subtables 81 for (featureEntry = 0; featureEntry < nFeatureEntries; featureEntry++) { 82 const FeatureTableEntry &featureTableEntry = featureTableRef(featureEntry, success); 83 le_int16 featureType = SWAPW(featureTableEntry.featureType); 84 le_int16 featureSetting = SWAPW(featureTableEntry.featureSetting); 85 le_uint32 enableFlags = SWAPL(featureTableEntry.enableFlags); 86 le_uint32 disableFlags = SWAPL(featureTableEntry.disableFlags); 87 switch (featureType) { 88 case ligaturesType: 89 if ((typoFlags & LE_Ligatures_FEATURE_ENUM ) && (featureSetting ^ 0x1)){ 90 flag &= disableFlags; 91 flag |= enableFlags; 92 } else { 93 if (((typoFlags & LE_RLIG_FEATURE_FLAG) && featureSetting == requiredLigaturesOnSelector) || 94 ((typoFlags & LE_CLIG_FEATURE_FLAG) && featureSetting == contextualLigaturesOnSelector) || 95 ((typoFlags & LE_HLIG_FEATURE_FLAG) && featureSetting == historicalLigaturesOnSelector) || 96 ((typoFlags & LE_LIGA_FEATURE_FLAG) && featureSetting == commonLigaturesOnSelector)) { 97 flag &= disableFlags; 98 flag |= enableFlags; 99 } 100 } 101 break; 102 case letterCaseType: 103 if ((typoFlags & LE_SMCP_FEATURE_FLAG) && featureSetting == smallCapsSelector) { 104 flag &= disableFlags; 105 flag |= enableFlags; 106 } 107 break; 108 case verticalSubstitutionType: 109 break; 110 case linguisticRearrangementType: 111 break; 112 case numberSpacingType: 113 break; 114 case smartSwashType: 115 if ((typoFlags & LE_SWSH_FEATURE_FLAG) && (featureSetting ^ 0x1)){ 116 flag &= disableFlags; 117 flag |= enableFlags; 118 } 119 break; 120 case diacriticsType: 121 break; 122 case verticalPositionType: 123 break; 124 case fractionsType: 125 if (((typoFlags & LE_FRAC_FEATURE_FLAG) && featureSetting == diagonalFractionsSelector) || 126 ((typoFlags & LE_AFRC_FEATURE_FLAG) && featureSetting == verticalFractionsSelector)) { 127 flag &= disableFlags; 128 flag |= enableFlags; 129 } else { 130 flag &= disableFlags; 131 } 132 break; 133 case typographicExtrasType: 134 if ((typoFlags & LE_ZERO_FEATURE_FLAG) && featureSetting == slashedZeroOnSelector) { 135 flag &= disableFlags; 136 flag |= enableFlags; 137 } 138 break; 139 case mathematicalExtrasType: 140 break; 141 case ornamentSetsType: 142 break; 143 case characterAlternativesType: 144 break; 145 case designComplexityType: 146 if (((typoFlags & LE_SS01_FEATURE_FLAG) && featureSetting == designLevel1Selector) || 147 ((typoFlags & LE_SS02_FEATURE_FLAG) && featureSetting == designLevel2Selector) || 148 ((typoFlags & LE_SS03_FEATURE_FLAG) && featureSetting == designLevel3Selector) || 149 ((typoFlags & LE_SS04_FEATURE_FLAG) && featureSetting == designLevel4Selector) || 150 ((typoFlags & LE_SS05_FEATURE_FLAG) && featureSetting == designLevel5Selector) || 151 ((typoFlags & LE_SS06_FEATURE_FLAG) && featureSetting == designLevel6Selector) || 152 ((typoFlags & LE_SS07_FEATURE_FLAG) && featureSetting == designLevel7Selector)) { 153 154 flag &= disableFlags; 155 flag |= enableFlags; 156 } 157 break; 158 case styleOptionsType: 159 break; 160 case characterShapeType: 161 break; 162 case numberCaseType: 163 break; 164 case textSpacingType: 165 break; 166 case transliterationType: 167 break; 168 case annotationType: 169 if ((typoFlags & LE_NALT_FEATURE_FLAG) && featureSetting == circleAnnotationSelector) { 170 flag &= disableFlags; 171 flag |= enableFlags; 172 } 173 break; 174 case kanaSpacingType: 175 break; 176 case ideographicSpacingType: 177 break; 178 case rubyKanaType: 179 if ((typoFlags & LE_RUBY_FEATURE_FLAG) && featureSetting == rubyKanaOnSelector) { 180 flag &= disableFlags; 181 flag |= enableFlags; 182 } 183 break; 184 case cjkRomanSpacingType: 185 break; 186 default: 187 break; 188 } 189 } 190 } 191 192 for (subtable = 0; LE_SUCCESS(success) && subtable < nSubtables; subtable++) { 193 if(subtable>0) { 194 le_uint32 length = SWAPL(subtableHeader->length); 195 if (length & 0x03) { // incorrect alignment for 32 bit tables 196 success = LE_MEMORY_ALLOCATION_ERROR; // as good a choice as any 197 return; 198 } 199 subtableHeader.addOffset(length, success); // Don't addOffset for the last entry. 200 if (LE_FAILURE(success)) break; 201 } 202 le_uint32 coverage = SWAPL(subtableHeader->coverage); 203 FeatureFlags subtableFeatures = SWAPL(subtableHeader->subtableFeatures); 204 // should check coverage more carefully... 205 if (((coverage & scfIgnoreVt2) || !(coverage & scfVertical2)) && (subtableFeatures & flag) != 0) { 206 subtableHeader->process(subtableHeader, glyphStorage, success); 207 } 208 } 209 } 210 } 211 212 void MorphSubtableHeader2::process(const LEReferenceTo<MorphSubtableHeader2> &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const 213 { 214 SubtableProcessor2 *processor = NULL; 215 216 if (LE_FAILURE(success)) return; 217 218 switch (SWAPL(coverage) & scfTypeMask2) 219 { 220 case mstIndicRearrangement: 221 processor = new IndicRearrangementProcessor2(base, success); 222 break; 223 224 case mstContextualGlyphSubstitution: 225 processor = new ContextualGlyphSubstitutionProcessor2(base, success); 226 break; 227 228 case mstLigatureSubstitution: 229 processor = new LigatureSubstitutionProcessor2(base, success); 230 break; 231 232 case mstReservedUnused: 233 break; 234 235 case mstNonContextualGlyphSubstitution: 236 processor = NonContextualGlyphSubstitutionProcessor2::createInstance(base, success); 237 break; 238 239 240 case mstContextualGlyphInsertion: 241 processor = new ContextualGlyphInsertionProcessor2(base, success); 242 break; 243 244 default: 245 return; 246 break; /*NOTREACHED*/ 247 } 248 249 if (processor != NULL) { 250 processor->process(glyphStorage, success); 251 delete processor; 252 } else { 253 if(LE_SUCCESS(success)) { 254 success = LE_MEMORY_ALLOCATION_ERROR; // because ptr is null and we didn't break out. 255 } 256 } 257 } 258 259 U_NAMESPACE_END