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 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 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 89static 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 107const FeatureMap *ArabicShaping::getFeatureMap(le_int32 &count) 108{ 109 count = LE_ARRAY_SIZE(featureMap); 110 111 return featureMap; 112} 113 114void 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 125void 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 212U_NAMESPACE_END 213