Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenshape.c
Go to the documentation of this file.
00001 /* 00002 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll) 00003 * 00004 * Copyright 2010 CodeWeavers, Aric Stewart 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 * 00020 */ 00021 #include <stdarg.h> 00022 #include <stdlib.h> 00023 00024 #include "windef.h" 00025 #include "winbase.h" 00026 #include "wingdi.h" 00027 #include "winuser.h" 00028 #include "winnls.h" 00029 #include "usp10.h" 00030 #include "winternl.h" 00031 00032 #include "usp10_internal.h" 00033 00034 #include "wine/debug.h" 00035 00036 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe); 00037 00038 #define FIRST_ARABIC_CHAR 0x0600 00039 #define LAST_ARABIC_CHAR 0x06ff 00040 00041 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*, 00042 WCHAR*, INT, WORD*, INT*, INT, WORD*); 00043 00044 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00045 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00046 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00047 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00048 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00049 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00050 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00051 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00052 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00053 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00054 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00055 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00056 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00057 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00058 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); 00059 00060 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*); 00061 00062 static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp); 00063 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00064 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00065 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00066 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00067 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00068 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00069 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00070 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00071 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00072 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00073 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00074 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00075 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00076 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00077 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ); 00078 00079 extern const unsigned short indic_syllabic_table[]; 00080 extern const unsigned short wine_shaping_table[]; 00081 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4]; 00082 00083 enum joining_types { 00084 jtU, 00085 jtT, 00086 jtR, 00087 jtL, 00088 jtD, 00089 jtC 00090 }; 00091 00092 enum joined_forms { 00093 Xn=0, 00094 Xr, 00095 Xl, 00096 Xm, 00097 /* Syriac Alaph */ 00098 Afj, 00099 Afn, 00100 Afx 00101 }; 00102 00103 typedef struct tagVowelComponents 00104 { 00105 WCHAR base; 00106 WCHAR parts[3]; 00107 } VowelComponents; 00108 00109 typedef struct tagConsonantComponents 00110 { 00111 WCHAR parts[3]; 00112 WCHAR output; 00113 } ConsonantComponents; 00114 00115 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex); 00116 00117 /* the orders of joined_forms and contextual_features need to line up */ 00118 static const char* contextual_features[] = 00119 { 00120 "isol", 00121 "fina", 00122 "init", 00123 "medi", 00124 /* Syriac Alaph */ 00125 "med2", 00126 "fin2", 00127 "fin3" 00128 }; 00129 00130 static OPENTYPE_FEATURE_RECORD standard_features[] = 00131 { 00132 { MS_MAKE_TAG('c','c','m','p'), 1}, 00133 { MS_MAKE_TAG('l','o','c','l'), 1}, 00134 }; 00135 00136 static OPENTYPE_FEATURE_RECORD latin_features[] = 00137 { 00138 { MS_MAKE_TAG('l','i','g','a'), 1}, 00139 { MS_MAKE_TAG('c','l','i','g'), 1}, 00140 }; 00141 00142 static OPENTYPE_FEATURE_RECORD arabic_features[] = 00143 { 00144 { MS_MAKE_TAG('r','l','i','g'), 1}, 00145 { MS_MAKE_TAG('c','a','l','t'), 1}, 00146 { MS_MAKE_TAG('l','i','g','a'), 1}, 00147 { MS_MAKE_TAG('d','l','i','g'), 1}, 00148 { MS_MAKE_TAG('c','s','w','h'), 1}, 00149 { MS_MAKE_TAG('m','s','e','t'), 1}, 00150 }; 00151 00152 static const char* required_arabic_features[] = 00153 { 00154 "fina", 00155 "init", 00156 "medi", 00157 "rlig", 00158 NULL 00159 }; 00160 00161 static OPENTYPE_FEATURE_RECORD hebrew_features[] = 00162 { 00163 { MS_MAKE_TAG('d','l','i','g'), 0}, 00164 }; 00165 00166 static OPENTYPE_FEATURE_RECORD syriac_features[] = 00167 { 00168 { MS_MAKE_TAG('r','l','i','g'), 1}, 00169 { MS_MAKE_TAG('c','a','l','t'), 1}, 00170 { MS_MAKE_TAG('l','i','g','a'), 1}, 00171 { MS_MAKE_TAG('d','l','i','g'), 1}, 00172 }; 00173 00174 static const char* required_syriac_features[] = 00175 { 00176 "fina", 00177 "fin2", 00178 "fin3", 00179 "init", 00180 "medi", 00181 "med2", 00182 "rlig", 00183 NULL 00184 }; 00185 00186 static OPENTYPE_FEATURE_RECORD sinhala_features[] = 00187 { 00188 /* Presentation forms */ 00189 { MS_MAKE_TAG('b','l','w','s'), 1}, 00190 { MS_MAKE_TAG('a','b','v','s'), 1}, 00191 { MS_MAKE_TAG('p','s','t','s'), 1}, 00192 }; 00193 00194 static OPENTYPE_FEATURE_RECORD tibetan_features[] = 00195 { 00196 { MS_MAKE_TAG('a','b','v','s'), 1}, 00197 { MS_MAKE_TAG('b','l','w','s'), 1}, 00198 }; 00199 00200 static OPENTYPE_FEATURE_RECORD phags_features[] = 00201 { 00202 { MS_MAKE_TAG('a','b','v','s'), 1}, 00203 { MS_MAKE_TAG('b','l','w','s'), 1}, 00204 { MS_MAKE_TAG('c','a','l','t'), 1}, 00205 }; 00206 00207 static OPENTYPE_FEATURE_RECORD thai_features[] = 00208 { 00209 { MS_MAKE_TAG('c','c','m','p'), 1}, 00210 }; 00211 00212 static const char* required_lao_features[] = 00213 { 00214 "ccmp", 00215 NULL 00216 }; 00217 00218 static const char* required_devanagari_features[] = 00219 { 00220 "nukt", 00221 "akhn", 00222 "rphf", 00223 "blwf", 00224 "half", 00225 "vatu", 00226 "pres", 00227 "abvs", 00228 "blws", 00229 "psts", 00230 "haln", 00231 NULL 00232 }; 00233 00234 static OPENTYPE_FEATURE_RECORD devanagari_features[] = 00235 { 00236 { MS_MAKE_TAG('p','r','e','s'), 1}, 00237 { MS_MAKE_TAG('a','b','v','s'), 1}, 00238 { MS_MAKE_TAG('b','l','w','s'), 1}, 00239 { MS_MAKE_TAG('p','s','t','s'), 1}, 00240 { MS_MAKE_TAG('h','a','l','n'), 1}, 00241 { MS_MAKE_TAG('c','a','l','t'), 1}, 00242 }; 00243 00244 static OPENTYPE_FEATURE_RECORD myanmar_features[] = 00245 { 00246 { MS_MAKE_TAG('l','i','g','a'), 1}, 00247 { MS_MAKE_TAG('c','l','i','g'), 1}, 00248 }; 00249 00250 static const char* required_bengali_features[] = 00251 { 00252 "nukt", 00253 "akhn", 00254 "rphf", 00255 "blwf", 00256 "half", 00257 "vatu", 00258 "pstf", 00259 "init", 00260 "abvs", 00261 "blws", 00262 "psts", 00263 "haln", 00264 NULL 00265 }; 00266 00267 static const char* required_gurmukhi_features[] = 00268 { 00269 "nukt", 00270 "akhn", 00271 "rphf", 00272 "blwf", 00273 "half", 00274 "pstf", 00275 "vatu", 00276 "cjct", 00277 "pres", 00278 "abvs", 00279 "blws", 00280 "psts", 00281 "haln", 00282 "calt", 00283 NULL 00284 }; 00285 00286 static const char* required_oriya_features[] = 00287 { 00288 "nukt", 00289 "akhn", 00290 "rphf", 00291 "blwf", 00292 "pstf", 00293 "cjct", 00294 "pres", 00295 "abvs", 00296 "blws", 00297 "psts", 00298 "haln", 00299 "calt", 00300 NULL 00301 }; 00302 00303 static const char* required_tamil_features[] = 00304 { 00305 "nukt", 00306 "akhn", 00307 "rphf", 00308 "pref", 00309 "half", 00310 "pres", 00311 "abvs", 00312 "blws", 00313 "psts", 00314 "haln", 00315 "calt", 00316 NULL 00317 }; 00318 00319 static const char* required_telugu_features[] = 00320 { 00321 "nukt", 00322 "akhn", 00323 "rphf", 00324 "pref", 00325 "half", 00326 "pstf", 00327 "cjct", 00328 "pres", 00329 "abvs", 00330 "blws", 00331 "psts", 00332 "haln", 00333 "calt", 00334 NULL 00335 }; 00336 00337 static OPENTYPE_FEATURE_RECORD khmer_features[] = 00338 { 00339 { MS_MAKE_TAG('p','r','e','s'), 1}, 00340 { MS_MAKE_TAG('b','l','w','s'), 1}, 00341 { MS_MAKE_TAG('a','b','v','s'), 1}, 00342 { MS_MAKE_TAG('p','s','t','s'), 1}, 00343 { MS_MAKE_TAG('c','l','i','g'), 1}, 00344 }; 00345 00346 static const char* required_khmer_features[] = 00347 { 00348 "pref", 00349 "blwf", 00350 "abvf", 00351 "pstf", 00352 "pres", 00353 "blws", 00354 "abvs", 00355 "psts", 00356 "clig", 00357 NULL 00358 }; 00359 00360 static OPENTYPE_FEATURE_RECORD ethiopic_features[] = 00361 { 00362 { MS_MAKE_TAG('c','c','m','p'), 1}, 00363 { MS_MAKE_TAG('l','o','c','l'), 1}, 00364 { MS_MAKE_TAG('c','a','l','t'), 1}, 00365 { MS_MAKE_TAG('l','i','g','a'), 1}, 00366 }; 00367 00368 static OPENTYPE_FEATURE_RECORD mongolian_features[] = 00369 { 00370 { MS_MAKE_TAG('c','c','m','p'), 1}, 00371 { MS_MAKE_TAG('l','o','c','l'), 1}, 00372 { MS_MAKE_TAG('c','a','l','t'), 1}, 00373 { MS_MAKE_TAG('r','l','i','g'), 1}, 00374 }; 00375 00376 typedef struct ScriptShapeDataTag { 00377 TEXTRANGE_PROPERTIES defaultTextRange; 00378 const char** requiredFeatures; 00379 OPENTYPE_TAG newOtTag; 00380 ContextualShapingProc contextProc; 00381 ShapeCharGlyphPropProc charGlyphPropProc; 00382 } ScriptShapeData; 00383 00384 /* in order of scripts */ 00385 static const ScriptShapeData ShapingData[] = 00386 { 00387 {{ standard_features, 2}, NULL, 0, NULL, NULL}, 00388 {{ latin_features, 2}, NULL, 0, NULL, NULL}, 00389 {{ latin_features, 2}, NULL, 0, NULL, NULL}, 00390 {{ latin_features, 2}, NULL, 0, NULL, NULL}, 00391 {{ standard_features, 2}, NULL, 0, NULL, NULL}, 00392 {{ latin_features, 2}, NULL, 0, NULL, NULL}, 00393 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic}, 00394 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic}, 00395 {{ hebrew_features, 1}, NULL, 0, NULL, NULL}, 00396 {{ syriac_features, 4}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None}, 00397 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic}, 00398 {{ NULL, 0}, NULL, 0, NULL, ShapeCharGlyphProp_None}, 00399 {{ standard_features, 2}, NULL, 0, NULL, NULL}, 00400 {{ standard_features, 2}, NULL, 0, NULL, NULL}, 00401 {{ standard_features, 2}, NULL, 0, NULL, NULL}, 00402 {{ standard_features, 2}, NULL, 0, NULL, NULL}, 00403 {{ sinhala_features, 3}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala}, 00404 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet}, 00405 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet}, 00406 {{ phags_features, 3}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai}, 00407 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai}, 00408 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai}, 00409 {{ thai_features, 1}, required_lao_features, 0, NULL, ShapeCharGlyphProp_Thai}, 00410 {{ thai_features, 1}, required_lao_features, 0, NULL, ShapeCharGlyphProp_Thai}, 00411 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari}, 00412 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari}, 00413 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali}, 00414 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali}, 00415 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali}, 00416 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi}, 00417 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi}, 00418 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati}, 00419 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati}, 00420 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati}, 00421 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya}, 00422 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya}, 00423 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil}, 00424 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil}, 00425 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu}, 00426 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu}, 00427 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada}, 00428 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada}, 00429 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam}, 00430 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam}, 00431 {{ standard_features, 2}, NULL, 0, NULL, NULL}, 00432 {{ latin_features, 2}, NULL, 0, NULL, NULL}, 00433 {{ standard_features, 2}, NULL, 0, NULL, NULL}, 00434 {{ myanmar_features, 2}, NULL, 0, NULL, NULL}, 00435 {{ myanmar_features, 2}, NULL, 0, NULL, NULL}, 00436 {{ standard_features, 2}, NULL, 0, NULL, NULL}, 00437 {{ standard_features, 2}, NULL, 0, NULL, NULL}, 00438 {{ standard_features, 2}, NULL, 0, NULL, NULL}, 00439 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer}, 00440 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer}, 00441 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00442 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00443 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00444 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00445 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00446 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00447 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL}, 00448 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL}, 00449 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL}, 00450 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL}, 00451 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00452 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00453 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00454 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00455 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00456 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00457 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00458 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00459 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00460 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00461 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00462 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00463 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00464 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00465 {{ NULL, 0}, NULL, 0, NULL, NULL}, 00466 {{ hebrew_features, 1}, NULL, 0, NULL, NULL}, 00467 {{ latin_features, 2}, NULL, 0, NULL, NULL}, 00468 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai}, 00469 }; 00470 00471 extern scriptData scriptInformation[]; 00472 00473 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) 00474 { 00475 int i; 00476 int out_index = GSUB_E_NOGLYPH; 00477 00478 TRACE("%i lookups\n", feature->lookup_count); 00479 for (i = 0; i < feature->lookup_count; i++) 00480 { 00481 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count); 00482 if (out_index != GSUB_E_NOGLYPH) 00483 break; 00484 } 00485 if (out_index == GSUB_E_NOGLYPH) 00486 TRACE("lookups found no glyphs\n"); 00487 else 00488 { 00489 int out2; 00490 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count); 00491 if (out2!=GSUB_E_NOGLYPH) 00492 out_index = out2; 00493 } 00494 return out_index; 00495 } 00496 00497 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew) 00498 { 00499 UINT charset; 00500 00501 if (psc->userScript != 0) 00502 { 00503 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag) 00504 return ShapingData[psa->eScript].newOtTag; 00505 else 00506 return psc->userScript; 00507 } 00508 00509 if (tryNew && ShapingData[psa->eScript].newOtTag != 0) 00510 return ShapingData[psa->eScript].newOtTag; 00511 00512 if (scriptInformation[psa->eScript].scriptTag) 00513 return scriptInformation[psa->eScript].scriptTag; 00514 00515 /* 00516 * fall back to the font charset 00517 */ 00518 charset = GetTextCharsetInfo(hdc, NULL, 0x0); 00519 switch (charset) 00520 { 00521 case ANSI_CHARSET: 00522 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n'); 00523 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i'); 00524 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */ 00525 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i'); 00526 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k'); 00527 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g'); 00528 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l'); 00529 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a'); 00530 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */ 00531 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); 00532 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */ 00533 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b'); 00534 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r'); 00535 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i'); 00536 default: return MS_MAKE_TAG('l','a','t','n'); 00537 } 00538 } 00539 00540 static LoadedFeature* load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat) 00541 { 00542 LoadedFeature *feature = NULL; 00543 00544 if (psc->GSUB_Table) 00545 { 00546 int attempt = 2; 00547 OPENTYPE_TAG tags; 00548 OPENTYPE_TAG language; 00549 OPENTYPE_TAG script; 00550 int cTags; 00551 00552 do 00553 { 00554 script = get_opentype_script(hdc,psa,psc,(attempt==2)); 00555 if (psc->userLang != 0) 00556 language = psc->userLang; 00557 else 00558 language = MS_MAKE_TAG('d','f','l','t'); 00559 attempt--; 00560 00561 OpenType_GSUB_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature); 00562 00563 } while(attempt && !feature); 00564 00565 /* try in the default (latin) table */ 00566 if (!feature) 00567 OpenType_GSUB_GetFontFeatureTags(psc, MS_MAKE_TAG('l','a','t','n'), MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature); 00568 } 00569 00570 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature); 00571 return feature; 00572 } 00573 00574 static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *glyphs, INT index, INT write_dir, INT* glyph_count, const char* feat) 00575 { 00576 LoadedFeature *feature; 00577 00578 feature = load_GSUB_feature(hdc, psa, psc, feat); 00579 if (!feature) 00580 return GSUB_E_NOFEATURE; 00581 00582 TRACE("applying feature %s\n",feat); 00583 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count); 00584 } 00585 00586 static VOID *load_gsub_table(HDC hdc) 00587 { 00588 VOID* GSUB_Table = NULL; 00589 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0); 00590 if (length != GDI_ERROR) 00591 { 00592 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length); 00593 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length); 00594 TRACE("Loaded GSUB table of %i bytes\n",length); 00595 } 00596 return GSUB_Table; 00597 } 00598 00599 INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, const WCHAR *chars, INT write_dir, INT count, const char* feature) 00600 { 00601 WORD *glyphs; 00602 INT glyph_count = count; 00603 INT rc; 00604 00605 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2)); 00606 GetGlyphIndicesW(hdc, chars, count, glyphs, 0); 00607 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature); 00608 if (rc > GSUB_E_NOGLYPH) 00609 rc = count - glyph_count; 00610 else 00611 rc = 0; 00612 00613 HeapFree(GetProcessHeap(),0,glyphs); 00614 return rc; 00615 } 00616 00617 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp) 00618 { 00619 int i; 00620 00621 for (i = 0; i < cGlyphs; i++) 00622 { 00623 if (!pGlyphProp[i].sva.fClusterStart) 00624 { 00625 int j; 00626 for (j = 0; j < cChars; j++) 00627 { 00628 if (pwLogClust[j] == i) 00629 { 00630 int k = j; 00631 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars) 00632 k-=1; 00633 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart) 00634 pwLogClust[j] = pwLogClust[k]; 00635 } 00636 } 00637 } 00638 } 00639 } 00640 00641 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust ) 00642 { 00643 if (changeCount == 0) 00644 return; 00645 else 00646 { 00647 int i; 00648 int target_glyph = nextIndex - write_dir; 00649 int seeking_glyph; 00650 int target_index = -1; 00651 int replacing_glyph = -1; 00652 int changed = 0; 00653 int top_logclust = 0; 00654 00655 if (changeCount > 0) 00656 { 00657 if (write_dir > 0) 00658 target_glyph = nextIndex - changeCount; 00659 else 00660 target_glyph = nextIndex + (changeCount + 1); 00661 } 00662 00663 seeking_glyph = target_glyph; 00664 for (i = 0; i < chars; i++) 00665 if (pwLogClust[i] > top_logclust) 00666 top_logclust = pwLogClust[i]; 00667 00668 do { 00669 if (write_dir > 0) 00670 for (i = 0; i < chars; i++) 00671 { 00672 if (pwLogClust[i] == seeking_glyph) 00673 { 00674 target_index = i; 00675 break; 00676 } 00677 } 00678 else 00679 for (i = chars - 1; i >= 0; i--) 00680 { 00681 if (pwLogClust[i] == seeking_glyph) 00682 { 00683 target_index = i; 00684 break; 00685 } 00686 } 00687 if (target_index == -1) 00688 seeking_glyph ++; 00689 } 00690 while (target_index == -1 && seeking_glyph <= top_logclust); 00691 00692 if (target_index == -1) 00693 { 00694 ERR("Unable to find target glyph\n"); 00695 return; 00696 } 00697 00698 if (changeCount < 0) 00699 { 00700 /* merge glyphs */ 00701 for(i = target_index; i < chars && i >= 0; i+=write_dir) 00702 { 00703 if (pwLogClust[i] == target_glyph) 00704 continue; 00705 if(pwLogClust[i] == replacing_glyph) 00706 pwLogClust[i] = target_glyph; 00707 else 00708 { 00709 changed--; 00710 if (changed >= changeCount) 00711 { 00712 replacing_glyph = pwLogClust[i]; 00713 pwLogClust[i] = target_glyph; 00714 } 00715 else 00716 break; 00717 } 00718 } 00719 00720 /* renumber trailing indexes*/ 00721 for(i = target_index; i < chars && i >= 0; i+=write_dir) 00722 { 00723 if (pwLogClust[i] != target_glyph) 00724 pwLogClust[i] += changeCount; 00725 } 00726 } 00727 else 00728 { 00729 for(i = target_index; i < chars && i >= 0; i+=write_dir) 00730 pwLogClust[i] += changeCount; 00731 } 00732 } 00733 } 00734 00735 static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *pwOutGlyphs, int write_dir, INT* pcGlyphs, INT cChars, const char* feat, WORD *pwLogClust ) 00736 { 00737 if (psc->GSUB_Table) 00738 { 00739 LoadedFeature *feature; 00740 int lookup_index; 00741 00742 feature = load_GSUB_feature(hdc, psa, psc, feat); 00743 if (!feature) 00744 return GSUB_E_NOFEATURE; 00745 00746 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count); 00747 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++) 00748 { 00749 int i; 00750 00751 if (write_dir > 0) 00752 i = 0; 00753 else 00754 i = *pcGlyphs-1; 00755 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count); 00756 while(i < *pcGlyphs && i >= 0) 00757 { 00758 INT nextIndex; 00759 INT prevCount = *pcGlyphs; 00760 00761 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs); 00762 if (*pcGlyphs != prevCount) 00763 { 00764 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust); 00765 i = nextIndex; 00766 } 00767 else 00768 i+=write_dir; 00769 } 00770 } 00771 return *pcGlyphs; 00772 } 00773 return GSUB_E_NOFEATURE; 00774 } 00775 00776 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc) 00777 { 00778 OPENTYPE_TAG tag; 00779 HRESULT hr; 00780 int count = 0; 00781 00782 hr = OpenType_GSUB_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count, NULL); 00783 00784 return(SUCCEEDED(hr)); 00785 } 00786 00787 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen) 00788 { 00789 if (i + delta < 0) 00790 return 0; 00791 if ( i+ delta >= cchLen) 00792 return 0; 00793 00794 i += delta; 00795 00796 return chars[i]; 00797 } 00798 00799 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa) 00800 { 00801 if (i + delta < 0) 00802 { 00803 if (psa->fLinkBefore) 00804 return jtR; 00805 else 00806 return jtU; 00807 } 00808 if ( i+ delta >= cchLen) 00809 { 00810 if (psa->fLinkAfter) 00811 return jtL; 00812 else 00813 return jtU; 00814 } 00815 00816 i += delta; 00817 00818 if (context_type[i] == jtT) 00819 return neighbour_joining_type(i,delta,context_type,cchLen,psa); 00820 else 00821 return context_type[i]; 00822 } 00823 00824 static inline BOOL right_join_causing(CHAR joining_type) 00825 { 00826 return (joining_type == jtL || joining_type == jtD || joining_type == jtC); 00827 } 00828 00829 static inline BOOL left_join_causing(CHAR joining_type) 00830 { 00831 return (joining_type == jtR || joining_type == jtD || joining_type == jtC); 00832 } 00833 00834 static inline BOOL word_break_causing(WCHAR chr) 00835 { 00836 /* we are working within a string of characters already guareented to 00837 be within one script, Syriac, so we do not worry about any character 00838 other than the space character outside of that range */ 00839 return (chr == 0 || chr == 0x20 ); 00840 } 00841 00842 /* 00843 * ContextualShape_Arabic 00844 */ 00845 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 00846 { 00847 CHAR *context_type; 00848 INT *context_shape; 00849 INT dirR, dirL; 00850 int i; 00851 00852 if (*pcGlyphs != cChars) 00853 { 00854 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 00855 return; 00856 } 00857 00858 if (!psa->fLogicalOrder && psa->fRTL) 00859 { 00860 dirR = 1; 00861 dirL = -1; 00862 } 00863 else 00864 { 00865 dirR = -1; 00866 dirL = 1; 00867 } 00868 00869 if (!psc->GSUB_Table) 00870 psc->GSUB_Table = load_gsub_table(hdc); 00871 00872 context_type = HeapAlloc(GetProcessHeap(),0,cChars); 00873 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars); 00874 00875 for (i = 0; i < cChars; i++) 00876 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] ); 00877 00878 for (i = 0; i < cChars; i++) 00879 { 00880 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa))) 00881 context_shape[i] = Xr; 00882 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa))) 00883 context_shape[i] = Xl; 00884 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)) && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa))) 00885 context_shape[i] = Xm; 00886 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa))) 00887 context_shape[i] = Xr; 00888 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa))) 00889 context_shape[i] = Xl; 00890 else 00891 context_shape[i] = Xn; 00892 } 00893 00894 /* Contextual Shaping */ 00895 i = 0; 00896 while(i < *pcGlyphs) 00897 { 00898 BOOL shaped = FALSE; 00899 00900 if (psc->GSUB_Table) 00901 { 00902 INT nextIndex; 00903 INT prevCount = *pcGlyphs; 00904 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]); 00905 if (nextIndex > GSUB_E_NOGLYPH) 00906 { 00907 i = nextIndex; 00908 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust); 00909 } 00910 shaped = (nextIndex > GSUB_E_NOGLYPH); 00911 } 00912 00913 if (!shaped) 00914 { 00915 if (context_shape[i] == Xn) 00916 { 00917 WORD newGlyph = pwOutGlyphs[i]; 00918 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR) 00919 { 00920 /* fall back to presentation form B */ 00921 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]]; 00922 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000) 00923 pwOutGlyphs[i] = newGlyph; 00924 } 00925 } 00926 i++; 00927 } 00928 } 00929 00930 HeapFree(GetProcessHeap(),0,context_shape); 00931 HeapFree(GetProcessHeap(),0,context_type); 00932 } 00933 00934 /* 00935 * ContextualShape_Syriac 00936 */ 00937 00938 #define ALAPH 0x710 00939 #define DALATH 0x715 00940 #define RISH 0x72A 00941 00942 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 00943 { 00944 CHAR *context_type; 00945 INT *context_shape; 00946 INT dirR, dirL; 00947 int i; 00948 00949 if (*pcGlyphs != cChars) 00950 { 00951 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 00952 return; 00953 } 00954 00955 if (!psa->fLogicalOrder && psa->fRTL) 00956 { 00957 dirR = 1; 00958 dirL = -1; 00959 } 00960 else 00961 { 00962 dirR = -1; 00963 dirL = 1; 00964 } 00965 00966 if (!psc->GSUB_Table) 00967 psc->GSUB_Table = load_gsub_table(hdc); 00968 00969 if (!psc->GSUB_Table) 00970 return; 00971 00972 context_type = HeapAlloc(GetProcessHeap(),0,cChars); 00973 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars); 00974 00975 for (i = 0; i < cChars; i++) 00976 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] ); 00977 00978 for (i = 0; i < cChars; i++) 00979 { 00980 if (pwcChars[i] == ALAPH) 00981 { 00982 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars); 00983 00984 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars))) 00985 context_shape[i] = Afj; 00986 else if ( rchar != DALATH && rchar != RISH && 00987 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && 00988 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars))) 00989 context_shape[i] = Afn; 00990 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars))) 00991 context_shape[i] = Afx; 00992 else 00993 context_shape[i] = Xn; 00994 } 00995 else if (context_type[i] == jtR && 00996 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa))) 00997 context_shape[i] = Xr; 00998 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa))) 00999 context_shape[i] = Xl; 01000 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)) && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa))) 01001 context_shape[i] = Xm; 01002 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa))) 01003 context_shape[i] = Xr; 01004 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa))) 01005 context_shape[i] = Xl; 01006 else 01007 context_shape[i] = Xn; 01008 } 01009 01010 /* Contextual Shaping */ 01011 i = 0; 01012 while(i < *pcGlyphs) 01013 { 01014 INT nextIndex; 01015 INT prevCount = *pcGlyphs; 01016 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]); 01017 if (nextIndex > GSUB_E_NOGLYPH) 01018 { 01019 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust); 01020 i = nextIndex; 01021 } 01022 else 01023 i++; 01024 } 01025 01026 HeapFree(GetProcessHeap(),0,context_shape); 01027 HeapFree(GetProcessHeap(),0,context_type); 01028 } 01029 01030 /* 01031 * ContextualShape_Phags_pa 01032 */ 01033 01034 #define phags_pa_CANDRABINDU 0xA873 01035 #define phags_pa_START 0xA840 01036 #define phags_pa_END 0xA87F 01037 01038 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 01039 { 01040 INT *context_shape; 01041 INT dirR, dirL; 01042 int i; 01043 01044 if (*pcGlyphs != cChars) 01045 { 01046 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 01047 return; 01048 } 01049 01050 if (!psa->fLogicalOrder && psa->fRTL) 01051 { 01052 dirR = 1; 01053 dirL = -1; 01054 } 01055 else 01056 { 01057 dirR = -1; 01058 dirL = 1; 01059 } 01060 01061 if (!psc->GSUB_Table) 01062 psc->GSUB_Table = load_gsub_table(hdc); 01063 01064 if (!psc->GSUB_Table) 01065 return; 01066 01067 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars); 01068 01069 for (i = 0; i < cChars; i++) 01070 { 01071 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END) 01072 { 01073 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars); 01074 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars); 01075 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END); 01076 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END); 01077 01078 if (jrchar && jlchar) 01079 context_shape[i] = Xm; 01080 else if (jrchar) 01081 context_shape[i] = Xr; 01082 else if (jlchar) 01083 context_shape[i] = Xl; 01084 else 01085 context_shape[i] = Xn; 01086 } 01087 else 01088 context_shape[i] = -1; 01089 } 01090 01091 /* Contextual Shaping */ 01092 i = 0; 01093 while(i < *pcGlyphs) 01094 { 01095 if (context_shape[i] >= 0) 01096 { 01097 INT nextIndex; 01098 INT prevCount = *pcGlyphs; 01099 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]); 01100 if (nextIndex > GSUB_E_NOGLYPH) 01101 { 01102 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust); 01103 i = nextIndex; 01104 } 01105 else 01106 i++; 01107 } 01108 else 01109 i++; 01110 } 01111 01112 HeapFree(GetProcessHeap(),0,context_shape); 01113 } 01114 01115 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements) 01116 { 01117 int i; 01118 01119 /* Replace */ 01120 pwOutChars[cWalk] = replacements[0]; 01121 cWalk=cWalk+1; 01122 01123 /* Insert */ 01124 for (i = 1; replacements[i] != 0x0000 && i < 3; i++) 01125 { 01126 int j; 01127 for (j = *pcChars; j > cWalk; j--) 01128 pwOutChars[j] = pwOutChars[j-1]; 01129 *pcChars= *pcChars+1; 01130 pwOutChars[cWalk] = replacements[i]; 01131 cWalk = cWalk+1; 01132 } 01133 } 01134 01135 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars) 01136 { 01137 int i; 01138 int cWalk; 01139 01140 for (cWalk = 0; cWalk < *pcChars; cWalk++) 01141 { 01142 for (i = 0; vowels[i].base != 0x0; i++) 01143 { 01144 if (pwOutChars[cWalk] == vowels[i].base) 01145 { 01146 int o = 0; 01147 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts); 01148 if (vowels[i].parts[1]) { cWalk++; o++; } 01149 if (vowels[i].parts[2]) { cWalk++; o++; } 01150 UpdateClusters(cWalk, o, 1, cChars, pwLogClust); 01151 break; 01152 } 01153 } 01154 } 01155 } 01156 01157 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust) 01158 { 01159 int i; 01160 int offset = 0; 01161 int cWalk; 01162 01163 for (cWalk = 0; cWalk < *pcChars; cWalk++) 01164 { 01165 for (i = 0; consonants[i].output!= 0x0; i++) 01166 { 01167 int j; 01168 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++) 01169 if (pwOutChars[cWalk+j] != consonants[i].parts[j]) 01170 break; 01171 01172 if (consonants[i].parts[j]==0x0) /* matched all */ 01173 { 01174 int k; 01175 j--; 01176 pwOutChars[cWalk] = consonants[i].output; 01177 for(k = cWalk+1; k < *pcChars - j; k++) 01178 pwOutChars[k] = pwOutChars[k+j]; 01179 *pcChars = *pcChars - j; 01180 for (k = j ; k > 0; k--) 01181 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset]; 01182 offset += j; 01183 for (k = cWalk + j + offset; k < *pcChars + offset; k++) 01184 pwLogClust[k]--; 01185 break; 01186 } 01187 } 01188 cWalk++; 01189 } 01190 } 01191 01192 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical) 01193 { 01194 if (s->ralf >= 0) 01195 { 01196 int j; 01197 WORD Ra = pwChar[s->start]; 01198 WORD H = pwChar[s->start+1]; 01199 01200 TRACE("Doing reorder of Ra to %i\n",s->base); 01201 for (j = s->start; j < s->base-1; j++) 01202 pwChar[j] = pwChar[j+2]; 01203 pwChar[s->base-1] = Ra; 01204 pwChar[s->base] = H; 01205 01206 s->ralf = s->base-1; 01207 s->base -= 2; 01208 } 01209 } 01210 01211 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical) 01212 { 01213 if (s->ralf >= 0) 01214 { 01215 int j,loc; 01216 int stop = (s->blwf >=0)? s->blwf+1 : s->base; 01217 WORD Ra = pwChar[s->start]; 01218 WORD H = pwChar[s->start+1]; 01219 for (loc = s->end; loc > stop; loc--) 01220 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below) 01221 break; 01222 01223 TRACE("Doing reorder of Ra to %i\n",loc); 01224 for (j = s->start; j < loc-1; j++) 01225 pwChar[j] = pwChar[j+2]; 01226 pwChar[loc-1] = Ra; 01227 pwChar[loc] = H; 01228 01229 s->ralf = loc-1; 01230 s->base -= 2; 01231 if (s->blwf >= 0) s->blwf -= 2; 01232 if (s->pref >= 0) s->pref -= 2; 01233 } 01234 } 01235 01236 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical) 01237 { 01238 if (s->ralf >= 0) 01239 { 01240 int j; 01241 WORD Ra = pwChar[s->start]; 01242 WORD H = pwChar[s->start+1]; 01243 01244 TRACE("Doing reorder of Ra to %i\n",s->end-1); 01245 for (j = s->start; j < s->end-1; j++) 01246 pwChar[j] = pwChar[j+2]; 01247 pwChar[s->end-1] = Ra; 01248 pwChar[s->end] = H; 01249 01250 s->ralf = s->end-1; 01251 s->base -= 2; 01252 if (s->blwf >= 0) s->blwf -= 2; 01253 if (s->pref >= 0) s->pref -= 2; 01254 } 01255 } 01256 01257 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical) 01258 { 01259 int i; 01260 01261 /* reorder Matras */ 01262 if (s->end > s->base) 01263 { 01264 for (i = 1; i <= s->end-s->base; i++) 01265 { 01266 if (lexical(pwChar[s->base+i]) == lex_Matra_pre) 01267 { 01268 int j; 01269 WCHAR c = pwChar[s->base+i]; 01270 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]); 01271 for (j = s->base+i; j > s->base; j--) 01272 pwChar[j] = pwChar[j-1]; 01273 pwChar[s->base] = c; 01274 01275 if (s->ralf >= s->base) s->ralf++; 01276 if (s->blwf >= s->base) s->blwf++; 01277 if (s->pref >= s->base) s->pref++; 01278 s->base ++; 01279 } 01280 } 01281 } 01282 } 01283 01284 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical) 01285 { 01286 int i; 01287 01288 /* reorder Matras */ 01289 if (s->end > s->base) 01290 { 01291 for (i = 1; i <= s->end-s->base; i++) 01292 { 01293 if (lexical(pwChar[s->base+i]) == lex_Matra_pre) 01294 { 01295 int j; 01296 WCHAR c = pwChar[s->base+i]; 01297 TRACE("Doing reorder of %x to %i\n",c,s->start); 01298 for (j = s->base+i; j > s->start; j--) 01299 pwChar[j] = pwChar[j-1]; 01300 pwChar[s->start] = c; 01301 01302 if (s->ralf >= 0) s->ralf++; 01303 if (s->blwf >= 0) s->blwf++; 01304 if (s->pref >= 0) s->pref++; 01305 s->base ++; 01306 } 01307 } 01308 } 01309 } 01310 01311 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical) 01312 { 01313 if (s->blwf >= 0 && g->blwf > g->base) 01314 { 01315 int j,loc; 01316 int g_offset; 01317 for (loc = s->end; loc > s->blwf; loc--) 01318 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post) 01319 break; 01320 01321 g_offset = (loc - s->blwf) - 1; 01322 01323 if (loc != s->blwf) 01324 { 01325 WORD blwf = glyphs[g->blwf]; 01326 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset); 01327 /* do not care about the pwChar array anymore, just the glyphs */ 01328 for (j = 0; j < g_offset; j++) 01329 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1]; 01330 glyphs[g->blwf + g_offset] = blwf; 01331 } 01332 } 01333 } 01334 01335 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical) 01336 { 01337 int i; 01338 01339 /* reorder previously moved Matras to correct position*/ 01340 for (i = s->start; i < s->base; i++) 01341 { 01342 if (lexical(pwChar[i]) == lex_Matra_pre) 01343 { 01344 int j; 01345 int g_start = g->start + i - s->start; 01346 if (g_start < g->base -1 ) 01347 { 01348 WCHAR og = glyphs[g_start]; 01349 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base); 01350 for (j = g_start; j < g->base-1; j++) 01351 glyphs[j] = glyphs[j+1]; 01352 glyphs[g->base-1] = og; 01353 } 01354 } 01355 } 01356 } 01357 01358 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical) 01359 { 01360 if (s->pref >= 0 && g->pref > g->base) 01361 { 01362 int j; 01363 WCHAR og = glyphs[g->pref]; 01364 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base); 01365 for (j = g->pref; j > g->base; j--) 01366 glyphs[j] = glyphs[j-1]; 01367 glyphs[g->base] = og; 01368 } 01369 } 01370 01371 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical) 01372 { 01373 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end); 01374 if (s->start == s->base && s->base == s->end) return; 01375 if (lexical(pwChar[s->base]) == lex_Vowel) return; 01376 01377 Reorder_Ra_follows_base(pwChar, s, lexical); 01378 Reorder_Matra_precede_base(pwChar, s, lexical); 01379 } 01380 01381 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical) 01382 { 01383 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end); 01384 if (s->start == s->base && s->base == s->end) return; 01385 if (lexical(pwChar[s->base]) == lex_Vowel) return; 01386 01387 Reorder_Ra_follows_matra(pwChar, s, lexical); 01388 Reorder_Matra_precede_syllable(pwChar, s, lexical); 01389 } 01390 01391 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical) 01392 { 01393 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end); 01394 if (s->start == s->base && s->base == s->end) return; 01395 if (lexical(pwChar[s->base]) == lex_Vowel) return; 01396 01397 Reorder_Ra_follows_base(pwChar, s, lexical); 01398 Reorder_Matra_precede_syllable(pwChar, s, lexical); 01399 } 01400 01401 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical) 01402 { 01403 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end); 01404 if (s->start == s->base && s->base == s->end) return; 01405 if (lexical(pwChar[s->base]) == lex_Vowel) return; 01406 01407 Reorder_Ra_follows_syllable(pwChar, s, lexical); 01408 Reorder_Matra_precede_syllable(pwChar, s, lexical); 01409 } 01410 01411 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical) 01412 { 01413 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end); 01414 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end); 01415 if (s->start == s->base && s->base == s->end) return; 01416 if (lexical(pwChar[s->base]) == lex_Vowel) return; 01417 01418 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical); 01419 } 01420 01421 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical) 01422 { 01423 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end); 01424 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end); 01425 if (s->start == s->base && s->base == s->end) return; 01426 if (lexical(pwChar[s->base]) == lex_Vowel) return; 01427 01428 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical); 01429 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical); 01430 } 01431 01432 01433 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift) 01434 { 01435 if (shift == 0) 01436 return; 01437 01438 if (glyph_index->start > index) 01439 glyph_index->start += shift; 01440 if (glyph_index->base > index) 01441 glyph_index->base+= shift; 01442 if (glyph_index->end > index) 01443 glyph_index->end+= shift; 01444 if (glyph_index->ralf > index) 01445 glyph_index->ralf+= shift; 01446 if (glyph_index->blwf > index) 01447 glyph_index->blwf+= shift; 01448 if (glyph_index->pref > index) 01449 glyph_index->pref+= shift; 01450 } 01451 01452 static void Apply_Indic_BasicForm(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, LoadedFeature *feature ) 01453 { 01454 int index = glyph_index->start; 01455 01456 if (!feature) 01457 return; 01458 01459 while(index <= glyph_index->end) 01460 { 01461 INT nextIndex; 01462 INT prevCount = *pcGlyphs; 01463 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs); 01464 if (nextIndex > GSUB_E_NOGLYPH) 01465 { 01466 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust); 01467 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount); 01468 index = nextIndex; 01469 } 01470 else 01471 index++; 01472 } 01473 } 01474 01475 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical) 01476 { 01477 int i = 0; 01478 while (i + index < end - 1 && !(is_consonant(lexical(pwChars[index+i])) && (lexical(pwChars[index+i+1]) == lex_Halant || (index + i < end - 2 && lexical(pwChars[index+i+1]) == lex_Nukta && lexical(pwChars[index+i+2] == lex_Halant))))) 01479 i++; 01480 if (index + i <= end-1) 01481 return index + i; 01482 else 01483 return -1; 01484 } 01485 01486 static void Apply_Indic_PreBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, const char* feature) 01487 { 01488 INT index, nextIndex; 01489 INT count,g_offset; 01490 01491 count = syllable->base - syllable->start; 01492 01493 g_offset = 0; 01494 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical); 01495 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start)) 01496 { 01497 INT prevCount = *pcGlyphs; 01498 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature); 01499 if (nextIndex > GSUB_E_NOGLYPH) 01500 { 01501 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust); 01502 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount)); 01503 g_offset += (*pcGlyphs - prevCount); 01504 } 01505 01506 index+=2; 01507 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical); 01508 } 01509 } 01510 01511 static void Apply_Indic_Rphf(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index) 01512 { 01513 INT nextIndex; 01514 INT prevCount = *pcGlyphs; 01515 01516 if (syllable->ralf >= 0) 01517 { 01518 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf"); 01519 if (nextIndex > GSUB_E_NOGLYPH) 01520 { 01521 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust); 01522 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount); 01523 } 01524 } 01525 } 01526 01527 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical) 01528 { 01529 int i = 0; 01530 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant && 01531 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) || 01532 is_consonant(lexical(pwChars[index+i+1]))))) 01533 i++; 01534 if (index + i <= end-1) 01535 return index+i; 01536 else 01537 return -1; 01538 } 01539 01540 static void Apply_Indic_PostBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, BOOL modern, const char* feat) 01541 { 01542 INT index, nextIndex; 01543 INT count, g_offset=0; 01544 INT ralf = syllable->ralf; 01545 01546 count = syllable->end - syllable->base; 01547 01548 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical); 01549 01550 while (index >= 0) 01551 { 01552 INT prevCount = *pcGlyphs; 01553 if (ralf >=0 && ralf < index) 01554 { 01555 g_offset--; 01556 ralf = -1; 01557 } 01558 01559 if (!modern) 01560 { 01561 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset]; 01562 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1]; 01563 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g; 01564 } 01565 01566 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat); 01567 if (nextIndex > GSUB_E_NOGLYPH) 01568 { 01569 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust); 01570 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount)); 01571 g_offset += (*pcGlyphs - prevCount); 01572 } 01573 else if (!modern) 01574 { 01575 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset]; 01576 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1]; 01577 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g; 01578 } 01579 01580 index+=2; 01581 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical); 01582 } 01583 } 01584 01585 static void ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllables, INT syllable_count, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, second_reorder_function second_reorder, BOOL modern) 01586 { 01587 int c; 01588 int overall_shift = 0; 01589 LoadedFeature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL; 01590 LoadedFeature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt"); 01591 LoadedFeature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn"); 01592 LoadedFeature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL; 01593 LoadedFeature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf"); 01594 LoadedFeature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL; 01595 LoadedFeature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL; 01596 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL); 01597 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL); 01598 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL); 01599 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL); 01600 IndicSyllable glyph_indexs; 01601 01602 for (c = 0; c < syllable_count; c++) 01603 { 01604 int old_end; 01605 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable)); 01606 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift); 01607 old_end = glyph_indexs.end; 01608 01609 if (locl) 01610 { 01611 TRACE("applying feature locl\n"); 01612 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl); 01613 } 01614 if (nukt) 01615 { 01616 TRACE("applying feature nukt\n"); 01617 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt); 01618 } 01619 if (akhn) 01620 { 01621 TRACE("applying feature akhn\n"); 01622 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn); 01623 } 01624 01625 if (rphf) 01626 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs); 01627 if (rkrf) 01628 { 01629 TRACE("applying feature rkrf\n"); 01630 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf); 01631 } 01632 if (pref) 01633 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref"); 01634 if (blwf) 01635 { 01636 if (!modern) 01637 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf"); 01638 01639 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf"); 01640 01641 } 01642 if (half) 01643 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half"); 01644 if (pstf) 01645 { 01646 TRACE("applying feature pstf\n"); 01647 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf); 01648 } 01649 if (vatu) 01650 { 01651 TRACE("applying feature vatu\n"); 01652 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu); 01653 } 01654 if (cjct) 01655 { 01656 TRACE("applying feature cjct\n"); 01657 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct); 01658 } 01659 01660 if (second_reorder) 01661 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical); 01662 01663 overall_shift += glyph_indexs.end - old_end; 01664 } 01665 } 01666 01667 static inline int unicode_lex(WCHAR c) 01668 { 01669 int type; 01670 01671 if (!c) return lex_Generic; 01672 if (c == 0x200D) return lex_ZWJ; 01673 if (c == 0x200C) return lex_ZWNJ; 01674 if (c == 0x00A0) return lex_NBSP; 01675 01676 type = get_table_entry( indic_syllabic_table, c ); 01677 01678 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff; 01679 01680 switch( type ) 01681 { 01682 case 0x0d07: /* Unknown */ 01683 case 0x0e07: /* Unknwon */ 01684 default: return lex_Generic; 01685 case 0x0001: 01686 case 0x0002: 01687 case 0x0011: 01688 case 0x0012: 01689 case 0x0013: 01690 case 0x0014: return lex_Modifier; 01691 case 0x0003: 01692 case 0x0009: 01693 case 0x000a: 01694 case 0x000b: 01695 case 0x000d: 01696 case 0x000e: 01697 case 0x000f: 01698 case 0x0010: return lex_Consonant; 01699 case 0x0004: return lex_Nukta; 01700 case 0x0005: return lex_Halant; 01701 case 0x0006: 01702 case 0x0008: return lex_Vowel; 01703 case 0x0007: 01704 case 0x0107: return lex_Matra_post; 01705 case 0x0207: 01706 case 0x0307: return lex_Matra_pre; 01707 case 0x0807: 01708 case 0x0907: 01709 case 0x0a07: 01710 case 0x0b07: 01711 case 0x0c07: 01712 case 0x0407: return lex_Composed_Vowel; 01713 case 0x0507: return lex_Matra_above; 01714 case 0x0607: return lex_Matra_below; 01715 case 0x000c: return lex_Ra; 01716 }; 01717 } 01718 01719 static int sinhala_lex(WCHAR c) 01720 { 01721 switch (c) 01722 { 01723 case 0x0DDA: 01724 case 0x0DDD: 01725 case 0x0DDC: 01726 case 0x0DDE: return lex_Matra_post; 01727 default: 01728 return unicode_lex(c); 01729 } 01730 } 01731 01732 static const VowelComponents Sinhala_vowels[] = { 01733 {0x0DDA, {0x0DD9,0x0DDA,0x0}}, 01734 {0x0DDC, {0x0DD9,0x0DDC,0x0}}, 01735 {0x0DDD, {0x0DD9,0x0DDD,0x0}}, 01736 {0x0DDE, {0x0DD9,0x0DDE,0x0}}, 01737 {0x0000, {0x0000,0x0000,0x0}}}; 01738 01739 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 01740 { 01741 int cCount = cChars; 01742 int i; 01743 WCHAR *input; 01744 IndicSyllable *syllables = NULL; 01745 int syllable_count = 0; 01746 01747 if (*pcGlyphs != cChars) 01748 { 01749 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 01750 return; 01751 } 01752 01753 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3)); 01754 01755 memcpy(input, pwcChars, cChars * sizeof(WCHAR)); 01756 01757 /* Step 1: Decompose multi part vowels */ 01758 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars); 01759 01760 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount); 01761 01762 /* Step 2: Reorder within Syllables */ 01763 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE); 01764 TRACE("reordered string %s\n",debugstr_wn(input,cCount)); 01765 01766 /* Step 3: Strip dangling joiners */ 01767 for (i = 0; i < cCount; i++) 01768 { 01769 if ((input[i] == 0x200D || input[i] == 0x200C) && 01770 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020)) 01771 input[i] = 0x0020; 01772 } 01773 01774 /* Step 4: Base Form application to syllables */ 01775 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0); 01776 *pcGlyphs = cCount; 01777 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE); 01778 01779 HeapFree(GetProcessHeap(),0,input); 01780 HeapFree(GetProcessHeap(),0,syllables); 01781 } 01782 01783 static int devanagari_lex(WCHAR c) 01784 { 01785 switch (c) 01786 { 01787 case 0x0930: return lex_Ra; 01788 default: 01789 return unicode_lex(c); 01790 } 01791 } 01792 01793 static const ConsonantComponents Devanagari_consonants[] ={ 01794 {{0x0928, 0x093C, 0x00000}, 0x0929}, 01795 {{0x0930, 0x093C, 0x00000}, 0x0931}, 01796 {{0x0933, 0x093C, 0x00000}, 0x0934}, 01797 {{0x0915, 0x093C, 0x00000}, 0x0958}, 01798 {{0x0916, 0x093C, 0x00000}, 0x0959}, 01799 {{0x0917, 0x093C, 0x00000}, 0x095A}, 01800 {{0x091C, 0x093C, 0x00000}, 0x095B}, 01801 {{0x0921, 0x093C, 0x00000}, 0x095C}, 01802 {{0x0922, 0x093C, 0x00000}, 0x095D}, 01803 {{0x092B, 0x093C, 0x00000}, 0x095E}, 01804 {{0x092F, 0x093C, 0x00000}, 0x095F}}; 01805 01806 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 01807 { 01808 int cCount = cChars; 01809 WCHAR *input; 01810 IndicSyllable *syllables = NULL; 01811 int syllable_count = 0; 01812 BOOL modern = get_GSUB_Indic2(psa, psc); 01813 01814 if (*pcGlyphs != cChars) 01815 { 01816 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 01817 return; 01818 } 01819 01820 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR)); 01821 memcpy(input, pwcChars, cChars * sizeof(WCHAR)); 01822 01823 /* Step 1: Compose Consonant and Nukta */ 01824 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust); 01825 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount); 01826 01827 /* Step 2: Reorder within Syllables */ 01828 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern); 01829 TRACE("reordered string %s\n",debugstr_wn(input,cCount)); 01830 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0); 01831 *pcGlyphs = cCount; 01832 01833 /* Step 3: Base Form application to syllables */ 01834 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern); 01835 01836 HeapFree(GetProcessHeap(),0,input); 01837 HeapFree(GetProcessHeap(),0,syllables); 01838 } 01839 01840 static int bengali_lex(WCHAR c) 01841 { 01842 switch (c) 01843 { 01844 case 0x09B0: return lex_Ra; 01845 default: 01846 return unicode_lex(c); 01847 } 01848 } 01849 01850 static const VowelComponents Bengali_vowels[] = { 01851 {0x09CB, {0x09C7,0x09BE,0x0000}}, 01852 {0x09CC, {0x09C7,0x09D7,0x0000}}, 01853 {0x0000, {0x0000,0x0000,0x0000}}}; 01854 01855 static const ConsonantComponents Bengali_consonants[] = { 01856 {{0x09A4,0x09CD,0x200D}, 0x09CE}, 01857 {{0x09A1,0x09BC,0x0000}, 0x09DC}, 01858 {{0x09A2,0x09BC,0x0000}, 0x09DD}, 01859 {{0x09AF,0x09BC,0x0000}, 0x09DF}, 01860 {{0x0000,0x0000,0x0000}, 0x0000}}; 01861 01862 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 01863 { 01864 int cCount = cChars; 01865 WCHAR *input; 01866 IndicSyllable *syllables = NULL; 01867 int syllable_count = 0; 01868 BOOL modern = get_GSUB_Indic2(psa, psc); 01869 01870 if (*pcGlyphs != cChars) 01871 { 01872 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 01873 return; 01874 } 01875 01876 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR)); 01877 memcpy(input, pwcChars, cChars * sizeof(WCHAR)); 01878 01879 /* Step 1: Decompose Vowels and Compose Consonents */ 01880 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars); 01881 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust); 01882 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount); 01883 01884 /* Step 2: Reorder within Syllables */ 01885 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern); 01886 TRACE("reordered string %s\n",debugstr_wn(input,cCount)); 01887 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0); 01888 *pcGlyphs = cCount; 01889 01890 /* Step 3: Initial form is only applied to the beginning of words */ 01891 for (cCount = cCount - 1 ; cCount >= 0; cCount --) 01892 { 01893 if (cCount == 0 || input[cCount] == 0x0020) /* space */ 01894 { 01895 int index = cCount; 01896 int gCount = 1; 01897 if (index > 0) index++; 01898 01899 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init"); 01900 } 01901 } 01902 01903 /* Step 4: Base Form application to syllables */ 01904 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern); 01905 01906 HeapFree(GetProcessHeap(),0,input); 01907 HeapFree(GetProcessHeap(),0,syllables); 01908 } 01909 01910 static int gurmukhi_lex(WCHAR c) 01911 { 01912 if (c == 0x0A71) 01913 return lex_Modifier; 01914 else 01915 return unicode_lex(c); 01916 } 01917 01918 static const ConsonantComponents Gurmukhi_consonants[] = { 01919 {{0x0A32,0x0A3C,0x0000}, 0x0A33}, 01920 {{0x0A16,0x0A3C,0x0000}, 0x0A59}, 01921 {{0x0A17,0x0A3C,0x0000}, 0x0A5A}, 01922 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B}, 01923 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E}, 01924 {{0x0000,0x0000,0x0000}, 0x0000}}; 01925 01926 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 01927 { 01928 int cCount = cChars; 01929 WCHAR *input; 01930 IndicSyllable *syllables = NULL; 01931 int syllable_count = 0; 01932 BOOL modern = get_GSUB_Indic2(psa, psc); 01933 01934 if (*pcGlyphs != cChars) 01935 { 01936 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 01937 return; 01938 } 01939 01940 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR)); 01941 memcpy(input, pwcChars, cChars * sizeof(WCHAR)); 01942 01943 /* Step 1: Compose Consonents */ 01944 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust); 01945 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount); 01946 01947 /* Step 2: Reorder within Syllables */ 01948 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern); 01949 TRACE("reordered string %s\n",debugstr_wn(input,cCount)); 01950 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0); 01951 *pcGlyphs = cCount; 01952 01953 /* Step 3: Base Form application to syllables */ 01954 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern); 01955 01956 HeapFree(GetProcessHeap(),0,input); 01957 HeapFree(GetProcessHeap(),0,syllables); 01958 } 01959 01960 static int gujarati_lex(WCHAR c) 01961 { 01962 switch (c) 01963 { 01964 case 0x0AB0: return lex_Ra; 01965 default: 01966 return unicode_lex(c); 01967 } 01968 } 01969 01970 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 01971 { 01972 int cCount = cChars; 01973 WCHAR *input; 01974 IndicSyllable *syllables = NULL; 01975 int syllable_count = 0; 01976 BOOL modern = get_GSUB_Indic2(psa, psc); 01977 01978 if (*pcGlyphs != cChars) 01979 { 01980 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 01981 return; 01982 } 01983 01984 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR)); 01985 memcpy(input, pwcChars, cChars * sizeof(WCHAR)); 01986 01987 /* Step 1: Reorder within Syllables */ 01988 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern); 01989 TRACE("reordered string %s\n",debugstr_wn(input,cCount)); 01990 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0); 01991 *pcGlyphs = cCount; 01992 01993 /* Step 2: Base Form application to syllables */ 01994 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern); 01995 01996 HeapFree(GetProcessHeap(),0,input); 01997 HeapFree(GetProcessHeap(),0,syllables); 01998 } 01999 02000 static int oriya_lex(WCHAR c) 02001 { 02002 switch (c) 02003 { 02004 case 0x0B30: return lex_Ra; 02005 default: 02006 return unicode_lex(c); 02007 } 02008 } 02009 02010 static const VowelComponents Oriya_vowels[] = { 02011 {0x0B48, {0x0B47,0x0B56,0x0000}}, 02012 {0x0B4B, {0x0B47,0x0B3E,0x0000}}, 02013 {0x0B4C, {0x0B47,0x0B57,0x0000}}, 02014 {0x0000, {0x0000,0x0000,0x0000}}}; 02015 02016 static const ConsonantComponents Oriya_consonants[] = { 02017 {{0x0B21,0x0B3C,0x0000}, 0x0B5C}, 02018 {{0x0B22,0x0B3C,0x0000}, 0x0B5D}, 02019 {{0x0000,0x0000,0x0000}, 0x0000}}; 02020 02021 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 02022 { 02023 int cCount = cChars; 02024 WCHAR *input; 02025 IndicSyllable *syllables = NULL; 02026 int syllable_count = 0; 02027 BOOL modern = get_GSUB_Indic2(psa, psc); 02028 02029 if (*pcGlyphs != cChars) 02030 { 02031 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 02032 return; 02033 } 02034 02035 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR)); 02036 memcpy(input, pwcChars, cChars * sizeof(WCHAR)); 02037 02038 /* Step 1: Decompose Vowels and Compose Consonents */ 02039 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars); 02040 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust); 02041 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount); 02042 02043 /* Step 2: Reorder within Syllables */ 02044 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern); 02045 TRACE("reordered string %s\n",debugstr_wn(input,cCount)); 02046 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0); 02047 *pcGlyphs = cCount; 02048 02049 /* Step 3: Base Form application to syllables */ 02050 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern); 02051 02052 HeapFree(GetProcessHeap(),0,input); 02053 HeapFree(GetProcessHeap(),0,syllables); 02054 } 02055 02056 static int tamil_lex(WCHAR c) 02057 { 02058 return unicode_lex(c); 02059 } 02060 02061 static const VowelComponents Tamil_vowels[] = { 02062 {0x0BCA, {0x0BC6,0x0BBE,0x0000}}, 02063 {0x0BCB, {0x0BC7,0x0BBE,0x0000}}, 02064 {0x0BCB, {0x0BC6,0x0BD7,0x0000}}, 02065 {0x0000, {0x0000,0x0000,0x0000}}}; 02066 02067 static const ConsonantComponents Tamil_consonants[] = { 02068 {{0x0B92,0x0BD7,0x0000}, 0x0B94}, 02069 {{0x0000,0x0000,0x0000}, 0x0000}}; 02070 02071 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 02072 { 02073 int cCount = cChars; 02074 WCHAR *input; 02075 IndicSyllable *syllables = NULL; 02076 int syllable_count = 0; 02077 BOOL modern = get_GSUB_Indic2(psa, psc); 02078 02079 if (*pcGlyphs != cChars) 02080 { 02081 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 02082 return; 02083 } 02084 02085 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR)); 02086 memcpy(input, pwcChars, cChars * sizeof(WCHAR)); 02087 02088 /* Step 1: Decompose Vowels and Compose Consonents */ 02089 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars); 02090 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust); 02091 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount); 02092 02093 /* Step 2: Reorder within Syllables */ 02094 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern); 02095 TRACE("reordered string %s\n",debugstr_wn(input,cCount)); 02096 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0); 02097 *pcGlyphs = cCount; 02098 02099 /* Step 3: Base Form application to syllables */ 02100 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern); 02101 02102 HeapFree(GetProcessHeap(),0,input); 02103 HeapFree(GetProcessHeap(),0,syllables); 02104 } 02105 02106 static int telugu_lex(WCHAR c) 02107 { 02108 switch (c) 02109 { 02110 case 0x0C43: 02111 case 0x0C44: return lex_Modifier; 02112 default: 02113 return unicode_lex(c); 02114 } 02115 } 02116 02117 static const VowelComponents Telugu_vowels[] = { 02118 {0x0C48, {0x0C46,0x0C56,0x0000}}, 02119 {0x0000, {0x0000,0x0000,0x0000}}}; 02120 02121 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 02122 { 02123 int cCount = cChars; 02124 WCHAR *input; 02125 IndicSyllable *syllables = NULL; 02126 int syllable_count = 0; 02127 BOOL modern = get_GSUB_Indic2(psa, psc); 02128 02129 if (*pcGlyphs != cChars) 02130 { 02131 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 02132 return; 02133 } 02134 02135 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR)); 02136 memcpy(input, pwcChars, cChars * sizeof(WCHAR)); 02137 02138 /* Step 1: Decompose Vowels */ 02139 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars); 02140 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount); 02141 02142 /* Step 2: Reorder within Syllables */ 02143 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern); 02144 TRACE("reordered string %s\n",debugstr_wn(input,cCount)); 02145 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0); 02146 *pcGlyphs = cCount; 02147 02148 /* Step 3: Base Form application to syllables */ 02149 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern); 02150 02151 HeapFree(GetProcessHeap(),0,input); 02152 HeapFree(GetProcessHeap(),0,syllables); 02153 } 02154 02155 static int kannada_lex(WCHAR c) 02156 { 02157 switch (c) 02158 { 02159 case 0x0CB0: return lex_Ra; 02160 default: 02161 return unicode_lex(c); 02162 } 02163 } 02164 02165 static const VowelComponents Kannada_vowels[] = { 02166 {0x0CC0, {0x0CBF,0x0CD5,0x0000}}, 02167 {0x0CC7, {0x0CC6,0x0CD5,0x0000}}, 02168 {0x0CC8, {0x0CC6,0x0CD6,0x0000}}, 02169 {0x0CCA, {0x0CC6,0x0CC2,0x0000}}, 02170 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}}, 02171 {0x0000, {0x0000,0x0000,0x0000}}}; 02172 02173 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 02174 { 02175 int cCount = cChars; 02176 WCHAR *input; 02177 IndicSyllable *syllables = NULL; 02178 int syllable_count = 0; 02179 BOOL modern = get_GSUB_Indic2(psa, psc); 02180 02181 if (*pcGlyphs != cChars) 02182 { 02183 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 02184 return; 02185 } 02186 02187 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR)); 02188 memcpy(input, pwcChars, cChars * sizeof(WCHAR)); 02189 02190 /* Step 1: Decompose Vowels */ 02191 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars); 02192 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount); 02193 02194 /* Step 2: Reorder within Syllables */ 02195 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern); 02196 TRACE("reordered string %s\n",debugstr_wn(input,cCount)); 02197 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0); 02198 *pcGlyphs = cCount; 02199 02200 /* Step 3: Base Form application to syllables */ 02201 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern); 02202 02203 HeapFree(GetProcessHeap(),0,input); 02204 HeapFree(GetProcessHeap(),0,syllables); 02205 } 02206 02207 static int malayalam_lex(WCHAR c) 02208 { 02209 return unicode_lex(c); 02210 } 02211 02212 static const VowelComponents Malayalam_vowels[] = { 02213 {0x0D4A, {0x0D46,0x0D3E,0x0000}}, 02214 {0x0D4B, {0x0D47,0x0D3E,0x0000}}, 02215 {0x0D4C, {0x0D46,0x0D57,0x0000}}, 02216 {0x0000, {0x0000,0x0000,0x0000}}}; 02217 02218 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 02219 { 02220 int cCount = cChars; 02221 WCHAR *input; 02222 IndicSyllable *syllables = NULL; 02223 int syllable_count = 0; 02224 BOOL modern = get_GSUB_Indic2(psa, psc); 02225 02226 if (*pcGlyphs != cChars) 02227 { 02228 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 02229 return; 02230 } 02231 02232 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR)); 02233 memcpy(input, pwcChars, cChars * sizeof(WCHAR)); 02234 02235 /* Step 1: Decompose Vowels */ 02236 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars); 02237 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount); 02238 02239 /* Step 2: Reorder within Syllables */ 02240 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern); 02241 TRACE("reordered string %s\n",debugstr_wn(input,cCount)); 02242 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0); 02243 *pcGlyphs = cCount; 02244 02245 /* Step 3: Base Form application to syllables */ 02246 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern); 02247 02248 HeapFree(GetProcessHeap(),0,input); 02249 HeapFree(GetProcessHeap(),0,syllables); 02250 } 02251 02252 static int khmer_lex(WCHAR c) 02253 { 02254 return unicode_lex(c); 02255 } 02256 02257 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 02258 { 02259 int cCount = cChars; 02260 WCHAR *input; 02261 IndicSyllable *syllables = NULL; 02262 int syllable_count = 0; 02263 02264 if (*pcGlyphs != cChars) 02265 { 02266 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 02267 return; 02268 } 02269 02270 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR)); 02271 memcpy(input, pwcChars, cChars * sizeof(WCHAR)); 02272 02273 /* Step 1: Reorder within Syllables */ 02274 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE); 02275 TRACE("reordered string %s\n",debugstr_wn(input,cCount)); 02276 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0); 02277 *pcGlyphs = cCount; 02278 02279 /* Step 2: Base Form application to syllables */ 02280 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE); 02281 02282 HeapFree(GetProcessHeap(),0,input); 02283 HeapFree(GetProcessHeap(),0,syllables); 02284 } 02285 02286 static inline BOOL mongolian_wordbreak(WCHAR chr) 02287 { 02288 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807)); 02289 } 02290 02291 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 02292 { 02293 INT *context_shape; 02294 INT dirL; 02295 int i; 02296 02297 if (*pcGlyphs != cChars) 02298 { 02299 ERR("Number of Glyphs and Chars need to match at the beginning\n"); 02300 return; 02301 } 02302 02303 if (!psa->fLogicalOrder && psa->fRTL) 02304 dirL = -1; 02305 else 02306 dirL = 1; 02307 02308 if (!psc->GSUB_Table) 02309 psc->GSUB_Table = load_gsub_table(hdc); 02310 02311 if (!psc->GSUB_Table) 02312 return; 02313 02314 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars); 02315 02316 for (i = 0; i < cChars; i++) 02317 { 02318 if (i == 0 || mongolian_wordbreak(pwcChars[i-1])) 02319 { 02320 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1])) 02321 context_shape[i] = Xn; 02322 else 02323 context_shape[i] = Xl; 02324 } 02325 else 02326 { 02327 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1])) 02328 context_shape[i] = Xr; 02329 else 02330 context_shape[i] = Xm; 02331 } 02332 } 02333 02334 /* Contextual Shaping */ 02335 i = 0; 02336 while(i < *pcGlyphs) 02337 { 02338 INT nextIndex; 02339 INT prevCount = *pcGlyphs; 02340 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]); 02341 if (nextIndex > GSUB_E_NOGLYPH) 02342 { 02343 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust); 02344 i = nextIndex; 02345 } 02346 else 02347 i++; 02348 } 02349 02350 HeapFree(GetProcessHeap(),0,context_shape); 02351 } 02352 02353 static void ShapeCharGlyphProp_Default( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp) 02354 { 02355 int i,k; 02356 02357 for (i = 0; i < cGlyphs; i++) 02358 { 02359 int char_index[20]; 02360 int char_count = 0; 02361 02362 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i); 02363 if (k>=0) 02364 { 02365 for (; k < cChars && pwLogClust[k] == i; k++) 02366 char_index[char_count++] = k; 02367 } 02368 02369 if (char_count == 0) 02370 continue; 02371 02372 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */ 02373 { 02374 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK; 02375 pCharProp[char_index[0]].fCanGlyphAlone = 1; 02376 } 02377 else 02378 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER; 02379 } 02380 02381 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp); 02382 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp); 02383 } 02384 02385 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ) 02386 { 02387 int i,k; 02388 int initGlyph, finaGlyph; 02389 INT dirR, dirL; 02390 BYTE *spaces; 02391 02392 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs); 02393 memset(spaces,0,cGlyphs); 02394 02395 if (!psa->fLogicalOrder && psa->fRTL) 02396 { 02397 initGlyph = cGlyphs-1; 02398 finaGlyph = 0; 02399 dirR = 1; 02400 dirL = -1; 02401 } 02402 else 02403 { 02404 initGlyph = 0; 02405 finaGlyph = cGlyphs-1; 02406 dirR = -1; 02407 dirL = 1; 02408 } 02409 02410 for (i = 0; i < cGlyphs; i++) 02411 { 02412 for (k = 0; k < cChars; k++) 02413 if (pwLogClust[k] == i) 02414 { 02415 if (pwcChars[k] == 0x0020) 02416 spaces[i] = 1; 02417 } 02418 } 02419 02420 for (i = 0; i < cGlyphs; i++) 02421 { 02422 int char_index[20]; 02423 int char_count = 0; 02424 BOOL isInit, isFinal; 02425 02426 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i); 02427 if (k>=0) 02428 { 02429 for (; k < cChars && pwLogClust[k] == i; k++) 02430 char_index[char_count++] = k; 02431 } 02432 02433 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR])); 02434 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL])); 02435 02436 if (char_count == 0) 02437 continue; 02438 02439 if (char_count == 1) 02440 { 02441 if (pwcChars[char_index[0]] == 0x0020) /* space */ 02442 { 02443 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK; 02444 pCharProp[char_index[0]].fCanGlyphAlone = 1; 02445 } 02446 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */ 02447 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA; 02448 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */ 02449 { 02450 if (!isInit && !isFinal) 02451 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M; 02452 else if (isInit) 02453 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN; 02454 else 02455 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE; 02456 } 02457 else if (!isInit) 02458 { 02459 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */ 02460 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA; 02461 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */ 02462 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA; 02463 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */ 02464 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA; 02465 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */ 02466 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF; 02467 else 02468 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE; 02469 } 02470 else if (!isInit && !isFinal) 02471 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL; 02472 else 02473 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE; 02474 } 02475 else if (char_count == 2) 02476 { 02477 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */ 02478 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA; 02479 else if (!isInit) 02480 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL; 02481 else 02482 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE; 02483 } 02484 else if (!isInit && !isFinal) 02485 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL; 02486 else 02487 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE; 02488 } 02489 02490 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp); 02491 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp); 02492 HeapFree(GetProcessHeap(),0,spaces); 02493 } 02494 02495 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ) 02496 { 02497 int i,k; 02498 int finaGlyph; 02499 INT dirL; 02500 BYTE *spaces; 02501 02502 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs); 02503 memset(spaces,0,cGlyphs); 02504 02505 if (!psa->fLogicalOrder && psa->fRTL) 02506 { 02507 finaGlyph = 0; 02508 dirL = -1; 02509 } 02510 else 02511 { 02512 finaGlyph = cGlyphs-1; 02513 dirL = 1; 02514 } 02515 02516 for (i = 0; i < cGlyphs; i++) 02517 { 02518 for (k = 0; k < cChars; k++) 02519 if (pwLogClust[k] == i) 02520 { 02521 if (pwcChars[k] == 0x0020) 02522 spaces[i] = 1; 02523 } 02524 } 02525 02526 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp); 02527 02528 for (i = 0; i < cGlyphs; i++) 02529 { 02530 int char_index[20]; 02531 int char_count = 0; 02532 02533 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i); 02534 if (k>=0) 02535 { 02536 for (; k < cChars && pwLogClust[k] == i; k++) 02537 char_index[char_count++] = k; 02538 } 02539 02540 if (char_count == 0) 02541 continue; 02542 02543 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */ 02544 { 02545 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER; 02546 pCharProp[char_index[0]].fCanGlyphAlone = 1; 02547 } 02548 else if (i == finaGlyph) 02549 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE; 02550 else 02551 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER; 02552 02553 /* handle Thai SARA AM (U+0E33) differently than GDEF */ 02554 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33) 02555 pGlyphProp[i].sva.fClusterStart = 0; 02556 } 02557 02558 HeapFree(GetProcessHeap(),0,spaces); 02559 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp); 02560 02561 /* Do not allow justification between marks and their base */ 02562 for (i = 0; i < cGlyphs; i++) 02563 { 02564 if (!pGlyphProp[i].sva.fClusterStart) 02565 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE; 02566 } 02567 } 02568 02569 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp) 02570 { 02571 int i,k; 02572 02573 for (i = 0; i < cGlyphs; i++) 02574 { 02575 int char_index[20]; 02576 int char_count = 0; 02577 02578 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i); 02579 if (k>=0) 02580 { 02581 for (; k < cChars && pwLogClust[k] == i; k++) 02582 char_index[char_count++] = k; 02583 } 02584 02585 if (char_count == 0) 02586 continue; 02587 02588 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */ 02589 { 02590 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER; 02591 pCharProp[char_index[0]].fCanGlyphAlone = 1; 02592 } 02593 else 02594 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE; 02595 } 02596 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp); 02597 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp); 02598 } 02599 02600 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp) 02601 { 02602 int i,k; 02603 02604 for (i = 0; i < cGlyphs; i++) 02605 { 02606 int char_index[20]; 02607 int char_count = 0; 02608 02609 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i); 02610 if (k>=0) 02611 { 02612 for (; k < cChars && pwLogClust[k] == i; k++) 02613 char_index[char_count++] = k; 02614 } 02615 02616 if (char_count == 0) 02617 continue; 02618 02619 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */ 02620 { 02621 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK; 02622 pCharProp[char_index[0]].fCanGlyphAlone = 1; 02623 } 02624 else 02625 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE; 02626 } 02627 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp); 02628 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp); 02629 02630 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */ 02631 for (i = 0; i < cGlyphs; i++) 02632 { 02633 if (!pGlyphProp[i].sva.fClusterStart) 02634 { 02635 pGlyphProp[i].sva.fDiacritic = 0; 02636 pGlyphProp[i].sva.fZeroWidth = 0; 02637 } 02638 } 02639 } 02640 02641 static void ShapeCharGlyphProp_BaseIndic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp, lexical_function lexical, BOOL use_syllables, BOOL override_gsub) 02642 { 02643 int i,k; 02644 02645 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp); 02646 for (i = 0; i < cGlyphs; i++) 02647 { 02648 int char_index[20]; 02649 int char_count = 0; 02650 02651 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i); 02652 if (k>=0) 02653 { 02654 for (; k < cChars && pwLogClust[k] == i; k++) 02655 char_index[char_count++] = k; 02656 } 02657 02658 if (override_gsub) 02659 { 02660 /* Most indic scripts do not set fDiacritic or fZeroWidth */ 02661 pGlyphProp[i].sva.fDiacritic = FALSE; 02662 pGlyphProp[i].sva.fZeroWidth = FALSE; 02663 } 02664 02665 if (char_count == 0) 02666 continue; 02667 02668 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */ 02669 { 02670 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK; 02671 pCharProp[char_index[0]].fCanGlyphAlone = 1; 02672 } 02673 else 02674 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE; 02675 02676 pGlyphProp[i].sva.fClusterStart = 0; 02677 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++) 02678 switch (lexical(pwcChars[char_index[k]])) 02679 { 02680 case lex_Matra_pre: 02681 case lex_Matra_post: 02682 case lex_Matra_above: 02683 case lex_Matra_below: 02684 case lex_Modifier: 02685 case lex_Halant: 02686 break; 02687 case lex_ZWJ: 02688 case lex_ZWNJ: 02689 /* check for dangling joiners */ 02690 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020) 02691 pGlyphProp[i].sva.fClusterStart = 1; 02692 else 02693 k = char_count; 02694 break; 02695 default: 02696 pGlyphProp[i].sva.fClusterStart = 1; 02697 break; 02698 } 02699 } 02700 02701 if (use_syllables) 02702 { 02703 IndicSyllable *syllables = NULL; 02704 int syllable_count = 0; 02705 BOOL modern = get_GSUB_Indic2(psa, psc); 02706 02707 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern); 02708 02709 for (i = 0; i < syllable_count; i++) 02710 { 02711 int j; 02712 WORD g = pwLogClust[syllables[i].start]; 02713 for (j = syllables[i].start+1; j <= syllables[i].end; j++) 02714 { 02715 if (pwLogClust[j] != g) 02716 { 02717 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0; 02718 pwLogClust[j] = g; 02719 } 02720 } 02721 } 02722 02723 HeapFree(GetProcessHeap(), 0, syllables); 02724 } 02725 02726 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp); 02727 } 02728 02729 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ) 02730 { 02731 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE); 02732 } 02733 02734 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ) 02735 { 02736 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE); 02737 } 02738 02739 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ) 02740 { 02741 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE); 02742 } 02743 02744 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ) 02745 { 02746 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE); 02747 } 02748 02749 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ) 02750 { 02751 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE); 02752 } 02753 02754 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ) 02755 { 02756 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE); 02757 } 02758 02759 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ) 02760 { 02761 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE); 02762 } 02763 02764 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ) 02765 { 02766 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE); 02767 } 02768 02769 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ) 02770 { 02771 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE); 02772 } 02773 02774 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ) 02775 { 02776 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE); 02777 } 02778 02779 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp ) 02780 { 02781 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE); 02782 } 02783 02784 void SHAPE_CharGlyphProp(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp) 02785 { 02786 if (ShapingData[psa->eScript].charGlyphPropProc) 02787 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp); 02788 else 02789 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp); 02790 } 02791 02792 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust) 02793 { 02794 if (!psc->GSUB_Table) 02795 psc->GSUB_Table = load_gsub_table(hdc); 02796 02797 if (ShapingData[psa->eScript].contextProc) 02798 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust); 02799 } 02800 02801 static void SHAPE_ApplyOpenTypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, const TEXTRANGE_PROPERTIES *rpRangeProperties, WORD *pwLogClust) 02802 { 02803 int i; 02804 INT dirL; 02805 02806 if (!rpRangeProperties) 02807 return; 02808 02809 if (!psc->GSUB_Table) 02810 psc->GSUB_Table = load_gsub_table(hdc); 02811 02812 if (!psc->GSUB_Table) 02813 return; 02814 02815 if (!psa->fLogicalOrder && psa->fRTL) 02816 dirL = -1; 02817 else 02818 dirL = 1; 02819 02820 for (i = 0; i < rpRangeProperties->cotfRecords; i++) 02821 { 02822 if (rpRangeProperties->potfRecords[i].lParameter > 0) 02823 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust); 02824 } 02825 } 02826 02827 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust) 02828 { 02829 const TEXTRANGE_PROPERTIES *rpRangeProperties; 02830 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange; 02831 02832 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust); 02833 } 02834 02835 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa) 02836 { 02837 LoadedFeature *feature; 02838 int i; 02839 02840 if (!ShapingData[psa->eScript].requiredFeatures) 02841 return S_OK; 02842 02843 if (!psc->GSUB_Table) 02844 psc->GSUB_Table = load_gsub_table(hdc); 02845 02846 /* we need to have at least one of the required features */ 02847 i = 0; 02848 while (ShapingData[psa->eScript].requiredFeatures[i]) 02849 { 02850 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]); 02851 if (feature) 02852 return S_OK; 02853 i++; 02854 } 02855 02856 return USP_E_SCRIPT_NOT_IN_FONT; 02857 } 02858 02859 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc, 02860 SCRIPT_ANALYSIS *psa, int cMaxTags, 02861 OPENTYPE_TAG *pScriptTags, int *pcTags) 02862 { 02863 HRESULT hr; 02864 OPENTYPE_TAG searching = 0x00000000; 02865 02866 if (!psc->GSUB_Table) 02867 psc->GSUB_Table = load_gsub_table(hdc); 02868 02869 if (psa && scriptInformation[psa->eScript].scriptTag) 02870 searching = scriptInformation[psa->eScript].scriptTag; 02871 02872 hr = OpenType_GSUB_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags, NULL); 02873 if (FAILED(hr)) 02874 *pcTags = 0; 02875 return hr; 02876 } 02877 02878 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc, 02879 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, 02880 int cMaxTags, OPENTYPE_TAG *pLangSysTags, 02881 int *pcTags) 02882 { 02883 HRESULT hr; 02884 OPENTYPE_TAG searching = 0x00000000; 02885 BOOL fellback = FALSE; 02886 02887 if (!psc->GSUB_Table) 02888 psc->GSUB_Table = load_gsub_table(hdc); 02889 02890 if (psa && psc->userLang != 0) 02891 searching = psc->userLang; 02892 02893 hr = OpenType_GSUB_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags, NULL); 02894 if (FAILED(hr)) 02895 { 02896 fellback = TRUE; 02897 hr = OpenType_GSUB_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags, NULL); 02898 } 02899 02900 if (FAILED(hr) || fellback) 02901 *pcTags = 0; 02902 if (SUCCEEDED(hr) && fellback && psa) 02903 hr = E_INVALIDARG; 02904 return hr; 02905 } 02906 02907 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc, 02908 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, 02909 OPENTYPE_TAG tagLangSys, int cMaxTags, 02910 OPENTYPE_TAG *pFeatureTags, int *pcTags) 02911 { 02912 HRESULT hr; 02913 BOOL filter = FALSE; 02914 02915 if (!psc->GSUB_Table) 02916 psc->GSUB_Table = load_gsub_table(hdc); 02917 02918 if (psa && scriptInformation[psa->eScript].scriptTag) 02919 { 02920 FIXME("Filtering not implemented\n"); 02921 filter = TRUE; 02922 } 02923 02924 hr = OpenType_GSUB_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL); 02925 02926 if (FAILED(hr)) 02927 *pcTags = 0; 02928 return hr; 02929 } Generated on Sat May 26 2012 04:25:19 for ReactOS by
1.7.6.1
|