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