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
GdiFlush(VOID)44 GdiFlush(VOID)
45 {
46 NtGdiFlush();
47 return TRUE;
48 }
49
50 /*
51 * @unimplemented
52 */
53 INT
54 WINAPI
Escape(_In_ HDC hdc,_In_ INT nEscape,_In_ INT cbInput,_In_ LPCSTR lpvInData,_Out_ LPVOID lpvOutData)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
ExtEscape(HDC hDC,int nEscape,int cbInput,LPCSTR lpszInData,int cbOutput,LPSTR lpszOutData)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
NamedEscape(HDC hdc,PWCHAR pDriver,INT iEsc,INT cjIn,LPSTR pjIn,INT cjOut,LPSTR pjOut)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
DrawEscape(HDC hDC,INT nEscape,INT cbInput,LPCSTR lpszInData)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 */
UXTHEME_StretchBlt(HDC hdcDst,int nXOriginDst,int nYOriginDst,int nWidthDst,int nHeightDst,HDC hdcSrc,int nXOriginSrc,int nYOriginSrc,int nWidthSrc,int nHeightSrc,INT transparent,COLORREF transcolor)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 */
UXTHEME_Blt(HDC hdcDest,int nXOriginDest,int nYOriginDest,int nWidthDest,int nHeightDest,HDC hdcSrc,int nXOriginSrc,int nYOriginSrc,INT transparent,COLORREF transcolor)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 */
UXTHEME_SizedBlt(HDC hdcDst,int nXOriginDst,int nYOriginDst,int nWidthDst,int nHeightDst,HDC hdcSrc,int nXOriginSrc,int nYOriginSrc,int nWidthSrc,int nHeightSrc,int sizingtype,INT transparent,COLORREF transcolor)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 */
UXTHEME_DrawImageBackground(HDC hdc,HBITMAP bmpSrc,RECT * prcSrc,INT transparent,COLORREF transparentcolor,BOOL borderonly,int sizingtype,MARGINS * psm,RECT * pRect)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
GdiDrawStream(HDC dc,ULONG l,PGDI_DRAW_STREAM pDS)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
GdiValidateHandle(HGDIOBJ hobj)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
GdiFixUpHandle(HGDIOBJ hGdiObj)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
GdiQueryTable(VOID)756 GdiQueryTable(VOID)
757 {
758 return (PVOID)GdiHandleTable;
759 }
760
GdiGetHandleUserData(HGDIOBJ hGdiObj,DWORD ObjectType,PVOID * UserData)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
GdiGetLDC(HDC hdc)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
GdiSetLDC(HDC hdc,PVOID pvLDC)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
GdiSAPCallback(PLDC pldc)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
GdiSetBatchLimit(DWORD Limit)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
GdiGetBatchLimit(VOID)862 GdiGetBatchLimit(VOID)
863 {
864 return GDI_BatchLimit;
865 }
866
867
868 /*
869 * @implemented
870 */
871 VOID
872 WINAPI
GdiSetLastError(DWORD dwErrCode)873 GdiSetLastError(DWORD dwErrCode)
874 {
875 NtCurrentTeb()->LastErrorValue = (ULONG) dwErrCode;
876 }
877
878 HGDIOBJ
879 FASTCALL
hGetPEBHandle(HANDLECACHETYPE Type,COLORREF cr)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
bMakePathNameW(LPWSTR lpBuffer,LPCWSTR lpFileName,LPWSTR * lpFilePart,DWORD unknown)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
GdiConvertToDevmodeW(const DEVMODEA * dmA)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
GdiRealizationInfo(HDC hdc,PREALIZATION_INFO pri)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 */
GdiInitializeLanguagePack(DWORD InitParam)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
GdiAddGlsBounds(HDC hdc,LPRECT prc)1061 GdiAddGlsBounds(HDC hdc,LPRECT prc)
1062 {
1063 return NtGdiSetBoundsRect(hdc, prc, DCB_WINDOWMGR|DCB_ACCUMULATE ) ? TRUE : FALSE;
1064 }
1065
1066 BOOL
1067 WINAPI
GetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags)1068 GetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags)
1069 {
1070 return NtGdiGetBoundsRect(hdc, prc, flags);
1071 }
1072
1073 BOOL
1074 WINAPI
SetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags)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
GdiAddGlsRecord(HDC hdc,DWORD unknown1,LPCSTR unknown2,LPRECT unknown3)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