1 /* 2 * 3 * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved 4 * 5 */ 6 7 #include "LETypes.h" 8 #include "OpenTypeTables.h" 9 #include "ArabicShaping.h" 10 #include "LEGlyphStorage.h" 11 #include "ClassDefinitionTables.h" 12 13 U_NAMESPACE_BEGIN 14 15 // This table maps Unicode joining types to 16 // ShapeTypes. 17 const ArabicShaping::ShapeType ArabicShaping::shapeTypes[] = 18 { 19 ArabicShaping::ST_NOSHAPE_NONE, // [U] 20 ArabicShaping::ST_NOSHAPE_DUAL, // [C] 21 ArabicShaping::ST_DUAL, // [D] 22 ArabicShaping::ST_LEFT, // [L] 23 ArabicShaping::ST_RIGHT, // [R] 24 ArabicShaping::ST_TRANSPARENT // [T] 25 }; 26 27 /* 28 shaping array holds types for Arabic chars between 0610 and 0700 29 other values are either unshaped, or transparent if a mark or format 30 code, except for format codes 200c (zero-width non-joiner) and 200d 31 (dual-width joiner) which are both unshaped and non_joining or 32 dual-joining, respectively. 33 */ 34 ArabicShaping::ShapeType ArabicShaping::getShapeType(LEUnicode c) 35 { 36 LEErrorCode success = LE_NO_ERROR; 37 const LEReferenceTo<ClassDefinitionTable> joiningTypes((const ClassDefinitionTable *) ArabicShaping::shapingTypeTable, 38 ArabicShaping::shapingTypeTableLen); 39 le_int32 joiningType = joiningTypes->getGlyphClass(joiningTypes, c, success); 40 41 if (joiningType >= 0 && joiningType < ArabicShaping::JT_COUNT && LE_SUCCESS(success)) { 42 return ArabicShaping::shapeTypes[joiningType]; 43 } 44 45 return ArabicShaping::ST_NOSHAPE_NONE; 46 } 47 48 #define isolFeatureTag LE_ISOL_FEATURE_TAG 49 #define initFeatureTag LE_INIT_FEATURE_TAG 50 #define mediFeatureTag LE_MEDI_FEATURE_TAG 51 #define finaFeatureTag LE_FINA_FEATURE_TAG 52 #define ligaFeatureTag LE_LIGA_FEATURE_TAG 53 #define msetFeatureTag LE_MSET_FEATURE_TAG 54 #define markFeatureTag LE_MARK_FEATURE_TAG 55 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG 56 #define rligFeatureTag LE_RLIG_FEATURE_TAG 57 #define caltFeatureTag LE_CALT_FEATURE_TAG 58 #define dligFeatureTag LE_DLIG_FEATURE_TAG 59 #define cswhFeatureTag LE_CSWH_FEATURE_TAG 60 #define cursFeatureTag LE_CURS_FEATURE_TAG 61 #define kernFeatureTag LE_KERN_FEATURE_TAG 62 #define mkmkFeatureTag LE_MKMK_FEATURE_TAG 63 64 // NOTE: 65 // The isol, fina, init and medi features must be 66 // defined in the above order, and have masks that 67 // are all in the same nibble. 68 #define isolFeatureMask 0x80000000UL 69 #define finaFeatureMask 0x40000000UL 70 #define initFeatureMask 0x20000000UL 71 #define mediFeatureMask 0x10000000UL 72 #define ccmpFeatureMask 0x08000000UL 73 #define rligFeatureMask 0x04000000UL 74 #define caltFeatureMask 0x02000000UL 75 #define ligaFeatureMask 0x01000000UL 76 #define dligFeatureMask 0x00800000UL 77 #define cswhFeatureMask 0x00400000UL 78 #define msetFeatureMask 0x00200000UL 79 #define cursFeatureMask 0x00100000UL 80 #define kernFeatureMask 0x00080000UL 81 #define markFeatureMask 0x00040000UL 82 #define mkmkFeatureMask 0x00020000UL 83 84 #define NO_FEATURES 0 85 #define ISOL_FEATURES (isolFeatureMask | ligaFeatureMask | msetFeatureMask | markFeatureMask | ccmpFeatureMask | rligFeatureMask | caltFeatureMask | dligFeatureMask | cswhFeatureMask | cursFeatureMask | kernFeatureMask | mkmkFeatureMask) 86 87 #define SHAPE_MASK 0xF0000000UL 88 89 static const FeatureMap featureMap[] = { 90 {ccmpFeatureTag, ccmpFeatureMask}, 91 {isolFeatureTag, isolFeatureMask}, 92 {finaFeatureTag, finaFeatureMask}, 93 {mediFeatureTag, mediFeatureMask}, 94 {initFeatureTag, initFeatureMask}, 95 {rligFeatureTag, rligFeatureMask}, 96 {caltFeatureTag, caltFeatureMask}, 97 {ligaFeatureTag, ligaFeatureMask}, 98 {dligFeatureTag, dligFeatureMask}, 99 {cswhFeatureTag, cswhFeatureMask}, 100 {msetFeatureTag, msetFeatureMask}, 101 {cursFeatureTag, cursFeatureMask}, 102 {kernFeatureTag, kernFeatureMask}, 103 {markFeatureTag, markFeatureMask}, 104 {mkmkFeatureTag, mkmkFeatureMask} 105 }; 106 107 const FeatureMap *ArabicShaping::getFeatureMap(le_int32 &count) 108 { 109 count = LE_ARRAY_SIZE(featureMap); 110 111 return featureMap; 112 } 113 114 void ArabicShaping::adjustTags(le_int32 outIndex, le_int32 shapeOffset, LEGlyphStorage &glyphStorage) 115 { 116 LEErrorCode success = LE_NO_ERROR; 117 FeatureMask featureMask = (FeatureMask) glyphStorage.getAuxData(outIndex, success); 118 FeatureMask shape = featureMask & SHAPE_MASK; 119 120 shape >>= shapeOffset; 121 122 glyphStorage.setAuxData(outIndex, ((featureMask & ~SHAPE_MASK) | shape), success); 123 } 124 125 void ArabicShaping::shape(const LEUnicode *chars, le_int32 offset, le_int32 charCount, le_int32 charMax, 126 le_bool rightToLeft, LEGlyphStorage &glyphStorage) 127 { 128 // iterate in logical order, store tags in visible order 129 // 130 // the effective right char is the most recently encountered 131 // non-transparent char 132 // 133 // four boolean states: 134 // the effective right char shapes 135 // the effective right char causes left shaping 136 // the current char shapes 137 // the current char causes right shaping 138 // 139 // if both cause shaping, then 140 // shaper.shape(errout, 2) (isolate to initial, or final to medial) 141 // shaper.shape(out, 1) (isolate to final) 142 143 ShapeType rightType = ST_NOSHAPE_NONE, leftType = ST_NOSHAPE_NONE; 144 LEErrorCode success = LE_NO_ERROR; 145 le_int32 i; 146 147 for (i = offset - 1; i >= 0; i -= 1) { 148 rightType = getShapeType(chars[i]); 149 150 if (rightType != ST_TRANSPARENT) { 151 break; 152 } 153 } 154 155 for (i = offset + charCount; i < charMax; i += 1) { 156 leftType = getShapeType(chars[i]); 157 158 if (leftType != ST_TRANSPARENT) { 159 break; 160 } 161 } 162 163 // erout is effective right logical index 164 le_int32 erout = -1; 165 le_bool rightShapes = FALSE; 166 le_bool rightCauses = (rightType & MASK_SHAPE_LEFT) != 0; 167 le_int32 in, e, out = 0, dir = 1; 168 169 if (rightToLeft) { 170 out = charCount - 1; 171 erout = charCount; 172 dir = -1; 173 } 174 175 for (in = offset, e = offset + charCount; in < e; in += 1, out += dir) { 176 LEUnicode c = chars[in]; 177 ShapeType t = getShapeType(c); 178 179 if (t == ST_NOSHAPE_NONE) { 180 glyphStorage.setAuxData(out, NO_FEATURES, success); 181 } else { 182 glyphStorage.setAuxData(out, ISOL_FEATURES, success); 183 } 184 185 if ((t & MASK_TRANSPARENT) != 0) { 186 continue; 187 } 188 189 le_bool curShapes = (t & MASK_NOSHAPE) == 0; 190 le_bool curCauses = (t & MASK_SHAPE_RIGHT) != 0; 191 192 if (rightCauses && curCauses) { 193 if (rightShapes) { 194 adjustTags(erout, 2, glyphStorage); 195 } 196 197 if (curShapes) { 198 adjustTags(out, 1, glyphStorage); 199 } 200 } 201 202 rightShapes = curShapes; 203 rightCauses = (t & MASK_SHAPE_LEFT) != 0; 204 erout = out; 205 } 206 207 if (rightShapes && rightCauses && (leftType & MASK_SHAPE_RIGHT) != 0) { 208 adjustTags(erout, 2, glyphStorage); 209 } 210 } 211 212 U_NAMESPACE_END 213