ole32: Implement FTMarshalImpl_GetMarshalSizeMax.
[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     /* This implementation currently treats the entire string represented in 
199      * pwcInChars as a single entity.  Hence pcItems will be set to 1.          */
200
201     FIXME("%s,%d,%d,%p,%p,%p,%p: semi-stub\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems, 
202           psControl, psState, pItems, pcItems);
203
204     if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
205         return E_INVALIDARG;
206
207     /*  Set a sensible default                              */
208     /*  Set SCRIPT_ITEM                                     */
209     pItems[0].iCharPos = 0;
210     /*  Set the SCRIPT_ANALYSIS                             */
211     pItems[0].a.eScript = SCRIPT_UNDEFINED;
212     pItems[0].a.fRTL = 0;
213     pItems[0].a.fLayoutRTL = 0;
214     pItems[0].a.fLinkBefore = 0;
215     pItems[0].a.fLinkAfter = 0;
216     pItems[0].a.fLogicalOrder = 0;
217     pItems[0].a.fNoGlyphIndex = 0;
218     /*  set the SCRIPT_STATE                                */
219     pItems[0].a.s.uBidiLevel = 0;
220     pItems[0].a.s.fOverrideDirection = 0;
221     pItems[0].a.s.fInhibitSymSwap = FALSE;
222     pItems[0].a.s.fCharShape = 0;
223     pItems[0].a.s.fDigitSubstitute = 0;
224     pItems[0].a.s.fInhibitLigate = 0;
225     pItems[0].a.s.fDisplayZWG = 0;
226     pItems[0].a.s.fArabicNumContext = 0;
227     pItems[0].a.s.fGcpClusters = 0;
228     pItems[0].a.s.fReserved = 0;
229     pItems[0].a.s.fEngineReserved = 0;
230
231     /* While not strickly necessary according to the spec, make sure the n+1
232      * item is set up to prevent random behaviour if the caller eroneously
233      * checks the n+1 structure                                              */
234     pItems[1].a.eScript = 0;
235     pItems[1].a.fRTL = 0;
236     pItems[1].a.fLayoutRTL = 0;
237     pItems[1].a.fLinkBefore = 0;
238     pItems[1].a.fLinkAfter = 0;
239     pItems[1].a.fLogicalOrder = 0;
240     pItems[1].a.fNoGlyphIndex = 0;
241     /*  set the SCRIPT_STATE                                */
242     pItems[1].a.s.uBidiLevel = 0;
243     pItems[1].a.s.fOverrideDirection = 0;
244     pItems[1].a.s.fInhibitSymSwap = FALSE;
245     pItems[1].a.s.fCharShape = 0;
246     pItems[1].a.s.fDigitSubstitute = 0;
247     pItems[1].a.s.fInhibitLigate = 0;
248     pItems[1].a.s.fDisplayZWG = 0;
249     pItems[1].a.s.fArabicNumContext = 0;
250     pItems[1].a.s.fGcpClusters = 0;
251     pItems[1].a.s.fReserved = 0;
252     pItems[1].a.s.fEngineReserved = 0;
253
254     /*  Set one SCRIPT_STATE item being returned  */
255     *pcItems = 1;
256
257     /*  Set SCRIPT_ITEM                                     */
258     pItems[1].iCharPos = cInChars - pItems[0].iCharPos ; /* the last + 1 item
259                                              contains the ptr to the lastchar */
260     TRACE("%s,%d,%d,%p,%p,%p,%p,%d\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems, 
261           psControl, psState, pItems, pcItems, *pcItems);
262     TRACE("Start Pos in string: %d, Stop Pos %d\n", pItems[0].iCharPos, pItems[1].iCharPos);
263     return 0;
264 }
265
266 /***********************************************************************
267  *      ScriptStringAnalyse (USP10.@)
268  *
269  */
270 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, 
271                                    const void *pString, 
272                                    int cString, 
273                                    int cGlyphs,
274                                    int iCharset,
275                                    DWORD dwFlags,
276                                    int iReqWidth,
277                                    SCRIPT_CONTROL *psControl,
278                                    SCRIPT_STATE *psState,
279                                    const int *piDx,
280                                    SCRIPT_TABDEF *pTabdef,
281                                    const BYTE *pbInClass,
282                                    SCRIPT_STRING_ANALYSIS *pssa)
283 {
284   FIXME("(%p,%p,%d,%d,%d,0x%lx,%d,%p,%p,%p,%p,%p,%p): stub\n",
285         hdc, pString, cString, cGlyphs, iCharset, dwFlags,
286         iReqWidth, psControl, psState, piDx, pTabdef, pbInClass, pssa);
287   if (1 > cString || NULL == pString) {
288     return E_INVALIDARG;
289   }
290   if ((dwFlags & SSA_GLYPHS) && NULL == hdc) {
291     return E_PENDING;
292   }
293
294   return E_NOTIMPL;
295 }
296
297 /***********************************************************************
298  *      ScriptStringOut (USP10.@)
299  *
300  */
301 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa, 
302                                int iX, 
303                                int iY, 
304                                UINT uOptions, 
305                                const RECT *prc, 
306                                int iMinSel, 
307                                int iMaxSel, 
308                                BOOL fDisabled)
309 {
310     FIXME("(%p,%d,%d,0x%1x,%p,%d,%d,%d): stub\n",
311          ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
312     if  (!ssa) {
313         return E_INVALIDARG;
314     }
315
316     return E_NOTIMPL;
317 }
318
319 /***********************************************************************
320  *      ScriptStringFree (USP10.@)
321  *
322  */
323 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa) {
324     FIXME("(%p): stub\n",pssa);
325     return S_OK;
326 }
327
328 /***********************************************************************
329  *      ScriptCPtoX (USP10.@)
330  *
331  */
332 HRESULT WINAPI ScriptCPtoX(int iCP,
333                            BOOL fTrailing,
334                            int cChars,
335                            int cGlyphs,
336                            const WORD *pwLogClust,
337                            const SCRIPT_VISATTR *psva,
338                            const int *piAdvance,
339                            const SCRIPT_ANALYSIS *psa,
340                            int *piX)
341 {
342     FIXME("(%d,%d,%d,%d,%p,%p,%p,%p,%p): stub\n",
343           iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
344           psa, piX);
345
346     *piX = 1;                    /* Return something in range */
347     return S_OK;
348 }
349
350 /***********************************************************************
351  *      ScriptXtoCP (USP10.@)
352  *
353  */
354 HRESULT WINAPI ScriptXtoCP(int iX,
355                            int cChars,
356                            int cGlyphs,
357                            const WORD *pwLogClust,
358                            const SCRIPT_VISATTR *psva,
359                            const int *piAdvance,
360                            const SCRIPT_ANALYSIS *psa,
361                            int *piCP,
362                            int *piTrailing)
363 {
364     FIXME("(%d,%d,%d,%p,%p,%p,%p,%p,%p): stub\n",
365           iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
366           psa, piCP, piTrailing);
367
368     *piCP = 1;                   /* Return something in range */
369     *piTrailing = 0;
370     return S_OK;
371 }
372
373 /***********************************************************************
374  *      ScriptBreak (USP10.@)
375  *
376  */
377 HRESULT WINAPI ScriptBreak(const WCHAR *pwcChars, int cChars,  const SCRIPT_ANALYSIS *psa,
378                     SCRIPT_LOGATTR *psla)
379 {
380     FIXME("(%p,%d,%p,%p): stub\n",
381           pwcChars, cChars, psa, psla);
382
383     return S_OK;
384 }
385
386 /***********************************************************************
387  *      ScriptIsComplex (USP10.@)
388  *
389  */
390 HRESULT WINAPI ScriptIsComplex(const WCHAR* pwcInChars, int cInChars, DWORD dwFlags) {
391   FIXME("(%s,%d,0x%lx): stub\n",  debugstr_wn(pwcInChars, cInChars), cInChars, dwFlags);
392    return E_NOTIMPL;
393 }
394
395 /***********************************************************************
396  *      ScriptShape (USP10.@)
397  *
398  */
399 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars, 
400                            int cChars, int cMaxGlyphs,
401                            SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust, 
402                            SCRIPT_VISATTR *psva, int *pcGlyphs)
403 {
404     /*  Note SCRIPT_CACHE (*psc) appears to be a good place to save info that needs to be 
405      *  passed between functions.                                                         */
406
407     HDC phdc;
408     int cnt;
409     DWORD hr;
410     Scriptcache *pScriptcache;
411     *pcGlyphs = cChars;
412     FIXME("(%p, %p, %p, %d, %d, %p): semi-stub\n",  hdc, psc, pwcChars,
413                                        cChars, cMaxGlyphs, psa);
414     if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
415                                          psa->fLinkBefore, psa->fLinkAfter,
416                                          psa->fLogicalOrder, psa->fNoGlyphIndex);
417
418     if  (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
419
420     if  (!hdc && !*psc) {
421         TRACE("No Script_Cache (psc) and no hdc. Ask for one. Hdc=%p, psc=%p\n", hdc, *psc);
422         return E_PENDING;
423     }   else 
424         if  (hdc && !*psc) {
425             pScriptcache = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Scriptcache) );
426             pScriptcache->hdc = (HDC) hdc;
427             phdc = hdc;
428             *psc = (Scriptcache *) pScriptcache;
429        }   else
430             if  (*psc) {
431                 pScriptcache = (Scriptcache *) *psc;
432                 phdc = pScriptcache->hdc;
433             }
434                 
435     TRACE("Before: ");
436     for (cnt = 0; cnt < cChars; cnt++)
437          TRACE("%4x",pwcChars[cnt]);
438     TRACE("\n");
439
440     if  (!psa->fNoGlyphIndex) {                                         /* Glyph translate */
441         hr = GetGlyphIndicesW(phdc, pwcChars, cChars, pwOutGlyphs, 0);
442         TRACE("After:  ");
443         for (cnt = 0; cnt < cChars; cnt++) {
444              TRACE("%04x",pwOutGlyphs[cnt]);
445         }
446         TRACE("\n");
447     }
448     else {
449         TRACE("After:  ");
450         for (cnt = 0; cnt < cChars; cnt++) {                           /* no translate so set up */
451              pwOutGlyphs[cnt] = pwcChars[cnt];                         /* copy in to out and     */
452              TRACE("%04x",pwOutGlyphs[cnt]);
453         }
454        TRACE("\n");
455     }
456
457     /*  Set up a valid SCRIPT_VISATTR and LogClust for each char in this run */     
458     for (cnt = 0;  cnt < cChars; cnt++) {
459          psva[cnt].uJustification = 2;
460          psva[cnt].fClusterStart = 1;
461          psva[cnt].fDiacritic = 0;
462          psva[cnt].fZeroWidth = 0;
463          pwLogClust[cnt] = cnt;
464     }
465     return 0; 
466 }
467
468 /***********************************************************************
469  *      ScriptPlace (USP10.@)
470  *
471  */
472 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs, 
473                            int cGlyphs, const SCRIPT_VISATTR *psva,
474                            SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
475 {
476     HDC phdc;
477     int wcnt;
478     LPABC lpABC;
479     Scriptcache *pScriptcache;
480     FIXME("(%p, %p, %p, %s, %d, %p, %p, %p): semi-stub\n",  hdc, psc, pwGlyphs,
481                                                 debugstr_wn(pwGlyphs, cGlyphs), 
482                                                 cGlyphs, psva, psa, 
483                                                 piAdvance);
484
485     /*  We need a valid hdc to do any of the font calls.  The spec says that hdc is optional and 
486      *  psc will be used first.  If psc and hdc are not specified E_PENDING is returned to get 
487      *  the caller to return the hdc.  For convience, the hdc is cached in SCRIPT_CACHE.    */
488
489     if  (!hdc && !*psc) {
490         TRACE("No Script_Cache (psc) and no hdc. Ask for one. Hdc=%p, psc=%p\n", hdc, *psc);
491         return E_PENDING;
492     }   else 
493         if  (hdc && !*psc) {
494             pScriptcache = HeapAlloc( GetProcessHeap(), 0, sizeof(Scriptcache) );
495             pScriptcache->hdc = hdc;
496             phdc = hdc;
497             *psc = pScriptcache;
498         }   else
499             if  (*psc) {
500                 pScriptcache = *psc;
501                 phdc = pScriptcache->hdc;
502             }
503
504     /*   Here we need to calculate the width of the run unit.  At this point the input string
505      *   has been converted to glyphs and we till need to translate back to the original chars
506      *   to get the correct ABC widths.   */
507
508      lpABC = HeapAlloc(GetProcessHeap(), 0 , sizeof(ABC)*cGlyphs);
509      pABC->abcA = 0; 
510      pABC->abcB = 0; 
511      pABC->abcC = 0; 
512      if  (!GetCharABCWidthsI(phdc, 0, cGlyphs, (WORD *) pwGlyphs, lpABC )) 
513      {
514          WARN("Could not get ABC values\n");
515          for (wcnt = 0; wcnt < cGlyphs; wcnt++) {
516              piAdvance[wcnt] = 0;
517              pGoffset[wcnt].du = 0;
518              pGoffset[wcnt].dv = 0;
519          }
520      }
521      else
522      {
523          for (wcnt = 0; wcnt < cGlyphs ; wcnt++) {          /* add up the char lengths  */
524              TRACE("     Glyph=%04x,  abcA=%d,  abcB=%d,  abcC=%d  wcnt=%d\n",
525                                   pwGlyphs[wcnt],  
526                                   lpABC[wcnt].abcA,
527                                   lpABC[wcnt].abcB,
528                                   lpABC[wcnt].abcC, wcnt);
529              pABC->abcA += lpABC[wcnt].abcA;
530              pABC->abcB += lpABC[wcnt].abcB;
531              pABC->abcC += lpABC[wcnt].abcC;
532              piAdvance[wcnt] = lpABC[wcnt].abcA + lpABC[wcnt].abcB + lpABC[wcnt].abcC;
533              pGoffset[wcnt].du = 0;
534              pGoffset[wcnt].dv = 0;
535          }
536      }
537      TRACE("Total for run:   abcA=%d,  abcB=%d,  abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
538
539      HeapFree(GetProcessHeap(), 0, lpABC );
540
541      return 0;
542 }
543
544 /***********************************************************************
545  *      ScriptGetCMap (USP10.@)
546  *
547  */
548 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
549                               int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
550 {
551     HDC phdc;
552     int cnt;
553     DWORD hr;
554     Scriptcache *pScriptcache;
555     FIXME("(%p,%p,%s,%d,0x%lx,%p): semi-stub\n", hdc, psc, debugstr_wn(pwcInChars,cChars), 
556                                                  cChars, dwFlags, pwOutGlyphs);
557
558     if  (!psc)
559         return E_INVALIDARG;
560
561     if  (!hdc && !*psc) {
562         TRACE("No Script_Cache (psc) and no hdc. Ask for one. Hdc=%p, psc=%p\n", hdc, *psc);
563         return E_PENDING;
564     }   else 
565         if  (hdc && !*psc) {
566             pScriptcache = HeapAlloc( GetProcessHeap(), 0, sizeof(Scriptcache) );
567             pScriptcache->hdc = hdc;
568             phdc = hdc;
569             *psc = pScriptcache;
570         }   else
571             if  (*psc) {
572                 pScriptcache = *psc;
573                 phdc = pScriptcache->hdc;
574             }
575
576     TRACE("Before: ");
577     for (cnt = 0; cnt < cChars; cnt++)
578          TRACE("%4x",pwcInChars[cnt]);
579     TRACE("\n");
580
581     hr = GetGlyphIndicesW(phdc, pwcInChars, cChars, pwOutGlyphs, 0);
582     TRACE("After:  ");
583     for (cnt = 0; cnt < cChars; cnt++) {
584          TRACE("%04x",pwOutGlyphs[cnt]);
585     }
586     TRACE("\n");
587
588     return 0; 
589 }
590
591 /***********************************************************************
592  *      ScriptTextOut (USP10.@)
593  *
594  */
595 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions, 
596                              const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved, 
597                              int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance, 
598                              const int *piJustify, const GOFFSET *pGoffset)
599 {
600     HDC phdc;
601     DWORD hr;
602     Scriptcache *pScriptcache;
603     TRACE     ("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p): stub\n",
604          hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
605          piAdvance, piJustify, pGoffset);
606
607     if  (!hdc || !psc || !piAdvance || !psa || !pwGlyphs)         /* hdc is mandatory                 */
608         return E_INVALIDARG;
609         
610     if  (!*psc) {
611         pScriptcache = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Scriptcache) );
612         pScriptcache->hdc = hdc;
613         phdc = hdc;
614         *psc = pScriptcache;
615     } else {
616         pScriptcache = *psc;
617         phdc = pScriptcache->hdc;
618     }
619
620     fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
621     if  (!psa->fNoGlyphIndex)                                     /* Have Glyphs?                      */
622         fuOptions |= ETO_GLYPH_INDEX;                             /* Say don't do tranlastion to glyph */
623
624     hr = ExtTextOutW(phdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL);
625
626     if  (hr) return S_OK;
627     else {
628         FIXME("ExtTextOut returned:=%ld\n", hr);
629         return hr;
630     }
631 }