1 2 /* 3 * 4 * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved 5 * 6 */ 7 8 #include "LETypes.h" 9 #include "LEScripts.h" 10 #include "LEGlyphFilter.h" 11 #include "LEGlyphStorage.h" 12 #include "LayoutEngine.h" 13 #include "OpenTypeLayoutEngine.h" 14 #include "ArabicLayoutEngine.h" 15 #include "ScriptAndLanguageTags.h" 16 #include "CharSubstitutionFilter.h" 17 18 #include "GlyphSubstitutionTables.h" 19 #include "GlyphDefinitionTables.h" 20 #include "GlyphPositioningTables.h" 21 22 #include "GDEFMarkFilter.h" 23 24 #include "ArabicShaping.h" 25 #include "CanonShaping.h" 26 27 U_NAMESPACE_BEGIN 28 29 le_bool CharSubstitutionFilter::accept(LEGlyphID glyph) const 30 { 31 return fFontInstance->canDisplay((LEUnicode) glyph); 32 } 33 34 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ArabicOpenTypeLayoutEngine) 35 36 ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, 37 le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) 38 : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success) 39 { 40 fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount); 41 fFeatureOrder = TRUE; 42 } 43 44 ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, 45 le_int32 typoFlags, LEErrorCode &success) 46 : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success) 47 { 48 fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount); 49 50 // NOTE: We don't need to set fFeatureOrder to TRUE here 51 // because this constructor is only called by the constructor 52 // for UnicodeArabicOpenTypeLayoutEngine, which uses a pre-built 53 // GSUB table that has the features in the correct order. 54 55 //fFeatureOrder = TRUE; 56 } 57 58 ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine() 59 { 60 // nothing to do 61 } 62 63 // Input: characters 64 // Output: characters, char indices, tags 65 // Returns: output character count 66 le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, 67 LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) 68 { 69 if (LE_FAILURE(success)) { 70 return 0; 71 } 72 73 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { 74 success = LE_ILLEGAL_ARGUMENT_ERROR; 75 return 0; 76 } 77 78 outChars = LE_NEW_ARRAY(LEUnicode, count); 79 80 if (outChars == NULL) { 81 success = LE_MEMORY_ALLOCATION_ERROR; 82 return 0; 83 } 84 85 glyphStorage.allocateGlyphArray(count, rightToLeft, success); 86 glyphStorage.allocateAuxData(success); 87 88 if (LE_FAILURE(success)) { 89 LE_DELETE_ARRAY(outChars); 90 return 0; 91 } 92 93 CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, outChars, glyphStorage); 94 95 // Note: This processes the *original* character array so we can get context 96 // for the first and last characters. This is OK because only the marks 97 // will have been reordered, and they don't contribute to shaping. 98 ArabicShaping::shape(chars, offset, count, max, rightToLeft, glyphStorage); 99 100 return count; 101 } 102 103 void ArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, 104 LEGlyphStorage &glyphStorage, LEErrorCode &success) 105 { 106 if (LE_FAILURE(success)) { 107 return; 108 } 109 110 if (chars == NULL || offset < 0 || count < 0) { 111 success = LE_ILLEGAL_ARGUMENT_ERROR; 112 return; 113 } 114 115 if (fGPOSTable != NULL) { 116 OpenTypeLayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success); 117 } else if (fGDEFTable != NULL) { 118 GDEFMarkFilter filter(fGDEFTable); 119 120 adjustMarkGlyphs(glyphStorage, &filter, success); 121 } else { 122 GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable; 123 GDEFMarkFilter filter(gdefTable); 124 125 adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); 126 } 127 } 128 129 UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) 130 : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success) 131 { 132 fGSUBTable = (const GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable; 133 fGDEFTable = (const GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable; 134 135 fSubstitutionFilter = new CharSubstitutionFilter(fontInstance); 136 } 137 138 UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine() 139 { 140 delete fSubstitutionFilter; 141 } 142 143 // "glyphs", "indices" -> glyphs, indices 144 le_int32 UnicodeArabicOpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success) 145 { 146 if (LE_FAILURE(success)) { 147 return 0; 148 } 149 150 // FIXME: we could avoid the memory allocation and copy if we 151 // made a clone of mapCharsToGlyphs which took the fake glyphs 152 // directly. 153 le_int32 tempGlyphCount = tempGlyphStorage.getGlyphCount(); 154 LEUnicode *tempChars = LE_NEW_ARRAY(LEUnicode, tempGlyphCount); 155 156 if (tempChars == NULL) { 157 success = LE_MEMORY_ALLOCATION_ERROR; 158 return 0; 159 } 160 161 for (le_int32 i = 0; i < tempGlyphCount; i += 1) { 162 tempChars[i] = (LEUnicode) LE_GET_GLYPH(tempGlyphStorage[i]); 163 } 164 165 glyphStorage.adoptCharIndicesArray(tempGlyphStorage); 166 167 ArabicOpenTypeLayoutEngine::mapCharsToGlyphs(tempChars, 0, tempGlyphCount, FALSE, TRUE, glyphStorage, success); 168 169 LE_DELETE_ARRAY(tempChars); 170 171 return tempGlyphCount; 172 } 173 174 void UnicodeArabicOpenTypeLayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool /*mirror*/, LEGlyphStorage &glyphStorage, LEErrorCode &success) 175 { 176 if (LE_FAILURE(success)) { 177 return; 178 } 179 180 if (chars == NULL || offset < 0 || count < 0) { 181 success = LE_ILLEGAL_ARGUMENT_ERROR; 182 return; 183 } 184 185 le_int32 i, dir = 1, out = 0; 186 187 if (reverse) { 188 out = count - 1; 189 dir = -1; 190 } 191 192 glyphStorage.allocateGlyphArray(count, reverse, success); 193 194 for (i = 0; i < count; i += 1, out += dir) { 195 glyphStorage[out] = (LEGlyphID) chars[offset + i]; 196 } 197 } 198 199 void UnicodeArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, 200 LEGlyphStorage &glyphStorage, LEErrorCode &success) 201 { 202 if (LE_FAILURE(success)) { 203 return; 204 } 205 206 if (chars == NULL || offset < 0 || count < 0) { 207 success = LE_ILLEGAL_ARGUMENT_ERROR; 208 return; 209 } 210 211 GDEFMarkFilter filter(fGDEFTable); 212 213 adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); 214 } 215 216 U_NAMESPACE_END 217 218