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 13U_NAMESPACE_BEGIN 14 15// This table maps Unicode joining types to 16// ShapeTypes. 17const 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*/ 34ArabicShaping::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 87static 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 105const FeatureMap *ArabicShaping::getFeatureMap(le_int32 &count) 106{ 107 count = LE_ARRAY_SIZE(featureMap); 108 109 return featureMap; 110} 111 112void 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 123void 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 210U_NAMESPACE_END 211