mshtml: Added beginning OnDataAvailable implementation.
[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_INVALIDARG;
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  *      ScriptIsComplex (USP10.@)
330  *
331  */
332 HRESULT WINAPI ScriptIsComplex(const WCHAR* pwcInChars, int cInChars, DWORD dwFlags) {
333   FIXME("(%s,%d,0x%lx): stub\n",  debugstr_wn(pwcInChars, cInChars), cInChars, dwFlags);
334    return E_NOTIMPL;
335 }
336
337 /***********************************************************************
338  *      ScriptShape (USP10.@)
339  *
340  */
341 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars, 
342                            int cChars, int cMaxGlyphs,
343                            SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust, 
344                            SCRIPT_VISATTR *psva, int *pcGlyphs)
345 {
346     /*  Note SCRIPT_CACHE (*psc) appears to be a good place to save info that needs to be 
347      *  passed between functions.                                                         */
348
349     HDC phdc;
350     int cnt;
351     DWORD hr;
352     Scriptcache *pScriptcache;
353     *pcGlyphs = cChars;
354     FIXME("(%p, %p, %p, %d, %d, %p): semi-stub\n",  hdc, psc, pwcChars,
355                                        cChars, cMaxGlyphs, psa);
356     if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
357                                          psa->fLinkBefore, psa->fLinkAfter,
358                                          psa->fLogicalOrder, psa->fNoGlyphIndex);
359
360     if  (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
361
362     if  (!hdc && !*psc) {
363         TRACE("No Script_Cache (psc) and no hdc. Ask for one. Hdc=%p, psc=%p\n", hdc, *psc);
364         return E_PENDING;
365     }   else 
366         if  (hdc && !*psc) {
367             pScriptcache = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Scriptcache) );
368             pScriptcache->hdc = (HDC) hdc;
369             phdc = hdc;
370             *psc = (Scriptcache *) pScriptcache;
371        }   else
372             if  (*psc) {
373                 pScriptcache = (Scriptcache *) *psc;
374                 phdc = pScriptcache->hdc;
375             }
376                 
377     TRACE("Before: ");
378     for (cnt = 0; cnt < cChars; cnt++)
379          TRACE("%4x",pwcChars[cnt]);
380     TRACE("\n");
381
382     if  (!psa->fNoGlyphIndex) {                                         /* Glyph translate */
383         hr = GetGlyphIndicesW(phdc, pwcChars, cChars, pwOutGlyphs, 0);
384         TRACE("After:  ");
385         for (cnt = 0; cnt < cChars; cnt++) {
386              TRACE("%04x",pwOutGlyphs[cnt]);
387         }
388         TRACE("\n");
389     }
390     else {
391         TRACE("After:  ");
392         for (cnt = 0; cnt < cChars; cnt++) {                           /* no translate so set up */
393              pwOutGlyphs[cnt] = pwcChars[cnt];                         /* copy in to out and     */
394              TRACE("%04x",pwOutGlyphs[cnt]);
395         }
396        TRACE("\n");
397     }
398
399     /*  Set up a valid SCRIPT_VISATTR and LogClust for each char in this run */     
400     for (cnt = 0;  cnt < cChars; cnt++) {
401          psva[cnt].uJustification = 2;
402          psva[cnt].fClusterStart = 1;
403          psva[cnt].fDiacritic = 0;
404          psva[cnt].fZeroWidth = 0;
405          pwLogClust[cnt] = cnt;
406     }
407     return 0; 
408 }
409
410 /***********************************************************************
411  *      ScriptPlace (USP10.@)
412  *
413  */
414 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs, 
415                            int cGlyphs, const SCRIPT_VISATTR *psva,
416                            SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
417 {
418     HDC phdc;
419     int wcnt;
420     LPABC lpABC;
421     Scriptcache *pScriptcache;
422     FIXME("(%p, %p, %p, %s, %d, %p, %p, %p): semi-stub\n",  hdc, psc, pwGlyphs,
423                                                 debugstr_wn(pwGlyphs, cGlyphs), 
424                                                 cGlyphs, psva, psa, 
425                                                 piAdvance);
426
427     /*  We need a valid hdc to do any of the font calls.  The spec says that hdc is optional and 
428      *  psc will be used first.  If psc and hdc are not specified E_PENDING is returned to get 
429      *  the caller to return the hdc.  For convience, the hdc is cached in SCRIPT_CACHE.    */
430
431     if  (!hdc && !*psc) {
432         TRACE("No Script_Cache (psc) and no hdc. Ask for one. Hdc=%p, psc=%p\n", hdc, *psc);
433         return E_PENDING;
434     }   else 
435         if  (hdc && !*psc) {
436             pScriptcache = HeapAlloc( GetProcessHeap(), 0, sizeof(Scriptcache) );
437             pScriptcache->hdc = hdc;
438             phdc = hdc;
439             *psc = pScriptcache;
440         }   else
441             if  (*psc) {
442                 pScriptcache = *psc;
443                 phdc = pScriptcache->hdc;
444             }
445
446     /*   Here we need to calculate the width of the run unit.  At this point the input string
447      *   has been converted to glyphs and we till need to translate back to the original chars
448      *   to get the correct ABC widths.   */
449
450      lpABC = HeapAlloc(GetProcessHeap(), 0 , sizeof(ABC)*cGlyphs);
451      pABC->abcA = 0; 
452      pABC->abcB = 0; 
453      pABC->abcC = 0; 
454      if  (!GetCharABCWidthsI(phdc, 0, cGlyphs, (WORD *) pwGlyphs, lpABC )) 
455      {
456          WARN("Could not get ABC values\n");
457          for (wcnt = 0; wcnt < cGlyphs; wcnt++) {
458              piAdvance[wcnt] = 0;
459              pGoffset[wcnt].du = 0;
460              pGoffset[wcnt].dv = 0;
461          }
462      }
463      else
464      {
465          for (wcnt = 0; wcnt < cGlyphs ; wcnt++) {          /* add up the char lengths  */
466              TRACE("     Glyph=%04x,  abcA=%d,  abcB=%d,  abcC=%d  wcnt=%d\n",
467                                   pwGlyphs[wcnt],  
468                                   lpABC[wcnt].abcA,
469                                   lpABC[wcnt].abcB,
470                                   lpABC[wcnt].abcC, wcnt);
471              pABC->abcA += lpABC[wcnt].abcA;
472              pABC->abcB += lpABC[wcnt].abcB;
473              pABC->abcC += lpABC[wcnt].abcC;
474              piAdvance[wcnt] = lpABC[wcnt].abcA + lpABC[wcnt].abcB + lpABC[wcnt].abcC;
475              pGoffset[wcnt].du = 0;
476              pGoffset[wcnt].dv = 0;
477          }
478      }
479      TRACE("Total for run:   abcA=%d,  abcB=%d,  abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
480
481      HeapFree(GetProcessHeap(), 0, lpABC );
482
483      return 0;
484 }
485
486 /***********************************************************************
487  *      ScriptGetCMap (USP10.@)
488  *
489  */
490 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
491                               int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
492 {
493     HDC phdc;
494     int cnt;
495     DWORD hr;
496     Scriptcache *pScriptcache;
497     FIXME("(%p,%p,%s,%d,0x%lx,%p): semi-stub\n", hdc, psc, debugstr_wn(pwcInChars,cChars), 
498                                                  cChars, dwFlags, pwOutGlyphs);
499
500     if  (!psc || !pwcInChars || !pwOutGlyphs)
501         return E_INVALIDARG;
502
503     if  (!hdc && !*psc) {
504         TRACE("No Script_Cache (psc) and no hdc. Ask for one. Hdc=%p, psc=%p\n", hdc, *psc);
505         return E_PENDING;
506     }   else 
507         if  (hdc && !*psc) {
508             pScriptcache = HeapAlloc( GetProcessHeap(), 0, sizeof(Scriptcache) );
509             pScriptcache->hdc = hdc;
510             phdc = hdc;
511             *psc = pScriptcache;
512         }   else
513             if  (*psc) {
514                 pScriptcache = *psc;
515                 phdc = pScriptcache->hdc;
516             }
517
518     TRACE("Before: ");
519     for (cnt = 0; cnt < cChars; cnt++)
520          TRACE("%4x",pwcInChars[cnt]);
521     TRACE("\n");
522
523     hr = GetGlyphIndicesW(phdc, pwcInChars, cChars, pwOutGlyphs, 0);
524     TRACE("After:  ");
525     for (cnt = 0; cnt < cChars; cnt++) {
526          TRACE("%04x",pwOutGlyphs[cnt]);
527     }
528     TRACE("\n");
529
530     return 0; 
531 }
532
533 /***********************************************************************
534  *      ScriptTextOut (USP10.@)
535  *
536  */
537 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions, 
538                              const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved, 
539                              int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance, 
540                              const int *piJustify, const GOFFSET *pGoffset)
541 {
542     HDC phdc;
543     DWORD hr;
544     Scriptcache *pScriptcache;
545     TRACE     ("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p): stub\n",
546          hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
547          piAdvance, piJustify, pGoffset);
548
549     if  (!psc || !piAdvance || !psa || !pwGlyphs)
550         return E_INVALIDARG;
551         
552     if  (!hdc && !*psc) {
553         TRACE("No Script_Cache (psc) and no hdc. Ask for one. Hdc=%p, psc=%p\n", hdc, *psc);
554         return E_PENDING;
555     }   else 
556         if  (hdc && !*psc) {
557             pScriptcache = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Scriptcache) );
558             pScriptcache->hdc = hdc;
559             phdc = hdc;
560             *psc = pScriptcache;
561         }   else
562             if  (*psc) {
563                 pScriptcache = *psc;
564                 phdc = pScriptcache->hdc;
565             }
566
567     fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
568     if  (!psa->fNoGlyphIndex)                                     /* Have Glyphs?                      */
569         fuOptions |= ETO_GLYPH_INDEX;                             /* Say don't do tranlastion to glyph */
570
571     hr = ExtTextOutW(phdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL);
572
573     if  (hr) return S_OK;
574     else {
575         FIXME("ExtTextOut returned:=%ld\n", hr);
576         return hr;
577     }
578 }