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 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, 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 44ArabicOpenTypeLayoutEngine::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 58ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine() 59{ 60 // nothing to do 61} 62 63// Input: characters 64// Output: characters, char indices, tags 65// Returns: output character count 66le_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 103void 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 129UnicodeArabicOpenTypeLayoutEngine::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 138UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine() 139{ 140 delete fSubstitutionFilter; 141} 142 143// "glyphs", "indices" -> glyphs, indices 144le_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 174void 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 199void 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 216U_NAMESPACE_END 217 218