4039d47a488ef060dfc0c2267ad89d63dbcd320b
[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 typedef struct GDI_DRAW_STREAM_TAG
287 {
288 DWORD signature; // must be 0x44727753;//"Swrd"
289 DWORD reserved; // must be 0
290 HDC hDC; // handle to the device object of windiw to draw.
291 RECT rcDest; // desination rect of window to draw.
292 DWORD unknown1; // must be 1.
293 HBITMAP hImage;
294 DWORD unknown2; // must be 9.
295 RECT rcClip; // desination rect of window to draw.
296 RECT rcSrc; // source rect of bitmap to draw.
297 DWORD drawOption; // 0x2 is tile instead of stretch. 0x4 is transparent. 0x20 is true size
298 DWORD leftSizingMargin;
299 DWORD rightSizingMargin;
300 DWORD topSizingMargin;
301 DWORD bottomSizingMargin;
302 DWORD crTransparent; // transparent color.
303
304 } GDI_DRAW_STREAM, *PGDI_DRAW_STREAM;
305
306 enum SIZINGTYPE {
307 ST_TRUESIZE = 0,
308 ST_STRETCH = 1,
309 ST_TILE = 2,
310 };
311
312 #define TransparentBlt GdiTransparentBlt
313 #define AlphaBlend GdiAlphaBlend
314
315 /***********************************************************************
316 * UXTHEME_StretchBlt
317 *
318 * Pseudo TransparentBlt/StretchBlt
319 */
320 static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
321 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
322 INT transparent, COLORREF transcolor)
323 {
324 static const BLENDFUNCTION blendFunc =
325 {
326 AC_SRC_OVER, /* BlendOp */
327 0, /* BlendFlag */
328 255, /* SourceConstantAlpha */
329 AC_SRC_ALPHA /* AlphaFormat */
330 };
331
332 BOOL ret = TRUE;
333 int old_stretch_mode;
334 POINT old_brush_org;
335
336 old_stretch_mode = SetStretchBltMode(hdcDst, HALFTONE);
337 SetBrushOrgEx(hdcDst, nXOriginDst, nYOriginDst, &old_brush_org);
338
339 if (transparent == ALPHABLEND_BINARY) {
340 /* Ensure we don't pass any negative values to TransparentBlt */
341 ret = TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
342 hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
343 transcolor);
344 } else if ((transparent == ALPHABLEND_NONE) ||
345 !AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
346 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
347 blendFunc))
348 {
349 ret = StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
350 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
351 SRCCOPY);
352 }
353
354 SetBrushOrgEx(hdcDst, old_brush_org.x, old_brush_org.y, NULL);
355 SetStretchBltMode(hdcDst, old_stretch_mode);
356
357 return ret;
358 }
359
360 /***********************************************************************
361 * UXTHEME_Blt
362 *
363 * Simplify sending same width/height for both source and dest
364 */
365 static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
366 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
367 INT transparent, COLORREF transcolor)
368 {
369 return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
370 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
371 transparent, transcolor);
372 }
373
374 /***********************************************************************
375 * UXTHEME_SizedBlt
376 *
377 * Stretches or tiles, depending on sizingtype.
378 */
379 static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst,
380 int nWidthDst, int nHeightDst,
381 HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
382 int nWidthSrc, int nHeightSrc,
383 int sizingtype,
384 INT transparent, COLORREF transcolor)
385 {
386 if (sizingtype == ST_TILE)
387 {
388 HDC hdcTemp;
389 BOOL result = FALSE;
390
391 if (!nWidthSrc || !nHeightSrc) return TRUE;
392
393 /* For destination width/height less than or equal to source
394 width/height, do not bother with memory bitmap optimization */
395 if (nWidthSrc >= nWidthDst && nHeightSrc >= nHeightDst)
396 {
397 int bltWidth = min (nWidthDst, nWidthSrc);
398 int bltHeight = min (nHeightDst, nHeightSrc);
399
400 return UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, bltWidth, bltHeight,
401 hdcSrc, nXOriginSrc, nYOriginSrc,
402 transparent, transcolor);
403 }
404
405 /* Create a DC with a bitmap consisting of a tiling of the source
406 bitmap, with standard GDI functions. This is faster than an
407 iteration with UXTHEME_Blt(). */
408 hdcTemp = CreateCompatibleDC(hdcSrc);
409 if (hdcTemp != 0)
410 {
411 HBITMAP bitmapTemp;
412 HBITMAP bitmapOrig;
413 int nWidthTemp, nHeightTemp;
414 int xOfs, xRemaining;
415 int yOfs, yRemaining;
416 int growSize;
417
418 /* Calculate temp dimensions of integer multiples of source dimensions */
419 nWidthTemp = ((nWidthDst + nWidthSrc - 1) / nWidthSrc) * nWidthSrc;
420 nHeightTemp = ((nHeightDst + nHeightSrc - 1) / nHeightSrc) * nHeightSrc;
421 bitmapTemp = CreateCompatibleBitmap(hdcSrc, nWidthTemp, nHeightTemp);
422 bitmapOrig = SelectObject(hdcTemp, bitmapTemp);
423
424 /* Initial copy of bitmap */
425 BitBlt(hdcTemp, 0, 0, nWidthSrc, nHeightSrc, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
426
427 /* Extend bitmap in the X direction. Growth of width is exponential */
428 xOfs = nWidthSrc;
429 xRemaining = nWidthTemp - nWidthSrc;
430 growSize = nWidthSrc;
431 while (xRemaining > 0)
432 {
433 growSize = min(growSize, xRemaining);
434 BitBlt(hdcTemp, xOfs, 0, growSize, nHeightSrc, hdcTemp, 0, 0, SRCCOPY);
435 xOfs += growSize;
436 xRemaining -= growSize;
437 growSize *= 2;
438 }
439
440 /* Extend bitmap in the Y direction. Growth of height is exponential */
441 yOfs = nHeightSrc;
442 yRemaining = nHeightTemp - nHeightSrc;
443 growSize = nHeightSrc;
444 while (yRemaining > 0)
445 {
446 growSize = min(growSize, yRemaining);
447 BitBlt(hdcTemp, 0, yOfs, nWidthTemp, growSize, hdcTemp, 0, 0, SRCCOPY);
448 yOfs += growSize;
449 yRemaining -= growSize;
450 growSize *= 2;
451 }
452
453 /* Use temporary hdc for source */
454 result = UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
455 hdcTemp, 0, 0,
456 transparent, transcolor);
457
458 SelectObject(hdcTemp, bitmapOrig);
459 DeleteObject(bitmapTemp);
460 }
461 DeleteDC(hdcTemp);
462 return result;
463 }
464 else
465 {
466 return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
467 hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
468 transparent, transcolor);
469 }
470 }
471
472 /***********************************************************************
473 * UXTHEME_DrawImageBackground
474 *
475 * Draw an imagefile background
476 */
477 static HRESULT UXTHEME_DrawImageBackground(HDC hdc, HBITMAP bmpSrc, RECT *prcSrc, INT transparent,
478 COLORREF transparentcolor, BOOL borderonly, int sizingtype, MARGINS *psm, RECT *pRect)
479 {
480 HRESULT hr = S_OK;
481 HBITMAP bmpSrcResized = NULL;
482 HGDIOBJ oldSrc;
483 HDC hdcSrc, hdcOrigSrc = NULL;
484 RECT rcDst;
485 POINT dstSize;
486 POINT srcSize;
487 RECT rcSrc;
488 MARGINS sm;
489
490 rcDst = *pRect;
491 rcSrc = *prcSrc;
492 sm = *psm;
493
494 hdcSrc = CreateCompatibleDC(hdc);
495 if(!hdcSrc) {
496 hr = HRESULT_FROM_WIN32(GetLastError());
497 return hr;
498 }
499 oldSrc = SelectObject(hdcSrc, bmpSrc);
500
501 dstSize.x = rcDst.right-rcDst.left;
502 dstSize.y = rcDst.bottom-rcDst.top;
503 srcSize.x = rcSrc.right-rcSrc.left;
504 srcSize.y = rcSrc.bottom-rcSrc.top;
505
506 if(sizingtype == ST_TRUESIZE) {
507 if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, dstSize.x, dstSize.y,
508 hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
509 transparent, transparentcolor))
510 hr = HRESULT_FROM_WIN32(GetLastError());
511 }
512 else {
513 HDC hdcDst = NULL;
514 POINT org;
515
516 dstSize.x = abs(dstSize.x);
517 dstSize.y = abs(dstSize.y);
518
519 /* Resize source image if destination smaller than margins */
520 #ifndef __REACTOS__
521 /* Revert Wine Commit 2b650fa as it breaks themed Explorer Toolbar Separators
522 FIXME: Revisit this when the bug is fixed. CORE-9636 and Wine Bug #38538 */
523 if (sm.cyTopHeight + sm.cyBottomHeight > dstSize.y || sm.cxLeftWidth + sm.cxRightWidth > dstSize.x) {
524 if (sm.cyTopHeight + sm.cyBottomHeight > dstSize.y) {
525 sm.cyTopHeight = MulDiv(sm.cyTopHeight, dstSize.y, srcSize.y);
526 sm.cyBottomHeight = dstSize.y - sm.cyTopHeight;
527 srcSize.y = dstSize.y;
528 }
529
530 if (sm.cxLeftWidth + sm.cxRightWidth > dstSize.x) {
531 sm.cxLeftWidth = MulDiv(sm.cxLeftWidth, dstSize.x, srcSize.x);
532 sm.cxRightWidth = dstSize.x - sm.cxLeftWidth;
533 srcSize.x = dstSize.x;
534 }
535
536 hdcOrigSrc = hdcSrc;
537 hdcSrc = CreateCompatibleDC(NULL);
538 bmpSrcResized = CreateBitmap(srcSize.x, srcSize.y, 1, 32, NULL);
539 SelectObject(hdcSrc, bmpSrcResized);
540
541 UXTHEME_StretchBlt(hdcSrc, 0, 0, srcSize.x, srcSize.y, hdcOrigSrc, rcSrc.left, rcSrc.top,
542 rcSrc.right - rcSrc.left, rcSrc.bottom - rcSrc.top, transparent, transparentcolor);
543
544 rcSrc.left = 0;
545 rcSrc.top = 0;
546 rcSrc.right = srcSize.x;
547 rcSrc.bottom = srcSize.y;
548 }
549 #endif /* __REACTOS__ */
550
551 hdcDst = hdc;
552 OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
553
554 /* Upper left corner */
555 if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
556 hdcSrc, rcSrc.left, rcSrc.top,
557 transparent, transparentcolor)) {
558 hr = HRESULT_FROM_WIN32(GetLastError());
559 goto draw_error;
560 }
561 /* Upper right corner */
562 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
563 sm.cxRightWidth, sm.cyTopHeight,
564 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
565 transparent, transparentcolor)) {
566 hr = HRESULT_FROM_WIN32(GetLastError());
567 goto draw_error;
568 }
569 /* Lower left corner */
570 if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
571 sm.cxLeftWidth, sm.cyBottomHeight,
572 hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
573 transparent, transparentcolor)) {
574 hr = HRESULT_FROM_WIN32(GetLastError());
575 goto draw_error;
576 }
577 /* Lower right corner */
578 if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
579 sm.cxRightWidth, sm.cyBottomHeight,
580 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
581 transparent, transparentcolor)) {
582 hr = HRESULT_FROM_WIN32(GetLastError());
583 goto draw_error;
584 }
585
586 if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
587 int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
588 int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
589 int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
590 int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
591
592 if(destCenterWidth > 0) {
593 /* Center top */
594 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
595 destCenterWidth, sm.cyTopHeight,
596 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
597 srcCenterWidth, sm.cyTopHeight,
598 sizingtype, transparent, transparentcolor)) {
599 hr = HRESULT_FROM_WIN32(GetLastError());
600 goto draw_error;
601 }
602 /* Center bottom */
603 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
604 destCenterWidth, sm.cyBottomHeight,
605 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
606 srcCenterWidth, sm.cyBottomHeight,
607 sizingtype, transparent, transparentcolor)) {
608 hr = HRESULT_FROM_WIN32(GetLastError());
609 goto draw_error;
610 }
611 }
612 if(destCenterHeight > 0) {
613 /* Left center */
614 if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
615 sm.cxLeftWidth, destCenterHeight,
616 hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
617 sm.cxLeftWidth, srcCenterHeight,
618 sizingtype,
619 transparent, transparentcolor)) {
620 hr = HRESULT_FROM_WIN32(GetLastError());
621 goto draw_error;
622 }
623 /* Right center */
624 if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
625 sm.cxRightWidth, destCenterHeight,
626 hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
627 sm.cxRightWidth, srcCenterHeight,
628 sizingtype, transparent, transparentcolor)) {
629 hr = HRESULT_FROM_WIN32(GetLastError());
630 goto draw_error;
631 }
632 }
633 if(destCenterHeight > 0 && destCenterWidth > 0) {
634 if(!borderonly) {
635 /* Center */
636 if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
637 destCenterWidth, destCenterHeight,
638 hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
639 srcCenterWidth, srcCenterHeight,
640 sizingtype, transparent, transparentcolor)) {
641 hr = HRESULT_FROM_WIN32(GetLastError());
642 goto draw_error;
643 }
644 }
645 }
646 }
647
648 draw_error:
649 SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
650 }
651 SelectObject(hdcSrc, oldSrc);
652 DeleteDC(hdcSrc);
653 if (bmpSrcResized) DeleteObject(bmpSrcResized);
654 if (hdcOrigSrc) DeleteDC(hdcOrigSrc);
655 *pRect = rcDst;
656 return hr;
657 }
658
659 /*
660 * @unimplemented
661 */
662 BOOL
663 WINAPI
664 GdiDrawStream(HDC dc, ULONG l, PGDI_DRAW_STREAM pDS)
665 {
666 if (!pDS || l != sizeof(*pDS))
667 {
668 DPRINT1("GdiDrawStream: Invalid params\n");
669 return 0;
670 }
671
672 if (pDS->signature != 0x44727753 ||
673 pDS->reserved != 0 ||
674 pDS->unknown1 != 1 ||
675 pDS->unknown2 != 9)
676 {
677 DPRINT1("GdiDrawStream: Got unknown pDS data\n");
678 return 0;
679 }
680
681 {
682 MARGINS sm = {pDS->leftSizingMargin, pDS->rightSizingMargin, pDS->topSizingMargin, pDS->bottomSizingMargin};
683 INT transparent = 0;
684 int sizingtype;
685
686 if (pDS->drawOption & 0x4)
687 transparent = ALPHABLEND_FULL;
688 else if (pDS->drawOption & 0x8)
689 transparent = ALPHABLEND_BINARY;
690 else
691 transparent = ALPHABLEND_NONE;
692
693 if (pDS->drawOption & 0x2)
694 sizingtype = ST_TILE;
695 else if (pDS->drawOption & 0x20)
696 sizingtype = ST_TRUESIZE;
697 else
698 sizingtype = ST_STRETCH;
699
700 UXTHEME_DrawImageBackground(pDS->hDC,
701 pDS->hImage,
702 &pDS->rcSrc,
703 transparent,
704 pDS->crTransparent,
705 FALSE,
706 sizingtype,
707 &sm,
708 &pDS->rcDest);
709 }
710 return 0;
711 }
712
713
714 /*
715 * @implemented
716 */
717 BOOL
718 WINAPI
719 GdiValidateHandle(HGDIOBJ hobj)
720 {
721 PGDI_TABLE_ENTRY Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hobj);
722 if ( (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0 &&
723 ( (Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK ) ==
724 GDI_HANDLE_GET_TYPE(hobj) )
725 {
726 HANDLE pid = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1);
727 if(pid == NULL || pid == CurrentProcessId)
728 {
729 return TRUE;
730 }
731 }
732 return FALSE;
733
734 }
735
736 /*
737 * @implemented
738 */
739 HGDIOBJ
740 WINAPI
741 GdiFixUpHandle(HGDIOBJ hGdiObj)
742 {
743 PGDI_TABLE_ENTRY Entry;
744
745 if (((ULONG_PTR)(hGdiObj)) & GDI_HANDLE_UPPER_MASK )
746 {
747 return hGdiObj;
748 }
749
750 /* FIXME is this right ?? */
751
752 Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hGdiObj);
753
754 /* Rebuild handle for Object */
755 return hGdiObj = (HGDIOBJ)(((LONG_PTR)(hGdiObj)) | (Entry->Type << GDI_ENTRY_UPPER_SHIFT));
756 }
757
758 /*
759 * @implemented
760 */
761 PVOID
762 WINAPI
763 GdiQueryTable(VOID)
764 {
765 return (PVOID)GdiHandleTable;
766 }
767
768 BOOL GdiIsHandleValid(HGDIOBJ hGdiObj)
769 {
770 PGDI_TABLE_ENTRY Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hGdiObj);
771 // We are only looking for TYPE not the rest here, and why is FullUnique filled up with CRAP!?
772 // DPRINT1("FullUnique -> %x\n", Entry->FullUnique);
773 if((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0 &&
774 ( (Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK ) ==
775 GDI_HANDLE_GET_TYPE(hGdiObj))
776 {
777 HANDLE pid = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1);
778 if(pid == NULL || pid == CurrentProcessId)
779 {
780 return TRUE;
781 }
782 }
783 return FALSE;
784 }
785
786 BOOL GdiGetHandleUserData(HGDIOBJ hGdiObj, DWORD ObjectType, PVOID *UserData)
787 {
788 PGDI_TABLE_ENTRY Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hGdiObj);
789
790 /* Check if twe have the correct type */
791 if (GDI_HANDLE_GET_TYPE(hGdiObj) != ObjectType ||
792 ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK) != ObjectType ||
793 (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != (ObjectType & GDI_ENTRY_BASETYPE_MASK))
794 {
795 return FALSE;
796 }
797
798 /* Check if we are the owner */
799 if ((HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) != CurrentProcessId)
800 {
801 return FALSE;
802 }
803
804 *UserData = Entry->UserData;
805 return TRUE;
806 }
807
808 PLDC
809 FASTCALL
810 GdiGetLDC(HDC hdc)
811 {
812 PDC_ATTR pdcattr;
813
814 /* Get the DC attribute */
815 pdcattr = GdiGetDcAttr(hdc);
816 if (pdcattr == NULL)
817 {
818 return NULL;
819 }
820
821 /* Return the LDC pointer */
822 return pdcattr->pvLDC;
823 }
824
825 BOOL
826 FASTCALL
827 GdiSetLDC(HDC hdc, PVOID pvLDC)
828 {
829 PDC_ATTR pdcattr;
830
831 /* Get the DC attribute */
832 pdcattr = GdiGetDcAttr(hdc);
833 if (pdcattr == NULL)
834 {
835 return FALSE;
836 }
837
838 /* Set the LDC pointer */
839 pdcattr->pvLDC = pvLDC;
840 return TRUE;
841 }
842
843
844 VOID GdiSAPCallback(PLDC pldc)
845 {
846 DWORD Time, NewTime = GetTickCount();
847
848 Time = NewTime - pldc->CallBackTick;
849
850 if ( Time < SAPCALLBACKDELAY) return;
851
852 pldc->CallBackTick = NewTime;
853
854 if ( !pldc->pAbortProc(pldc->hDC, 0) )
855 {
856 CancelDC(pldc->hDC);
857 AbortDoc(pldc->hDC);
858 }
859 }
860
861 /*
862 * @implemented
863 */
864 DWORD
865 WINAPI
866 GdiSetBatchLimit(DWORD Limit)
867 {
868 DWORD OldLimit = GDI_BatchLimit;
869
870 if ( (!Limit) ||
871 (Limit >= GDI_BATCH_LIMIT))
872 {
873 return Limit;
874 }
875
876 GdiFlush();
877 GDI_BatchLimit = Limit;
878 return OldLimit;
879 }
880
881
882 /*
883 * @implemented
884 */
885 DWORD
886 WINAPI
887 GdiGetBatchLimit(VOID)
888 {
889 return GDI_BatchLimit;
890 }
891
892
893 /*
894 * @implemented
895 */
896 VOID
897 WINAPI
898 GdiSetLastError(DWORD dwErrCode)
899 {
900 NtCurrentTeb()->LastErrorValue = (ULONG) dwErrCode;
901 }
902
903 HGDIOBJ
904 FASTCALL
905 hGetPEBHandle(HANDLECACHETYPE Type, COLORREF cr)
906 {
907 int Number, Offset, MaxNum, GdiType;
908 HANDLE Lock;
909 HGDIOBJ Handle = NULL;
910
911 Lock = InterlockedCompareExchangePointer( (PVOID*)&GdiHandleCache->ulLock,
912 NtCurrentTeb(),
913 NULL );
914
915 if (Lock) return Handle;
916
917 Number = GdiHandleCache->ulNumHandles[Type];
918
919 if (Type == hctBrushHandle)
920 {
921 Offset = 0;
922 MaxNum = CACHE_BRUSH_ENTRIES;
923 GdiType = GDILoObjType_LO_BRUSH_TYPE;
924 }
925 else if (Type == hctPenHandle)
926 {
927 Offset = CACHE_BRUSH_ENTRIES;
928 MaxNum = CACHE_PEN_ENTRIES;
929 GdiType = GDILoObjType_LO_PEN_TYPE;
930 }
931 else if (Type == hctRegionHandle)
932 {
933 Offset = CACHE_BRUSH_ENTRIES+CACHE_PEN_ENTRIES;
934 MaxNum = CACHE_REGION_ENTRIES;
935 GdiType = GDILoObjType_LO_REGION_TYPE;
936 }
937 else // Font is not supported here.
938 {
939 return Handle;
940 }
941
942 if ( Number && Number <= MaxNum )
943 {
944 PBRUSH_ATTR pBrush_Attr;
945 HGDIOBJ *hPtr;
946 hPtr = GdiHandleCache->Handle + Offset;
947 Handle = hPtr[Number - 1];
948
949 if (GdiGetHandleUserData( Handle, GdiType, (PVOID) &pBrush_Attr))
950 {
951 if (pBrush_Attr->AttrFlags & ATTR_CACHED)
952 {
953 DPRINT("Get Handle! Type %d Count %lu PEB 0x%p\n", Type, GdiHandleCache->ulNumHandles[Type], NtCurrentTeb()->ProcessEnvironmentBlock);
954 pBrush_Attr->AttrFlags &= ~ATTR_CACHED;
955 hPtr[Number - 1] = NULL;
956 GdiHandleCache->ulNumHandles[Type]--;
957 if ( Type == hctBrushHandle ) // Handle only brush.
958 {
959 if ( pBrush_Attr->lbColor != cr )
960 {
961 pBrush_Attr->lbColor = cr ;
962 pBrush_Attr->AttrFlags |= ATTR_NEW_COLOR;
963 }
964 }
965 }
966 }
967 else
968 {
969 Handle = NULL;
970 }
971 }
972 (void)InterlockedExchangePointer((PVOID*)&GdiHandleCache->ulLock, Lock);
973 return Handle;
974 }
975
976 /*
977 * @unimplemented
978 */
979 BOOL
980 WINAPI
981 bMakePathNameW(LPWSTR lpBuffer,LPCWSTR lpFileName,LPWSTR *lpFilePart,DWORD unknown)
982 {
983 UNIMPLEMENTED;
984 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
985 return 0;
986 }
987
988 /*
989 * @implemented
990 */
991 DEVMODEW *
992 WINAPI
993 GdiConvertToDevmodeW(const DEVMODEA *dmA)
994 {
995 DEVMODEW *dmW;
996 WORD dmW_size, dmA_size;
997
998 dmA_size = dmA->dmSize;
999
1000 /* this is the minimal dmSize that XP accepts */
1001 if (dmA_size < FIELD_OFFSET(DEVMODEA, dmFields))
1002 return NULL;
1003
1004 if (dmA_size > sizeof(DEVMODEA))
1005 dmA_size = sizeof(DEVMODEA);
1006
1007 dmW_size = dmA_size + CCHDEVICENAME;
1008 if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME)
1009 dmW_size += CCHFORMNAME;
1010
1011 dmW = HeapAlloc(GetProcessHeap(), 0, dmW_size + dmA->dmDriverExtra);
1012 if (!dmW) return NULL;
1013
1014 MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmDeviceName, CCHDEVICENAME,
1015 dmW->dmDeviceName, CCHDEVICENAME);
1016 /* copy slightly more, to avoid long computations */
1017 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion, dmA_size - CCHDEVICENAME);
1018
1019 if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME)
1020 {
1021 MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmFormName, CCHFORMNAME,
1022 dmW->dmFormName, CCHFORMNAME);
1023 if (dmA_size > FIELD_OFFSET(DEVMODEA, dmLogPixels))
1024 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA_size - FIELD_OFFSET(DEVMODEA, dmLogPixels));
1025 }
1026
1027 if (dmA->dmDriverExtra)
1028 memcpy((char *)dmW + dmW_size, (const char *)dmA + dmA_size, dmA->dmDriverExtra);
1029
1030 dmW->dmSize = dmW_size;
1031
1032 return dmW;
1033 }
1034
1035 /*
1036 * @unimplemented
1037 */
1038 BOOL
1039 WINAPI
1040 GdiRealizationInfo(HDC hdc,
1041 PREALIZATION_INFO pri)
1042 {
1043 // ATM we do not support local font data and Language Pack.
1044 return NtGdiGetRealizationInfo(hdc, pri, (HFONT) NULL);
1045 }
1046
1047
1048 /*
1049 * @unimplemented
1050 */
1051 VOID WINAPI GdiInitializeLanguagePack(DWORD InitParam)
1052 {
1053 UNIMPLEMENTED;
1054 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1055 }
1056
1057 BOOL
1058 WINAPI
1059 GdiAddGlsBounds(HDC hdc,LPRECT prc)
1060 {
1061 //FIXME: Lookup what 0x8000 means
1062 return NtGdiSetBoundsRect(hdc, prc, 0x8000 | DCB_ACCUMULATE ) ? TRUE : FALSE;
1063 }
1064
1065 /*
1066 * @unimplemented
1067 */
1068 BOOL
1069 WINAPI
1070 GdiAddGlsRecord(HDC hdc,
1071 DWORD unknown1,
1072 LPCSTR unknown2,
1073 LPRECT unknown3)
1074 {
1075 UNIMPLEMENTED;
1076 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1077 return 0;
1078 }
1079