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 27U_NAMESPACE_BEGIN 28 29le_bool CharSubstitutionFilter::accept(LEGlyphID glyph) const 30{ 31 return fFontInstance->canDisplay((LEUnicode) glyph); 32} 33 34UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ArabicOpenTypeLayoutEngine) 35 36ArabicOpenTypeLayoutEngine::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 46ArabicOpenTypeLayoutEngine::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 61ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine() 62{ 63 // nothing to do 64} 65 66// Input: characters 67// Output: characters, char indices, tags 68// Returns: output character count 69le_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 107void 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 132UnicodeArabicOpenTypeLayoutEngine::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 140UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine() 141{ 142 /* OpenTypeLayoutEngine will cleanup the substitution filter */ 143} 144 145// "glyphs", "indices" -> glyphs, indices 146le_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 176void 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 201void 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 218U_NAMESPACE_END 219 220