usp10: Remove unnecessary casts in test suite.
[wine] / dlls / usp10 / usp10.c
1 /*
2  * Implementation of Uniscribe Script Processor (usp10.dll)
3  *
4  * Copyright 2005 Steven Edwards for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Notes:
21  * Uniscribe allows for processing of complex scripts such as joining
22  * and filtering characters and bi-directional text with custom line breaks.
23  */
24
25 #include <stdarg.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "usp10.h"
32
33 #include "wine/debug.h"
34
35 /**
36  * some documentation here:
37  *   http://www.microsoft.com/typography/developers/uniscribe/uniscribe.htm
38  */
39
40 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
41
42 #define MAX_SCRIPTS  8
43
44 /*  Set up a default for ScriptGetProperties    */
45 static const SCRIPT_PROPERTIES Default_Script_0 = {0, 0, 0, 0, 0, 0, 0, 0, 
46                                             0, 0, 0, 0, 0, 0, 0};
47 static const SCRIPT_PROPERTIES Default_Script_1 = {0, 0, 0, 0, 0, 0, 0, 0, 
48                                             0, 0, 0, 0, 0, 0, 0};
49 static const SCRIPT_PROPERTIES Default_Script_2 = {0, 0, 0, 0, 0, 0, 0, 0, 
50                                             0, 0, 0, 0, 0, 0, 0};
51 static const SCRIPT_PROPERTIES Default_Script_3 = {9, 0, 0, 0, 0, 0, 0, 0, 
52                                             0, 0, 0, 0, 0, 0, 0};
53 static const SCRIPT_PROPERTIES Default_Script_4 = {9, 1, 0, 0, 0, 0, 0, 0, 
54                                             0, 0, 0, 0, 0, 0, 0};
55 static const SCRIPT_PROPERTIES Default_Script_5 = {9, 0, 0, 0, 0, 0, 0, 0, 
56                                             0, 0, 0, 0, 1, 0, 0};
57 static const SCRIPT_PROPERTIES Default_Script_6 = {9, 1, 0, 0, 0, 0, 0, 0, 
58                                             0, 0, 0, 0, 1, 0, 0};
59 static const SCRIPT_PROPERTIES Default_Script_7 = {8, 0, 0, 0, 0, 161, 0, 0, 
60                                             0, 0, 0, 0, 0, 0, 0};
61 static const SCRIPT_PROPERTIES *Global_Script[MAX_SCRIPTS] =
62                                       {&Default_Script_0,
63                                        &Default_Script_1,
64                                        &Default_Script_2,
65                                        &Default_Script_3,
66                                        &Default_Script_4,
67                                        &Default_Script_5,
68                                        &Default_Script_6,
69                                        &Default_Script_7};
70
71 typedef struct scriptcache {
72        HDC hdc;
73 } Scriptcache;
74
75 /***********************************************************************
76  *      DllMain
77  *
78  */
79 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
80 {
81     switch(fdwReason) {
82         case DLL_PROCESS_ATTACH:
83             DisableThreadLibraryCalls(hInstDLL);
84             break;
85         case DLL_PROCESS_DETACH:
86             break;
87     }
88     return TRUE;
89 }
90
91 /***********************************************************************
92  *      ScriptFreeCache (USP10.@)
93  *
94  */
95 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
96 {
97     TRACE("%p\n", psc);
98
99     if (psc) {
100        HeapFree ( GetProcessHeap(), 0, *psc);
101        *psc = NULL;
102     }
103     return 0;
104 }
105
106 /***********************************************************************
107  *      ScriptGetProperties (USP10.@)
108  *
109  */
110 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***ppSp, int *piNumScripts)
111 {
112     TRACE("%p,%p\n", ppSp, piNumScripts);
113
114     if (!ppSp && !piNumScripts) return E_INVALIDARG;
115
116     /* Set up a sensible default and intialise pointers  */
117     if (piNumScripts) *piNumScripts = MAX_SCRIPTS;
118     if (ppSp) *ppSp = Global_Script;
119     TRACE("ppSp:%p, *ppSp:%p, **ppSp:%p, %d\n",
120           ppSp, ppSp ? *ppSp : NULL, (ppSp && *ppSp) ? **ppSp : NULL,
121           piNumScripts ? *piNumScripts : -1);
122     return 0;
123 }
124
125 /***********************************************************************
126  *      ScriptGetFontProperties (USP10.@)
127  *
128  */
129 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
130 {
131     HDC phdc;
132     Scriptcache *pScriptcache;
133     TEXTMETRICW ptm;
134
135     TRACE("%p,%p,%p\n", hdc, psc, sfp);
136
137     if (!psc || !sfp)
138         return E_INVALIDARG;
139     if  (!hdc && !*psc) {
140         TRACE("No Script_Cache (psc) and no hdc. Ask for one. Hdc=%p, psc=%p\n", hdc, *psc);
141         return E_PENDING;
142     }   else 
143         if  (hdc && !*psc) {
144             pScriptcache = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Scriptcache) );
145             pScriptcache->hdc = (HDC) hdc;
146             phdc = hdc;
147             *psc = (Scriptcache *) pScriptcache;
148         }   else
149             if  (*psc) {
150                 pScriptcache = (Scriptcache *) *psc;
151                 phdc = pScriptcache->hdc;
152             }
153                 
154     if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
155         return E_INVALIDARG;
156
157     /* return something sensible? */
158     sfp->wgBlank       = 0;
159     if  (GetTextMetricsW(phdc, &ptm)) 
160         sfp->wgDefault = ptm.tmDefaultChar;
161     else
162         sfp->wgDefault = 0;
163     sfp->wgInvalid     = 0;
164     sfp->wgKashida     = 0xffff;
165     sfp->iKashidaWidth = 0;
166     return 0;
167 }
168
169 /***********************************************************************
170  *      ScriptRecordDigitSubstitution (USP10.@)
171  *
172  */
173 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID Locale,SCRIPT_DIGITSUBSTITUTE *psds)
174 {
175     FIXME("%ld,%p\n",Locale,psds);
176     return E_NOTIMPL;
177 }
178
179 /***********************************************************************
180  *      ScriptApplyDigitSubstitution (USP10.@)
181  *
182  */
183 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE* psds, 
184                                             SCRIPT_CONTROL* psc, SCRIPT_STATE* pss)
185 {
186     FIXME("%p,%p,%p\n",psds,psc,pss);
187     return E_NOTIMPL;
188 }
189
190 /***********************************************************************
191  *      ScriptItemize (USP10.@)
192  *
193  */
194 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems, 
195                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState, 
196                              SCRIPT_ITEM *pItems, int *pcItems)
197 {
198
199 #define Numeric_start 0x0030
200 #define Numeric_stop  0x0039
201 #define Numeric_space 0x0020
202 #define Arabic_start  0x0600
203 #define Arabic_stop   0x06ff
204 #define Latin_start   0x0001
205 #define Latin_stop    0x024f
206 #define Script_Arabic  6
207 #define Script_Latin   1
208 #define Script_Numeric 5
209
210     int   cnt = 0, index = 0;
211     int   New_Script = SCRIPT_UNDEFINED;
212
213     TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems, 
214           psControl, psState, pItems, pcItems);
215
216     if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
217         return E_INVALIDARG;
218
219     if  (pwcInChars[cnt] >= Numeric_start && pwcInChars[cnt] <= Numeric_stop)
220         pItems[index].a.eScript = Script_Numeric;
221     else
222     if  (pwcInChars[cnt] >= Arabic_start && pwcInChars[cnt] <= Arabic_stop)
223         pItems[index].a.eScript = Script_Arabic;
224     else
225     if  (pwcInChars[cnt] >= Latin_start && pwcInChars[cnt] <= Latin_stop)
226         pItems[index].a.eScript = Script_Latin;
227     else
228         pItems[index].a.eScript = SCRIPT_UNDEFINED;
229     pItems[index].iCharPos = 0;
230     /*  Set the SCRIPT_ANALYSIS                             */
231     pItems[index].a.fRTL = 0;
232     pItems[index].a.fLayoutRTL = 0;
233     pItems[index].a.fLinkBefore = 0;
234     pItems[index].a.fLinkAfter = 0;
235     pItems[index].a.fLogicalOrder = 0;
236     pItems[index].a.fNoGlyphIndex = 0;
237     /*  set the SCRIPT_STATE                                */
238     if  (New_Script == Script_Arabic)
239         pItems[index].a.s.uBidiLevel = 1;
240     else
241         pItems[index].a.s.uBidiLevel = 0;
242     pItems[index].a.s.fOverrideDirection = 0;
243     pItems[index].a.s.fInhibitSymSwap = FALSE;
244     pItems[index].a.s.fCharShape = 0;
245     pItems[index].a.s.fDigitSubstitute = 0;
246     pItems[index].a.s.fInhibitLigate = 0;
247     pItems[index].a.s.fDisplayZWG = 0;
248     pItems[index].a.s.fArabicNumContext = 0;
249     pItems[index].a.s.fGcpClusters = 0;
250     pItems[index].a.s.fReserved = 0;
251     pItems[index].a.s.fEngineReserved = 0;
252     TRACE("New_Script=%d, eScript=%d ", New_Script, pItems[index].a.eScript);
253     TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos = cnt);
254
255     for (cnt=0; cnt < cInChars; cnt++)
256     {
257         if  ((pwcInChars[cnt] >= Numeric_start && pwcInChars[cnt] <= Numeric_stop)
258              || (New_Script == Script_Numeric && pwcInChars[cnt] == Numeric_space))
259             New_Script = Script_Numeric;
260         else
261         if  ((pwcInChars[cnt] >= Arabic_start && pwcInChars[cnt] <= Arabic_stop)
262              || (New_Script == Script_Arabic && pwcInChars[cnt] == Numeric_space))
263             New_Script = Script_Arabic;
264         else
265         if  ((WCHAR) pwcInChars[cnt] >= Latin_start && (WCHAR) pwcInChars[cnt] <= Latin_stop)
266             New_Script = Script_Latin;
267         else
268             New_Script = SCRIPT_UNDEFINED;
269         
270         if  (New_Script != pItems[index].a.eScript)
271         {
272             TRACE("New_Script=%d, eScript=%d ", New_Script, pItems[index].a.eScript);
273             index++;
274             if  (index+1 > cMaxItems)
275                 return E_OUTOFMEMORY;
276             pItems[index].iCharPos = cnt;
277             if  (New_Script == Script_Arabic)
278                 pItems[index].a.s.uBidiLevel = 1;
279             /*  Set SCRIPT_ITEM                                     */
280             pItems[index].iCharPos = cnt;
281             /*  Set the SCRIPT_ANALYSIS                             */
282             pItems[index].a.eScript = New_Script;
283             pItems[index].a.fRTL = 0;
284             pItems[index].a.fLayoutRTL = 0;
285             pItems[index].a.fLinkBefore = 0;
286             pItems[index].a.fLinkAfter = 0;
287             pItems[index].a.fLogicalOrder = 0;
288             pItems[index].a.fNoGlyphIndex = 0;
289             /*  set the SCRIPT_STATE                                */
290             if  (New_Script == Script_Arabic)
291                 pItems[index].a.s.uBidiLevel = 1;
292             else
293                 pItems[index].a.s.uBidiLevel = 0;
294             pItems[index].a.s.fOverrideDirection = 0;
295             pItems[index].a.s.fInhibitSymSwap = FALSE;
296             pItems[index].a.s.fCharShape = 0;
297             pItems[index].a.s.fDigitSubstitute = 0;
298             pItems[index].a.s.fInhibitLigate = 0;
299             pItems[index].a.s.fDisplayZWG = 0;
300             pItems[index].a.s.fArabicNumContext = 0;
301             pItems[index].a.s.fGcpClusters = 0;
302             pItems[index].a.s.fReserved = 0;
303             pItems[index].a.s.fEngineReserved = 0;
304             TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos = cnt);
305         }
306     }
307
308     /* While not strickly necessary according to the spec, make sure the n+1
309      * item is set up to prevent random behaviour if the caller eroneously
310      * checks the n+1 structure                                              */
311     pItems[index+1].a.eScript = 0;
312     pItems[index+1].a.fRTL = 0;
313     pItems[index+1].a.fLayoutRTL = 0;
314     pItems[index+1].a.fLinkBefore = 0;
315     pItems[index+1].a.fLinkAfter = 0;
316     pItems[index+1].a.fLogicalOrder = 0;
317     pItems[index+1].a.fNoGlyphIndex = 0;
318     /*  set the SCRIPT_STATE                                */
319     pItems[index+1].a.s.uBidiLevel = 0;
320     pItems[index+1].a.s.fOverrideDirection = 0;
321     pItems[index+1].a.s.fInhibitSymSwap = FALSE;
322     pItems[index+1].a.s.fCharShape = 0;
323     pItems[index+1].a.s.fDigitSubstitute = 0;
324     pItems[index+1].a.s.fInhibitLigate = 0;
325     pItems[index+1].a.s.fDisplayZWG = 0;
326     pItems[index+1].a.s.fArabicNumContext = 0;
327     pItems[index+1].a.s.fGcpClusters = 0;
328     pItems[index+1].a.s.fReserved = 0;
329     pItems[index+1].a.s.fEngineReserved = 0;
330     TRACE("index=%d cnt=%d iCharPos=%d\n", index+1, cnt, pItems[index+1].iCharPos = cnt);
331
332     /*  Set one SCRIPT_STATE item being returned  */
333     *pcItems = index + 1;
334
335     /*  Set SCRIPT_ITEM                                     */
336     pItems[index+1].iCharPos = cnt;       /* the last + 1 item
337                                              contains the ptr to the lastchar */
338     return S_OK;
339 }
340
341 /***********************************************************************
342  *      ScriptStringAnalyse (USP10.@)
343  *
344  */
345 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, 
346                                    const void *pString, 
347                                    int cString, 
348                                    int cGlyphs,
349                                    int iCharset,
350                                    DWORD dwFlags,
351                                    int iReqWidth,
352                                    SCRIPT_CONTROL *psControl,
353                                    SCRIPT_STATE *psState,
354                                    const int *piDx,
355                                    SCRIPT_TABDEF *pTabdef,
356                                    const BYTE *pbInClass,
357                                    SCRIPT_STRING_ANALYSIS *pssa)
358 {
359   FIXME("(%p,%p,%d,%d,%d,0x%lx,%d,%p,%p,%p,%p,%p,%p): stub\n",
360         hdc, pString, cString, cGlyphs, iCharset, dwFlags,
361         iReqWidth, psControl, psState, piDx, pTabdef, pbInClass, pssa);
362   if (1 > cString || NULL == pString) {
363     return E_INVALIDARG;
364   }
365   if ((dwFlags & SSA_GLYPHS) && NULL == hdc) {
366     return E_PENDING;
367   }
368
369   return E_NOTIMPL;
370 }
371
372 /***********************************************************************
373  *      ScriptStringOut (USP10.@)
374  *
375  */
376 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa, 
377                                int iX, 
378                                int iY, 
379                                UINT uOptions, 
380                                const RECT *prc, 
381                                int iMinSel, 
382                                int iMaxSel, 
383                                BOOL fDisabled)
384 {
385     FIXME("(%p,%d,%d,0x%1x,%p,%d,%d,%d): stub\n",
386          ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
387     if  (!ssa) {
388         return E_INVALIDARG;
389     }
390
391     return E_NOTIMPL;
392 }
393
394 /***********************************************************************
395  *      ScriptStringCPtoX (USP10.@)
396  *
397  */
398 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
399 {
400     FIXME("(%p), %d, %d, (%p): stub\n", ssa, icp, fTrailing, pX);
401     *pX = 0;                             /* Set a reasonable value */
402     return S_OK;
403 }
404
405 /***********************************************************************
406  *      ScriptStringXtoCP (USP10.@)
407  *
408  */
409 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing) 
410 {
411     FIXME("(%p), %d, (%p), (%p): stub\n", ssa, iX, piCh, piTrailing);
412     *piCh = 0;                          /* Set a reasonable value */
413     *piTrailing = 0;
414     return S_OK;
415 }
416
417 /***********************************************************************
418  *      ScriptStringFree (USP10.@)
419  *
420  */
421 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa) {
422     FIXME("(%p): stub\n",pssa);
423     return S_OK;
424 }
425
426 /***********************************************************************
427  *      ScriptCPtoX (USP10.@)
428  *
429  */
430 HRESULT WINAPI ScriptCPtoX(int iCP,
431                            BOOL fTrailing,
432                            int cChars,
433                            int cGlyphs,
434                            const WORD *pwLogClust,
435                            const SCRIPT_VISATTR *psva,
436                            const int *piAdvance,
437                            const SCRIPT_ANALYSIS *psa,
438                            int *piX)
439 {
440     int  item;
441     int  iPosX;
442     float  fMaxPosX = 0;
443     TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
444           iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
445           psa, piX);
446     for (item=0; item < cGlyphs; item++)            /* total piAdvance           */
447         fMaxPosX += piAdvance[item];
448     iPosX = (fMaxPosX/cGlyphs)*(iCP+fTrailing);
449     if  (iPosX > fMaxPosX)
450         iPosX = fMaxPosX;
451     *piX = iPosX;                                    /* Return something in range */
452
453     TRACE("*piX=%d\n", *piX);
454     return S_OK;
455 }
456
457 /***********************************************************************
458  *      ScriptXtoCP (USP10.@)
459  *
460  */
461 HRESULT WINAPI ScriptXtoCP(int iX,
462                            int cChars,
463                            int cGlyphs,
464                            const WORD *pwLogClust,
465                            const SCRIPT_VISATTR *psva,
466                            const int *piAdvance,
467                            const SCRIPT_ANALYSIS *psa,
468                            int *piCP,
469                            int *piTrailing)
470 {
471     int item;
472     int iPosX = 1;
473     float fMaxPosX = 1;
474     float fAvePosX;
475     TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
476           iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
477           psa, piCP, piTrailing);
478     if  (iX < 0)                                    /* iX is before start of run */
479     {
480         *piCP = -1;
481         *piTrailing = TRUE;
482         return S_OK;
483     }
484
485     for (item=0; item < cGlyphs; item++)            /* total piAdvance           */
486         fMaxPosX += piAdvance[item];
487
488     if  (iX >= fMaxPosX)                            /* iX too large              */
489     {
490         *piCP = cChars;
491         *piTrailing = FALSE;
492         return S_OK;
493     }        
494
495     fAvePosX = fMaxPosX / cGlyphs;
496     for (item = 0; item < cGlyphs  && iPosX < iX; item++)
497         iPosX = fAvePosX * (item +1);
498     if  (iPosX - iX > fAvePosX/2)
499         *piTrailing = 0;
500     else
501         *piTrailing = 1;                            /* yep we are over half way  */
502     
503     *piCP = item -1;                                /* Return character position */
504     TRACE("*piCP=%d iPposX=%d\n", *piCP, iPosX);
505     return S_OK;
506 }
507
508 /***********************************************************************
509  *      ScriptBreak (USP10.@)
510  *
511  */
512 HRESULT WINAPI ScriptBreak(const WCHAR *pwcChars, int cChars,  const SCRIPT_ANALYSIS *psa,
513                     SCRIPT_LOGATTR *psla)
514 {
515     FIXME("(%p,%d,%p,%p): stub\n",
516           pwcChars, cChars, psa, psla);
517
518     return S_OK;
519 }
520
521 static const struct
522 {
523     WCHAR start;
524     WCHAR end;
525     DWORD flag;
526 }
527 complex_ranges[] =
528 {
529     { 0, 0x0b, SIC_COMPLEX },
530     { 0x0c, 0x0c, SIC_NEUTRAL },
531     { 0x0d, 0x1f, SIC_COMPLEX },
532     { 0x20, 0x2f, SIC_NEUTRAL },
533     { 0x30, 0x39, SIC_ASCIIDIGIT },
534     { 0x3a, 0x40, SIC_NEUTRAL },
535     { 0x5b, 0x60, SIC_NEUTRAL },
536     { 0x7b, 0x7e, SIC_NEUTRAL },
537     { 0x7f, 0x9f, SIC_COMPLEX },
538     { 0xa0, 0xa5, SIC_NEUTRAL },
539     { 0xa7, 0xa8, SIC_NEUTRAL },
540     { 0xab, 0xab, SIC_NEUTRAL },
541     { 0xad, 0xad, SIC_NEUTRAL },
542     { 0xaf, 0xaf, SIC_NEUTRAL },
543     { 0xb0, 0xb1, SIC_NEUTRAL },
544     { 0xb4, 0xb4, SIC_NEUTRAL },
545     { 0xb6, 0xb8, SIC_NEUTRAL },
546     { 0xbb, 0xbf, SIC_NEUTRAL },
547     { 0xd7, 0xd7, SIC_NEUTRAL },
548     { 0xf7, 0xf7, SIC_NEUTRAL },
549     { 0x2b9, 0x2ba, SIC_NEUTRAL },
550     { 0x2c2, 0x2cf, SIC_NEUTRAL },
551     { 0x2d2, 0x2df, SIC_NEUTRAL },
552     { 0x2e5, 0x2e9, SIC_COMPLEX },
553     { 0x2ea, 0x2ed, SIC_NEUTRAL },
554     { 0x300, 0x362, SIC_COMPLEX },
555     { 0x530, 0x60b, SIC_COMPLEX },
556     { 0x60c, 0x60d, SIC_NEUTRAL },
557     { 0x60e, 0x669, SIC_COMPLEX },
558     { 0x66a, 0x66a, SIC_NEUTRAL },
559     { 0x66b, 0x6e8, SIC_COMPLEX },
560     { 0x6e9, 0x6e9, SIC_NEUTRAL },
561     { 0x6ea, 0x7bf, SIC_COMPLEX },
562     { 0x900, 0x1360, SIC_COMPLEX },
563     { 0x137d, 0x137f, SIC_COMPLEX },
564     { 0x1680, 0x1680, SIC_NEUTRAL },
565     { 0x1780, 0x18af, SIC_COMPLEX },
566     { 0x2000, 0x200a, SIC_NEUTRAL },
567     { 0x200b, 0x200f, SIC_COMPLEX },
568     { 0x2010, 0x2016, SIC_NEUTRAL },
569     { 0x2018, 0x2022, SIC_NEUTRAL },
570     { 0x2024, 0x2028, SIC_NEUTRAL },
571     { 0x2029, 0x202e, SIC_COMPLEX },
572     { 0x202f, 0x2037, SIC_NEUTRAL },
573     { 0x2039, 0x203c, SIC_NEUTRAL },
574     { 0x2044, 0x2046, SIC_NEUTRAL },
575     { 0x206a, 0x206f, SIC_COMPLEX },
576     { 0x207a, 0x207e, SIC_NEUTRAL },
577     { 0x208a, 0x20aa, SIC_NEUTRAL },
578     { 0x20ac, 0x20cf, SIC_NEUTRAL },
579     { 0x20d0, 0x20ff, SIC_COMPLEX },
580     { 0x2103, 0x2103, SIC_NEUTRAL },
581     { 0x2105, 0x2105, SIC_NEUTRAL },
582     { 0x2109, 0x2109, SIC_NEUTRAL },
583     { 0x2116, 0x2116, SIC_NEUTRAL },
584     { 0x2121, 0x2122, SIC_NEUTRAL },
585     { 0x212e, 0x212e, SIC_NEUTRAL },
586     { 0x2153, 0x2154, SIC_NEUTRAL },
587     { 0x215b, 0x215e, SIC_NEUTRAL },
588     { 0x2190, 0x2199, SIC_NEUTRAL },
589     { 0x21b8, 0x21b9, SIC_NEUTRAL },
590     { 0x21d2, 0x21d2, SIC_NEUTRAL },
591     { 0x21d4, 0x21d4, SIC_NEUTRAL },
592     { 0x21e7, 0x21e7, SIC_NEUTRAL },
593     { 0x2200, 0x2200, SIC_NEUTRAL },
594     { 0x2202, 0x2203, SIC_NEUTRAL },
595     { 0x2207, 0x2208, SIC_NEUTRAL },
596     { 0x220b, 0x220b, SIC_NEUTRAL },
597     { 0x220f, 0x220f, SIC_NEUTRAL },
598     { 0x2211, 0x2213, SIC_NEUTRAL },
599     { 0x2215, 0x2215, SIC_NEUTRAL },
600     { 0x221a, 0x221a, SIC_NEUTRAL },
601     { 0x221d, 0x2220, SIC_NEUTRAL },
602     { 0x2223, 0x2223, SIC_NEUTRAL },
603     { 0x2225, 0x2225, SIC_NEUTRAL },
604     { 0x2227, 0x222c, SIC_NEUTRAL },
605     { 0x222e, 0x222e, SIC_NEUTRAL },
606     { 0x2234, 0x2237, SIC_NEUTRAL },
607     { 0x223c, 0x223d, SIC_NEUTRAL },
608     { 0x2248, 0x2248, SIC_NEUTRAL },
609     { 0x224c, 0x224c, SIC_NEUTRAL },
610     { 0x2252, 0x2252, SIC_NEUTRAL },
611     { 0x2260, 0x2261, SIC_NEUTRAL },
612     { 0x2264, 0x2267, SIC_NEUTRAL },
613     { 0x226a, 0x226b, SIC_NEUTRAL },
614     { 0x226e, 0x226f, SIC_NEUTRAL },
615     { 0x2282, 0x2283, SIC_NEUTRAL },
616     { 0x2286, 0x2287, SIC_NEUTRAL },
617     { 0x2295, 0x2295, SIC_NEUTRAL },
618     { 0x2299, 0x2299, SIC_NEUTRAL },
619     { 0x22a5, 0x22a5, SIC_NEUTRAL },
620     { 0x22bf, 0x22bf, SIC_NEUTRAL },
621     { 0x2312, 0x2312, SIC_NEUTRAL },
622     { 0x24ea, 0x24ea, SIC_COMPLEX },
623     { 0x2500, 0x254b, SIC_NEUTRAL },
624     { 0x2550, 0x256d, SIC_NEUTRAL },
625     { 0x256e, 0x2574, SIC_NEUTRAL },
626     { 0x2581, 0x258f, SIC_NEUTRAL },
627     { 0x2592, 0x2595, SIC_NEUTRAL },
628     { 0x25a0, 0x25a1, SIC_NEUTRAL },
629     { 0x25a3, 0x25a9, SIC_NEUTRAL },
630     { 0x25b2, 0x25b3, SIC_NEUTRAL },
631     { 0x25b6, 0x25b7, SIC_NEUTRAL },
632     { 0x25bc, 0x25bd, SIC_NEUTRAL },
633     { 0x25c0, 0x25c1, SIC_NEUTRAL },
634     { 0x25c6, 0x25c8, SIC_NEUTRAL },
635     { 0x25cb, 0x25cb, SIC_NEUTRAL },
636     { 0x25ce, 0x25d1, SIC_NEUTRAL },
637     { 0x25e2, 0x25e5, SIC_NEUTRAL },
638     { 0x25ef, 0x25ef, SIC_NEUTRAL },
639     { 0x2605, 0x2606, SIC_NEUTRAL },
640     { 0x2609, 0x2609, SIC_NEUTRAL },
641     { 0x260e, 0x260f, SIC_NEUTRAL },
642     { 0x261c, 0x261c, SIC_NEUTRAL },
643     { 0x261e, 0x261e, SIC_NEUTRAL },
644     { 0x2640, 0x2640, SIC_NEUTRAL },
645     { 0x2642, 0x2642, SIC_NEUTRAL },
646     { 0x2660, 0x2661, SIC_NEUTRAL },
647     { 0x2663, 0x2665, SIC_NEUTRAL },
648     { 0x2667, 0x266a, SIC_NEUTRAL },
649     { 0x266c, 0x266d, SIC_NEUTRAL },
650     { 0x266f, 0x266f, SIC_NEUTRAL },
651     { 0x273d, 0x273d, SIC_NEUTRAL },
652     { 0x2e80, 0x312f, SIC_COMPLEX },
653     { 0x3190, 0x31bf, SIC_COMPLEX },
654     { 0x31f0, 0x31ff, SIC_COMPLEX },
655     { 0x3220, 0x325f, SIC_COMPLEX },
656     { 0x3280, 0xa4ff, SIC_COMPLEX },
657     { 0xd800, 0xdfff, SIC_COMPLEX },
658     { 0xe000, 0xf8ff, SIC_NEUTRAL },
659     { 0xf900, 0xfaff, SIC_COMPLEX },
660     { 0xfb13, 0xfb28, SIC_COMPLEX },
661     { 0xfb29, 0xfb29, SIC_NEUTRAL },
662     { 0xfb2a, 0xfb4f, SIC_COMPLEX },
663     { 0xfd3e, 0xfd3f, SIC_NEUTRAL },
664     { 0xfdd0, 0xfdef, SIC_COMPLEX },
665     { 0xfe20, 0xfe6f, SIC_COMPLEX },
666     { 0xfeff, 0xfeff, SIC_COMPLEX },
667     { 0xff01, 0xff5e, SIC_COMPLEX },
668     { 0xff61, 0xff9f, SIC_COMPLEX },
669     { 0xffe0, 0xffe6, SIC_COMPLEX },
670     { 0xffe8, 0xffee, SIC_COMPLEX },
671     { 0xfff9, 0xfffb, SIC_COMPLEX },
672     { 0xfffe, 0xfffe, SIC_COMPLEX }
673 };
674
675 /***********************************************************************
676  *      ScriptIsComplex (USP10.@)
677  * 
678  *  Determine if a string is complex.
679  *
680  *  PARAMS
681  *   chars [I] Array of characters to test.
682  *   len   [I] Length in characters.
683  *   flag  [I] Flag.
684  *
685  *  RETURNS
686  *   Success: S_OK
687  *   Failure: S_FALSE
688  *
689  *  NOTES
690  *   Behaviour matches that of WinXP.
691  */
692 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
693 {
694     unsigned int i, j;
695
696     TRACE("(%s,%d,0x%lx)\n", debugstr_wn(chars, len), len, flag);
697
698     for (i = 0; i < len; i++)
699     {
700         for (j = 0; j < sizeof(complex_ranges)/sizeof(complex_ranges[0]); j++)
701         {
702             if (chars[i] >= complex_ranges[j].start &&
703                 chars[i] <= complex_ranges[j].end &&
704                 (flag & complex_ranges[j].flag)) return S_OK;
705         }
706     }
707     return S_FALSE;
708 }
709
710 /***********************************************************************
711  *      ScriptShape (USP10.@)
712  *
713  */
714 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars, 
715                            int cChars, int cMaxGlyphs,
716                            SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust, 
717                            SCRIPT_VISATTR *psva, int *pcGlyphs)
718 {
719     /*  Note SCRIPT_CACHE (*psc) appears to be a good place to save info that needs to be 
720      *  passed between functions.                                                         */
721
722     HDC phdc;
723     int cnt;
724     DWORD hr;
725     Scriptcache *pScriptcache;
726     *pcGlyphs = cChars;
727     FIXME("(%p, %p, %p, %d, %d, %p): semi-stub\n",  hdc, psc, pwcChars,
728                                        cChars, cMaxGlyphs, psa);
729     if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
730                                          psa->fLinkBefore, psa->fLinkAfter,
731                                          psa->fLogicalOrder, psa->fNoGlyphIndex);
732
733     if  (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
734
735     if  (!hdc && !*psc) {
736         TRACE("No Script_Cache (psc) and no hdc. Ask for one. Hdc=%p, psc=%p\n", hdc, *psc);
737         return E_PENDING;
738     }   else 
739         if  (hdc && !*psc) {
740             pScriptcache = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Scriptcache) );
741             pScriptcache->hdc = (HDC) hdc;
742             phdc = hdc;
743             *psc = (Scriptcache *) pScriptcache;
744        }   else
745             if  (*psc) {
746                 pScriptcache = (Scriptcache *) *psc;
747                 phdc = pScriptcache->hdc;
748             }
749                 
750     TRACE("Before: ");
751     for (cnt = 0; cnt < cChars; cnt++)
752          TRACE("%4x",pwcChars[cnt]);
753     TRACE("\n");
754
755     if  (!psa->fNoGlyphIndex) {                                         /* Glyph translate */
756         hr = GetGlyphIndicesW(phdc, pwcChars, cChars, pwOutGlyphs, 0);
757         TRACE("After:  ");
758         for (cnt = 0; cnt < cChars; cnt++) {
759              TRACE("%04x",pwOutGlyphs[cnt]);
760         }
761         TRACE("\n");
762     }
763     else {
764         TRACE("After:  ");
765         for (cnt = 0; cnt < cChars; cnt++) {                           /* no translate so set up */
766              pwOutGlyphs[cnt] = pwcChars[cnt];                         /* copy in to out and     */
767              TRACE("%04x",pwOutGlyphs[cnt]);
768         }
769        TRACE("\n");
770     }
771
772     /*  Set up a valid SCRIPT_VISATTR and LogClust for each char in this run */     
773     for (cnt = 0;  cnt < cChars; cnt++) {
774          psva[cnt].uJustification = 2;
775          psva[cnt].fClusterStart = 1;
776          psva[cnt].fDiacritic = 0;
777          psva[cnt].fZeroWidth = 0;
778          pwLogClust[cnt] = cnt;
779     }
780     return 0; 
781 }
782
783 /***********************************************************************
784  *      ScriptPlace (USP10.@)
785  *
786  */
787 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs, 
788                            int cGlyphs, const SCRIPT_VISATTR *psva,
789                            SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
790 {
791     HDC phdc;
792     int wcnt;
793     LPABC lpABC;
794     Scriptcache *pScriptcache;
795     FIXME("(%p, %p, %p, %s, %d, %p, %p, %p): semi-stub\n",  hdc, psc, pwGlyphs,
796                                                 debugstr_wn(pwGlyphs, cGlyphs), 
797                                                 cGlyphs, psva, psa, 
798                                                 piAdvance);
799
800     /*  We need a valid hdc to do any of the font calls.  The spec says that hdc is optional and 
801      *  psc will be used first.  If psc and hdc are not specified E_PENDING is returned to get 
802      *  the caller to return the hdc.  For convience, the hdc is cached in SCRIPT_CACHE.    */
803
804     if  (!hdc && !*psc) {
805         TRACE("No Script_Cache (psc) and no hdc. Ask for one. Hdc=%p, psc=%p\n", hdc, *psc);
806         return E_PENDING;
807     }   else 
808         if  (hdc && !*psc) {
809             pScriptcache = HeapAlloc( GetProcessHeap(), 0, sizeof(Scriptcache) );
810             pScriptcache->hdc = hdc;
811             phdc = hdc;
812             *psc = pScriptcache;
813         }   else
814             if  (*psc) {
815                 pScriptcache = *psc;
816                 phdc = pScriptcache->hdc;
817             }
818
819     /*   Here we need to calculate the width of the run unit.  At this point the input string
820      *   has been converted to glyphs and we till need to translate back to the original chars
821      *   to get the correct ABC widths.   */
822
823      lpABC = HeapAlloc(GetProcessHeap(), 0 , sizeof(ABC)*cGlyphs);
824      pABC->abcA = 0; 
825      pABC->abcB = 0; 
826      pABC->abcC = 0; 
827      if  (!GetCharABCWidthsI(phdc, 0, cGlyphs, (WORD *) pwGlyphs, lpABC )) 
828      {
829          WARN("Could not get ABC values\n");
830          for (wcnt = 0; wcnt < cGlyphs; wcnt++) {
831              piAdvance[wcnt] = 0;
832              pGoffset[wcnt].du = 0;
833              pGoffset[wcnt].dv = 0;
834          }
835      }
836      else
837      {
838          for (wcnt = 0; wcnt < cGlyphs ; wcnt++) {          /* add up the char lengths  */
839              TRACE("     Glyph=%04x,  abcA=%d,  abcB=%d,  abcC=%d  wcnt=%d\n",
840                                   pwGlyphs[wcnt],  
841                                   lpABC[wcnt].abcA,
842                                   lpABC[wcnt].abcB,
843                                   lpABC[wcnt].abcC, wcnt);
844              pABC->abcA += lpABC[wcnt].abcA;
845              pABC->abcB += lpABC[wcnt].abcB;
846              pABC->abcC += lpABC[wcnt].abcC;
847              piAdvance[wcnt] = lpABC[wcnt].abcA + lpABC[wcnt].abcB + lpABC[wcnt].abcC;
848              pGoffset[wcnt].du = 0;
849              pGoffset[wcnt].dv = 0;
850          }
851      }
852      TRACE("Total for run:   abcA=%d,  abcB=%d,  abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
853
854      HeapFree(GetProcessHeap(), 0, lpABC );
855
856      return 0;
857 }
858
859 /***********************************************************************
860  *      ScriptGetCMap (USP10.@)
861  *
862  */
863 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
864                               int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
865 {
866     HDC phdc;
867     int cnt;
868     DWORD hr;
869     Scriptcache *pScriptcache;
870     FIXME("(%p,%p,%s,%d,0x%lx,%p): semi-stub\n", hdc, psc, debugstr_wn(pwcInChars,cChars), 
871                                                  cChars, dwFlags, pwOutGlyphs);
872
873     if  (!psc)
874         return E_INVALIDARG;
875
876     if  (!hdc && !*psc) {
877         TRACE("No Script_Cache (psc) and no hdc. Ask for one. Hdc=%p, psc=%p\n", hdc, *psc);
878         return E_PENDING;
879     }   else 
880         if  (hdc && !*psc) {
881             pScriptcache = HeapAlloc( GetProcessHeap(), 0, sizeof(Scriptcache) );
882             pScriptcache->hdc = hdc;
883             phdc = hdc;
884             *psc = pScriptcache;
885         }   else
886             if  (*psc) {
887                 pScriptcache = *psc;
888                 phdc = pScriptcache->hdc;
889             }
890
891     TRACE("Before: ");
892     for (cnt = 0; cnt < cChars; cnt++)
893          TRACE("%4x",pwcInChars[cnt]);
894     TRACE("\n");
895
896     hr = GetGlyphIndicesW(phdc, pwcInChars, cChars, pwOutGlyphs, 0);
897     TRACE("After:  ");
898     for (cnt = 0; cnt < cChars; cnt++) {
899          TRACE("%04x",pwOutGlyphs[cnt]);
900     }
901     TRACE("\n");
902
903     return 0; 
904 }
905
906 /***********************************************************************
907  *      ScriptTextOut (USP10.@)
908  *
909  */
910 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions, 
911                              const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved, 
912                              int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance, 
913                              const int *piJustify, const GOFFSET *pGoffset)
914 {
915     HDC phdc;
916     DWORD hr;
917     Scriptcache *pScriptcache;
918     TRACE     ("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p): stub\n",
919          hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
920          piAdvance, piJustify, pGoffset);
921
922     if  (!hdc || !psc || !piAdvance || !psa || !pwGlyphs)         /* hdc is mandatory                 */
923         return E_INVALIDARG;
924         
925     if  (!*psc) {
926         pScriptcache = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Scriptcache) );
927         pScriptcache->hdc = hdc;
928         phdc = hdc;
929         *psc = pScriptcache;
930     } else {
931         pScriptcache = *psc;
932         phdc = pScriptcache->hdc;
933     }
934
935     fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
936     if  (!psa->fNoGlyphIndex)                                     /* Have Glyphs?                      */
937         fuOptions |= ETO_GLYPH_INDEX;                             /* Say don't do tranlastion to glyph */
938
939     hr = ExtTextOutW(phdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL);
940
941     if  (hr) return S_OK;
942     else {
943         FIXME("ExtTextOut returned:=%ld\n", hr);
944         return hr;
945     }
946 }
947
948 /***********************************************************************
949  *      ScriptCacheGetHeight (USP10.@)
950  *
951  * Retrieve the height of the font in the cache.
952  *
953  * PARAMS
954  *  hdc    [I]    Device context.
955  *  psc    [I/O]  Opaque pointer to a script cache.
956  *  height [O]    Receives font height.
957  *
958  * RETURNS
959  *  Success: S_OK
960  *  Failure: Non-zero HRESULT value.
961  */
962 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, long *height)
963 {
964     HDC phdc;
965     Scriptcache *pScriptcache;
966     TEXTMETRICW metric;
967
968     TRACE("(%p, %p, %p)\n", hdc, psc, height);
969
970     if  (!psc || !height)
971         return E_INVALIDARG;
972
973     if (!hdc) return E_PENDING;
974
975     if  (!*psc) {
976         pScriptcache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Scriptcache));
977         pScriptcache->hdc = hdc;
978         phdc = hdc;
979         *psc = pScriptcache;
980     } else {
981         pScriptcache = *psc;
982         phdc = pScriptcache->hdc;
983     }
984
985     /* FIXME: get this from the cache */
986     if (!GetTextMetricsW(phdc, &metric))
987         return E_INVALIDARG;
988
989     *height = metric.tmHeight;
990     return S_OK;
991 }
992
993 /***********************************************************************
994  *      ScriptGetGlyphABCWidth (USP10.@)
995  *
996  * Retrieve the width of a glyph.
997  *
998  * PARAMS
999  *  hdc    [I]    Device context.
1000  *  psc    [I/O]  Opaque pointer to a script cache.
1001  *  glyph  [I]    Glyph to retrieve the width for.
1002  *  abc    [O]    ABC widths of the glyph.
1003  *
1004  * RETURNS
1005  *  Success: S_OK
1006  *  Failure: Non-zero HRESULT value.
1007  */
1008 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
1009 {
1010     HDC phdc;
1011     Scriptcache *pScriptcache;
1012
1013     TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
1014
1015     if  (!psc)
1016         return E_INVALIDARG;
1017
1018     if (!hdc) return E_PENDING;
1019
1020     if  (!*psc) {
1021         pScriptcache = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Scriptcache));
1022         pScriptcache->hdc = hdc;
1023         phdc = hdc;
1024         *psc = pScriptcache;
1025     } else {
1026         pScriptcache = *psc;
1027         phdc = pScriptcache->hdc;
1028     }
1029
1030     /* FIXME: get this from the cache */
1031     if (!GetCharABCWidthsW(phdc, glyph, glyph, abc))
1032         return E_HANDLE;
1033
1034     return S_OK;
1035 }