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

usp10.c
Go to the documentation of this file.
00001 /*
00002  * Implementation of Uniscribe Script Processor (usp10.dll)
00003  *
00004  * Copyright 2005 Steven Edwards for CodeWeavers
00005  * Copyright 2006 Hans Leidekker
00006  * Copyright 2010 CodeWeavers, Aric Stewart
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00021  *
00022  * Notes:
00023  * Uniscribe allows for processing of complex scripts such as joining
00024  * and filtering characters and bi-directional text with custom line breaks.
00025  */
00026 
00027 #include <stdarg.h>
00028 #include <stdlib.h>
00029 
00030 #include "windef.h"
00031 #include "winbase.h"
00032 #include "wingdi.h"
00033 #include "winuser.h"
00034 #include "winnls.h"
00035 #include "winreg.h"
00036 #include "usp10.h"
00037 
00038 #include "usp10_internal.h"
00039 
00040 #include "wine/debug.h"
00041 #include "wine/unicode.h"
00042 
00043 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
00044 
00045 typedef struct _scriptRange
00046 {
00047     WORD script;
00048     DWORD rangeFirst;
00049     DWORD rangeLast;
00050     WORD numericScript;
00051     WORD punctScript;
00052 } scriptRange;
00053 
00054 static const scriptRange scriptRanges[] = {
00055     /* Basic Latin: U+0000–U+007A */
00056     { Script_Latin,      0x00,   0x07a ,  Script_Numeric, Script_Punctuation},
00057     /* Latin-1 Supplement: U+0080–U+00FF */
00058     /* Latin Extended-A: U+0100–U+017F */
00059     /* Latin Extended-B: U+0180–U+024F */
00060     /* IPA Extensions: U+0250–U+02AF */
00061     /* Spacing Modifier Letters:U+02B0–U+02FF */
00062     { Script_Latin,      0x80,   0x2ff ,  Script_Numeric2, Script_Punctuation},
00063     /* Combining Diacritical Marks : U+0300–U+036F */
00064     { Script_Diacritical,0x300,  0x36f,  0, 0},
00065     /* Greek: U+0370–U+03FF */
00066     { Script_Greek,      0x370,  0x3ff,  0, 0},
00067     /* Cyrillic: U+0400–U+04FF */
00068     /* Cyrillic Supplement: U+0500–U+052F */
00069     { Script_Cyrillic,   0x400,  0x52f,  0, 0},
00070     /* Armenian: U+0530–U+058F */
00071     { Script_Armenian,   0x530,  0x58f,  0, 0},
00072     /* Hebrew: U+0590–U+05FF */
00073     { Script_Hebrew,     0x590,  0x5ff,  0, 0},
00074     /* Arabic: U+0600–U+06FF */
00075     { Script_Arabic,     0x600,  0x6ef,  Script_Arabic_Numeric, 0},
00076     /* Defined by Windows */
00077     { Script_Persian,    0x6f0,  0x6f9,  0, 0},
00078     /* Continue Arabic: U+0600–U+06FF */
00079     { Script_Arabic,     0x6fa,  0x6ff,  0, 0},
00080     /* Syriac: U+0700–U+074F*/
00081     { Script_Syriac,     0x700,  0x74f,  0, 0},
00082     /* Arabic Supplement: U+0750–U+077F */
00083     { Script_Arabic,     0x750,  0x77f,  0, 0},
00084     /* Thaana: U+0780–U+07BF */
00085     { Script_Thaana,     0x780,  0x7bf,  0, 0},
00086     /* N’Ko: U+07C0–U+07FF */
00087     { Script_NKo,        0x7c0,  0x7ff,  0, 0},
00088     /* Devanagari: U+0900–U+097F */
00089     { Script_Devanagari, 0x900,  0x97f,  Script_Devanagari_Numeric, 0},
00090     /* Bengali: U+0980–U+09FF */
00091     { Script_Bengali,    0x980,  0x9ff,  Script_Bengali_Numeric, 0},
00092     /* Gurmukhi: U+0A00–U+0A7F*/
00093     { Script_Gurmukhi,   0xa00,  0xa7f,  Script_Gurmukhi_Numeric, 0},
00094     /* Gujarati: U+0A80–U+0AFF*/
00095     { Script_Gujarati,   0xa80,  0xaff,  Script_Gujarati_Numeric, 0},
00096     /* Oriya: U+0B00–U+0B7F */
00097     { Script_Oriya,      0xb00,  0xb7f,  Script_Oriya_Numeric, 0},
00098     /* Tamil: U+0B80–U+0BFF */
00099     { Script_Tamil,      0xb80,  0xbff,  Script_Tamil_Numeric, 0},
00100     /* Telugu: U+0C00–U+0C7F */
00101     { Script_Telugu,     0xc00,  0xc7f,  Script_Telugu_Numeric, 0},
00102     /* Kannada: U+0C80–U+0CFF */
00103     { Script_Kannada,    0xc80,  0xcff,  Script_Kannada_Numeric, 0},
00104     /* Malayalam: U+0D00–U+0D7F */
00105     { Script_Malayalam,  0xd00,  0xd7f,  Script_Malayalam_Numeric, 0},
00106     /* Sinhala: U+0D80–U+0DFF */
00107     { Script_Sinhala,   0xd80,  0xdff,  0, 0},
00108     /* Thai: U+0E00–U+0E7F */
00109     { Script_Thai,      0xe00,  0xe7f,  Script_Thai_Numeric, 0},
00110     /* Lao: U+0E80–U+0EFF */
00111     { Script_Lao,       0xe80,  0xeff,  Script_Lao_Numeric, 0},
00112     /* Tibetan: U+0F00–U+0FFF */
00113     { Script_Tibetan,   0xf00,  0xfff,  0, 0},
00114     /* Myanmar: U+1000–U+109F */
00115     { Script_Myanmar,    0x1000,  0x109f, Script_Myanmar_Numeric, 0},
00116     /* Georgian: U+10A0–U+10FF */
00117     { Script_Georgian,   0x10a0,  0x10ff,  0, 0},
00118     /* Hangul Jamo: U+1100–U+11FF */
00119     { Script_Hangul,     0x1100,  0x11ff,  0, 0},
00120     /* Ethiopic: U+1200–U+137F */
00121     /* Ethiopic Extensions: U+1380–U+139F */
00122     { Script_Ethiopic,   0x1200,  0x139f,  0, 0},
00123     /* Cherokee: U+13A0–U+13FF */
00124     { Script_Cherokee,   0x13a0,  0x13ff,  0, 0},
00125     /* Canadian Aboriginal Syllabics: U+1400–U+167F */
00126     { Script_Canadian,   0x1400,  0x167f,  0, 0},
00127     /* Ogham: U+1680–U+169F */
00128     { Script_Ogham,      0x1680,  0x169f,  0, 0},
00129     /* Runic: U+16A0–U+16F0 */
00130     { Script_Runic,      0x16a0,  0x16f0,  0, 0},
00131     /* Khmer: U+1780–U+17FF */
00132     { Script_Khmer,      0x1780,  0x17ff,  Script_Khmer_Numeric, 0},
00133     /* Mongolian: U+1800–U+18AF */
00134     { Script_Mongolian,  0x1800,  0x18af,  Script_Mongolian_Numeric, 0},
00135     /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
00136     { Script_Canadian,   0x18b0,  0x18ff,  0, 0},
00137     /* Tai Le: U+1950–U+197F */
00138     { Script_Tai_Le,     0x1950,  0x197f,  0, 0},
00139     /* New Tai Lue: U+1980–U+19DF */
00140     { Script_New_Tai_Lue,0x1980,  0x19df,  Script_New_Tai_Lue_Numeric, 0},
00141     /* Khmer Symbols: U+19E0–U+19FF */
00142     { Script_Khmer,      0x19e0,  0x19ff,  Script_Khmer_Numeric, 0},
00143     /* Vedic Extensions: U+1CD0-U+1CFF */
00144     { Script_Devanagari, 0x1cd0, 0x1cff, Script_Devanagari_Numeric, 0},
00145     /* Phonetic Extensions: U+1D00–U+1DBF */
00146     { Script_Latin,      0x1d00, 0x1dbf, 0, 0},
00147     /* Combining Diacritical Marks Supplement: U+1DC0–U+1DFF */
00148     { Script_Diacritical,0x1dc0, 0x1dff, 0, 0},
00149     /* Latin Extended Additional: U+1E00–U+1EFF */
00150     { Script_Latin,      0x1e00, 0x1eff, 0, 0},
00151     /* Greek Extended: U+1F00–U+1FFF */
00152     { Script_Greek,      0x1f00, 0x1fff, 0, 0},
00153     /* General Punctuation: U+2000 –U+206f */
00154     { Script_Latin,      0x2000, 0x206f, 0, 0},
00155     /* Superscripts and Subscripts : U+2070 –U+209f */
00156     /* Currency Symbols : U+20a0 –U+20cf */
00157     { Script_Numeric2,   0x2070, 0x2070, 0, 0},
00158     { Script_Latin,      0x2071, 0x2073, 0, 0},
00159     { Script_Numeric2,   0x2074, 0x2079, 0, 0},
00160     { Script_Latin,      0x207a, 0x207f, 0, 0},
00161     { Script_Numeric2,   0x2080, 0x2089, 0, 0},
00162     { Script_Latin,      0x208a, 0x20cf, 0, 0},
00163     /* Letterlike Symbols : U+2100 –U+214f */
00164     /* Number Forms : U+2150 –U+218f */
00165     /* Arrows : U+2190 –U+21ff */
00166     /* Mathematical Operators : U+2200 –U+22ff */
00167     /* Miscellaneous Technical : U+2300 –U+23ff */
00168     /* Control Pictures : U+2400 –U+243f */
00169     /* Optical Character Recognition : U+2440 –U+245f */
00170     /* Enclosed Alphanumerics : U+2460 –U+24ff */
00171     /* Box Drawing : U+2500 –U+25ff */
00172     /* Block Elements : U+2580 –U+259f */
00173     /* Geometric Shapes : U+25a0 –U+25ff */
00174     /* Miscellaneous Symbols : U+2600 –U+26ff */
00175     /* Dingbats : U+2700 –U+27bf */
00176     /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
00177     /* Supplemental Arrows-A : U+27f0 –U+27ff */
00178     { Script_Latin,      0x2100, 0x27ff, 0, 0},
00179     /* Braille Patterns: U+2800–U+28FF */
00180     { Script_Braille,    0x2800, 0x28ff, 0, 0},
00181     /* Supplemental Arrows-B : U+2900 –U+297f */
00182     /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
00183     /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
00184     /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
00185     { Script_Latin,      0x2900, 0x2bff, 0, 0},
00186     /* Latin Extended-C: U+2C60–U+2C7F */
00187     { Script_Latin,      0x2c60, 0x2c7f, 0, 0},
00188     /* Georgian: U+2D00–U+2D2F */
00189     { Script_Georgian,   0x2d00,  0x2d2f,  0, 0},
00190     /* Tifinagh: U+2D30–U+2D7F */
00191     { Script_Tifinagh,   0x2d30,  0x2d7f,  0, 0},
00192     /* Ethiopic Extensions: U+2D80–U+2DDF */
00193     { Script_Ethiopic,   0x2d80,  0x2ddf,  0, 0},
00194     /* Cyrillic Extended-A: U+2DE0–U+2DFF */
00195     { Script_Cyrillic,   0x2de0, 0x2dff,  0, 0},
00196     /* CJK Radicals Supplement: U+2E80–U+2EFF */
00197     /* Kangxi Radicals: U+2F00–U+2FDF */
00198     { Script_CJK_Han,    0x2e80, 0x2fdf,  0, 0},
00199     /* Ideographic Description Characters: U+2FF0–U+2FFF */
00200     { Script_Ideograph  ,0x2ff0, 0x2fff,  0, 0},
00201     /* CJK Symbols and Punctuation: U+3000–U+303F */
00202     { Script_Ideograph  ,0x3000, 0x3004,  0, 0},
00203     { Script_CJK_Han    ,0x3005, 0x3005,  0, 0},
00204     { Script_Ideograph  ,0x3006, 0x3006,  0, 0},
00205     { Script_CJK_Han    ,0x3007, 0x3007,  0, 0},
00206     { Script_Ideograph  ,0x3008, 0x3020,  0, 0},
00207     { Script_CJK_Han    ,0x3021, 0x3029,  0, 0},
00208     { Script_Ideograph  ,0x302a, 0x3030,  0, 0},
00209     /* Kana Marks: */
00210     { Script_Kana       ,0x3031, 0x3035,  0, 0},
00211     { Script_Ideograph  ,0x3036, 0x3037,  0, 0},
00212     { Script_CJK_Han    ,0x3038, 0x303b,  0, 0},
00213     { Script_Ideograph  ,0x303c, 0x303f,  0, 0},
00214     /* Hiragana: U+3040–U+309F */
00215     /* Katakana: U+30A0–U+30FF */
00216     { Script_Kana       ,0x3040, 0x30ff,  0, 0},
00217     /* Bopomofo: U+3100–U+312F */
00218     { Script_Bopomofo   ,0x3100, 0x312f,  0, 0},
00219     /* Hangul Compatibility Jamo: U+3130–U+318F */
00220     { Script_Hangul     ,0x3130, 0x318f,  0, 0},
00221     /* Kanbun: U+3190–U+319F */
00222     { Script_Ideograph  ,0x3190, 0x319f,  0, 0},
00223     /* Bopomofo Extended: U+31A0–U+31BF */
00224     { Script_Bopomofo   ,0x31a0, 0x31bf,  0, 0},
00225     /* CJK Strokes: U+31C0–U+31EF */
00226     { Script_Ideograph  ,0x31c0, 0x31ef,  0, 0},
00227     /* Katakana Phonetic Extensions: U+31F0–U+31FF */
00228     { Script_Kana       ,0x31f0, 0x31ff,  0, 0},
00229     /* Enclosed CJK Letters and Months: U+3200–U+32FF */
00230     { Script_Hangul     ,0x3200, 0x321f,  0, 0},
00231     { Script_Ideograph  ,0x3220, 0x325f,  0, 0},
00232     { Script_Hangul     ,0x3260, 0x327f,  0, 0},
00233     { Script_Ideograph  ,0x3280, 0x32ef,  0, 0},
00234     { Script_Kana       ,0x32d0, 0x31ff,  0, 0},
00235     /* CJK Compatibility: U+3300–U+33FF*/
00236     { Script_Kana       ,0x3300, 0x3357,  0, 0},
00237     { Script_Ideograph  ,0x3358, 0x33ff,  0, 0},
00238     /* CJK Unified Ideographs Extension A: U+3400–U+4DBF */
00239     { Script_CJK_Han    ,0x3400, 0x4dbf,  0, 0},
00240     /* CJK Unified Ideographs: U+4E00–U+9FFF */
00241     { Script_CJK_Han    ,0x4e00, 0x9fff,  0, 0},
00242     /* Yi: U+A000–U+A4CF */
00243     { Script_Yi         ,0xa000, 0xa4cf,  0, 0},
00244     /* Vai: U+A500–U+A63F */
00245     { Script_Vai        ,0xa500, 0xa63f,  Script_Vai_Numeric, 0},
00246     /* Cyrillic Extended-B: U+A640–U+A69F */
00247     { Script_Cyrillic,   0xa640, 0xa69f,  0, 0},
00248     /* Modifier Tone Letters: U+A700–U+A71F */
00249     /* Latin Extended-D: U+A720–U+A7FF */
00250     { Script_Latin,      0xa700, 0xa7ff, 0, 0},
00251     /* Phags-pa: U+A840–U+A87F */
00252     { Script_Phags_pa,   0xa840, 0xa87f, 0, 0},
00253     /* Devanagari Extended: U+A8E0-U+A8FF */
00254     { Script_Devanagari, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric, 0},
00255     /* Myanmar Extended-A: U+AA60–U+AA7F */
00256     { Script_Myanmar,    0xaa60,  0xaa7f, Script_Myanmar_Numeric, 0},
00257     /* Hangul Jamo Extended-A: U+A960–U+A97F */
00258     { Script_Hangul,     0xa960, 0xa97f,  0, 0},
00259     /* Hangul Syllables: U+AC00–U+D7A3 */
00260     { Script_Hangul,     0xac00, 0xd7a3,  0, 0},
00261     /* Hangul Jamo Extended-B: U+D7B0–U+D7FF */
00262     { Script_Hangul,     0xd7b0, 0xd7ff,  0, 0},
00263     /* Surrogates Area: U+D800–U+DFFF */
00264     { Script_Surrogates, 0xd800, 0xdbfe,  0, 0},
00265     { Script_Private,    0xdbff, 0xdc00,  0, 0},
00266     { Script_Surrogates, 0xdc01, 0xdfff,  0, 0},
00267     /* Private Use Area: U+E000–U+F8FF */
00268     { Script_Private,    0xe000, 0xf8ff,  0, 0},
00269     /* CJK Compatibility Ideographs: U+F900–U+FAFF */
00270     { Script_CJK_Han    ,0xf900, 0xfaff,  0, 0},
00271     /* Latin Ligatures: U+FB00–U+FB06 */
00272     { Script_Latin,      0xfb00, 0xfb06, 0, 0},
00273     /* Armenian ligatures U+FB13..U+FB17 */
00274     { Script_Armenian,   0xfb13, 0xfb17,  0, 0},
00275     /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
00276     { Script_Hebrew,     0xfb1d, 0xfb4f, 0, 0},
00277     /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
00278     { Script_Arabic,     0xfb50, 0xfdff, 0, 0},
00279     /* Vertical Forms: U+FE10–U+FE1F */
00280     /* Combining Half Marks: U+FE20–U+FE2F */
00281     /* CJK Compatibility Forms: U+FE30–U+FE4F */
00282     /* Small Form Variants: U+FE50–U+FE6F */
00283     { Script_Ideograph  ,0xfe10, 0xfe6f,  0, 0},
00284     /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
00285     { Script_Arabic,     0xfe70, 0xfeff, 0, 0},
00286     /* Halfwidth and Fullwidth Forms: U+FF00–FFEF */
00287     { Script_Ideograph  ,0xff00, 0xff64,  Script_Numeric2, 0},
00288     { Script_Kana       ,0xff65, 0xff9f,  0, 0},
00289     { Script_Hangul     ,0xffa0, 0xffdf,  0, 0},
00290     { Script_Ideograph  ,0xffe0, 0xffef,  0, 0},
00291     /* Plane - 1 */
00292     /* Deseret: U+10400–U+1044F */
00293     { Script_Deseret,     0x10400, 0x1044F,  0, 0},
00294     /* Osmanya: U+10480–U+104AF */
00295     { Script_Osmanya,    0x10480, 0x104AF,  Script_Osmanya_Numeric, 0},
00296     /* Mathematical Alphanumeric Symbols: U+1D400–U+1D7FF */
00297     { Script_MathAlpha,  0x1D400, 0x1D7FF,  0, 0},
00298     /* END */
00299     { SCRIPT_UNDEFINED,  0, 0, 0}
00300 };
00301 
00302 /* the must be in order so that the index matches the Script value */
00303 const scriptData scriptInformation[] = {
00304     {{SCRIPT_UNDEFINED, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00305      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00306      0x00000000,
00307      {0}},
00308     {{Script_Latin, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00309      {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
00310      MS_MAKE_TAG('l','a','t','n'),
00311      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
00312     {{Script_CR, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00313      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00314      0x00000000,
00315      {0}},
00316     {{Script_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00317      {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00318      0x00000000,
00319      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
00320     {{Script_Control, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00321      {LANG_ENGLISH, 0, 1, 0, 0, ANSI_CHARSET, 1, 0, 0, 0, 0, 0, 1, 0, 0},
00322      0x00000000,
00323      {0}},
00324     {{Script_Punctuation, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00325      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00326      0x00000000,
00327      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
00328     {{Script_Arabic, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
00329      {LANG_ARABIC, 0, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 1, 0},
00330      MS_MAKE_TAG('a','r','a','b'),
00331      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
00332     {{Script_Arabic_Numeric, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
00333      {LANG_ARABIC, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
00334      MS_MAKE_TAG('a','r','a','b'),
00335      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
00336     {{Script_Hebrew, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
00337      {LANG_HEBREW, 0, 1, 0, 1, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00338      MS_MAKE_TAG('h','e','b','r'),
00339      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
00340     {{Script_Syriac, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
00341      {LANG_SYRIAC, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 1, 0},
00342      MS_MAKE_TAG('s','y','r','c'),
00343      {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
00344     {{Script_Persian, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
00345      {LANG_PERSIAN, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00346      MS_MAKE_TAG('s','y','r','c'),
00347      {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
00348     {{Script_Thaana, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
00349      {LANG_DIVEHI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00350      MS_MAKE_TAG('t','h','a','a'),
00351      {'M','V',' ','B','o','l','i',0}},
00352     {{Script_Greek, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00353      {LANG_GREEK, 0, 0, 0, 0, GREEK_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00354      MS_MAKE_TAG('g','r','e','k'),
00355      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
00356     {{Script_Cyrillic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00357      {LANG_RUSSIAN, 0, 0, 0, 0, RUSSIAN_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00358      MS_MAKE_TAG('c','y','r','l'),
00359      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
00360     {{Script_Armenian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00361      {LANG_ARMENIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
00362      MS_MAKE_TAG('a','r','m','n'),
00363      {'S','y','l','f','a','e','n',0}},
00364     {{Script_Georgian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00365      {LANG_GEORGIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
00366      MS_MAKE_TAG('g','e','o','r'),
00367      {'S','y','l','f','a','e','n',0}},
00368     {{Script_Sinhala, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00369      {LANG_SINHALESE, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00370      MS_MAKE_TAG('s','i','n','h'),
00371      {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
00372     {{Script_Tibetan, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00373      {LANG_TIBETAN, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
00374      MS_MAKE_TAG('t','i','b','t'),
00375      {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
00376     {{Script_Tibetan_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00377      {LANG_TIBETAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00378      MS_MAKE_TAG('t','i','b','t'),
00379      {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
00380     {{Script_Phags_pa, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00381      {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00382      MS_MAKE_TAG('p','h','a','g'),
00383      {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
00384     {{Script_Thai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00385      {LANG_THAI, 0, 1, 1, 1, THAI_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 1},
00386      MS_MAKE_TAG('t','h','a','i'),
00387      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
00388     {{Script_Thai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00389      {LANG_THAI, 1, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00390      MS_MAKE_TAG('t','h','a','i'),
00391      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
00392     {{Script_Lao, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00393      {LANG_LAO, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
00394      MS_MAKE_TAG('l','a','o',' '),
00395      {'D','o','k','C','h','a','m','p','a',0}},
00396     {{Script_Lao_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00397      {LANG_LAO, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00398      MS_MAKE_TAG('l','a','o',' '),
00399      {'D','o','k','C','h','a','m','p','a',0}},
00400     {{Script_Devanagari, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00401      {LANG_HINDI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
00402      MS_MAKE_TAG('d','e','v','a'),
00403      {'M','a','n','g','a','l',0}},
00404     {{Script_Devanagari_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00405      {LANG_HINDI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00406      MS_MAKE_TAG('d','e','v','a'),
00407      {'M','a','n','g','a','l',0}},
00408     {{Script_Bengali, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00409      {LANG_BENGALI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
00410      MS_MAKE_TAG('b','e','n','g'),
00411      {'V','r','i','n','d','a',0}},
00412     {{Script_Bengali_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00413      {LANG_BENGALI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00414      MS_MAKE_TAG('b','e','n','g'),
00415      {'V','r','i','n','d','a',0}},
00416     {{Script_Bengali_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00417      {LANG_BENGALI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00418      MS_MAKE_TAG('b','e','n','g'),
00419      {'V','r','i','n','d','a',0}},
00420     {{Script_Gurmukhi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00421      {LANG_PUNJABI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
00422      MS_MAKE_TAG('g','u','r','u'),
00423      {'R','a','a','v','i',0}},
00424     {{Script_Gurmukhi_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00425      {LANG_PUNJABI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00426      MS_MAKE_TAG('g','u','r','u'),
00427      {'R','a','a','v','i',0}},
00428     {{Script_Gujarati, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00429      {LANG_GUJARATI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
00430      MS_MAKE_TAG('g','u','j','r'),
00431      {'S','h','r','u','t','i',0}},
00432     {{Script_Gujarati_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00433      {LANG_GUJARATI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00434      MS_MAKE_TAG('g','u','j','r'),
00435      {'S','h','r','u','t','i',0}},
00436     {{Script_Gujarati_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00437      {LANG_GUJARATI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00438      MS_MAKE_TAG('g','u','j','r'),
00439      {'S','h','r','u','t','i',0}},
00440     {{Script_Oriya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00441      {LANG_ORIYA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
00442      MS_MAKE_TAG('o','r','y','a'),
00443      {'K','a','l','i','n','g','a',0}},
00444     {{Script_Oriya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00445      {LANG_ORIYA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00446      MS_MAKE_TAG('o','r','y','a'),
00447      {'K','a','l','i','n','g','a',0}},
00448     {{Script_Tamil, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00449      {LANG_TAMIL, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
00450      MS_MAKE_TAG('t','a','m','l'),
00451      {'L','a','t','h','a',0}},
00452     {{Script_Tamil_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00453      {LANG_TAMIL, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00454      MS_MAKE_TAG('t','a','m','l'),
00455      {'L','a','t','h','a',0}},
00456     {{Script_Telugu, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00457      {LANG_TELUGU, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
00458      MS_MAKE_TAG('t','e','l','u'),
00459      {'G','a','u','t','a','m','i',0}},
00460     {{Script_Telugu_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00461      {LANG_TELUGU, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00462      MS_MAKE_TAG('t','e','l','u'),
00463      {'G','a','u','t','a','m','i',0}},
00464     {{Script_Kannada, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00465      {LANG_KANNADA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
00466      MS_MAKE_TAG('k','n','d','a'),
00467      {'T','u','n','g','a',0}},
00468     {{Script_Kannada_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00469      {LANG_KANNADA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00470      MS_MAKE_TAG('k','n','d','a'),
00471      {'T','u','n','g','a',0}},
00472     {{Script_Malayalam, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00473      {LANG_MALAYALAM, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
00474      MS_MAKE_TAG('m','l','y','m'),
00475      {'K','a','r','t','i','k','a',0}},
00476     {{Script_Malayalam_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00477      {LANG_MALAYALAM, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00478      MS_MAKE_TAG('m','l','y','m'),
00479      {'K','a','r','t','i','k','a',0}},
00480     {{Script_Diacritical, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00481      {LANG_ENGLISH, 0, 1, 0, 1, ANSI_CHARSET, 0, 0, 0, 0, 0, 1, 1, 0, 0},
00482      0x00000000,
00483      {0}},
00484     {{Script_Punctuation2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00485      {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00486      MS_MAKE_TAG('l','a','t','n'),
00487      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
00488     {{Script_Numeric2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00489      {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
00490      0x00000000,
00491      {0}},
00492     {{Script_Myanmar, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00493      {0x55, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
00494      MS_MAKE_TAG('m','y','m','r'),
00495      {'M','y','a','n','m','a','r',' ','T','e','x','t',0}},
00496     {{Script_Myanmar_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00497      {0x55, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00498      MS_MAKE_TAG('m','y','m','r'),
00499      {0}},
00500     {{Script_Tai_Le, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00501      {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00502      MS_MAKE_TAG('t','a','l','e'),
00503      {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e'}},
00504     {{Script_New_Tai_Lue, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00505      {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00506      MS_MAKE_TAG('t','a','l','u'),
00507      {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e'}},
00508     {{Script_New_Tai_Lue_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00509      {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00510      MS_MAKE_TAG('t','a','l','u'),
00511      {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e'}},
00512     {{Script_Khmer, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00513      {0x53, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
00514      MS_MAKE_TAG('k','h','m','r'),
00515      {'D','a','u','n','P','e','n','h'}},
00516     {{Script_Khmer, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00517      {0x53, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00518      MS_MAKE_TAG('k','h','m','r'),
00519      {'D','a','u','n','P','e','n','h'}},
00520     {{Script_CJK_Han, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00521      {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
00522      MS_MAKE_TAG('h','a','n','i'),
00523      {0}},
00524     {{Script_Ideograph, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00525      {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
00526      MS_MAKE_TAG('h','a','n','i'),
00527      {0}},
00528     {{Script_Bopomofo, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00529      {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
00530      MS_MAKE_TAG('b','o','p','o'),
00531      {0}},
00532     {{Script_Kana, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00533      {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
00534      MS_MAKE_TAG('k','a','n','a'),
00535      {0}},
00536     {{Script_Hangul, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00537      {LANG_KOREAN, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
00538      MS_MAKE_TAG('h','a','n','g'),
00539      {0}},
00540     {{Script_Yi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00541      {LANG_ENGLISH, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
00542      MS_MAKE_TAG('y','i',' ',' '),
00543      {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i'}},
00544     {{Script_Ethiopic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00545      {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00546      MS_MAKE_TAG('e','t','h','i'),
00547      {'N','y','a','l','a'}},
00548     {{Script_Ethiopic_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00549      {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00550      MS_MAKE_TAG('e','t','h','i'),
00551      {'N','y','a','l','a'}},
00552     {{Script_Mongolian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00553      {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00554      MS_MAKE_TAG('m','o','n','g'),
00555      {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i'}},
00556     {{Script_Mongolian_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00557      {LANG_MONGOLIAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00558      MS_MAKE_TAG('m','o','n','g'),
00559      {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i'}},
00560     {{Script_Tifinagh, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00561      {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00562      MS_MAKE_TAG('t','f','n','g'),
00563      {'E','b','r','i','m','a'}},
00564     {{Script_NKo, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
00565      {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00566      MS_MAKE_TAG('n','k','o',' '),
00567      {'E','b','r','i','m','a'}},
00568     {{Script_Vai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00569      {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00570      MS_MAKE_TAG('v','a','i',' '),
00571      {'E','b','r','i','m','a'}},
00572     {{Script_Vai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00573      {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00574      MS_MAKE_TAG('v','a','i',' '),
00575      {'E','b','r','i','m','a'}},
00576     {{Script_Cherokee, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00577      {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00578      MS_MAKE_TAG('c','h','e','r'),
00579      {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e'}},
00580     {{Script_Canadian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00581      {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00582      MS_MAKE_TAG('c','a','n','s'),
00583      {'E','u','p','h','e','m','i','a'}},
00584     {{Script_Ogham, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00585      {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00586      MS_MAKE_TAG('o','g','a','m'),
00587      {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
00588     {{Script_Runic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00589      {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00590      MS_MAKE_TAG('r','u','n','r'),
00591      {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
00592     {{Script_Braille, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00593      {LANG_ENGLISH, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00594      MS_MAKE_TAG('b','r','a','i'),
00595      {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
00596     {{Script_Surrogates, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00597      {LANG_ENGLISH, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
00598      0x00000000,
00599      {0}},
00600     {{Script_Private, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00601      {0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 1, 0, 0, 0, 0, 1, 0, 0},
00602      0x00000000,
00603      {0}},
00604     {{Script_Deseret, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00605      {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00606      MS_MAKE_TAG('d','s','r','t'),
00607      {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
00608     {{Script_Osmanya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00609      {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00610      MS_MAKE_TAG('o','s','m','a'),
00611      {'E','b','r','i','m','a'}},
00612     {{Script_Osmanya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00613      {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00614      MS_MAKE_TAG('o','s','m','a'),
00615      {'E','b','r','i','m','a'}},
00616     {{Script_MathAlpha, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00617      {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00618      MS_MAKE_TAG('m','a','t','h'),
00619      {'C','a','m','b','r','i','a',' ','M','a','t','h'}},
00620     {{Script_Hebrew_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00621      {LANG_HEBREW, 0, 1, 0, 0, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00622      MS_MAKE_TAG('h','e','b','r'),
00623      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
00624     {{Script_Vietnamese_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00625      {LANG_VIETNAMESE, 0, 0, 0, 0, VIETNAMESE_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00626      MS_MAKE_TAG('l','a','t','n'),
00627      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
00628     {{Script_Thai_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
00629      {LANG_THAI, 0, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00630      MS_MAKE_TAG('t','h','a','i'),
00631      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
00632 };
00633 
00634 static const SCRIPT_PROPERTIES *script_props[] =
00635 {
00636     &scriptInformation[0].props, &scriptInformation[1].props,
00637     &scriptInformation[2].props, &scriptInformation[3].props,
00638     &scriptInformation[4].props, &scriptInformation[5].props,
00639     &scriptInformation[6].props, &scriptInformation[7].props,
00640     &scriptInformation[8].props, &scriptInformation[9].props,
00641     &scriptInformation[10].props, &scriptInformation[11].props,
00642     &scriptInformation[12].props, &scriptInformation[13].props,
00643     &scriptInformation[14].props, &scriptInformation[15].props,
00644     &scriptInformation[16].props, &scriptInformation[17].props,
00645     &scriptInformation[18].props, &scriptInformation[19].props,
00646     &scriptInformation[20].props, &scriptInformation[21].props,
00647     &scriptInformation[22].props, &scriptInformation[23].props,
00648     &scriptInformation[24].props, &scriptInformation[25].props,
00649     &scriptInformation[26].props, &scriptInformation[27].props,
00650     &scriptInformation[28].props, &scriptInformation[29].props,
00651     &scriptInformation[30].props, &scriptInformation[31].props,
00652     &scriptInformation[32].props, &scriptInformation[33].props,
00653     &scriptInformation[34].props, &scriptInformation[35].props,
00654     &scriptInformation[36].props, &scriptInformation[37].props,
00655     &scriptInformation[38].props, &scriptInformation[39].props,
00656     &scriptInformation[40].props, &scriptInformation[41].props,
00657     &scriptInformation[42].props, &scriptInformation[43].props,
00658     &scriptInformation[44].props, &scriptInformation[45].props,
00659     &scriptInformation[46].props, &scriptInformation[47].props,
00660     &scriptInformation[48].props, &scriptInformation[49].props,
00661     &scriptInformation[50].props, &scriptInformation[51].props,
00662     &scriptInformation[52].props, &scriptInformation[53].props,
00663     &scriptInformation[54].props, &scriptInformation[55].props,
00664     &scriptInformation[56].props, &scriptInformation[57].props,
00665     &scriptInformation[58].props, &scriptInformation[59].props,
00666     &scriptInformation[60].props, &scriptInformation[61].props,
00667     &scriptInformation[62].props, &scriptInformation[63].props,
00668     &scriptInformation[64].props, &scriptInformation[65].props,
00669     &scriptInformation[66].props, &scriptInformation[67].props,
00670     &scriptInformation[68].props, &scriptInformation[69].props,
00671     &scriptInformation[70].props, &scriptInformation[71].props,
00672     &scriptInformation[72].props, &scriptInformation[73].props,
00673     &scriptInformation[74].props, &scriptInformation[75].props,
00674     &scriptInformation[76].props, &scriptInformation[77].props,
00675     &scriptInformation[78].props, &scriptInformation[79].props,
00676     &scriptInformation[80].props, &scriptInformation[81].props
00677 };
00678 
00679 typedef struct {
00680     ScriptCache *sc;
00681     int numGlyphs;
00682     WORD* glyphs;
00683     WORD* pwLogClust;
00684     int* piAdvance;
00685     SCRIPT_VISATTR* psva;
00686     GOFFSET* pGoffset;
00687     ABC* abc;
00688     int iMaxPosX;
00689     HFONT fallbackFont;
00690 } StringGlyphs;
00691 
00692 typedef struct {
00693     HDC hdc;
00694     DWORD dwFlags;
00695     BOOL invalid;
00696     int clip_len;
00697     int cItems;
00698     int cMaxGlyphs;
00699     SCRIPT_ITEM* pItem;
00700     int numItems;
00701     StringGlyphs* glyphs;
00702     SCRIPT_LOGATTR* logattrs;
00703     SIZE* sz;
00704     int* logical2visual;
00705 } StringAnalysis;
00706 
00707 typedef struct {
00708     BOOL ascending;
00709     WORD target;
00710 } FindGlyph_struct;
00711 
00712 static inline void *heap_alloc(SIZE_T size)
00713 {
00714     return HeapAlloc(GetProcessHeap(), 0, size);
00715 }
00716 
00717 static inline void *heap_alloc_zero(SIZE_T size)
00718 {
00719     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
00720 }
00721 
00722 static inline void *heap_realloc_zero(LPVOID mem, SIZE_T size)
00723 {
00724     return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size);
00725 }
00726 
00727 static inline BOOL heap_free(LPVOID mem)
00728 {
00729     return HeapFree(GetProcessHeap(), 0, mem);
00730 }
00731 
00732 static inline WCHAR get_cache_default_char(SCRIPT_CACHE *psc)
00733 {
00734     return ((ScriptCache *)*psc)->tm.tmDefaultChar;
00735 }
00736 
00737 static inline LONG get_cache_height(SCRIPT_CACHE *psc)
00738 {
00739     return ((ScriptCache *)*psc)->tm.tmHeight;
00740 }
00741 
00742 static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc)
00743 {
00744     return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
00745 }
00746 
00747 static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, DWORD c)
00748 {
00749     WORD *block = ((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
00750 
00751     if (!block) return 0;
00752     return block[c & GLYPH_BLOCK_MASK];
00753 }
00754 
00755 static inline WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph)
00756 {
00757     WORD **block = &((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
00758 
00759     if (!*block && !(*block = heap_alloc_zero(sizeof(WORD) * GLYPH_BLOCK_SIZE))) return 0;
00760     return ((*block)[c & GLYPH_BLOCK_MASK] = glyph);
00761 }
00762 
00763 static inline BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
00764 {
00765     static const ABC nil;
00766     ABC *block = ((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
00767 
00768     if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(ABC))) return FALSE;
00769     memcpy(abc, &block[glyph & GLYPH_BLOCK_MASK], sizeof(ABC));
00770     return TRUE;
00771 }
00772 
00773 static inline BOOL set_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
00774 {
00775     ABC **block = &((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
00776 
00777     if (!*block && !(*block = heap_alloc_zero(sizeof(ABC) * GLYPH_BLOCK_SIZE))) return FALSE;
00778     memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], abc, sizeof(ABC));
00779     return TRUE;
00780 }
00781 
00782 static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
00783 {
00784     ScriptCache *sc;
00785 
00786     if (!psc) return E_INVALIDARG;
00787     if (*psc) return S_OK;
00788     if (!hdc) return E_PENDING;
00789 
00790     if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
00791     if (!GetTextMetricsW(hdc, &sc->tm))
00792     {
00793         heap_free(sc);
00794         return E_INVALIDARG;
00795     }
00796     if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(LOGFONTW), &sc->lf))
00797     {
00798         heap_free(sc);
00799         return E_INVALIDARG;
00800     }
00801     sc->sfnt = (GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, NULL, 0)!=GDI_ERROR);
00802     *psc = sc;
00803     TRACE("<- %p\n", sc);
00804     return S_OK;
00805 }
00806 
00807 static WCHAR mirror_char( WCHAR ch )
00808 {
00809     extern const WCHAR wine_mirror_map[];
00810     return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
00811 }
00812 
00813 static inline DWORD decode_surrogate_pair(LPCWSTR str, INT index, INT end)
00814 {
00815     if (index < end-1 && IS_SURROGATE_PAIR(str[index],str[index+1]))
00816     {
00817         DWORD ch = 0x10000 + ((str[index] - 0xd800) << 10) + (str[index+1] - 0xdc00);
00818         TRACE("Surrogate Pair %x %x => %x\n",str[index], str[index+1], ch);
00819         return ch;
00820     }
00821     return 0;
00822 }
00823 
00824 static WORD get_char_script( LPCWSTR str, INT index, INT end, INT *consumed)
00825 {
00826     static const WCHAR latin_punc[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
00827     WORD type = 0;
00828     DWORD ch;
00829     int i;
00830 
00831     *consumed = 1;
00832 
00833     if (str[index] == 0xc || str[index] == 0x20 || str[index] == 0x202f)
00834         return Script_CR;
00835 
00836     /* These punctuation are separated out as Latin punctuation */
00837     if (strchrW(latin_punc,str[index]))
00838         return Script_Punctuation2;
00839 
00840     /* These chars are itemized as Punctuation by Windows */
00841     if (str[index] == 0x2212 || str[index] == 0x2044)
00842         return Script_Punctuation;
00843 
00844     /* Currency Symboles by Unicode point */
00845     switch (str[index])
00846     {
00847         case 0x09f2:
00848         case 0x09f3: return Script_Bengali_Currency;
00849         case 0x0af1: return Script_Gujarati_Currency;
00850         case 0x0e3f: return Script_Thai_Currency;
00851         case 0x20aa: return Script_Hebrew_Currency;
00852         case 0x20ab: return Script_Vietnamese_Currency;
00853         case 0xfb29: return Script_Hebrew_Currency;
00854     }
00855 
00856     GetStringTypeW(CT_CTYPE1, &str[index], 1, &type);
00857 
00858     if (type == 0)
00859         return SCRIPT_UNDEFINED;
00860 
00861     if (type & C1_CNTRL)
00862         return Script_Control;
00863 
00864     ch = decode_surrogate_pair(str, index, end);
00865     if (ch)
00866         *consumed = 2;
00867     else
00868         ch = str[index];
00869 
00870     i = 0;
00871     do
00872     {
00873         if (ch < scriptRanges[i].rangeFirst || scriptRanges[i].script == SCRIPT_UNDEFINED)
00874             break;
00875 
00876         if (ch >= scriptRanges[i].rangeFirst && ch <= scriptRanges[i].rangeLast)
00877         {
00878             if (scriptRanges[i].numericScript && type & C1_DIGIT)
00879                 return scriptRanges[i].numericScript;
00880             if (scriptRanges[i].punctScript && type & C1_PUNCT)
00881                 return scriptRanges[i].punctScript;
00882             return scriptRanges[i].script;
00883         }
00884         i++;
00885     } while (1);
00886 
00887     return SCRIPT_UNDEFINED;
00888 }
00889 
00890 static int compare_FindGlyph(const void *a, const void* b)
00891 {
00892     const FindGlyph_struct *find = (FindGlyph_struct*)a;
00893     const WORD *idx= (WORD*)b;
00894     int rc = 0;
00895 
00896     if ( find->target > *idx)
00897         rc = 1;
00898     else if (find->target < *idx)
00899         rc = -1;
00900 
00901     if (!find->ascending)
00902         rc *= -1;
00903     return rc;
00904 }
00905 
00906 int USP10_FindGlyphInLogClust(const WORD* pwLogClust, int cChars, WORD target)
00907 {
00908     FindGlyph_struct fgs;
00909     WORD *ptr;
00910     INT k;
00911 
00912     if (pwLogClust[0] < pwLogClust[cChars-1])
00913         fgs.ascending = TRUE;
00914     else
00915         fgs.ascending = FALSE;
00916 
00917     fgs.target = target;
00918     ptr = bsearch(&fgs, pwLogClust, cChars, sizeof(WORD), compare_FindGlyph);
00919 
00920     if (!ptr)
00921         return -1;
00922 
00923     for (k = (ptr - pwLogClust)-1; k >= 0 && pwLogClust[k] == target; k--)
00924     ;
00925     k++;
00926 
00927     return k;
00928 }
00929 
00930 /***********************************************************************
00931  *      DllMain
00932  *
00933  */
00934 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
00935 {
00936     switch(fdwReason)
00937     {
00938     case DLL_PROCESS_ATTACH:
00939         DisableThreadLibraryCalls(hInstDLL);
00940         break;
00941     case DLL_PROCESS_DETACH:
00942         break;
00943     }
00944     return TRUE;
00945 }
00946 
00947 /***********************************************************************
00948  *      ScriptFreeCache (USP10.@)
00949  *
00950  * Free a script cache.
00951  *
00952  * PARAMS
00953  *   psc [I/O] Script cache.
00954  *
00955  * RETURNS
00956  *  Success: S_OK
00957  *  Failure: Non-zero HRESULT value.
00958  */
00959 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
00960 {
00961     TRACE("%p\n", psc);
00962 
00963     if (psc && *psc)
00964     {
00965         unsigned int i;
00966         for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
00967         {
00968             heap_free(((ScriptCache *)*psc)->glyphs[i]);
00969             heap_free(((ScriptCache *)*psc)->widths[i]);
00970         }
00971         heap_free(((ScriptCache *)*psc)->GSUB_Table);
00972         heap_free(((ScriptCache *)*psc)->GDEF_Table);
00973         heap_free(((ScriptCache *)*psc)->CMAP_Table);
00974         for (i = 0; i < ((ScriptCache *)*psc)->script_count; i++)
00975         {
00976             int j;
00977             for (j = 0; j < ((ScriptCache *)*psc)->scripts[i].language_count; j++)
00978             {
00979                 int k;
00980                 for (k = 0; k < ((ScriptCache *)*psc)->scripts[i].languages[j].feature_count; k++)
00981                     heap_free(((ScriptCache *)*psc)->scripts[i].languages[j].features[k].lookups);
00982                 heap_free(((ScriptCache *)*psc)->scripts[i].languages[j].features);
00983             }
00984             heap_free(((ScriptCache *)*psc)->scripts[i].languages);
00985         }
00986         heap_free(((ScriptCache *)*psc)->scripts);
00987         heap_free(*psc);
00988         *psc = NULL;
00989     }
00990     return S_OK;
00991 }
00992 
00993 /***********************************************************************
00994  *      ScriptGetProperties (USP10.@)
00995  *
00996  * Retrieve a list of script properties.
00997  *
00998  * PARAMS
00999  *  props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
01000  *  num   [I] Pointer to the number of scripts.
01001  *
01002  * RETURNS
01003  *  Success: S_OK
01004  *  Failure: Non-zero HRESULT value.
01005  *
01006  * NOTES
01007  *  Behaviour matches WinXP.
01008  */
01009 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
01010 {
01011     TRACE("(%p,%p)\n", props, num);
01012 
01013     if (!props && !num) return E_INVALIDARG;
01014 
01015     if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
01016     if (props) *props = script_props;
01017 
01018     return S_OK;
01019 }
01020 
01021 /***********************************************************************
01022  *      ScriptGetFontProperties (USP10.@)
01023  *
01024  * Get information on special glyphs.
01025  *
01026  * PARAMS
01027  *  hdc [I]   Device context.
01028  *  psc [I/O] Opaque pointer to a script cache.
01029  *  sfp [O]   Font properties structure.
01030  */
01031 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
01032 {
01033     HRESULT hr;
01034 
01035     TRACE("%p,%p,%p\n", hdc, psc, sfp);
01036 
01037     if (!sfp) return E_INVALIDARG;
01038     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
01039 
01040     if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
01041         return E_INVALIDARG;
01042 
01043     /* return something sensible? */
01044     sfp->wgBlank = 0;
01045     sfp->wgDefault = get_cache_default_char(psc);
01046     sfp->wgInvalid = 0;
01047     sfp->wgKashida = 0xffff;
01048     sfp->iKashidaWidth = 0;
01049 
01050     return S_OK;
01051 }
01052 
01053 /***********************************************************************
01054  *      ScriptRecordDigitSubstitution (USP10.@)
01055  *
01056  *  Record digit substitution settings for a given locale.
01057  *
01058  *  PARAMS
01059  *   locale [I] Locale identifier.
01060  *   sds    [I] Structure to record substitution settings.
01061  *
01062  *  RETURNS
01063  *   Success: S_OK
01064  *   Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
01065  *
01066  *  SEE ALSO
01067  *   http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
01068  */
01069 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
01070 {
01071     DWORD plgid, sub;
01072 
01073     TRACE("0x%x, %p\n", locale, sds);
01074 
01075     /* This implementation appears to be correct for all languages, but it's
01076      * not clear if sds->DigitSubstitute is ever set to anything except 
01077      * CONTEXT or NONE in reality */
01078 
01079     if (!sds) return E_POINTER;
01080 
01081     locale = ConvertDefaultLocale(locale);
01082 
01083     if (!IsValidLocale(locale, LCID_INSTALLED))
01084         return E_INVALIDARG;
01085 
01086     plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
01087     sds->TraditionalDigitLanguage = plgid;
01088 
01089     if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
01090         sds->NationalDigitLanguage = plgid;
01091     else
01092         sds->NationalDigitLanguage = LANG_ENGLISH;
01093 
01094     if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
01095                         (LPWSTR)&sub, sizeof(sub)/sizeof(WCHAR))) return E_INVALIDARG;
01096 
01097     switch (sub)
01098     {
01099     case 0: 
01100         if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
01101             sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
01102         else
01103             sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
01104         break;
01105     case 1:
01106         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
01107         break;
01108     case 2:
01109         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
01110         break;
01111     default:
01112         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
01113         break;
01114     }
01115 
01116     sds->dwReserved = 0;
01117     return S_OK;
01118 }
01119 
01120 /***********************************************************************
01121  *      ScriptApplyDigitSubstitution (USP10.@)
01122  *
01123  *  Apply digit substitution settings.
01124  *
01125  *  PARAMS
01126  *   sds [I] Structure with recorded substitution settings.
01127  *   sc  [I] Script control structure.
01128  *   ss  [I] Script state structure.
01129  *
01130  *  RETURNS
01131  *   Success: S_OK
01132  *   Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
01133  */
01134 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds, 
01135                                             SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
01136 {
01137     SCRIPT_DIGITSUBSTITUTE psds;
01138 
01139     TRACE("%p, %p, %p\n", sds, sc, ss);
01140 
01141     if (!sc || !ss) return E_POINTER;
01142     if (!sds)
01143     {
01144         sds = &psds;
01145         if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
01146             return E_INVALIDARG;
01147     }
01148 
01149     sc->uDefaultLanguage = LANG_ENGLISH;
01150     sc->fContextDigits = 0;
01151     ss->fDigitSubstitute = 0;
01152 
01153     switch (sds->DigitSubstitute) {
01154         case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
01155         case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
01156         case SCRIPT_DIGITSUBSTITUTE_NONE:
01157         case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
01158             return S_OK;
01159         default:
01160             return E_INVALIDARG;
01161     }
01162 }
01163 
01164 static inline BOOL is_indic(WORD script)
01165 {
01166     return (script >= Script_Devanagari && script <= Script_Malayalam_Numeric);
01167 }
01168 
01169 static inline WORD base_indic(WORD script)
01170 {
01171     switch (script)
01172     {
01173         case Script_Devanagari:
01174         case Script_Devanagari_Numeric: return Script_Devanagari;
01175         case Script_Bengali:
01176         case Script_Bengali_Numeric:
01177         case Script_Bengali_Currency: return Script_Bengali;
01178         case Script_Gurmukhi:
01179         case Script_Gurmukhi_Numeric: return Script_Gurmukhi;
01180         case Script_Gujarati:
01181         case Script_Gujarati_Numeric:
01182         case Script_Gujarati_Currency: return Script_Gujarati;
01183         case Script_Oriya:
01184         case Script_Oriya_Numeric: return Script_Oriya;
01185         case Script_Tamil:
01186         case Script_Tamil_Numeric: return Script_Tamil;
01187         case Script_Telugu:
01188         case Script_Telugu_Numeric: return Script_Telugu;
01189         case Script_Kannada:
01190         case Script_Kannada_Numeric: return Script_Kannada;
01191         case Script_Malayalam:
01192         case Script_Malayalam_Numeric: return Script_Malayalam;
01193         default:
01194             return -1;
01195     };
01196 }
01197 
01198 /***********************************************************************
01199  *      ScriptItemizeOpenType (USP10.@)
01200  *
01201  * Split a Unicode string into shapeable parts.
01202  *
01203  * PARAMS
01204  *  pwcInChars  [I] String to split.
01205  *  cInChars    [I] Number of characters in pwcInChars.
01206  *  cMaxItems   [I] Maximum number of items to return.
01207  *  psControl   [I] Pointer to a SCRIPT_CONTROL structure.
01208  *  psState     [I] Pointer to a SCRIPT_STATE structure.
01209  *  pItems      [O] Buffer to receive SCRIPT_ITEM structures.
01210  *  pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
01211  *  pcItems     [O] Number of script items returned.
01212  *
01213  * RETURNS
01214  *  Success: S_OK
01215  *  Failure: Non-zero HRESULT value.
01216  */
01217 HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
01218                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
01219                              SCRIPT_ITEM *pItems, OPENTYPE_TAG *pScriptTags, int *pcItems)
01220 {
01221 
01222 #define Numeric_space 0x0020
01223 #define ZWNJ 0x200C
01224 #define ZWJ  0x200D
01225 
01226     int   cnt = 0, index = 0, str = 0;
01227     int   New_Script = -1;
01228     int   i;
01229     WORD  *levels = NULL;
01230     WORD  *strength = NULL;
01231     WORD  *scripts = NULL;
01232     WORD  baselevel = 0;
01233     BOOL  new_run;
01234     WORD  last_indic = -1;
01235     WORD layoutRTL = 0;
01236     BOOL forceLevels = FALSE;
01237     INT consumed = 0;
01238 
01239     TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems, 
01240           psControl, psState, pItems, pcItems);
01241 
01242     if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
01243         return E_INVALIDARG;
01244 
01245     scripts = heap_alloc(cInChars * sizeof(WORD));
01246     if (!scripts)
01247         return E_OUTOFMEMORY;
01248 
01249     for (i = 0; i < cInChars; i++)
01250     {
01251         if (consumed <= 0)
01252         {
01253             scripts[i] = get_char_script(pwcInChars,i,cInChars,&consumed);
01254             consumed --;
01255         }
01256         else
01257         {
01258             scripts[i] = scripts[i-1];
01259             consumed --;
01260         }
01261         /* Devanagari danda (U+0964) and double danda (U+0965) are used for
01262            all Indic scripts */
01263         if ((pwcInChars[i] == 0x964 || pwcInChars[i] ==0x965) && last_indic > 0)
01264             scripts[i] = last_indic;
01265         else if (is_indic(scripts[i]))
01266             last_indic = base_indic(scripts[i]);
01267 
01268         /* Some unicode points (Zero Width Space U+200B -
01269            Right-to-Left Mark U+200F) will force us into bidi mode */
01270         if (!forceLevels && pwcInChars[i] >= 0x200B && pwcInChars[i] <= 0x200F)
01271             forceLevels = TRUE;
01272 
01273         /* Diacritical marks merge with other scripts */
01274         if (scripts[i] == Script_Diacritical && i > 0)
01275                 scripts[i] = scripts[i-1];
01276     }
01277 
01278     for (i = 0; i < cInChars; i++)
01279     {
01280         /* Joiners get merged preferencially right */
01281         if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ))
01282         {
01283             int j;
01284             if (i+1 == cInChars)
01285                 scripts[i] = scripts[i-1];
01286             else
01287             {
01288                 for (j = i+1; j < cInChars; j++)
01289                 {
01290                     if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ && pwcInChars[j] != Numeric_space)
01291                     {
01292                         scripts[i] = scripts[j];
01293                         break;
01294                     }
01295                 }
01296             }
01297         }
01298     }
01299 
01300     if (psState && psControl)
01301     {
01302         levels = heap_alloc_zero(cInChars * sizeof(WORD));
01303         if (!levels)
01304         {
01305             heap_free(scripts);
01306             return E_OUTOFMEMORY;
01307         }
01308 
01309         BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels);
01310         baselevel = levels[0];
01311         for (i = 0; i < cInChars; i++)
01312             if (levels[i]!=levels[0])
01313                 break;
01314         if (i >= cInChars && !odd(baselevel) && !odd(psState->uBidiLevel) && !forceLevels)
01315         {
01316             heap_free(levels);
01317             levels = NULL;
01318         }
01319         else
01320         {
01321             BOOL inNumber = FALSE;
01322             static WCHAR math_punc[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
01323 
01324             strength = heap_alloc_zero(cInChars * sizeof(WORD));
01325             if (!strength)
01326             {
01327                 heap_free(scripts);
01328                 heap_free(levels);
01329                 return E_OUTOFMEMORY;
01330             }
01331             BIDI_GetStrengths(pwcInChars, cInChars, psControl, strength);
01332 
01333             /* We currently mis-level leading Diacriticals */
01334             if (scripts[0] == Script_Diacritical)
01335                 for (i = 0; i < cInChars && scripts[0] == Script_Diacritical; i++)
01336                 {
01337                     levels[i] = odd(levels[i])?levels[i]+1:levels[i];
01338                     strength[i] = BIDI_STRONG;
01339                 }
01340 
01341             for (i = 0; i < cInChars; i++)
01342             {
01343                 /* Script_Numeric and select puncuation at level 0 get bumped to level 2 */
01344                 if ((levels[i] == 0 || (odd(psState->uBidiLevel) && levels[i] == psState->uBidiLevel+1)) && inNumber && strchrW(math_punc,pwcInChars[i]))
01345                 {
01346                     scripts[i] = Script_Numeric;
01347                     levels[i] = 2;
01348                 }
01349                 else if ((levels[i] == 0 || (odd(psState->uBidiLevel) && levels[i] == psState->uBidiLevel+1)) && scripts[i] == Script_Numeric)
01350                 {
01351                     levels[i] = 2;
01352                     inNumber = TRUE;
01353                 }
01354                 else
01355                     inNumber = FALSE;
01356 
01357                 /* Joiners get merged preferencially right */
01358                 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ))
01359                 {
01360                     int j;
01361                     if (i+1 == cInChars && levels[i-1] == levels[i])
01362                         strength[i] = strength[i-1];
01363                     else
01364                         for (j = i+1; j < cInChars && levels[i] == levels[j]; j++)
01365                             if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ && pwcInChars[j] != Numeric_space)
01366                             {
01367                                 strength[i] = strength[j];
01368                                 break;
01369                             }
01370                 }
01371             }
01372             if (psControl->fMergeNeutralItems)
01373             {
01374                 /* Merge the neutrals */
01375                 for (i = 0; i < cInChars; i++)
01376                 {
01377                     if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
01378                     {
01379                         int j;
01380                         for (j = i; j > 0; j--)
01381                         {
01382                             if (levels[i] != levels[j])
01383                                 break;
01384                             if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
01385                             {
01386                                 scripts[i] = scripts[j];
01387                                 strength[i] = strength[j];
01388                                 break;
01389                             }
01390                         }
01391                     }
01392                     /* Try going the other way */
01393                     if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
01394                     {
01395                         int j;
01396                         for (j = i; j < cInChars; j++)
01397                         {
01398                             if (levels[i] != levels[j])
01399                                 break;
01400                             if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
01401                             {
01402                                 scripts[i] = scripts[j];
01403                                 strength[i] = strength[j];
01404                                 break;
01405                             }
01406                         }
01407                     }
01408                 }
01409             }
01410         }
01411     }
01412 
01413     while ((!levels || (levels && levels[cnt+1] == levels[0])) && (pwcInChars[cnt] == Numeric_space) && cnt < cInChars)
01414         cnt++;
01415 
01416     if (cnt == cInChars) /* All Spaces */
01417     {
01418         cnt = 0;
01419         New_Script = scripts[cnt];
01420     }
01421 
01422     pItems[index].iCharPos = 0;
01423     pItems[index].a = scriptInformation[scripts[cnt]].a;
01424     pScriptTags[index] = scriptInformation[scripts[cnt]].scriptTag;
01425 
01426     if (strength && strength[cnt] == BIDI_STRONG)
01427         str = strength[cnt];
01428     else if (strength)
01429         str = strength[0];
01430 
01431     cnt = 0;
01432 
01433     if (levels)
01434     {
01435         if (strength[cnt] == BIDI_STRONG)
01436             layoutRTL = (odd(levels[cnt]))?1:0;
01437         else
01438             layoutRTL = (psState->uBidiLevel || odd(levels[cnt]))?1:0;
01439         pItems[index].a.fRTL = odd(levels[cnt]);
01440         pItems[index].a.fLayoutRTL = layoutRTL;
01441         pItems[index].a.s.uBidiLevel = levels[cnt];
01442     }
01443     else if (!pItems[index].a.s.uBidiLevel)
01444     {
01445         layoutRTL = (odd(baselevel))?1:0;
01446         pItems[index].a.s.uBidiLevel = baselevel;
01447         pItems[index].a.fLayoutRTL = odd(baselevel);
01448         pItems[index].a.fRTL = odd(baselevel);
01449     }
01450 
01451     TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
01452           levels?levels[cnt]:-1, str, New_Script, pItems[index].a.eScript, index, cnt,
01453           pItems[index].iCharPos);
01454 
01455     for (cnt=1; cnt < cInChars; cnt++)
01456     {
01457         if(pwcInChars[cnt] != Numeric_space)
01458             New_Script = scripts[cnt];
01459         else if (levels)
01460         {
01461             int j = 1;
01462             while (cnt + j < cInChars - 1 && pwcInChars[cnt+j] == Numeric_space && levels[cnt] == levels[cnt+j])
01463                 j++;
01464             if (cnt + j < cInChars && levels[cnt] == levels[cnt+j])
01465                 New_Script = scripts[cnt+j];
01466             else
01467                 New_Script = scripts[cnt];
01468         }
01469 
01470         new_run = FALSE;
01471         /* merge space strengths*/
01472         if (strength && strength[cnt] == BIDI_STRONG && str != BIDI_STRONG && New_Script == pItems[index].a.eScript)
01473             str = BIDI_STRONG;
01474 
01475         if (strength && strength[cnt] == BIDI_NEUTRAL && str == BIDI_STRONG && pwcInChars[cnt] != Numeric_space && New_Script == pItems[index].a.eScript)
01476             str = BIDI_NEUTRAL;
01477 
01478         /* changes in level */
01479         if (levels && (levels[cnt] != pItems[index].a.s.uBidiLevel))
01480         {
01481             TRACE("Level break(%i/%i)\n",pItems[index].a.s.uBidiLevel,levels[cnt]);
01482             new_run = TRUE;
01483         }
01484         /* changes in strength */
01485         else if (strength && pwcInChars[cnt] != Numeric_space && str != strength[cnt])
01486         {
01487             TRACE("Strength break (%i/%i)\n",str,strength[cnt]);
01488             new_run = TRUE;
01489         }
01490         /* changes in script */
01491         else if (((pwcInChars[cnt] != Numeric_space) && (New_Script != -1) && (New_Script != pItems[index].a.eScript)) || (New_Script == Script_Control))
01492         {
01493             TRACE("Script break(%i/%i)\n",pItems[index].a.eScript,New_Script);
01494             new_run = TRUE;
01495         }
01496 
01497         if (!new_run && strength && str == BIDI_STRONG)
01498         {
01499             layoutRTL = odd(levels[cnt])?1:0;
01500             pItems[index].a.fLayoutRTL = layoutRTL;
01501         }
01502 
01503         if (new_run)
01504         {
01505             TRACE("New_Level = %i, New_Strength = %i, New_Script=%d, eScript=%d\n", levels?levels[cnt]:-1, strength?strength[cnt]:str, New_Script, pItems[index].a.eScript);
01506 
01507             index++;
01508             if  (index+1 > cMaxItems)
01509                 return E_OUTOFMEMORY;
01510 
01511             if (strength)
01512                 str = strength[cnt];
01513 
01514             pItems[index].iCharPos = cnt;
01515             memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
01516 
01517             pItems[index].a = scriptInformation[New_Script].a;
01518             pScriptTags[index] = scriptInformation[New_Script].scriptTag;
01519             if (levels)
01520             {
01521                 if (levels[cnt] == 0)
01522                     layoutRTL = 0;
01523                 else
01524                     layoutRTL = (layoutRTL || odd(levels[cnt]))?1:0;
01525                 pItems[index].a.fRTL = odd(levels[cnt]);
01526                 pItems[index].a.fLayoutRTL = layoutRTL;
01527                 pItems[index].a.s.uBidiLevel = levels[cnt];
01528             }
01529             else if (!pItems[index].a.s.uBidiLevel)
01530             {
01531                 pItems[index].a.s.uBidiLevel = baselevel;
01532                 pItems[index].a.fLayoutRTL = layoutRTL;
01533                 pItems[index].a.fRTL = odd(baselevel);
01534             }
01535 
01536             TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
01537         }
01538     }
01539 
01540     /* While not strictly necessary according to the spec, make sure the n+1
01541      * item is set up to prevent random behaviour if the caller erroneously
01542      * checks the n+1 structure                                              */
01543     index++;
01544     memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
01545 
01546     TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
01547 
01548     /*  Set one SCRIPT_STATE item being returned  */
01549     if  (index + 1 > cMaxItems) return E_OUTOFMEMORY;
01550     if (pcItems) *pcItems = index;
01551 
01552     /*  Set SCRIPT_ITEM                                     */
01553     pItems[index].iCharPos = cnt;         /* the last item contains the ptr to the lastchar */
01554     heap_free(levels);
01555     heap_free(strength);
01556     heap_free(scripts);
01557     return S_OK;
01558 }
01559 
01560 /***********************************************************************
01561  *      ScriptItemize (USP10.@)
01562  *
01563  * Split a Unicode string into shapeable parts.
01564  *
01565  * PARAMS
01566  *  pwcInChars [I] String to split.
01567  *  cInChars   [I] Number of characters in pwcInChars.
01568  *  cMaxItems  [I] Maximum number of items to return.
01569  *  psControl  [I] Pointer to a SCRIPT_CONTROL structure.
01570  *  psState    [I] Pointer to a SCRIPT_STATE structure.
01571  *  pItems     [O] Buffer to receive SCRIPT_ITEM structures.
01572  *  pcItems    [O] Number of script items returned.
01573  *
01574  * RETURNS
01575  *  Success: S_OK
01576  *  Failure: Non-zero HRESULT value.
01577  */
01578 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
01579                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
01580                              SCRIPT_ITEM *pItems, int *pcItems)
01581 {
01582     OPENTYPE_TAG *discarded_tags;
01583     HRESULT res;
01584 
01585     discarded_tags = heap_alloc(cMaxItems * sizeof(OPENTYPE_TAG));
01586     if (!discarded_tags)
01587         return E_OUTOFMEMORY;
01588     res = ScriptItemizeOpenType(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, discarded_tags, pcItems);
01589     heap_free(discarded_tags);
01590     return res;
01591 }
01592 
01593 static inline int getGivenTabWidth(ScriptCache *psc, SCRIPT_TABDEF *pTabdef, int charPos, int current_x)
01594 {
01595     int defWidth;
01596     int cTabStops=0;
01597     INT *lpTabPos = NULL;
01598     INT nTabOrg = 0;
01599     INT x = 0;
01600 
01601     if (pTabdef)
01602         lpTabPos = pTabdef->pTabStops;
01603 
01604     if (pTabdef && pTabdef->iTabOrigin)
01605     {
01606         if (pTabdef->iScale)
01607             nTabOrg = (pTabdef->iTabOrigin * pTabdef->iScale)/4;
01608         else
01609             nTabOrg = pTabdef->iTabOrigin * psc->tm.tmAveCharWidth;
01610     }
01611 
01612     if (pTabdef)
01613         cTabStops = pTabdef->cTabStops;
01614 
01615     if (cTabStops == 1)
01616     {
01617         if (pTabdef->iScale)
01618             defWidth = ((pTabdef->pTabStops[0])*pTabdef->iScale) / 4;
01619         else
01620             defWidth = (pTabdef->pTabStops[0])*psc->tm.tmAveCharWidth;
01621         cTabStops = 0;
01622     }
01623     else
01624         defWidth = 8 * psc->tm.tmAveCharWidth;
01625 
01626     for (; cTabStops>0 ; lpTabPos++, cTabStops--)
01627     {
01628         int position = *lpTabPos;
01629         if (position < 0)
01630             position = -1 * position;
01631         if (pTabdef->iScale)
01632             position = (position * pTabdef->iScale) / 4;
01633         else
01634             position = position * psc->tm.tmAveCharWidth;
01635 
01636         if( nTabOrg + position > current_x)
01637         {
01638             if( *lpTabPos >= 0)
01639             {
01640                 /* a left aligned tab */
01641                 x = (nTabOrg + *lpTabPos) - current_x;
01642                 break;
01643             }
01644             else
01645             {
01646                 FIXME("Negative tabstop\n");
01647                 break;
01648             }
01649         }
01650     }
01651     if ((!cTabStops) && (defWidth > 0))
01652         x =((((current_x - nTabOrg) / defWidth)+1) * defWidth) - current_x;
01653     else if ((!cTabStops) && (defWidth < 0))
01654         FIXME("TODO: Negative defWidth\n");
01655 
01656     return x;
01657 }
01658 
01659 /***********************************************************************
01660  * Helper function for ScriptStringAnalyse
01661  */
01662 static BOOL requires_fallback(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
01663                               const WCHAR *pwcInChars, int cChars )
01664 {
01665     /* FIXME: When to properly fallback is still a bit of a mystery */
01666     WORD *glyphs;
01667 
01668     if (psa->fNoGlyphIndex)
01669         return FALSE;
01670 
01671     if (init_script_cache(hdc, psc) != S_OK)
01672         return FALSE;
01673 
01674     if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
01675         return TRUE;
01676 
01677     glyphs = heap_alloc(sizeof(WORD) * cChars);
01678     if (!glyphs)
01679         return FALSE;
01680     if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
01681     {
01682         heap_free(glyphs);
01683         return TRUE;
01684     }
01685     heap_free(glyphs);
01686 
01687     return FALSE;
01688 }
01689 
01690 static void find_fallback_font(DWORD scriptid, LPWSTR FaceName)
01691 {
01692     HKEY hkey;
01693 
01694     if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Uniscribe\\Fallback", &hkey))
01695     {
01696         static const WCHAR szFmt[] = {'%','x',0};
01697         WCHAR value[10];
01698         DWORD count = LF_FACESIZE * sizeof(WCHAR);
01699         DWORD type;
01700 
01701         sprintfW(value, szFmt, scriptInformation[scriptid].scriptTag);
01702         if (RegQueryValueExW(hkey, value, 0, &type, (LPBYTE)FaceName, &count))
01703             lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
01704         RegCloseKey(hkey);
01705     }
01706     else
01707         lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
01708 }
01709 
01710 /***********************************************************************
01711  *      ScriptStringAnalyse (USP10.@)
01712  *
01713  */
01714 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
01715                                    int cGlyphs, int iCharset, DWORD dwFlags,
01716                                    int iReqWidth, SCRIPT_CONTROL *psControl,
01717                                    SCRIPT_STATE *psState, const int *piDx,
01718                                    SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
01719                                    SCRIPT_STRING_ANALYSIS *pssa)
01720 {
01721     HRESULT hr = E_OUTOFMEMORY;
01722     StringAnalysis *analysis = NULL;
01723     SCRIPT_CONTROL sControl;
01724     SCRIPT_STATE sState;
01725     int i, num_items = 255;
01726     BYTE   *BidiLevel;
01727     WCHAR *iString = NULL;
01728 
01729     TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
01730           hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
01731           psControl, psState, piDx, pTabdef, pbInClass, pssa);
01732 
01733     if (iCharset != -1)
01734     {
01735         FIXME("Only Unicode strings are supported\n");
01736         return E_INVALIDARG;
01737     }
01738     if (cString < 1 || !pString) return E_INVALIDARG;
01739     if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
01740 
01741     if (!(analysis = heap_alloc_zero(sizeof(StringAnalysis)))) return E_OUTOFMEMORY;
01742     if (!(analysis->pItem = heap_alloc_zero(num_items * sizeof(SCRIPT_ITEM) + 1))) goto error;
01743 
01744     /* FIXME: handle clipping */
01745     analysis->clip_len = cString;
01746     analysis->hdc = hdc;
01747     analysis->dwFlags = dwFlags;
01748 
01749     if (psState)
01750         sState = *psState;
01751     else
01752         memset(&sState, 0, sizeof(SCRIPT_STATE));
01753 
01754     if (psControl)
01755         sControl = *psControl;
01756     else
01757         memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
01758 
01759     if (dwFlags & SSA_PASSWORD)
01760     {
01761         iString = heap_alloc(sizeof(WCHAR)*cString);
01762         if (!iString)
01763         {
01764             hr = E_OUTOFMEMORY;
01765             goto error;
01766         }
01767         for (i = 0; i < cString; i++)
01768             iString[i] = *((const WCHAR *)pString);
01769         pString = iString;
01770     }
01771 
01772     hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
01773                        &analysis->numItems);
01774 
01775     if FAILED(hr)
01776     {
01777         if (hr == E_OUTOFMEMORY)
01778             hr = E_INVALIDARG;
01779         goto error;
01780     }
01781 
01782     /* set back to out of memory for default goto error behaviour */
01783     hr = E_OUTOFMEMORY;
01784 
01785     if (dwFlags & SSA_BREAK)
01786     {
01787         if ((analysis->logattrs = heap_alloc(sizeof(SCRIPT_LOGATTR) * cString)))
01788         {
01789             for (i = 0; i < analysis->numItems; i++)
01790                 ScriptBreak(&((LPWSTR)pString)[analysis->pItem[i].iCharPos], analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos, &analysis->pItem[i].a, &analysis->logattrs[analysis->pItem[i].iCharPos]);
01791         }
01792         else
01793             goto error;
01794     }
01795 
01796     if (!(analysis->logical2visual = heap_alloc_zero(sizeof(int) * analysis->numItems)))
01797         goto error;
01798     if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
01799         goto error;
01800 
01801     if (dwFlags & SSA_GLYPHS)
01802     {
01803         int tab_x = 0;
01804         if (!(analysis->glyphs = heap_alloc_zero(sizeof(StringGlyphs) * analysis->numItems)))
01805         {
01806             heap_free(BidiLevel);
01807             goto error;
01808         }
01809 
01810         for (i = 0; i < analysis->numItems; i++)
01811         {
01812             SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
01813             int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
01814             int numGlyphs = 1.5 * cChar + 16;
01815             WORD *glyphs = heap_alloc_zero(sizeof(WORD) * numGlyphs);
01816             WORD *pwLogClust = heap_alloc_zero(sizeof(WORD) * cChar);
01817             int *piAdvance = heap_alloc_zero(sizeof(int) * numGlyphs);
01818             SCRIPT_VISATTR *psva = heap_alloc_zero(sizeof(SCRIPT_VISATTR) * numGlyphs);
01819             GOFFSET *pGoffset = heap_alloc_zero(sizeof(GOFFSET) * numGlyphs);
01820             ABC *abc = heap_alloc_zero(sizeof(ABC));
01821             int numGlyphsReturned;
01822             HFONT originalFont = 0x0;
01823 
01824             /* FIXME: non unicode strings */
01825             const WCHAR* pStr = (const WCHAR*)pString;
01826             analysis->glyphs[i].fallbackFont = NULL;
01827 
01828             if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset || !abc)
01829             {
01830                 heap_free (BidiLevel);
01831                 heap_free (glyphs);
01832                 heap_free (pwLogClust);
01833                 heap_free (piAdvance);
01834                 heap_free (psva);
01835                 heap_free (pGoffset);
01836                 heap_free (abc);
01837                 hr = E_OUTOFMEMORY;
01838                 goto error;
01839             }
01840 
01841             if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
01842             {
01843                 LOGFONTW lf;
01844                 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
01845                 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
01846                 lf.lfFaceName[0] = 0;
01847                 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
01848                 if (lf.lfFaceName[0])
01849                 {
01850                     analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
01851                     if (analysis->glyphs[i].fallbackFont)
01852                     {
01853                         ScriptFreeCache(sc);
01854                         originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
01855                     }
01856                 }
01857             }
01858 
01859             /* FIXME: When we properly shape Hangul remove this check */
01860             if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && analysis->pItem[i].a.eScript == Script_Hangul)
01861                 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
01862 
01863             if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && !scriptInformation[analysis->pItem[i].a.eScript].props.fComplex)
01864                 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
01865 
01866             hr = ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos],
01867                              cChar, numGlyphs, &analysis->pItem[i].a,
01868                              glyphs, pwLogClust, psva, &numGlyphsReturned);
01869             hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
01870                              piAdvance, pGoffset, abc);
01871             if (originalFont)
01872                 SelectObject(hdc,originalFont);
01873 
01874             if (dwFlags & SSA_TAB)
01875             {
01876                 int tabi = 0;
01877                 for (tabi = 0; tabi < cChar; tabi++)
01878                 {
01879                     if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
01880                         piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
01881                     tab_x+=piAdvance[tabi];
01882                 }
01883             }
01884 
01885             analysis->glyphs[i].numGlyphs = numGlyphsReturned;
01886             analysis->glyphs[i].glyphs = glyphs;
01887             analysis->glyphs[i].pwLogClust = pwLogClust;
01888             analysis->glyphs[i].piAdvance = piAdvance;
01889             analysis->glyphs[i].psva = psva;
01890             analysis->glyphs[i].pGoffset = pGoffset;
01891             analysis->glyphs[i].abc = abc;
01892             analysis->glyphs[i].iMaxPosX= -1;
01893 
01894             BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
01895         }
01896     }
01897     else
01898     {
01899         for (i = 0; i < analysis->numItems; i++)
01900             BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
01901     }
01902 
01903     ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
01904     heap_free(BidiLevel);
01905 
01906     *pssa = analysis;
01907     heap_free(iString);
01908     return S_OK;
01909 
01910 error:
01911     heap_free(iString);
01912     heap_free(analysis->glyphs);
01913     heap_free(analysis->logattrs);
01914     heap_free(analysis->pItem);
01915     heap_free(analysis->logical2visual);
01916     heap_free(analysis);
01917     return hr;
01918 }
01919 
01920 static inline BOOL does_glyph_start_cluster(const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cChars, int glyph, int direction)
01921 {
01922     if (pva[glyph].fClusterStart)
01923         return TRUE;
01924     if (USP10_FindGlyphInLogClust(pwLogClust, cChars, glyph) >= 0)
01925         return TRUE;
01926 
01927     return FALSE;
01928 }
01929 
01930 
01931 static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
01932                            int iX,
01933                            int iY,
01934                            int iItem,
01935                            int cStart,
01936                            int cEnd,
01937                            UINT uOptions,
01938                            const RECT *prc,
01939                            BOOL fSelected,
01940                            BOOL fDisabled)
01941 {
01942     StringAnalysis *analysis;
01943     int off_x = 0;
01944     HRESULT hr;
01945     COLORREF BkColor = 0x0;
01946     COLORREF TextColor = 0x0;
01947     INT BkMode = 0;
01948     INT runStart, runEnd;
01949     INT iGlyph, cGlyphs;
01950     HFONT oldFont = 0x0;
01951     RECT  crc;
01952     int i;
01953 
01954     TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
01955          ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
01956 
01957     if (!(analysis = ssa)) return E_INVALIDARG;
01958 
01959     if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
01960          (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
01961             return S_OK;
01962 
01963     CopyRect(&crc,prc);
01964     if (fSelected)
01965     {
01966         BkMode = GetBkMode(analysis->hdc);
01967         SetBkMode( analysis->hdc, OPAQUE);
01968         BkColor = GetBkColor(analysis->hdc);
01969         SetBkColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHT));
01970         if (!fDisabled)
01971         {
01972             TextColor = GetTextColor(analysis->hdc);
01973             SetTextColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
01974         }
01975     }
01976     if (analysis->glyphs[iItem].fallbackFont)
01977         oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
01978 
01979     if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
01980         runStart = cStart - analysis->pItem[iItem].iCharPos;
01981     else
01982         runStart =  0;
01983     if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
01984         runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
01985     else
01986         runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
01987 
01988     if (analysis->pItem[iItem].a.fRTL)
01989     {
01990         if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
01991             ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
01992         else
01993             ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
01994         crc.left = iX + off_x;
01995     }
01996     else
01997     {
01998         if (cStart >=0 && runStart)
01999             ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
02000         else
02001             ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
02002         crc.left = iX + off_x;
02003     }
02004 
02005     if (analysis->pItem[iItem].a.fRTL)
02006         iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
02007     else
02008         iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
02009 
02010     if (analysis->pItem[iItem].a.fRTL)
02011         cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
02012     else
02013         cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
02014 
02015     cGlyphs++;
02016 
02017     /* adjust for cluster glyphs when starting */
02018     if (analysis->pItem[iItem].a.fRTL)
02019         i = analysis->pItem[iItem+1].iCharPos - 1;
02020     else
02021         i = analysis->pItem[iItem].iCharPos;
02022 
02023     for (; i >=analysis->pItem[iItem].iCharPos && i < analysis->pItem[iItem+1].iCharPos; (analysis->pItem[iItem].a.fRTL)?i--:i++)
02024     {
02025         if (analysis->glyphs[iItem].pwLogClust[i - analysis->pItem[iItem].iCharPos] == iGlyph)
02026         {
02027             if (analysis->pItem[iItem].a.fRTL)
02028                 ScriptStringCPtoX(ssa, i, TRUE, &off_x);
02029             else
02030                 ScriptStringCPtoX(ssa, i, FALSE, &off_x);
02031             break;
02032         }
02033     }
02034 
02035     if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
02036     {
02037         INT direction;
02038         INT clust_glyph;
02039 
02040         clust_glyph = iGlyph + cGlyphs;
02041         if (analysis->pItem[iItem].a.fRTL)
02042             direction = -1;
02043         else
02044             direction = 1;
02045 
02046         while(clust_glyph < analysis->glyphs[iItem].numGlyphs &&
02047               !does_glyph_start_cluster(analysis->glyphs[iItem].psva, analysis->glyphs[iItem].pwLogClust, (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos), clust_glyph, direction))
02048         {
02049             cGlyphs++;
02050             clust_glyph++;
02051         }
02052     }
02053 
02054     hr = ScriptTextOut(analysis->hdc,
02055                        (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
02056                        iY, uOptions, &crc, &analysis->pItem[iItem].a, NULL, 0,
02057                        &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
02058                        &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
02059                        &analysis->glyphs[iItem].pGoffset[iGlyph]);
02060 
02061     TRACE("ScriptTextOut hr=%08x\n", hr);
02062 
02063     if (fSelected)
02064     {
02065         SetBkColor(analysis->hdc, BkColor);
02066         SetBkMode( analysis->hdc, BkMode);
02067         if (!fDisabled)
02068             SetTextColor(analysis->hdc, TextColor);
02069     }
02070     if (analysis->glyphs[iItem].fallbackFont)
02071         SelectObject(analysis->hdc, oldFont);
02072 
02073     return hr;
02074 }
02075 
02076 /***********************************************************************
02077  *      ScriptStringOut (USP10.@)
02078  *
02079  * This function takes the output of ScriptStringAnalyse and joins the segments
02080  * of glyphs and passes the resulting string to ScriptTextOut.  ScriptStringOut
02081  * only processes glyphs.
02082  *
02083  * Parameters:
02084  *  ssa       [I] buffer to hold the analysed string components
02085  *  iX        [I] X axis displacement for output
02086  *  iY        [I] Y axis displacement for output
02087  *  uOptions  [I] flags controling output processing
02088  *  prc       [I] rectangle coordinates
02089  *  iMinSel   [I] starting pos for substringing output string
02090  *  iMaxSel   [I] ending pos for substringing output string
02091  *  fDisabled [I] controls text highlighting
02092  *
02093  *  RETURNS
02094  *   Success: S_OK
02095  *   Failure: is the value returned by ScriptTextOut
02096  */
02097 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
02098                                int iX,
02099                                int iY, 
02100                                UINT uOptions, 
02101                                const RECT *prc, 
02102                                int iMinSel, 
02103                                int iMaxSel,
02104                                BOOL fDisabled)
02105 {
02106     StringAnalysis *analysis;
02107     int   item;
02108     HRESULT hr;
02109 
02110     TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
02111          ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
02112 
02113     if (!(analysis = ssa)) return E_INVALIDARG;
02114     if (!(analysis->dwFlags & SSA_GLYPHS)) return E_INVALIDARG;
02115 
02116     for (item = 0; item < analysis->numItems; item++)
02117     {
02118         hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
02119         if (FAILED(hr))
02120             return hr;
02121     }
02122 
02123     if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
02124     {
02125         if (iMaxSel > 0 &&  iMinSel < 0)
02126             iMinSel = 0;
02127         for (item = 0; item < analysis->numItems; item++)
02128         {
02129             hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
02130             if (FAILED(hr))
02131                 return hr;
02132         }
02133     }
02134 
02135     return S_OK;
02136 }
02137 
02138 /***********************************************************************
02139  *      ScriptStringCPtoX (USP10.@)
02140  *
02141  */
02142 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
02143 {
02144     int item;
02145     int runningX = 0;
02146     StringAnalysis* analysis = ssa;
02147 
02148     TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
02149 
02150     if (!ssa || !pX) return S_FALSE;
02151     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
02152 
02153     /* icp out of range */
02154     if(icp < 0)
02155     {
02156         analysis->invalid = TRUE;
02157         return E_INVALIDARG;
02158     }
02159 
02160     for(item=0; item<analysis->numItems; item++)
02161     {
02162         int CP, i;
02163         int offset;
02164 
02165         i = analysis->logical2visual[item];
02166         CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
02167         /* initialize max extents for uninitialized runs */
02168         if (analysis->glyphs[i].iMaxPosX == -1)
02169         {
02170             if (analysis->pItem[i].a.fRTL)
02171                 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
02172                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
02173                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
02174             else
02175                 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
02176                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
02177                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
02178         }
02179 
02180         if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
02181         {
02182             runningX += analysis->glyphs[i].iMaxPosX;
02183             continue;
02184         }
02185 
02186         icp -= analysis->pItem[i].iCharPos;
02187         ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
02188                     analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
02189                     &analysis->pItem[i].a, &offset);
02190         runningX += offset;
02191 
02192         *pX = runningX;
02193         return S_OK;
02194     }
02195 
02196     /* icp out of range */
02197     analysis->invalid = TRUE;
02198     return E_INVALIDARG;
02199 }
02200 
02201 /***********************************************************************
02202  *      ScriptStringXtoCP (USP10.@)
02203  *
02204  */
02205 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
02206 {
02207     StringAnalysis* analysis = ssa;
02208     int item;
02209 
02210     TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
02211 
02212     if (!ssa || !piCh || !piTrailing) return S_FALSE;
02213     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
02214 
02215     /* out of range */
02216     if(iX < 0)
02217     {
02218         if (analysis->pItem[0].a.fRTL)
02219         {
02220             *piCh = 1;
02221             *piTrailing = FALSE;
02222         }
02223         else
02224         {
02225             *piCh = -1;
02226             *piTrailing = TRUE;
02227         }
02228         return S_OK;
02229     }
02230 
02231     for(item=0; item<analysis->numItems; item++)
02232     {
02233         int i;
02234         int CP;
02235 
02236         for (i = 0; i < analysis->numItems && analysis->logical2visual[i] != item; i++)
02237         /* nothing */;
02238 
02239         CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
02240         /* initialize max extents for uninitialized runs */
02241         if (analysis->glyphs[i].iMaxPosX == -1)
02242         {
02243             if (analysis->pItem[i].a.fRTL)
02244                 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
02245                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
02246                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
02247             else
02248                 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
02249                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
02250                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
02251         }
02252 
02253         if (iX > analysis->glyphs[i].iMaxPosX)
02254         {
02255             iX -= analysis->glyphs[i].iMaxPosX;
02256             continue;
02257         }
02258 
02259         ScriptXtoCP(iX, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
02260                     analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
02261                     &analysis->pItem[i].a, piCh, piTrailing);
02262         *piCh += analysis->pItem[i].iCharPos;
02263 
02264         return S_OK;
02265     }
02266 
02267     /* out of range */
02268     *piCh = analysis->pItem[analysis->numItems].iCharPos;
02269     *piTrailing = FALSE;
02270 
02271     return S_OK;
02272 }
02273 
02274 
02275 /***********************************************************************
02276  *      ScriptStringFree (USP10.@)
02277  *
02278  * Free a string analysis.
02279  *
02280  * PARAMS
02281  *  pssa [I] string analysis.
02282  *
02283  * RETURNS
02284  *  Success: S_OK
02285  *  Failure: Non-zero HRESULT value.
02286  */
02287 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
02288 {
02289     StringAnalysis* analysis;
02290     BOOL invalid;
02291     int i;
02292 
02293     TRACE("(%p)\n", pssa);
02294 
02295     if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
02296 
02297     invalid = analysis->invalid;
02298 
02299     if (analysis->glyphs)
02300     {
02301         for (i = 0; i < analysis->numItems; i++)
02302         {
02303             heap_free(analysis->glyphs[i].glyphs);
02304             heap_free(analysis->glyphs[i].pwLogClust);
02305             heap_free(analysis->glyphs[i].piAdvance);
02306             heap_free(analysis->glyphs[i].psva);
02307             heap_free(analysis->glyphs[i].pGoffset);
02308             heap_free(analysis->glyphs[i].abc);
02309             if (analysis->glyphs[i].fallbackFont)
02310                 DeleteObject(analysis->glyphs[i].fallbackFont);
02311             ScriptFreeCache((SCRIPT_CACHE *)&analysis->glyphs[i].sc);
02312             heap_free(analysis->glyphs[i].sc);
02313         }
02314         heap_free(analysis->glyphs);
02315     }
02316 
02317     heap_free(analysis->pItem);
02318     heap_free(analysis->logattrs);
02319     heap_free(analysis->sz);
02320     heap_free(analysis->logical2visual);
02321     heap_free(analysis);
02322 
02323     if (invalid) return E_INVALIDARG;
02324     return S_OK;
02325 }
02326 
02327 static inline int get_cluster_size(const WORD *pwLogClust, int cChars, int item,
02328                                    int direction, int* iCluster, int *check_out)
02329 {
02330     int clust_size = 1;
02331     int check;
02332     WORD clust = pwLogClust[item];
02333 
02334     for (check = item+direction; check < cChars && check >= 0; check+=direction)
02335     {
02336         if (pwLogClust[check] == clust)
02337         {
02338             clust_size ++;
02339             if (iCluster && *iCluster == -1)
02340                 *iCluster = item;
02341         }
02342         else break;
02343     }
02344 
02345     if (check_out)
02346         *check_out = check;
02347 
02348     return clust_size;
02349 }
02350 
02351 static inline int get_glyph_cluster_advance(const int* piAdvance, const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cGlyphs, int cChars, int glyph, int direction)
02352 {
02353     int advance;
02354     int log_clust_max;
02355 
02356     advance = piAdvance[glyph];
02357 
02358     if (pwLogClust[0] > pwLogClust[cChars-1])
02359         log_clust_max = pwLogClust[0];
02360     else
02361         log_clust_max = pwLogClust[cChars-1];
02362 
02363     if (glyph > log_clust_max)
02364         return advance;
02365 
02366     for (glyph+=direction; glyph < cGlyphs && glyph >= 0; glyph +=direction)
02367     {
02368 
02369         if (does_glyph_start_cluster(pva, pwLogClust, cChars, glyph, direction))
02370             break;
02371         if (glyph > log_clust_max)
02372             break;
02373         advance += piAdvance[glyph];
02374     }
02375 
02376     return advance;
02377 }
02378 
02379 /***********************************************************************
02380  *      ScriptCPtoX (USP10.@)
02381  *
02382  */
02383 HRESULT WINAPI ScriptCPtoX(int iCP,
02384                            BOOL fTrailing,
02385                            int cChars,
02386                            int cGlyphs,
02387                            const WORD *pwLogClust,
02388                            const SCRIPT_VISATTR *psva,
02389                            const int *piAdvance,
02390                            const SCRIPT_ANALYSIS *psa,
02391                            int *piX)
02392 {
02393     int item;
02394     float iPosX;
02395     int iSpecial = -1;
02396     int iCluster = -1;
02397     int clust_size = 1;
02398     float special_size = 0.0;
02399     int iMaxPos = 0;
02400     int advance = 0;
02401     BOOL rtl = FALSE;
02402 
02403     TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
02404           iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
02405           psa, piX);
02406 
02407     if (psa->fRTL && ! psa->fLogicalOrder)
02408         rtl = TRUE;
02409 
02410     if (fTrailing)
02411         iCP++;
02412 
02413     if (rtl)
02414     {
02415         int max_clust = pwLogClust[0];
02416 
02417         for (item=0; item < cGlyphs; item++)
02418             if (pwLogClust[item] > max_clust)
02419             {
02420                 ERR("We do not handle non reversed clusters properly\n");
02421                 break;
02422             }
02423 
02424         iMaxPos = 0;
02425         for (item = max_clust; item >=0; item --)
02426             iMaxPos += piAdvance[item];
02427     }
02428 
02429     iPosX = 0.0;
02430     for (item=0; item < iCP && item < cChars; item++)
02431     {
02432         if (iSpecial == -1 && (iCluster == -1 || (iCluster != -1 && iCluster+clust_size <= item)))
02433         {
02434             int check;
02435             int clust = pwLogClust[item];
02436 
02437             iCluster = -1;
02438             clust_size = get_cluster_size(pwLogClust, cChars, item, 1, &iCluster,
02439                                           &check);
02440 
02441             advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, 1);
02442 
02443             if (check >= cChars && !iMaxPos)
02444             {
02445                 for (check = clust; check < cChars; check++)
02446                     special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, check, 1);
02447                 iSpecial = item;
02448                 special_size /= (cChars - item);
02449                 iPosX += special_size;
02450             }
02451             else
02452             {
02453                 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
02454                 {
02455                     clust_size --;
02456                     if (clust_size == 0)
02457                         iPosX += advance;
02458                 }
02459                 else
02460                     iPosX += advance / (float)clust_size;
02461             }
02462         }
02463         else if (iSpecial != -1)
02464             iPosX += special_size;
02465         else /* (iCluster != -1) */
02466         {
02467             int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], 1);
02468             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
02469             {
02470                 clust_size --;
02471                 if (clust_size == 0)
02472                     iPosX += adv;
02473             }
02474             else
02475                 iPosX += adv / (float)clust_size;
02476         }
02477     }
02478 
02479     if (iMaxPos > 0)
02480     {
02481         iPosX = iMaxPos - iPosX;
02482         if (iPosX < 0)
02483             iPosX = 0;
02484     }
02485 
02486     *piX = iPosX;
02487     TRACE("*piX=%d\n", *piX);
02488     return S_OK;
02489 }
02490 
02491 /***********************************************************************
02492  *      ScriptXtoCP (USP10.@)
02493  *
02494  */
02495 HRESULT WINAPI ScriptXtoCP(int iX,
02496                            int cChars,
02497                            int cGlyphs,
02498                            const WORD *pwLogClust,
02499                            const SCRIPT_VISATTR *psva,
02500                            const int *piAdvance,
02501                            const SCRIPT_ANALYSIS *psa,
02502                            int *piCP,
02503                            int *piTrailing)
02504 {
02505     int item;
02506     float iPosX;
02507     float iLastPosX;
02508     int iSpecial = -1;
02509     int iCluster = -1;
02510     int clust_size = 1;
02511     int cjump = 0;
02512     int advance;
02513     float special_size = 0.0;
02514     int direction = 1;
02515 
02516     TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
02517           iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
02518           psa, piCP, piTrailing);
02519 
02520     if (psa->fRTL && ! psa->fLogicalOrder)
02521         direction = -1;
02522 
02523     if (direction<0)
02524     {
02525         int max_clust = pwLogClust[0];
02526 
02527         if (iX < 0)
02528         {
02529             *piCP = cChars;
02530             *piTrailing = 0;
02531             return S_OK;
02532         }
02533 
02534         for (item=0; item < cChars; item++)
02535             if (pwLogClust[item] > max_clust)
02536             {
02537                 ERR("We do not handle non reversed clusters properly\n");
02538                 break;
02539             }
02540     }
02541 
02542     if (iX < 0)
02543     {
02544         *piCP = -1;
02545         *piTrailing = 1;
02546         return S_OK;
02547     }
02548 
02549     iPosX = iLastPosX = 0;
02550     if (direction > 0)
02551         item = 0;
02552     else
02553         item = cChars - 1;
02554     for (; iPosX <= iX && item < cChars && item >= 0; item+=direction)
02555     {
02556         iLastPosX = iPosX;
02557         if (iSpecial == -1 &&
02558              (iCluster == -1 ||
02559               (iCluster != -1 &&
02560                  ((direction > 0 && iCluster+clust_size <= item) ||
02561                   (direction < 0 && iCluster-clust_size >= item))
02562               )
02563              )
02564             )
02565         {
02566             int check;
02567             int clust = pwLogClust[item];
02568 
02569             iCluster = -1;
02570             cjump = 0;
02571             clust_size = get_cluster_size(pwLogClust, cChars, item, direction,
02572                                           &iCluster, &check);
02573             advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, direction);
02574 
02575             if (check >= cChars && direction > 0)
02576             {
02577                 for (check = clust; check < cChars; check++)
02578                     special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, check, direction);
02579                 iSpecial = item;
02580                 special_size /= (cChars - item);
02581                 iPosX += special_size;
02582             }
02583             else
02584             {
02585                 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
02586                 {
02587                     if (!cjump)
02588                         iPosX += advance;
02589                     cjump++;
02590                 }
02591                 else
02592                     iPosX += advance / (float)clust_size;
02593             }
02594         }
02595         else if (iSpecial != -1)
02596             iPosX += special_size;
02597         else /* (iCluster != -1) */
02598         {
02599             int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], direction);
02600             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
02601             {
02602                 if (!cjump)
02603                     iPosX += adv;
02604                 cjump++;
02605             }
02606             else
02607                 iPosX += adv / (float)clust_size;
02608         }
02609     }
02610 
02611     if (direction > 0)
02612     {
02613         if (iPosX > iX)
02614             item--;
02615         if (item < cChars && ((iPosX - iLastPosX) / 2.0) + iX >= iPosX)
02616         {
02617             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo && clust_size > 1)
02618                 item+=(clust_size-1);
02619             *piTrailing = 1;
02620         }
02621         else
02622             *piTrailing = 0;
02623     }
02624     else
02625     {
02626         if (iX == iLastPosX)
02627             item++;
02628         if (iX >= iLastPosX && iX <= iPosX)
02629             item++;
02630 
02631         if (iLastPosX == iX)
02632             *piTrailing = 0;
02633         else if (item < 0 || ((iLastPosX - iPosX) / 2.0) + iX <= iLastPosX)
02634         {
02635             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo && clust_size > 1)
02636                 item-=(clust_size-1);
02637             *piTrailing = 1;
02638         }
02639         else
02640             *piTrailing = 0;
02641     }
02642 
02643     *piCP = item;
02644 
02645     TRACE("*piCP=%d\n", *piCP);
02646     TRACE("*piTrailing=%d\n", *piTrailing);
02647     return S_OK;
02648 }
02649 
02650 /***********************************************************************
02651  *      ScriptBreak (USP10.@)
02652  *
02653  *  Retrieve line break information.
02654  *
02655  *  PARAMS
02656  *   chars [I] Array of characters.
02657  *   sa    [I] String analysis.
02658  *   la    [I] Array of logical attribute structures.
02659  *
02660  *  RETURNS
02661  *   Success: S_OK
02662  *   Failure: S_FALSE
02663  */
02664 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
02665 {
02666     TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
02667 
02668     if (count < 0 || !la) return E_INVALIDARG;
02669     if (count == 0) return E_FAIL;
02670 
02671     BREAK_line(chars, count, sa, la);
02672 
02673     return S_OK;
02674 }
02675 
02676 /***********************************************************************
02677  *      ScriptIsComplex (USP10.@)
02678  *
02679  *  Determine if a string is complex.
02680  *
02681  *  PARAMS
02682  *   chars [I] Array of characters to test.
02683  *   len   [I] Length in characters.
02684  *   flag  [I] Flag.
02685  *
02686  *  RETURNS
02687  *   Success: S_OK
02688  *   Failure: S_FALSE
02689  *
02690  */
02691 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
02692 {
02693     int i;
02694     INT consumed = 0;
02695 
02696     TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
02697 
02698     for (i = 0; i < len; i+=consumed)
02699     {
02700         int script;
02701         if (i >= len)
02702             break;
02703 
02704         if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
02705             return S_OK;
02706 
02707         script = get_char_script(chars,i,len, &consumed);
02708         if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
02709             (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
02710             return S_OK;
02711     }
02712     return S_FALSE;
02713 }
02714 
02715 /***********************************************************************
02716  *      ScriptShapeOpenType (USP10.@)
02717  *
02718  * Produce glyphs and visual attributes for a run.
02719  *
02720  * PARAMS
02721  *  hdc         [I]   Device context.
02722  *  psc         [I/O] Opaque pointer to a script cache.
02723  *  psa         [I/O] Script analysis.
02724  *  tagScript   [I]   The OpenType tag for the Script
02725  *  tagLangSys  [I]   The OpenType tag for the Language
02726  *  rcRangeChars[I]   Array of Character counts in each range
02727  *  rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
02728  *  cRanges     [I]   Count of ranges
02729  *  pwcChars    [I]   Array of characters specifying the run.
02730  *  cChars      [I]   Number of characters in pwcChars.
02731  *  cMaxGlyphs  [I]   Length of pwOutGlyphs.
02732  *  pwLogClust  [O]   Array of logical cluster info.
02733  *  pCharProps  [O]   Array of character property values
02734  *  pwOutGlyphs [O]   Array of glyphs.
02735  *  pOutGlyphProps [O]  Array of attributes for the retrieved glyphs
02736  *  pcGlyphs    [O]   Number of glyphs returned.
02737  *
02738  * RETURNS
02739  *  Success: S_OK
02740  *  Failure: Non-zero HRESULT value.
02741  */
02742 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
02743                                     SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
02744                                     OPENTYPE_TAG tagLangSys, int *rcRangeChars,
02745                                     TEXTRANGE_PROPERTIES **rpRangeProperties,
02746                                     int cRanges, const WCHAR *pwcChars, int cChars,
02747                                     int cMaxGlyphs, WORD *pwLogClust,
02748                                     SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
02749                                     SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
02750 {
02751     HRESULT hr;
02752     unsigned int i,g;
02753     BOOL rtl;
02754     int cluster;
02755 
02756     TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
02757      hdc, psc, psa,
02758      debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
02759      rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
02760      cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
02761 
02762     if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
02763                    psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
02764 
02765     if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
02766     if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
02767 
02768     if (cRanges)
02769         FIXME("Ranges not supported yet\n");
02770 
02771     rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
02772 
02773     *pcGlyphs = cChars;
02774     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
02775     if (!pwLogClust) return E_FAIL;
02776 
02777     ((ScriptCache *)*psc)->userScript = tagScript;
02778     ((ScriptCache *)*psc)->userLang = tagLangSys;
02779 
02780     /* set fNoGlyphIndex non truetype/opentype fonts */
02781     if (psa && !psa->fNoGlyphIndex && !((ScriptCache *)*psc)->sfnt)
02782         psa->fNoGlyphIndex = TRUE;
02783 
02784     /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
02785     for (i = 0; i < cChars; i++)
02786     {
02787         int idx = i;
02788         if (rtl) idx = cChars - 1 - i;
02789         /* FIXME: set to better values */
02790         pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
02791         pOutGlyphProps[i].sva.fClusterStart  = 1;
02792         pOutGlyphProps[i].sva.fDiacritic     = 0;
02793         pOutGlyphProps[i].sva.fZeroWidth     = 0;
02794         pOutGlyphProps[i].sva.fReserved      = 0;
02795         pOutGlyphProps[i].sva.fShapeReserved = 0;
02796 
02797         /* FIXME: have the shaping engine set this */
02798         pCharProps[i].fCanGlyphAlone = 0;
02799 
02800         pwLogClust[i] = idx;
02801     }
02802 
02803     if (psa && !psa->fNoGlyphIndex)
02804     {
02805         WCHAR *rChars;
02806         if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
02807 
02808         rChars = heap_alloc(sizeof(WCHAR) * cChars);
02809         if (!rChars) return E_OUTOFMEMORY;
02810         for (i = 0, g = 0, cluster = 0; i < cChars; i++)
02811         {
02812             int idx = i;
02813             DWORD chInput;
02814 
02815             if (rtl) idx = cChars - 1 - i;
02816             if (!cluster)
02817             {
02818                 chInput = decode_surrogate_pair(pwcChars, idx, cChars);
02819                 if (!chInput)
02820                 {
02821                     if (psa->fRTL)
02822                         chInput = mirror_char(pwcChars[idx]);
02823                     else
02824                         chInput = pwcChars[idx];
02825                     /* special case for tabs */
02826                     if (chInput == 0x0009)
02827                         chInput = 0x0020;
02828                     rChars[i] = chInput;
02829                 }
02830                 else
02831                 {
02832                     rChars[i] = pwcChars[idx];
02833                     rChars[i+1] = pwcChars[(rtl)?idx-1:idx+1];
02834                     cluster = 1;
02835                 }
02836                 if (!(pwOutGlyphs[g] = get_cache_glyph(psc, chInput)))
02837                 {
02838                     WORD glyph;
02839                     if (!hdc)
02840                     {
02841                         heap_free(rChars);
02842                         return E_PENDING;
02843                     }
02844                     if (OpenType_CMAP_GetGlyphIndex(hdc, (ScriptCache *)*psc, chInput, &glyph, 0) == GDI_ERROR)
02845                     {
02846                         heap_free(rChars);
02847                         return S_FALSE;
02848                     }
02849                     pwOutGlyphs[g] = set_cache_glyph(psc, chInput, glyph);
02850                 }
02851                 g++;
02852             }
02853             else
02854             {
02855                 int k;
02856                 cluster--;
02857                 pwLogClust[idx] = (rtl)?pwLogClust[idx+1]:pwLogClust[idx-1];
02858                 for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
02859                     pwLogClust[k]--;
02860             }
02861         }
02862         *pcGlyphs = g;
02863 
02864         SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
02865         SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
02866         SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
02867         heap_free(rChars);
02868     }
02869     else
02870     {
02871         TRACE("no glyph translation\n");
02872         for (i = 0; i < cChars; i++)
02873         {
02874             int idx = i;
02875             /* No mirroring done here */
02876             if (rtl) idx = cChars - 1 - i;
02877             pwOutGlyphs[i] = pwcChars[idx];
02878         }
02879     }
02880 
02881     return S_OK;
02882 }
02883 
02884 
02885 /***********************************************************************
02886  *      ScriptShape (USP10.@)
02887  *
02888  * Produce glyphs and visual attributes for a run.
02889  *
02890  * PARAMS
02891  *  hdc         [I]   Device context.
02892  *  psc         [I/O] Opaque pointer to a script cache.
02893  *  pwcChars    [I]   Array of characters specifying the run.
02894  *  cChars      [I]   Number of characters in pwcChars.
02895  *  cMaxGlyphs  [I]   Length of pwOutGlyphs.
02896  *  psa         [I/O] Script analysis.
02897  *  pwOutGlyphs [O]   Array of glyphs.
02898  *  pwLogClust  [O]   Array of logical cluster info.
02899  *  psva        [O]   Array of visual attributes.
02900  *  pcGlyphs    [O]   Number of glyphs returned.
02901  *
02902  * RETURNS
02903  *  Success: S_OK
02904  *  Failure: Non-zero HRESULT value.
02905  */
02906 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
02907                            int cChars, int cMaxGlyphs,
02908                            SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
02909                            SCRIPT_VISATTR *psva, int *pcGlyphs)
02910 {
02911     HRESULT hr;
02912     int i;
02913     SCRIPT_CHARPROP *charProps;
02914     SCRIPT_GLYPHPROP *glyphProps;
02915 
02916     if (!psva || !pcGlyphs) return E_INVALIDARG;
02917     if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
02918 
02919     charProps = heap_alloc_zero(sizeof(SCRIPT_CHARPROP)*cChars);
02920     if (!charProps) return E_OUTOFMEMORY;
02921     glyphProps = heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP)*cMaxGlyphs);
02922     if (!glyphProps)
02923     {
02924         heap_free(charProps);
02925         return E_OUTOFMEMORY;
02926     }
02927 
02928     hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
02929 
02930     if (SUCCEEDED(hr))
02931     {
02932         for (i = 0; i < *pcGlyphs; i++)
02933             psva[i] = glyphProps[i].sva;
02934     }
02935 
02936     heap_free(charProps);
02937     heap_free(glyphProps);
02938 
02939     return hr;
02940 }
02941 
02942 /***********************************************************************
02943  *      ScriptPlaceOpenType (USP10.@)
02944  *
02945  * Produce advance widths for a run.
02946  *
02947  * PARAMS
02948  *  hdc       [I]   Device context.
02949  *  psc       [I/O] Opaque pointer to a script cache.
02950  *  psa       [I/O] String analysis.
02951  *  tagScript   [I]   The OpenType tag for the Script
02952  *  tagLangSys  [I]   The OpenType tag for the Language
02953  *  rcRangeChars[I]   Array of Character counts in each range
02954  *  rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
02955  *  cRanges     [I]   Count of ranges
02956  *  pwcChars    [I]   Array of characters specifying the run.
02957  *  pwLogClust  [I]   Array of logical cluster info
02958  *  pCharProps  [I]   Array of character property values
02959  *  cChars      [I]   Number of characters in pwcChars.
02960  *  pwGlyphs  [I]   Array of glyphs.
02961  *  pGlyphProps [I]  Array of attributes for the retrieved glyphs
02962  *  cGlyphs [I] Count of Glyphs
02963  *  piAdvance [O]   Array of advance widths.
02964  *  pGoffset  [O]   Glyph offsets.
02965  *  pABC      [O]   Combined ABC width.
02966  *
02967  * RETURNS
02968  *  Success: S_OK
02969  *  Failure: Non-zero HRESULT value.
02970  */
02971 
02972 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
02973                                     OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
02974                                     int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
02975                                     int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
02976                                     SCRIPT_CHARPROP *pCharProps, int cChars,
02977                                     const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
02978                                     int cGlyphs, int *piAdvance,
02979                                     GOFFSET *pGoffset, ABC *pABC
02980 )
02981 {
02982     HRESULT hr;
02983     int i;
02984 
02985     TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
02986      hdc, psc, psa,
02987      debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
02988      rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
02989      pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
02990      pGoffset, pABC);
02991 
02992     if (!pGlyphProps) return E_INVALIDARG;
02993     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
02994     if (!pGoffset) return E_FAIL;
02995 
02996     if (cRanges)
02997         FIXME("Ranges not supported yet\n");
02998 
02999     ((ScriptCache *)*psc)->userScript = tagScript;
03000     ((ScriptCache *)*psc)->userLang = tagLangSys;
03001 
03002     if (pABC) memset(pABC, 0, sizeof(ABC));
03003     for (i = 0; i < cGlyphs; i++)
03004     {
03005         ABC abc;
03006         if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
03007         {
03008             if (!hdc) return E_PENDING;
03009             if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE) && !psa->fNoGlyphIndex)
03010             {
03011                 if (!GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc)) return S_FALSE;
03012             }
03013             else
03014             {
03015                 INT width;
03016                 if (!GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width)) return S_FALSE;
03017                 abc.abcB = width;
03018                 abc.abcA = abc.abcC = 0;
03019             }
03020             set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
03021         }
03022         if (pABC)
03023         {
03024             pABC->abcA += abc.abcA;
03025             pABC->abcB += abc.abcB;
03026             pABC->abcC += abc.abcC;
03027         }
03028         /* FIXME: set to more reasonable values */
03029         pGoffset[i].du = pGoffset[i].dv = 0;
03030         if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
03031     }
03032 
03033     if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
03034     return S_OK;
03035 }
03036 
03037 /***********************************************************************
03038  *      ScriptPlace (USP10.@)
03039  *
03040  * Produce advance widths for a run.
03041  *
03042  * PARAMS
03043  *  hdc       [I]   Device context.
03044  *  psc       [I/O] Opaque pointer to a script cache.
03045  *  pwGlyphs  [I]   Array of glyphs.
03046  *  cGlyphs   [I]   Number of glyphs in pwGlyphs.
03047  *  psva      [I]   Array of visual attributes.
03048  *  psa       [I/O] String analysis.
03049  *  piAdvance [O]   Array of advance widths.
03050  *  pGoffset  [O]   Glyph offsets.
03051  *  pABC      [O]   Combined ABC width.
03052  *
03053  * RETURNS
03054  *  Success: S_OK
03055  *  Failure: Non-zero HRESULT value.
03056  */
03057 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs,
03058                            int cGlyphs, const SCRIPT_VISATTR *psva,
03059                            SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
03060 {
03061     HRESULT hr;
03062     SCRIPT_GLYPHPROP *glyphProps;
03063     int i;
03064 
03065     TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n",  hdc, psc, pwGlyphs, cGlyphs, psva, psa,
03066           piAdvance, pGoffset, pABC);
03067 
03068     if (!psva) return E_INVALIDARG;
03069     if (!pGoffset) return E_FAIL;
03070 
03071     glyphProps = heap_alloc(sizeof(SCRIPT_GLYPHPROP)*cGlyphs);
03072     if (!glyphProps) return E_OUTOFMEMORY;
03073 
03074     for (i = 0; i < cGlyphs; i++)
03075         glyphProps[i].sva = psva[i];
03076 
03077     hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
03078 
03079     heap_free(glyphProps);
03080 
03081     return hr;
03082 }
03083 
03084 /***********************************************************************
03085  *      ScriptGetCMap (USP10.@)
03086  *
03087  * Retrieve glyph indices.
03088  *
03089  * PARAMS
03090  *  hdc         [I]   Device context.
03091  *  psc         [I/O] Opaque pointer to a script cache.
03092  *  pwcInChars  [I]   Array of Unicode characters.
03093  *  cChars      [I]   Number of characters in pwcInChars.
03094  *  dwFlags     [I]   Flags.
03095  *  pwOutGlyphs [O]   Buffer to receive the array of glyph indices.
03096  *
03097  * RETURNS
03098  *  Success: S_OK
03099  *  Failure: Non-zero HRESULT value.
03100  */
03101 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
03102                              int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
03103 {
03104     HRESULT hr;
03105     int i;
03106 
03107     TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
03108           cChars, dwFlags, pwOutGlyphs);
03109 
03110     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
03111 
03112     hr = S_OK;
03113 
03114     if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
03115     {
03116         for (i = 0; i < cChars; i++)
03117         {
03118             WCHAR inChar;
03119             if (dwFlags == SGCM_RTL)
03120                 inChar = mirror_char(pwcInChars[i]);
03121             else
03122                 inChar = pwcInChars[i];
03123             if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
03124             {
03125                 WORD glyph;
03126                 if (!hdc) return E_PENDING;
03127                 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
03128                 if (glyph == 0xffff)
03129                 {
03130                     hr = S_FALSE;
03131                     glyph = 0x0;
03132                 }
03133                 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
03134             }
03135         }
03136     }
03137     else
03138     {
03139         TRACE("no glyph translation\n");
03140         for (i = 0; i < cChars; i++)
03141         {
03142             WCHAR inChar;
03143             if (dwFlags == SGCM_RTL)
03144                 inChar = mirror_char(pwcInChars[i]);
03145             else
03146                 inChar = pwcInChars[i];
03147             pwOutGlyphs[i] = inChar;
03148         }
03149     }
03150     return hr;
03151 }
03152 
03153 /***********************************************************************
03154  *      ScriptTextOut (USP10.@)
03155  *
03156  */
03157 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions, 
03158                              const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved, 
03159                              int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
03160                              const int *piJustify, const GOFFSET *pGoffset)
03161 {
03162     HRESULT hr = S_OK;
03163 
03164     TRACE("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p)\n",
03165          hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
03166          piAdvance, piJustify, pGoffset);
03167 
03168     if (!hdc || !psc) return E_INVALIDARG;
03169     if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
03170 
03171     fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
03172     fuOptions |= ETO_IGNORELANGUAGE;
03173     if  (!psa->fNoGlyphIndex)                                     /* Have Glyphs?                      */
03174         fuOptions |= ETO_GLYPH_INDEX;                             /* Say don't do translation to glyph */
03175 
03176     if (psa->fRTL && psa->fLogicalOrder)
03177     {
03178         int i;
03179         WORD *rtlGlyphs;
03180 
03181         rtlGlyphs = heap_alloc(cGlyphs * sizeof(WORD));
03182         if (!rtlGlyphs)
03183             return E_OUTOFMEMORY;
03184 
03185         for (i = 0; i < cGlyphs; i++)
03186             rtlGlyphs[i] = pwGlyphs[cGlyphs-1-i];
03187 
03188         if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, rtlGlyphs, cGlyphs, NULL))
03189             hr = S_FALSE;
03190         heap_free(rtlGlyphs);
03191     }
03192     else
03193         if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL))
03194             hr = S_FALSE;
03195 
03196     return hr;
03197 }
03198 
03199 /***********************************************************************
03200  *      ScriptCacheGetHeight (USP10.@)
03201  *
03202  * Retrieve the height of the font in the cache.
03203  *
03204  * PARAMS
03205  *  hdc    [I]    Device context.
03206  *  psc    [I/O]  Opaque pointer to a script cache.
03207  *  height [O]    Receives font height.
03208  *
03209  * RETURNS
03210  *  Success: S_OK
03211  *  Failure: Non-zero HRESULT value.
03212  */
03213 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
03214 {
03215     HRESULT hr;
03216 
03217     TRACE("(%p, %p, %p)\n", hdc, psc, height);
03218 
03219     if (!height) return E_INVALIDARG;
03220     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
03221 
03222     *height = get_cache_height(psc);
03223     return S_OK;
03224 }
03225 
03226 /***********************************************************************
03227  *      ScriptGetGlyphABCWidth (USP10.@)
03228  *
03229  * Retrieve the width of a glyph.
03230  *
03231  * PARAMS
03232  *  hdc    [I]    Device context.
03233  *  psc    [I/O]  Opaque pointer to a script cache.
03234  *  glyph  [I]    Glyph to retrieve the width for.
03235  *  abc    [O]    ABC widths of the glyph.
03236  *
03237  * RETURNS
03238  *  Success: S_OK
03239  *  Failure: Non-zero HRESULT value.
03240  */
03241 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
03242 {
03243     HRESULT hr;
03244 
03245     TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
03246 
03247     if (!abc) return E_INVALIDARG;
03248     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
03249 
03250     if (!get_cache_glyph_widths(psc, glyph, abc))
03251     {
03252         if (!hdc) return E_PENDING;
03253         if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
03254         {
03255             if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
03256         }
03257         else
03258         {
03259             INT width;
03260             if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
03261             abc->abcB = width;
03262             abc->abcA = abc->abcC = 0;
03263         }
03264         set_cache_glyph_widths(psc, glyph, abc);
03265     }
03266     return S_OK;
03267 }
03268 
03269 /***********************************************************************
03270  *      ScriptLayout (USP10.@)
03271  *
03272  * Map embedding levels to visual and/or logical order.
03273  *
03274  * PARAMS
03275  *  runs     [I] Size of level array.
03276  *  level    [I] Array of embedding levels.
03277  *  vistolog [O] Map of embedding levels from visual to logical order.
03278  *  logtovis [O] Map of embedding levels from logical to visual order.
03279  *
03280  * RETURNS
03281  *  Success: S_OK
03282  *  Failure: Non-zero HRESULT value.
03283  *
03284  * BUGS
03285  *  This stub works correctly for any sequence of a single
03286  *  embedding level but not for sequences of different
03287  *  embedding levels, i.e. mixtures of RTL and LTR scripts.
03288  */
03289 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
03290 {
03291     int* indexs;
03292     int ich;
03293 
03294     TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
03295 
03296     if (!level || (!vistolog && !logtovis))
03297         return E_INVALIDARG;
03298 
03299     indexs = heap_alloc(sizeof(int) * runs);
03300     if (!indexs)
03301         return E_OUTOFMEMORY;
03302 
03303 
03304     if (vistolog)
03305     {
03306         for( ich = 0; ich < runs; ich++)
03307             indexs[ich] = ich;
03308 
03309         ich = 0;
03310         while (ich < runs)
03311             ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
03312         for (ich = 0; ich < runs; ich++)
03313             vistolog[ich] = indexs[ich];
03314     }
03315 
03316 
03317     if (logtovis)
03318     {
03319         for( ich = 0; ich < runs; ich++)
03320             indexs[ich] = ich;
03321 
03322         ich = 0;
03323         while (ich < runs)
03324             ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
03325         for (ich = 0; ich < runs; ich++)
03326             logtovis[ich] = indexs[ich];
03327     }
03328     heap_free(indexs);
03329 
03330     return S_OK;
03331 }
03332 
03333 /***********************************************************************
03334  *      ScriptStringGetLogicalWidths (USP10.@)
03335  *
03336  * Returns logical widths from a string analysis.
03337  *
03338  * PARAMS
03339  *  ssa  [I] string analysis.
03340  *  piDx [O] logical widths returned.
03341  *
03342  * RETURNS
03343  *  Success: S_OK
03344  *  Failure: a non-zero HRESULT.
03345  */
03346 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
03347 {
03348     int i, j, next = 0;
03349     StringAnalysis *analysis = ssa;
03350 
03351     TRACE("%p, %p\n", ssa, piDx);
03352 
03353     if (!analysis) return S_FALSE;
03354     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
03355 
03356     for (i = 0; i < analysis->numItems; i++)
03357     {
03358         int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
03359         int direction = 1;
03360 
03361         if (analysis->pItem[i].a.fRTL && ! analysis->pItem[i].a.fLogicalOrder)
03362             direction = -1;
03363 
03364         for (j = 0; j < cChar; j++)
03365         {
03366             int k;
03367             int glyph = analysis->glyphs[i].pwLogClust[j];
03368             int clust_size = get_cluster_size(analysis->glyphs[i].pwLogClust,
03369                                               cChar, j, direction, NULL, NULL);
03370             int advance = get_glyph_cluster_advance(analysis->glyphs[i].piAdvance, analysis->glyphs[i].psva, analysis->glyphs[i].pwLogClust, analysis->glyphs[i].numGlyphs, cChar, glyph, direction);
03371 
03372             for (k = 0; k < clust_size; k++)
03373             {
03374                 piDx[next] = advance / clust_size;
03375                 next++;
03376                 if (k) j++;
03377             }
03378         }
03379     }
03380     return S_OK;
03381 }
03382 
03383 /***********************************************************************
03384  *      ScriptStringValidate (USP10.@)
03385  *
03386  * Validate a string analysis.
03387  *
03388  * PARAMS
03389  *  ssa [I] string analysis.
03390  *
03391  * RETURNS
03392  *  Success: S_OK
03393  *  Failure: S_FALSE if invalid sequences are found
03394  *           or a non-zero HRESULT if it fails.
03395  */
03396 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
03397 {
03398     StringAnalysis *analysis = ssa;
03399 
03400     TRACE("(%p)\n", ssa);
03401 
03402     if (!analysis) return E_INVALIDARG;
03403     return (analysis->invalid) ? S_FALSE : S_OK;
03404 }
03405 
03406 /***********************************************************************
03407  *      ScriptString_pSize (USP10.@)
03408  *
03409  * Retrieve width and height of an analysed string.
03410  *
03411  * PARAMS
03412  *  ssa [I] string analysis.
03413  *
03414  * RETURNS
03415  *  Success: Pointer to a SIZE structure.
03416  *  Failure: NULL
03417  */
03418 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
03419 {
03420     int i, j;
03421     StringAnalysis *analysis = ssa;
03422 
03423     TRACE("(%p)\n", ssa);
03424 
03425     if (!analysis) return NULL;
03426     if (!(analysis->dwFlags & SSA_GLYPHS)) return NULL;
03427 
03428     if (!analysis->sz)
03429     {
03430         if (!(analysis->sz = heap_alloc(sizeof(SIZE)))) return NULL;
03431         analysis->sz->cy = analysis->glyphs[0].sc->tm.tmHeight;
03432 
03433         analysis->sz->cx = 0;
03434         for (i = 0; i < analysis->numItems; i++)
03435         {
03436             if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz->cy)
03437                 analysis->sz->cy = analysis->glyphs[i].sc->tm.tmHeight;
03438             for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
03439                 analysis->sz->cx += analysis->glyphs[i].piAdvance[j];
03440         }
03441     }
03442     return analysis->sz;
03443 }
03444 
03445 /***********************************************************************
03446  *      ScriptString_pLogAttr (USP10.@)
03447  *
03448  * Retrieve logical attributes of an analysed string.
03449  *
03450  * PARAMS
03451  *  ssa [I] string analysis.
03452  *
03453  * RETURNS
03454  *  Success: Pointer to an array of SCRIPT_LOGATTR structures.
03455  *  Failure: NULL
03456  */
03457 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
03458 {
03459     StringAnalysis *analysis = ssa;
03460 
03461     TRACE("(%p)\n", ssa);
03462 
03463     if (!analysis) return NULL;
03464     if (!(analysis->dwFlags & SSA_BREAK)) return NULL;
03465     return analysis->logattrs;
03466 }
03467 
03468 /***********************************************************************
03469  *      ScriptString_pcOutChars (USP10.@)
03470  *
03471  * Retrieve the length of a string after clipping.
03472  *
03473  * PARAMS
03474  *  ssa [I] String analysis.
03475  *
03476  * RETURNS
03477  *  Success: Pointer to the length.
03478  *  Failure: NULL
03479  */
03480 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
03481 {
03482     StringAnalysis *analysis = ssa;
03483 
03484     TRACE("(%p)\n", ssa);
03485 
03486     if (!analysis) return NULL;
03487     return &analysis->clip_len;
03488 }
03489 
03490 /***********************************************************************
03491  *      ScriptStringGetOrder (USP10.@)
03492  *
03493  * Retrieve a glyph order map.
03494  *
03495  * PARAMS
03496  *  ssa   [I]   String analysis.
03497  *  order [I/O] Array of glyph positions.
03498  *
03499  * RETURNS
03500  *  Success: S_OK
03501  *  Failure: a non-zero HRESULT.
03502  */
03503 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
03504 {
03505     int i, j;
03506     unsigned int k;
03507     StringAnalysis *analysis = ssa;
03508 
03509     TRACE("(%p)\n", ssa);
03510 
03511     if (!analysis) return S_FALSE;
03512     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
03513 
03514     /* FIXME: handle RTL scripts */
03515     for (i = 0, k = 0; i < analysis->numItems; i++)
03516         for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
03517             order[k] = k;
03518 
03519     return S_OK;
03520 }
03521 
03522 /***********************************************************************
03523  *      ScriptGetLogicalWidths (USP10.@)
03524  *
03525  * Convert advance widths to logical widths.
03526  *
03527  * PARAMS
03528  *  sa          [I] Script analysis.
03529  *  nbchars     [I] Number of characters.
03530  *  nbglyphs    [I] Number of glyphs.
03531  *  glyph_width [I] Array of glyph widths.
03532  *  log_clust   [I] Array of logical clusters.
03533  *  sva         [I] Visual attributes.
03534  *  widths      [O] Array of logical widths.
03535  *
03536  * RETURNS
03537  *  Success: S_OK
03538  *  Failure: a non-zero HRESULT.
03539  */
03540 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
03541                                       const int *glyph_width, const WORD *log_clust,
03542                                       const SCRIPT_VISATTR *sva, int *widths)
03543 {
03544     int i;
03545 
03546     TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
03547           sa, nbchars, nbglyphs, glyph_width, log_clust, sva, widths);
03548 
03549     /* FIXME */
03550     for (i = 0; i < nbchars; i++) widths[i] = glyph_width[i];
03551     return S_OK;
03552 }
03553 
03554 /***********************************************************************
03555  *      ScriptApplyLogicalWidth (USP10.@)
03556  *
03557  * Generate glyph advance widths.
03558  *
03559  * PARAMS
03560  *  dx          [I]   Array of logical advance widths.
03561  *  num_chars   [I]   Number of characters.
03562  *  num_glyphs  [I]   Number of glyphs.
03563  *  log_clust   [I]   Array of logical clusters.
03564  *  sva         [I]   Visual attributes.
03565  *  advance     [I]   Array of glyph advance widths.
03566  *  sa          [I]   Script analysis.
03567  *  abc         [I/O] Summed ABC widths.
03568  *  justify     [O]   Array of glyph advance widths.
03569  *
03570  * RETURNS
03571  *  Success: S_OK
03572  *  Failure: a non-zero HRESULT.
03573  */
03574 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
03575                                        const WORD *log_clust, const SCRIPT_VISATTR *sva,
03576                                        const int *advance, const SCRIPT_ANALYSIS *sa,
03577                                        ABC *abc, int *justify)
03578 {
03579     int i;
03580 
03581     FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
03582           dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
03583 
03584     for (i = 0; i < num_chars; i++) justify[i] = advance[i];
03585     return S_OK;
03586 }
03587 
03588 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
03589                              int num_glyphs, int dx, int min_kashida, int *justify)
03590 {
03591     int i;
03592 
03593     FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
03594 
03595     for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
03596     return S_OK;
03597 }
03598 
03599 HRESULT WINAPI ScriptGetFontScriptTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags)
03600 {
03601     HRESULT hr;
03602     if (!pScriptTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
03603     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
03604 
03605     return SHAPE_GetFontScriptTags(hdc, (ScriptCache *)*psc, psa, cMaxTags, pScriptTags, pcTags);
03606 }
03607 
03608 HRESULT WINAPI ScriptGetFontLanguageTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags)
03609 {
03610     HRESULT hr;
03611     if (!pLangSysTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
03612     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
03613 
03614     return SHAPE_GetFontLanguageTags(hdc, (ScriptCache *)*psc, psa, tagScript, cMaxTags, pLangSysTags, pcTags);
03615 }
03616 
03617 HRESULT WINAPI ScriptGetFontFeatureTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags)
03618 {
03619     HRESULT hr;
03620     if (!pFeatureTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
03621     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
03622 
03623     return SHAPE_GetFontFeatureTags(hdc, (ScriptCache *)*psc, psa, tagScript, tagLangSys, cMaxTags, pFeatureTags, pcTags);
03624 }
03625 
03626 BOOL gbLpkPresent = FALSE;
03627 VOID WINAPI LpkPresent()
03628 {
03629     gbLpkPresent = TRUE; /* Turn it on this way! Wine is out of control! */
03630 }

Generated on Wed May 23 2012 04:24:39 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.