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 52U_NAMESPACE_BEGIN 53 54le_bool CharSubstitutionFilter::accept(LEGlyphID glyph, LEErrorCode &/*success*/) const 55{ 56 return fFontInstance->canDisplay((LEUnicode) glyph); 57} 58 59UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ArabicOpenTypeLayoutEngine) 60 61ArabicOpenTypeLayoutEngine::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 71ArabicOpenTypeLayoutEngine::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 86ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine() 87{ 88 // nothing to do 89} 90 91// Input: characters 92// Output: characters, char indices, tags 93// Returns: output character count 94le_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 132void 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(LETableReference::kStaticData, 151 CanonShaping::glyphDefinitionTable, 152 CanonShaping::glyphDefinitionTableLen); 153 GDEFMarkFilter filter(gdefTable, success); 154 155 adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); 156 } 157} 158 159UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) 160 : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags | LE_CHAR_FILTER_FEATURE_FLAG, success) 161{ 162 fGSUBTable.setTo(LETableReference::kStaticData, (const GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable, CanonShaping::glyphSubstitutionTableLen); 163 fGDEFTable.setTo(LETableReference::kStaticData, (const GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable, CanonShaping::glyphDefinitionTableLen); 164 /* OpenTypeLayoutEngine will allocate a substitution filter */ 165} 166 167UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine() 168{ 169 /* OpenTypeLayoutEngine will cleanup the substitution filter */ 170} 171 172// "glyphs", "indices" -> glyphs, indices 173le_int32 UnicodeArabicOpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success) 174{ 175 if (LE_FAILURE(success)) { 176 return 0; 177 } 178 179 // FIXME: we could avoid the memory allocation and copy if we 180 // made a clone of mapCharsToGlyphs which took the fake glyphs 181 // directly. 182 le_int32 tempGlyphCount = tempGlyphStorage.getGlyphCount(); 183 LEUnicode *tempChars = LE_NEW_ARRAY(LEUnicode, tempGlyphCount); 184 185 if (tempChars == NULL) { 186 success = LE_MEMORY_ALLOCATION_ERROR; 187 return 0; 188 } 189 190 for (le_int32 i = 0; i < tempGlyphCount; i += 1) { 191 tempChars[i] = (LEUnicode) LE_GET_GLYPH(tempGlyphStorage[i]); 192 } 193 194 glyphStorage.adoptCharIndicesArray(tempGlyphStorage); 195 196 ArabicOpenTypeLayoutEngine::mapCharsToGlyphs(tempChars, 0, tempGlyphCount, FALSE, TRUE, glyphStorage, success); 197 198 LE_DELETE_ARRAY(tempChars); 199 200 return tempGlyphCount; 201} 202 203void UnicodeArabicOpenTypeLayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool /*mirror*/, LEGlyphStorage &glyphStorage, LEErrorCode &success) 204{ 205 if (LE_FAILURE(success)) { 206 return; 207 } 208 209 if (chars == NULL || offset < 0 || count < 0) { 210 success = LE_ILLEGAL_ARGUMENT_ERROR; 211 return; 212 } 213 214 le_int32 i, dir = 1, out = 0; 215 216 if (reverse) { 217 out = count - 1; 218 dir = -1; 219 } 220 221 glyphStorage.allocateGlyphArray(count, reverse, success); 222 223 for (i = 0; i < count; i += 1, out += dir) { 224 glyphStorage[out] = (LEGlyphID) chars[offset + i]; 225 } 226} 227 228void UnicodeArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, 229 LEGlyphStorage &glyphStorage, LEErrorCode &success) 230{ 231 if (LE_FAILURE(success)) { 232 return; 233 } 234 235 if (chars == NULL || offset < 0 || count < 0) { 236 success = LE_ILLEGAL_ARGUMENT_ERROR; 237 return; 238 } 239 240 GDEFMarkFilter filter(fGDEFTable, success); 241 242 adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); 243} 244 245U_NAMESPACE_END 246 247