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