1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 27 /* 28 * 29 * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved 30 * 31 */ 32 33 #include "LETypes.h" 34 #include "LEScripts.h" 35 #include "LEGlyphFilter.h" 36 #include "LEGlyphStorage.h" 37 #include "LayoutEngine.h" 38 #include "OpenTypeLayoutEngine.h" 39 #include "ArabicLayoutEngine.h" 40 #include "ScriptAndLanguageTags.h" 41 #include "CharSubstitutionFilter.h" 42 43 #include "GlyphSubstitutionTables.h" 44 #include "GlyphDefinitionTables.h" 45 #include "GlyphPositioningTables.h" 46 47 #include "GDEFMarkFilter.h" 48 49 #include "ArabicShaping.h" 50 #include "CanonShaping.h" 51 52 U_NAMESPACE_BEGIN 53 54 le_bool CharSubstitutionFilter::accept(LEGlyphID glyph) const 55 { 56 return fFontInstance->canDisplay((LEUnicode) glyph); 57 } 58 59 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ArabicOpenTypeLayoutEngine) 60 61 ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, 62 le_int32 languageCode, le_int32 typoFlags, 63 const LEReferenceTo<GlyphSubstitutionTableHeader> &gsubTable, 64 LEErrorCode &success) 65 : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success) 66 { 67 fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount); 68 fFeatureOrder = TRUE; 69 } 70 71 ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, 72 le_int32 languageCode, 73 le_int32 typoFlags, LEErrorCode &success) 74 : OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success) 75 { 76 fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount); 77 78 // NOTE: We don't need to set fFeatureOrder to TRUE here 79 // because this constructor is only called by the constructor 80 // for UnicodeArabicOpenTypeLayoutEngine, which uses a pre-built 81 // GSUB table that has the features in the correct order. 82 83 //fFeatureOrder = TRUE; 84 } 85 86 ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine() 87 { 88 // nothing to do 89 } 90 91 // Input: characters 92 // Output: characters, char indices, tags 93 // Returns: output character count 94 le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, 95 le_int32 max, le_bool rightToLeft, LEUnicode *&outChars, 96 LEGlyphStorage &glyphStorage, LEErrorCode &success) 97 { 98 if (LE_FAILURE(success)) { 99 return 0; 100 } 101 102 if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { 103 success = LE_ILLEGAL_ARGUMENT_ERROR; 104 return 0; 105 } 106 107 outChars = LE_NEW_ARRAY(LEUnicode, count); 108 109 if (outChars == NULL) { 110 success = LE_MEMORY_ALLOCATION_ERROR; 111 return 0; 112 } 113 114 glyphStorage.allocateGlyphArray(count, rightToLeft, success); 115 glyphStorage.allocateAuxData(success); 116 117 if (LE_FAILURE(success)) { 118 LE_DELETE_ARRAY(outChars); 119 return 0; 120 } 121 122 CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, outChars, glyphStorage); 123 124 // Note: This processes the *original* character array so we can get context 125 // for the first and last characters. This is OK because only the marks 126 // will have been reordered, and they don't contribute to shaping. 127 ArabicShaping::shape(chars, offset, count, max, rightToLeft, glyphStorage); 128 129 return count; 130 } 131 132 void ArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, 133 LEGlyphStorage &glyphStorage, LEErrorCode &success) 134 { 135 if (LE_FAILURE(success)) { 136 return; 137 } 138 139 if (chars == NULL || offset < 0 || count < 0) { 140 success = LE_ILLEGAL_ARGUMENT_ERROR; 141 return; 142 } 143 144 if (!fGPOSTable.isEmpty()) { 145 OpenTypeLayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success); 146 } else if (!fGDEFTable.isEmpty()) { 147 GDEFMarkFilter filter(fGDEFTable, success); 148 adjustMarkGlyphs(glyphStorage, &filter, success); 149 } else { 150 LEReferenceTo<GlyphDefinitionTableHeader> gdefTable(CanonShaping::glyphDefinitionTable, CanonShaping::glyphDefinitionTableLen); 151 GDEFMarkFilter filter(gdefTable, success); 152 153 adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); 154 } 155 } 156 157 UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) 158 : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags | LE_CHAR_FILTER_FEATURE_FLAG, success) 159 { 160 fGSUBTable = (const GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable; 161 fGDEFTable = (const GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable; 162 /* OpenTypeLayoutEngine will allocate a substitution filter */ 163 } 164 165 UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine() 166 { 167 /* OpenTypeLayoutEngine will cleanup the substitution filter */ 168 } 169 170 // "glyphs", "indices" -> glyphs, indices 171 le_int32 UnicodeArabicOpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success) 172 { 173 if (LE_FAILURE(success)) { 174 return 0; 175 } 176 177 // FIXME: we could avoid the memory allocation and copy if we 178 // made a clone of mapCharsToGlyphs which took the fake glyphs 179 // directly. 180 le_int32 tempGlyphCount = tempGlyphStorage.getGlyphCount(); 181 LEUnicode *tempChars = LE_NEW_ARRAY(LEUnicode, tempGlyphCount); 182 183 if (tempChars == NULL) { 184 success = LE_MEMORY_ALLOCATION_ERROR; 185 return 0; 186 } 187 188 for (le_int32 i = 0; i < tempGlyphCount; i += 1) { 189 tempChars[i] = (LEUnicode) LE_GET_GLYPH(tempGlyphStorage[i]); 190 } 191 192 glyphStorage.adoptCharIndicesArray(tempGlyphStorage); 193 194 ArabicOpenTypeLayoutEngine::mapCharsToGlyphs(tempChars, 0, tempGlyphCount, FALSE, TRUE, glyphStorage, success); 195 196 LE_DELETE_ARRAY(tempChars); 197 198 return tempGlyphCount; 199 } 200 201 void UnicodeArabicOpenTypeLayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool /*mirror*/, LEGlyphStorage &glyphStorage, LEErrorCode &success) 202 { 203 if (LE_FAILURE(success)) { 204 return; 205 } 206 207 if (chars == NULL || offset < 0 || count < 0) { 208 success = LE_ILLEGAL_ARGUMENT_ERROR; 209 return; 210 } 211 212 le_int32 i, dir = 1, out = 0; 213 214 if (reverse) { 215 out = count - 1; 216 dir = -1; 217 } 218 219 glyphStorage.allocateGlyphArray(count, reverse, success); 220 221 for (i = 0; i < count; i += 1, out += dir) { 222 glyphStorage[out] = (LEGlyphID) chars[offset + i]; 223 } 224 } 225 226 void UnicodeArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, 227 LEGlyphStorage &glyphStorage, LEErrorCode &success) 228 { 229 if (LE_FAILURE(success)) { 230 return; 231 } 232 233 if (chars == NULL || offset < 0 || count < 0) { 234 success = LE_ILLEGAL_ARGUMENT_ERROR; 235 return; 236 } 237 238 GDEFMarkFilter filter(fGDEFTable, success); 239 240 adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); 241 } 242 243 U_NAMESPACE_END 244