xref: /reactos/win32ss/gdi/gdi32/misc/misc.c (revision 84344399)
1 /*
2  *  ReactOS GDI lib
3  *  Copyright (C) 2003 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * PROJECT:         ReactOS gdi32.dll
21  * FILE:            win32ss/gdi/gdi32/misc/misc.c
22  * PURPOSE:         Miscellaneous functions
23  * PROGRAMMER:      Thomas Weidenmueller <w3seek@reactos.com>
24  * UPDATE HISTORY:
25  *      2004/09/04  Created
26  */
27 
28 #include <precomp.h>
29 
30 #define NDEBUG
31 #include <debug.h>
32 
33 PGDI_TABLE_ENTRY GdiHandleTable = NULL;
34 PGDI_SHARED_HANDLE_TABLE GdiSharedHandleTable = NULL;
35 HANDLE CurrentProcessId = NULL;
36 DWORD GDI_BatchLimit = 1;
37 extern PGDIHANDLECACHE GdiHandleCache;
38 
39 /*
40  * @implemented
41  */
42 BOOL
43 WINAPI
44 GdiFlush(VOID)
45 {
46     NtGdiFlush();
47     return TRUE;
48 }
49 
50 /*
51  * @unimplemented
52  */
53 INT
54 WINAPI
55 Escape(
56     _In_ HDC hdc,
57     _In_ INT nEscape,
58     _In_ INT cbInput,
59     _In_ LPCSTR lpvInData,
60     _Out_ LPVOID lpvOutData)
61 {
62     INT retValue = SP_ERROR;
63     ULONG ulObjType;
64 
65     ulObjType = GDI_HANDLE_GET_TYPE(hdc);
66 
67     if (ulObjType == GDILoObjType_LO_METADC16_TYPE)
68     {
69         return METADC_ExtEscape(hdc, nEscape, cbInput, lpvInData, 0, lpvOutData);
70     }
71 
72     switch (nEscape)
73     {
74         case ABORTDOC:
75             /* Note: Windows checks if the handle has any user data for the ABORTDOC command
76              * ReactOS copies this behavior to be compatible with windows 2003
77              */
78             if (GdiGetDcAttr(hdc) == NULL)
79             {
80                 GdiSetLastError(ERROR_INVALID_HANDLE);
81                 retValue = FALSE;
82             }
83             else
84             {
85                 retValue = AbortDoc(hdc);
86             }
87             break;
88 
89         case DRAFTMODE:
90         case FLUSHOUTPUT:
91         case SETCOLORTABLE:
92             /* Note 1: DRAFTMODE, FLUSHOUTPUT, SETCOLORTABLE are outdated */
93             /* Note 2: Windows checks if the handle has any user data for the DRAFTMODE, FLUSHOUTPUT, SETCOLORTABLE commands
94              * ReactOS copies this behavior to be compatible with windows 2003
95              */
96             if (GdiGetDcAttr(hdc) == NULL)
97             {
98                 GdiSetLastError(ERROR_INVALID_HANDLE);
99             }
100             retValue = FALSE;
101             break;
102 
103         case SETABORTPROC:
104             /* Note: Windows checks if the handle has any user data for the SETABORTPROC command
105              * ReactOS copies this behavior to be compatible with windows 2003
106              */
107             if (GdiGetDcAttr(hdc) == NULL)
108             {
109                 GdiSetLastError(ERROR_INVALID_HANDLE);
110                 retValue = FALSE;
111             }
112             retValue = SetAbortProc(hdc, (ABORTPROC)lpvInData);
113             break;
114 
115         case GETCOLORTABLE:
116             retValue = GetSystemPaletteEntries(hdc, (UINT)*lpvInData, 1, (LPPALETTEENTRY)lpvOutData);
117             if (!retValue)
118             {
119                 retValue = SP_ERROR;
120             }
121             break;
122 
123         case ENDDOC:
124             /* Note: Windows checks if the handle has any user data for the ENDDOC command
125              * ReactOS copies this behavior to be compatible with windows 2003
126              */
127             if (GdiGetDcAttr(hdc) == NULL)
128             {
129                 GdiSetLastError(ERROR_INVALID_HANDLE);
130                 retValue = FALSE;
131             }
132             retValue = EndDoc(hdc);
133             break;
134 
135         case GETSCALINGFACTOR:
136             /* Note GETSCALINGFACTOR is outdated have been replace by GetDeviceCaps */
137             if (ulObjType == GDI_OBJECT_TYPE_DC)
138             {
139                 if (lpvOutData)
140                 {
141                     PPOINT ptr = (PPOINT)lpvOutData;
142                     ptr->x = 0;
143                     ptr->y = 0;
144                 }
145             }
146             retValue = FALSE;
147             break;
148 
149         case GETEXTENDEDTEXTMETRICS:
150             retValue = GetETM(hdc, (EXTTEXTMETRIC *)lpvOutData) != 0;
151             break;
152 
153         case STARTDOC:
154         {
155             DOCINFOA di;
156 
157             /* Note: Windows checks if the handle has any user data for the STARTDOC command
158              * ReactOS copies this behavior to be compatible with windows 2003
159              */
160             if (GdiGetDcAttr(hdc) == NULL)
161             {
162                 GdiSetLastError(ERROR_INVALID_HANDLE);
163                 retValue = FALSE;
164             }
165 
166             di.cbSize = sizeof(DOCINFOA);
167             di.lpszOutput = 0;
168             di.lpszDatatype = 0;
169             di.fwType = 0;
170             di.lpszDocName = lpvInData;
171 
172             /* NOTE : doc for StartDocA/W at msdn http://msdn2.microsoft.com/en-us/library/ms535793(VS.85).aspx */
173             retValue = StartDocA(hdc, &di);
174 
175             /* Check if StartDocA failed */
176             if (retValue < 0)
177             {
178                 {
179                     retValue = GetLastError();
180 
181                     /* Translate StartDocA error code to STARTDOC error code
182                      * see msdn http://msdn2.microsoft.com/en-us/library/ms535472.aspx
183                      */
184                     switch(retValue)
185                     {
186                     case ERROR_NOT_ENOUGH_MEMORY:
187                         retValue = SP_OUTOFMEMORY;
188                         break;
189 
190                     case ERROR_PRINT_CANCELLED:
191                         retValue = SP_USERABORT;
192                         break;
193 
194                     case ERROR_DISK_FULL:
195                         retValue = SP_OUTOFDISK;
196                         break;
197 
198                     default:
199                         retValue = SP_ERROR;
200                         break;
201                     }
202                 }
203             }
204         }
205         break;
206 
207         default:
208             UNIMPLEMENTED;
209             SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
210     }
211 
212     return retValue;
213 }
214 
215 INT
216 WINAPI
217 ExtEscape(HDC hDC,
218           int nEscape,
219           int cbInput,
220           LPCSTR lpszInData,
221           int cbOutput,
222           LPSTR lpszOutData)
223 {
224     return NtGdiExtEscape(hDC, NULL, 0, nEscape, cbInput, (LPSTR)lpszInData, cbOutput, lpszOutData);
225 }
226 
227 INT
228 WINAPI
229 NamedEscape(HDC hdc,
230             PWCHAR pDriver,
231             INT iEsc,
232             INT cjIn,
233             LPSTR pjIn,
234             INT cjOut,
235             LPSTR pjOut)
236 {
237     /* FIXME metadc, metadc are done most in user mode, and we do not support it
238      * Windows 2000/XP/Vista ignore the current hdc, that are being pass and always set hdc to NULL
239      * when it calls to NtGdiExtEscape from NamedEscape
240      */
241     return NtGdiExtEscape(NULL,pDriver,wcslen(pDriver),iEsc,cjIn,pjIn,cjOut,pjOut);
242 }
243 
244 /*
245  * @implemented
246  */
247 int
248 WINAPI
249 DrawEscape(HDC  hDC,
250            INT nEscape,
251            INT cbInput,
252            LPCSTR lpszInData)
253 {
254     if (GDI_HANDLE_GET_TYPE(hDC) == GDI_OBJECT_TYPE_DC)
255         return NtGdiDrawEscape(hDC, nEscape, cbInput, (LPSTR) lpszInData);
256 
257     if (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_METADC)
258     {
259         PLDC pLDC = GdiGetLDC(hDC);
260         if ( pLDC )
261         {
262             if (pLDC->Flags & LDC_META_PRINT)
263             {
264 //           if (nEscape != QUERYESCSUPPORT)
265 //              return EMFDRV_WriteEscape(hDC, nEscape, cbInput, lpszInData, EMR_DRAWESCAPE);
266 
267                 return NtGdiDrawEscape(hDC, nEscape, cbInput, (LPSTR) lpszInData);
268             }
269         }
270         SetLastError(ERROR_INVALID_HANDLE);
271     }
272     return 0;
273 }
274 
275 #define ALPHABLEND_NONE             0
276 #define ALPHABLEND_BINARY           1
277 #define ALPHABLEND_FULL             2
278 
279 typedef struct _MARGINS {
280     int cxLeftWidth;
281     int cxRightWidth;
282     int cyTopHeight;
283     int cyBottomHeight;
284 } MARGINS, *PMARGINS;
285 
286 enum SIZINGTYPE {
287     ST_TRUESIZE = 0,
288     ST_STRETCH = 1,
289     ST_TILE = 2,
290 };
291 
292 #define TransparentBlt GdiTransparentBlt
293 #define AlphaBlend GdiAlphaBlend
294 
295 /***********************************************************************
296  *      UXTHEME_StretchBlt
297  *
298  * Pseudo TransparentBlt/StretchBlt
299  */
300 static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
301                                       HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
302                                       INT transparent, COLORREF transcolor)
303 {
304     static const BLENDFUNCTION blendFunc =
305     {
306       AC_SRC_OVER, /* BlendOp */
307       0,           /* BlendFlag */
308       255,         /* SourceConstantAlpha */
309       AC_SRC_ALPHA /* AlphaFormat */
310     };
311 
312     BOOL ret = TRUE;
313     int old_stretch_mode;
314     POINT old_brush_org;
315 
316     old_stretch_mode = SetStretchBltMode(hdcDst, HALFTONE);
317     SetBrushOrgEx(hdcDst, nXOriginDst, nYOriginDst, &old_brush_org);
318 
319     if (transparent == ALPHABLEND_BINARY) {
320         /* Ensure we don't pass any negative values to TransparentBlt */
321         ret = TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
322                               hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
323                               transcolor);
324     } else if ((transparent == ALPHABLEND_NONE) ||
325         !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
326                     hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
327                     blendFunc))
328     {
329         ret = StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
330                           hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
331                           SRCCOPY);
332     }
333 
334     SetBrushOrgEx(hdcDst, old_brush_org.x, old_brush_org.y, NULL);
335     SetStretchBltMode(hdcDst, old_stretch_mode);
336 
337     return ret;
338 }
339 
340 /***********************************************************************
341  *      UXTHEME_Blt
342  *
343  * Simplify sending same width/height for both source and dest
344  */
345 static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
346                                HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
347                                INT transparent, COLORREF transcolor)
348 {
349     return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
350                               hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
351                               transparent, transcolor);
352 }
353 
354 /***********************************************************************
355  *      UXTHEME_SizedBlt
356  *
357  * Stretches or tiles, depending on sizingtype.
358  */
359 static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst,
360                                      int nWidthDst, int nHeightDst,
361                                      HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
362                                      int nWidthSrc, int nHeightSrc,
363                                      int sizingtype,
364                                      INT transparent, COLORREF transcolor)
365 {
366     if (sizingtype == ST_TILE)
367     {
368         HDC hdcTemp;
369         BOOL result = FALSE;
370 
371         if (!nWidthSrc || !nHeightSrc) return TRUE;
372 
373         /* For destination width/height less than or equal to source
374            width/height, do not bother with memory bitmap optimization */
375         if (nWidthSrc >= nWidthDst && nHeightSrc >= nHeightDst)
376         {
377             int bltWidth = min (nWidthDst, nWidthSrc);
378             int bltHeight = min (nHeightDst, nHeightSrc);
379 
380             return UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, bltWidth, bltHeight,
381                                 hdcSrc, nXOriginSrc, nYOriginSrc,
382                                 transparent, transcolor);
383         }
384 
385         /* Create a DC with a bitmap consisting of a tiling of the source
386            bitmap, with standard GDI functions. This is faster than an
387            iteration with UXTHEME_Blt(). */
388         hdcTemp = CreateCompatibleDC(hdcSrc);
389         if (hdcTemp != 0)
390         {
391             HBITMAP bitmapTemp;
392             HBITMAP bitmapOrig;
393             int nWidthTemp, nHeightTemp;
394             int xOfs, xRemaining;
395             int yOfs, yRemaining;
396             int growSize;
397 
398             /* Calculate temp dimensions of integer multiples of source dimensions */
399             nWidthTemp = ((nWidthDst + nWidthSrc - 1) / nWidthSrc) * nWidthSrc;
400             nHeightTemp = ((nHeightDst + nHeightSrc - 1) / nHeightSrc) * nHeightSrc;
401             bitmapTemp = CreateCompatibleBitmap(hdcSrc, nWidthTemp, nHeightTemp);
402             bitmapOrig = SelectObject(hdcTemp, bitmapTemp);
403 
404             /* Initial copy of bitmap */
405             BitBlt(hdcTemp, 0, 0, nWidthSrc, nHeightSrc, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
406 
407             /* Extend bitmap in the X direction. Growth of width is exponential */
408             xOfs = nWidthSrc;
409             xRemaining = nWidthTemp - nWidthSrc;
410             growSize = nWidthSrc;
411             while (xRemaining > 0)
412             {
413                 growSize = min(growSize, xRemaining);
414                 BitBlt(hdcTemp, xOfs, 0, growSize, nHeightSrc, hdcTemp, 0, 0, SRCCOPY);
415                 xOfs += growSize;
416                 xRemaining -= growSize;
417                 growSize *= 2;
418             }
419 
420             /* Extend bitmap in the Y direction. Growth of height is exponential */
421             yOfs = nHeightSrc;
422             yRemaining = nHeightTemp - nHeightSrc;
423             growSize = nHeightSrc;
424             while (yRemaining > 0)
425             {
426                 growSize = min(growSize, yRemaining);
427                 BitBlt(hdcTemp, 0, yOfs, nWidthTemp, growSize, hdcTemp, 0, 0, SRCCOPY);
428                 yOfs += growSize;
429                 yRemaining -= growSize;
430                 growSize *= 2;
431             }
432 
433             /* Use temporary hdc for source */
434             result = UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
435                           hdcTemp, 0, 0,
436                           transparent, transcolor);
437 
438             SelectObject(hdcTemp, bitmapOrig);
439             DeleteObject(bitmapTemp);
440         }
441         DeleteDC(hdcTemp);
442         return result;
443     }
444     else
445     {
446         return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
447                                    hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
448                                    transparent, transcolor);
449     }
450 }
451 
452 /***********************************************************************
453  *      UXTHEME_DrawImageBackground
454  *
455  * Draw an imagefile background
456  */
457 static HRESULT UXTHEME_DrawImageBackground(HDC hdc, HBITMAP bmpSrc, RECT *prcSrc, INT transparent,
458                                     COLORREF transparentcolor, BOOL borderonly, int sizingtype, MARGINS *psm, RECT *pRect)
459 {
460     HRESULT hr = S_OK;
461     HBITMAP bmpSrcResized = NULL;
462     HGDIOBJ oldSrc;
463     HDC hdcSrc, hdcOrigSrc = NULL;
464     RECT rcDst;
465     POINT dstSize;
466     POINT srcSize;
467     RECT rcSrc;
468     MARGINS sm;
469 
470     rcDst = *pRect;
471     rcSrc = *prcSrc;
472     sm = *psm;
473 
474     hdcSrc = CreateCompatibleDC(hdc);
475     if(!hdcSrc) {
476         hr = HRESULT_FROM_WIN32(GetLastError());
477         return hr;
478     }
479     oldSrc = SelectObject(hdcSrc, bmpSrc);
480 
481     dstSize.x = rcDst.right-rcDst.left;
482     dstSize.y = rcDst.bottom-rcDst.top;
483     srcSize.x = rcSrc.right-rcSrc.left;
484     srcSize.y = rcSrc.bottom-rcSrc.top;
485 
486     if(sizingtype == ST_TRUESIZE) {
487         if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, dstSize.x, dstSize.y,
488                                 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
489                                 transparent, transparentcolor))
490             hr = HRESULT_FROM_WIN32(GetLastError());
491     }
492     else {
493         HDC hdcDst = NULL;
494         POINT org;
495 
496         dstSize.x = abs(dstSize.x);
497         dstSize.y = abs(dstSize.y);
498 
499         /* Resize source image if destination smaller than margins */
500 #ifndef __REACTOS__
501         /* Revert Wine Commit 2b650fa as it breaks themed Explorer Toolbar Separators
502            FIXME: Revisit this when the bug is fixed. CORE-9636 and Wine Bug #38538 */
503         if (sm.cyTopHeight + sm.cyBottomHeight > dstSize.y || sm.cxLeftWidth + sm.cxRightWidth > dstSize.x) {
504             if (sm.cyTopHeight + sm.cyBottomHeight > dstSize.y) {
505                 sm.cyTopHeight = MulDiv(sm.cyTopHeight, dstSize.y, srcSize.y);
506                 sm.cyBottomHeight = dstSize.y - sm.cyTopHeight;
507                 srcSize.y = dstSize.y;
508             }
509 
510             if (sm.cxLeftWidth + sm.cxRightWidth > dstSize.x) {
511                 sm.cxLeftWidth = MulDiv(sm.cxLeftWidth, dstSize.x, srcSize.x);
512                 sm.cxRightWidth = dstSize.x - sm.cxLeftWidth;
513                 srcSize.x = dstSize.x;
514             }
515 
516             hdcOrigSrc = hdcSrc;
517             hdcSrc = CreateCompatibleDC(NULL);
518             bmpSrcResized = CreateBitmap(srcSize.x, srcSize.y, 1, 32, NULL);
519             SelectObject(hdcSrc, bmpSrcResized);
520 
521             UXTHEME_StretchBlt(hdcSrc, 0, 0, srcSize.x, srcSize.y, hdcOrigSrc, rcSrc.left, rcSrc.top,
522                                rcSrc.right - rcSrc.left, rcSrc.bottom - rcSrc.top, transparent, transparentcolor);
523 
524             rcSrc.left = 0;
525             rcSrc.top = 0;
526             rcSrc.right = srcSize.x;
527             rcSrc.bottom = srcSize.y;
528         }
529 #endif /* __REACTOS__ */
530 
531         hdcDst = hdc;
532         OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
533 
534         /* Upper left corner */
535         if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
536                         hdcSrc, rcSrc.left, rcSrc.top,
537                         transparent, transparentcolor)) {
538             hr = HRESULT_FROM_WIN32(GetLastError());
539             goto draw_error;
540         }
541         /* Upper right corner */
542         if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
543                          sm.cxRightWidth, sm.cyTopHeight,
544                          hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
545                          transparent, transparentcolor)) {
546             hr = HRESULT_FROM_WIN32(GetLastError());
547             goto draw_error;
548         }
549         /* Lower left corner */
550         if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
551                          sm.cxLeftWidth, sm.cyBottomHeight,
552                          hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
553                          transparent, transparentcolor)) {
554             hr = HRESULT_FROM_WIN32(GetLastError());
555             goto draw_error;
556         }
557         /* Lower right corner */
558         if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
559                          sm.cxRightWidth, sm.cyBottomHeight,
560                          hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
561                          transparent, transparentcolor)) {
562             hr = HRESULT_FROM_WIN32(GetLastError());
563             goto draw_error;
564         }
565 
566         if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
567             int destCenterWidth  = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
568             int srcCenterWidth   = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
569             int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
570             int srcCenterHeight  = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
571 
572             if(destCenterWidth > 0) {
573                 /* Center top */
574                 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
575                                       destCenterWidth, sm.cyTopHeight,
576                                       hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
577                                       srcCenterWidth, sm.cyTopHeight,
578                                       sizingtype, transparent, transparentcolor)) {
579                     hr = HRESULT_FROM_WIN32(GetLastError());
580                     goto draw_error;
581                 }
582                 /* Center bottom */
583                 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
584                                       destCenterWidth, sm.cyBottomHeight,
585                                       hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
586                                       srcCenterWidth, sm.cyBottomHeight,
587                                       sizingtype, transparent, transparentcolor)) {
588                     hr = HRESULT_FROM_WIN32(GetLastError());
589                     goto draw_error;
590                 }
591             }
592             if(destCenterHeight > 0) {
593                 /* Left center */
594                 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
595                                       sm.cxLeftWidth, destCenterHeight,
596                                       hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
597                                       sm.cxLeftWidth, srcCenterHeight,
598                                       sizingtype,
599                                       transparent, transparentcolor)) {
600                     hr = HRESULT_FROM_WIN32(GetLastError());
601                     goto draw_error;
602                 }
603                 /* Right center */
604                 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
605                                       sm.cxRightWidth, destCenterHeight,
606                                       hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
607                                       sm.cxRightWidth, srcCenterHeight,
608                                       sizingtype, transparent, transparentcolor)) {
609                     hr = HRESULT_FROM_WIN32(GetLastError());
610                     goto draw_error;
611                 }
612             }
613             if(destCenterHeight > 0 && destCenterWidth > 0) {
614                 if(!borderonly) {
615                     /* Center */
616                     if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
617                                           destCenterWidth, destCenterHeight,
618                                           hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
619                                           srcCenterWidth, srcCenterHeight,
620                                           sizingtype, transparent, transparentcolor)) {
621                         hr = HRESULT_FROM_WIN32(GetLastError());
622                         goto draw_error;
623                     }
624                 }
625             }
626         }
627 
628 draw_error:
629         SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
630     }
631     SelectObject(hdcSrc, oldSrc);
632     DeleteDC(hdcSrc);
633     if (bmpSrcResized) DeleteObject(bmpSrcResized);
634     if (hdcOrigSrc) DeleteDC(hdcOrigSrc);
635     *pRect = rcDst;
636     return hr;
637 }
638 
639 /*
640  * @unimplemented
641  */
642 BOOL
643 WINAPI
644 GdiDrawStream(HDC dc, ULONG l, PGDI_DRAW_STREAM pDS)
645 {
646     if (!pDS || l != sizeof(*pDS))
647     {
648         DPRINT1("GdiDrawStream: Invalid params\n");
649         return 0;
650     }
651 
652     if (pDS->signature != 0x44727753 ||
653         pDS->reserved != 0 ||
654         pDS->unknown1 != 1 ||
655         pDS->unknown2 != 9)
656     {
657         DPRINT1("GdiDrawStream: Got unknown pDS data\n");
658         return 0;
659     }
660 
661     {
662         MARGINS sm = {pDS->leftSizingMargin, pDS->rightSizingMargin, pDS->topSizingMargin, pDS->bottomSizingMargin};
663         INT transparent = 0;
664         int sizingtype;
665 
666         if (pDS->drawOption & DS_TRANSPARENTALPHA)
667             transparent = ALPHABLEND_FULL;
668         else if (pDS->drawOption & DS_TRANSPARENTCLR)
669             transparent = ALPHABLEND_BINARY;
670         else
671             transparent = ALPHABLEND_NONE;
672 
673         if (pDS->drawOption & DS_TILE)
674             sizingtype = ST_TILE;
675         else if (pDS->drawOption & DS_TRUESIZE)
676             sizingtype = ST_TRUESIZE;
677         else
678             sizingtype = ST_STRETCH;
679 
680         if (pDS->rcDest.right < pDS->rcDest.left || pDS->rcDest.bottom < pDS->rcDest.top)
681             return 0;
682 
683         if (sm.cxLeftWidth + sm.cxRightWidth > pDS->rcDest.right - pDS->rcDest.left)
684         {
685             sm.cxLeftWidth = sm.cxRightWidth = 0;
686         }
687 
688         if (sm.cyTopHeight + sm.cyBottomHeight > pDS->rcDest.bottom - pDS->rcDest.top)
689         {
690             sm.cyTopHeight = sm.cyBottomHeight = 0;
691         }
692 
693         UXTHEME_DrawImageBackground(pDS->hDC,
694                                     pDS->hImage,
695                                     &pDS->rcSrc,
696                                     transparent,
697                                     pDS->crTransparent,
698                                     FALSE,
699                                     sizingtype,
700                                     &sm,
701                                     &pDS->rcDest);
702     }
703     return 0;
704 }
705 
706 
707 /*
708  * @implemented
709  */
710 BOOL
711 WINAPI
712 GdiValidateHandle(HGDIOBJ hobj)
713 {
714     PGDI_TABLE_ENTRY Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hobj);
715     if ( (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0 &&
716             ( (Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK ) ==
717             GDI_HANDLE_GET_TYPE(hobj) )
718     {
719         HANDLE pid = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1);
720         if(pid == NULL || pid == CurrentProcessId)
721         {
722             return TRUE;
723         }
724     }
725     return FALSE;
726 
727 }
728 
729 /*
730  * @implemented
731  */
732 HGDIOBJ
733 WINAPI
734 GdiFixUpHandle(HGDIOBJ hGdiObj)
735 {
736     PGDI_TABLE_ENTRY Entry;
737 
738     if (GDI_HANDLE_GET_UPPER(hGdiObj))
739     {
740         return hGdiObj;
741     }
742 
743     /* FIXME is this right ?? */
744 
745     Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hGdiObj);
746 
747     /* Rebuild handle for Object */
748     return (HGDIOBJ)(((ULONG_PTR)(hGdiObj)) | (Entry->Type << GDI_ENTRY_UPPER_SHIFT));
749 }
750 
751 /*
752  * @implemented
753  */
754 PVOID
755 WINAPI
756 GdiQueryTable(VOID)
757 {
758     return (PVOID)GdiHandleTable;
759 }
760 
761 BOOL GdiGetHandleUserData(HGDIOBJ hGdiObj, DWORD ObjectType, PVOID *UserData)
762 {
763     PGDI_TABLE_ENTRY Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hGdiObj);
764 
765     /* Check if twe have the correct type */
766     if (GDI_HANDLE_GET_TYPE(hGdiObj) != ObjectType ||
767         ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK) != ObjectType ||
768         (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != (ObjectType & GDI_ENTRY_BASETYPE_MASK))
769     {
770         return FALSE;
771     }
772 
773     /* Check if we are the owner */
774     if ((HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) != CurrentProcessId)
775     {
776         return FALSE;
777     }
778 
779     *UserData = Entry->UserData;
780     return TRUE;
781 }
782 
783 PLDC
784 FASTCALL
785 GdiGetLDC(HDC hdc)
786 {
787     PDC_ATTR pdcattr;
788 
789     /* Get the DC attribute */
790     pdcattr = GdiGetDcAttr(hdc);
791     if (pdcattr == NULL)
792     {
793         return NULL;
794     }
795 
796     /* Return the LDC pointer */
797     return pdcattr->pvLDC;
798 }
799 
800 BOOL
801 FASTCALL
802 GdiSetLDC(HDC hdc, PVOID pvLDC)
803 {
804     PDC_ATTR pdcattr;
805 
806     /* Get the DC attribute */
807     pdcattr = GdiGetDcAttr(hdc);
808     if (pdcattr == NULL)
809     {
810         return FALSE;
811     }
812 
813     /* Set the LDC pointer */
814     pdcattr->pvLDC = pvLDC;
815     return TRUE;
816 }
817 
818 
819 VOID GdiSAPCallback(PLDC pldc)
820 {
821     DWORD Time, NewTime = GetTickCount();
822 
823     Time = NewTime - pldc->CallBackTick;
824 
825     if ( Time < SAPCALLBACKDELAY) return;
826 
827     pldc->CallBackTick = NewTime;
828 
829     if ( !pldc->pAbortProc(pldc->hDC, 0) )
830     {
831         CancelDC(pldc->hDC);
832         AbortDoc(pldc->hDC);
833     }
834 }
835 
836 /*
837  * @implemented
838  */
839 DWORD
840 WINAPI
841 GdiSetBatchLimit(DWORD	Limit)
842 {
843     DWORD OldLimit = GDI_BatchLimit;
844 
845     if ( (!Limit) ||
846             (Limit >= GDI_BATCH_LIMIT))
847     {
848         return Limit;
849     }
850 
851     GdiFlush();
852     GDI_BatchLimit = Limit;
853     return OldLimit;
854 }
855 
856 
857 /*
858  * @implemented
859  */
860 DWORD
861 WINAPI
862 GdiGetBatchLimit(VOID)
863 {
864     return GDI_BatchLimit;
865 }
866 
867 
868 /*
869  * @implemented
870  */
871 VOID
872 WINAPI
873 GdiSetLastError(DWORD dwErrCode)
874 {
875     NtCurrentTeb()->LastErrorValue = (ULONG) dwErrCode;
876 }
877 
878 HGDIOBJ
879 FASTCALL
880 hGetPEBHandle(HANDLECACHETYPE Type, COLORREF cr)
881 {
882     int Number, Offset, MaxNum, GdiType;
883     HANDLE Lock;
884     HGDIOBJ Handle = NULL;
885 
886     Lock = InterlockedCompareExchangePointer( (PVOID*)&GdiHandleCache->ulLock,
887             NtCurrentTeb(),
888             NULL );
889 
890     if (Lock) return Handle;
891 
892     Number = GdiHandleCache->ulNumHandles[Type];
893 
894     if (Type == hctBrushHandle)
895     {
896        Offset = 0;
897        MaxNum = CACHE_BRUSH_ENTRIES;
898        GdiType = GDILoObjType_LO_BRUSH_TYPE;
899     }
900     else if (Type == hctPenHandle)
901     {
902        Offset = CACHE_BRUSH_ENTRIES;
903        MaxNum = CACHE_PEN_ENTRIES;
904        GdiType = GDILoObjType_LO_PEN_TYPE;
905     }
906     else if (Type == hctRegionHandle)
907     {
908        Offset = CACHE_BRUSH_ENTRIES+CACHE_PEN_ENTRIES;
909        MaxNum = CACHE_REGION_ENTRIES;
910        GdiType = GDILoObjType_LO_REGION_TYPE;
911     }
912     else // Font is not supported here.
913     {
914        return Handle;
915     }
916 
917     if ( Number && Number <= MaxNum )
918     {
919        PBRUSH_ATTR pBrush_Attr;
920        HGDIOBJ *hPtr;
921        hPtr = GdiHandleCache->Handle + Offset;
922        Handle = hPtr[Number - 1];
923 
924        if (GdiGetHandleUserData( Handle, GdiType, (PVOID) &pBrush_Attr))
925        {
926           if (pBrush_Attr->AttrFlags & ATTR_CACHED)
927           {
928              DPRINT("Get Handle! Type %d Count %lu PEB 0x%p\n", Type, GdiHandleCache->ulNumHandles[Type], NtCurrentTeb()->ProcessEnvironmentBlock);
929              pBrush_Attr->AttrFlags &= ~ATTR_CACHED;
930              hPtr[Number - 1] = NULL;
931              GdiHandleCache->ulNumHandles[Type]--;
932              if ( Type == hctBrushHandle ) // Handle only brush.
933              {
934                 if ( pBrush_Attr->lbColor != cr )
935                 {
936                    pBrush_Attr->lbColor = cr ;
937                    pBrush_Attr->AttrFlags |= ATTR_NEW_COLOR;
938                 }
939              }
940           }
941        }
942        else
943        {
944           Handle = NULL;
945        }
946     }
947     (void)InterlockedExchangePointer((PVOID*)&GdiHandleCache->ulLock, Lock);
948     return Handle;
949 }
950 
951 /*
952  * @unimplemented
953  */
954 BOOL
955 WINAPI
956 bMakePathNameW(LPWSTR lpBuffer,LPCWSTR lpFileName,LPWSTR *lpFilePart,DWORD unknown)
957 {
958     UNIMPLEMENTED;
959     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
960     return 0;
961 }
962 
963 /*
964  * @implemented
965  * Synchronized with WINE dlls/gdi32/driver.c
966  */
967 DEVMODEW *
968 WINAPI
969 GdiConvertToDevmodeW(const DEVMODEA *dmA)
970 {
971     DEVMODEW *dmW;
972     WORD dmW_size, dmA_size;
973 
974     dmA_size = dmA->dmSize;
975 
976     /* this is the minimal dmSize that XP accepts */
977     if (dmA_size < FIELD_OFFSET(DEVMODEA, dmFields))
978         return NULL;
979 
980     if (dmA_size > sizeof(DEVMODEA))
981         dmA_size = sizeof(DEVMODEA);
982 
983     dmW_size = dmA_size + CCHDEVICENAME;
984     if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME)
985         dmW_size += CCHFORMNAME;
986 
987     dmW = HeapAlloc(GetProcessHeap(), 0, dmW_size + dmA->dmDriverExtra);
988     if (!dmW) return NULL;
989 
990     MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmDeviceName, -1,
991                                    dmW->dmDeviceName, CCHDEVICENAME);
992     /* copy slightly more, to avoid long computations */
993     memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion, dmA_size - CCHDEVICENAME);
994 
995     if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME)
996     {
997         if (dmA->dmFields & DM_FORMNAME)
998             MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmFormName, -1,
999                                        dmW->dmFormName, CCHFORMNAME);
1000         else
1001             dmW->dmFormName[0] = 0;
1002 
1003         if (dmA_size > FIELD_OFFSET(DEVMODEA, dmLogPixels))
1004             memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA_size - FIELD_OFFSET(DEVMODEA, dmLogPixels));
1005     }
1006 
1007     if (dmA->dmDriverExtra)
1008         memcpy((char *)dmW + dmW_size, (const char *)dmA + dmA_size, dmA->dmDriverExtra);
1009 
1010     dmW->dmSize = dmW_size;
1011 
1012     return dmW;
1013 }
1014 
1015 /*
1016  * @unimplemented
1017  */
1018 BOOL
1019 WINAPI
1020 GdiRealizationInfo(HDC hdc,
1021                    PREALIZATION_INFO pri)
1022 {
1023     // ATM we do not support local font data and Language Pack.
1024     return NtGdiGetRealizationInfo(hdc, pri, (HFONT) NULL);
1025 }
1026 
1027 
1028 /*
1029  * @halfplemented
1030  */
1031 VOID WINAPI GdiInitializeLanguagePack(DWORD InitParam)
1032 {
1033     /* Lpk function pointers to be passed to user32 */
1034 #if 0
1035     FARPROC hookfuncs[4];
1036 #endif
1037 
1038 #ifdef LANGPACK
1039     if (!LoadLPK(LPK_INIT)) // no lpk found!
1040 #endif
1041         return;
1042 
1043      /* Call InitializeLpkHooks with 4 procedure addresses
1044         loaded from lpk.dll but currently only one of them is currently implemented.
1045         Then InitializeLpkHooks (in user32) uses these to replace certain internal functions
1046         and ORs a DWORD being used also by ClientThreadSetup and calls
1047         NtUserOneParam with parameter 54 which is ONEPARAM_ROUTINE_REGISTERLPK
1048         which most likely changes the value of dwLpkEntryPoints in the
1049         PROCESSINFO struct */
1050 
1051 #if 0
1052         hookfuncs[0] = GetProcAddress(hLpk, "LpkPSMTextOut");
1053         InitializeLpkHooks(hookfuncs);
1054 #endif
1055 
1056     gbLpk = TRUE;
1057 }
1058 
1059 BOOL
1060 WINAPI
1061 GdiAddGlsBounds(HDC hdc,LPRECT prc)
1062 {
1063     return NtGdiSetBoundsRect(hdc, prc, DCB_WINDOWMGR|DCB_ACCUMULATE ) ? TRUE : FALSE;
1064 }
1065 
1066 BOOL
1067 WINAPI
1068 GetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags)
1069 {
1070     return NtGdiGetBoundsRect(hdc, prc, flags);
1071 }
1072 
1073 BOOL
1074 WINAPI
1075 SetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags)
1076 {
1077     return NtGdiSetBoundsRect(hdc, prc, flags );
1078 }
1079 
1080 /*
1081  * @unimplemented
1082  */
1083 BOOL
1084 WINAPI
1085 GdiAddGlsRecord(HDC hdc,
1086                 DWORD unknown1,
1087                 LPCSTR unknown2,
1088                 LPRECT unknown3)
1089 {
1090     UNIMPLEMENTED;
1091     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1092     return 0;
1093 }
1094 
1095