[GDI32] Remove obsolete function GdiIsHandleValid, which is just a copy of GdiValidat...
[reactos.git] / reactos / win32ss / gdi / gdi32 / misc / misc.c
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 METADC16_Escape(hdc, nEscape, cbInput, lpvInData, 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 UXTHEME_DrawImageBackground(pDS->hDC,
681 pDS->hImage,
682 &pDS->rcSrc,
683 transparent,
684 pDS->crTransparent,
685 FALSE,
686 sizingtype,
687 &sm,
688 &pDS->rcDest);
689 }
690 return 0;
691 }
692
693
694 /*
695 * @implemented
696 */
697 BOOL
698 WINAPI
699 GdiValidateHandle(HGDIOBJ hobj)
700 {
701 PGDI_TABLE_ENTRY Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hobj);
702 if ( (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0 &&
703 ( (Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK ) ==
704 GDI_HANDLE_GET_TYPE(hobj) )
705 {
706 HANDLE pid = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1);
707 if(pid == NULL || pid == CurrentProcessId)
708 {
709 return TRUE;
710 }
711 }
712 return FALSE;
713
714 }
715
716 /*
717 * @implemented
718 */
719 HGDIOBJ
720 WINAPI
721 GdiFixUpHandle(HGDIOBJ hGdiObj)
722 {
723 PGDI_TABLE_ENTRY Entry;
724
725 if (((ULONG_PTR)(hGdiObj)) & GDI_HANDLE_UPPER_MASK )
726 {
727 return hGdiObj;
728 }
729
730 /* FIXME is this right ?? */
731
732 Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hGdiObj);
733
734 /* Rebuild handle for Object */
735 return hGdiObj = (HGDIOBJ)(((LONG_PTR)(hGdiObj)) | (Entry->Type << GDI_ENTRY_UPPER_SHIFT));
736 }
737
738 /*
739 * @implemented
740 */
741 PVOID
742 WINAPI
743 GdiQueryTable(VOID)
744 {
745 return (PVOID)GdiHandleTable;
746 }
747
748 BOOL GdiGetHandleUserData(HGDIOBJ hGdiObj, DWORD ObjectType, PVOID *UserData)
749 {
750 PGDI_TABLE_ENTRY Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hGdiObj);
751
752 /* Check if twe have the correct type */
753 if (GDI_HANDLE_GET_TYPE(hGdiObj) != ObjectType ||
754 ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK) != ObjectType ||
755 (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != (ObjectType & GDI_ENTRY_BASETYPE_MASK))
756 {
757 return FALSE;
758 }
759
760 /* Check if we are the owner */
761 if ((HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) != CurrentProcessId)
762 {
763 return FALSE;
764 }
765
766 *UserData = Entry->UserData;
767 return TRUE;
768 }
769
770 PLDC
771 FASTCALL
772 GdiGetLDC(HDC hdc)
773 {
774 PDC_ATTR pdcattr;
775
776 /* Get the DC attribute */
777 pdcattr = GdiGetDcAttr(hdc);
778 if (pdcattr == NULL)
779 {
780 return NULL;
781 }
782
783 /* Return the LDC pointer */
784 return pdcattr->pvLDC;
785 }
786
787 BOOL
788 FASTCALL
789 GdiSetLDC(HDC hdc, PVOID pvLDC)
790 {
791 PDC_ATTR pdcattr;
792
793 /* Get the DC attribute */
794 pdcattr = GdiGetDcAttr(hdc);
795 if (pdcattr == NULL)
796 {
797 return FALSE;
798 }
799
800 /* Set the LDC pointer */
801 pdcattr->pvLDC = pvLDC;
802 return TRUE;
803 }
804
805
806 VOID GdiSAPCallback(PLDC pldc)
807 {
808 DWORD Time, NewTime = GetTickCount();
809
810 Time = NewTime - pldc->CallBackTick;
811
812 if ( Time < SAPCALLBACKDELAY) return;
813
814 pldc->CallBackTick = NewTime;
815
816 if ( !pldc->pAbortProc(pldc->hDC, 0) )
817 {
818 CancelDC(pldc->hDC);
819 AbortDoc(pldc->hDC);
820 }
821 }
822
823 /*
824 * @implemented
825 */
826 DWORD
827 WINAPI
828 GdiSetBatchLimit(DWORD Limit)
829 {
830 DWORD OldLimit = GDI_BatchLimit;
831
832 if ( (!Limit) ||
833 (Limit >= GDI_BATCH_LIMIT))
834 {
835 return Limit;
836 }
837
838 GdiFlush();
839 GDI_BatchLimit = Limit;
840 return OldLimit;
841 }
842
843
844 /*
845 * @implemented
846 */
847 DWORD
848 WINAPI
849 GdiGetBatchLimit(VOID)
850 {
851 return GDI_BatchLimit;
852 }
853
854
855 /*
856 * @implemented
857 */
858 VOID
859 WINAPI
860 GdiSetLastError(DWORD dwErrCode)
861 {
862 NtCurrentTeb()->LastErrorValue = (ULONG) dwErrCode;
863 }
864
865 HGDIOBJ
866 FASTCALL
867 hGetPEBHandle(HANDLECACHETYPE Type, COLORREF cr)
868 {
869 int Number, Offset, MaxNum, GdiType;
870 HANDLE Lock;
871 HGDIOBJ Handle = NULL;
872
873 Lock = InterlockedCompareExchangePointer( (PVOID*)&GdiHandleCache->ulLock,
874 NtCurrentTeb(),
875 NULL );
876
877 if (Lock) return Handle;
878
879 Number = GdiHandleCache->ulNumHandles[Type];
880
881 if (Type == hctBrushHandle)
882 {
883 Offset = 0;
884 MaxNum = CACHE_BRUSH_ENTRIES;
885 GdiType = GDILoObjType_LO_BRUSH_TYPE;
886 }
887 else if (Type == hctPenHandle)
888 {
889 Offset = CACHE_BRUSH_ENTRIES;
890 MaxNum = CACHE_PEN_ENTRIES;
891 GdiType = GDILoObjType_LO_PEN_TYPE;
892 }
893 else if (Type == hctRegionHandle)
894 {
895 Offset = CACHE_BRUSH_ENTRIES+CACHE_PEN_ENTRIES;
896 MaxNum = CACHE_REGION_ENTRIES;
897 GdiType = GDILoObjType_LO_REGION_TYPE;
898 }
899 else // Font is not supported here.
900 {
901 return Handle;
902 }
903
904 if ( Number && Number <= MaxNum )
905 {
906 PBRUSH_ATTR pBrush_Attr;
907 HGDIOBJ *hPtr;
908 hPtr = GdiHandleCache->Handle + Offset;
909 Handle = hPtr[Number - 1];
910
911 if (GdiGetHandleUserData( Handle, GdiType, (PVOID) &pBrush_Attr))
912 {
913 if (pBrush_Attr->AttrFlags & ATTR_CACHED)
914 {
915 DPRINT("Get Handle! Type %d Count %lu PEB 0x%p\n", Type, GdiHandleCache->ulNumHandles[Type], NtCurrentTeb()->ProcessEnvironmentBlock);
916 pBrush_Attr->AttrFlags &= ~ATTR_CACHED;
917 hPtr[Number - 1] = NULL;
918 GdiHandleCache->ulNumHandles[Type]--;
919 if ( Type == hctBrushHandle ) // Handle only brush.
920 {
921 if ( pBrush_Attr->lbColor != cr )
922 {
923 pBrush_Attr->lbColor = cr ;
924 pBrush_Attr->AttrFlags |= ATTR_NEW_COLOR;
925 }
926 }
927 }
928 }
929 else
930 {
931 Handle = NULL;
932 }
933 }
934 (void)InterlockedExchangePointer((PVOID*)&GdiHandleCache->ulLock, Lock);
935 return Handle;
936 }
937
938 /*
939 * @unimplemented
940 */
941 BOOL
942 WINAPI
943 bMakePathNameW(LPWSTR lpBuffer,LPCWSTR lpFileName,LPWSTR *lpFilePart,DWORD unknown)
944 {
945 UNIMPLEMENTED;
946 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
947 return 0;
948 }
949
950 /*
951 * @implemented
952 */
953 DEVMODEW *
954 WINAPI
955 GdiConvertToDevmodeW(const DEVMODEA *dmA)
956 {
957 DEVMODEW *dmW;
958 WORD dmW_size, dmA_size;
959
960 dmA_size = dmA->dmSize;
961
962 /* this is the minimal dmSize that XP accepts */
963 if (dmA_size < FIELD_OFFSET(DEVMODEA, dmFields))
964 return NULL;
965
966 if (dmA_size > sizeof(DEVMODEA))
967 dmA_size = sizeof(DEVMODEA);
968
969 dmW_size = dmA_size + CCHDEVICENAME;
970 if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME)
971 dmW_size += CCHFORMNAME;
972
973 dmW = HeapAlloc(GetProcessHeap(), 0, dmW_size + dmA->dmDriverExtra);
974 if (!dmW) return NULL;
975
976 MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmDeviceName, CCHDEVICENAME,
977 dmW->dmDeviceName, CCHDEVICENAME);
978 /* copy slightly more, to avoid long computations */
979 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion, dmA_size - CCHDEVICENAME);
980
981 if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME)
982 {
983 MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmFormName, CCHFORMNAME,
984 dmW->dmFormName, CCHFORMNAME);
985 if (dmA_size > FIELD_OFFSET(DEVMODEA, dmLogPixels))
986 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA_size - FIELD_OFFSET(DEVMODEA, dmLogPixels));
987 }
988
989 if (dmA->dmDriverExtra)
990 memcpy((char *)dmW + dmW_size, (const char *)dmA + dmA_size, dmA->dmDriverExtra);
991
992 dmW->dmSize = dmW_size;
993
994 return dmW;
995 }
996
997 /*
998 * @unimplemented
999 */
1000 BOOL
1001 WINAPI
1002 GdiRealizationInfo(HDC hdc,
1003 PREALIZATION_INFO pri)
1004 {
1005 // ATM we do not support local font data and Language Pack.
1006 return NtGdiGetRealizationInfo(hdc, pri, (HFONT) NULL);
1007 }
1008
1009
1010 /*
1011 * @unimplemented
1012 */
1013 VOID WINAPI GdiInitializeLanguagePack(DWORD InitParam)
1014 {
1015 UNIMPLEMENTED;
1016 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1017 }
1018
1019 BOOL
1020 WINAPI
1021 GdiAddGlsBounds(HDC hdc,LPRECT prc)
1022 {
1023 return NtGdiSetBoundsRect(hdc, prc, DCB_WINDOWMGR|DCB_ACCUMULATE ) ? TRUE : FALSE;
1024 }
1025
1026 BOOL
1027 WINAPI
1028 GetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags)
1029 {
1030 return NtGdiGetBoundsRect(hdc, prc, flags);
1031 }
1032
1033 BOOL
1034 WINAPI
1035 SetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags)
1036 {
1037 return NtGdiSetBoundsRect(hdc, prc, flags );
1038 }
1039
1040 /*
1041 * @unimplemented
1042 */
1043 BOOL
1044 WINAPI
1045 GdiAddGlsRecord(HDC hdc,
1046 DWORD unknown1,
1047 LPCSTR unknown2,
1048 LPRECT unknown3)
1049 {
1050 UNIMPLEMENTED;
1051 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1052 return 0;
1053 }
1054