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