ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

shape.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.