[Gdi32]
[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 GdiIsHandleValid(HGDIOBJ hGdiObj)
749 {
750 PGDI_TABLE_ENTRY Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hGdiObj);
751 // We are only looking for TYPE not the rest here, and why is FullUnique filled up with CRAP!?
752 // DPRINT1("FullUnique -> %x\n", Entry->FullUnique);
753 if((Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0 &&
754 ( (Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK ) ==
755 GDI_HANDLE_GET_TYPE(hGdiObj))
756 {
757 HANDLE pid = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1);
758 if(pid == NULL || pid == CurrentProcessId)
759 {
760 return TRUE;
761 }
762 }
763 return FALSE;
764 }
765
766 BOOL GdiGetHandleUserData(HGDIOBJ hGdiObj, DWORD ObjectType, PVOID *UserData)
767 {
768 PGDI_TABLE_ENTRY Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hGdiObj);
769
770 /* Check if twe have the correct type */
771 if (GDI_HANDLE_GET_TYPE(hGdiObj) != ObjectType ||
772 ((Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK) != ObjectType ||
773 (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != (ObjectType & GDI_ENTRY_BASETYPE_MASK))
774 {
775 return FALSE;
776 }
777
778 /* Check if we are the owner */
779 if ((HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) != CurrentProcessId)
780 {
781 return FALSE;
782 }
783
784 *UserData = Entry->UserData;
785 return TRUE;
786 }
787
788 PLDC
789 FASTCALL
790 GdiGetLDC(HDC hdc)
791 {
792 PDC_ATTR pdcattr;
793
794 /* Get the DC attribute */
795 pdcattr = GdiGetDcAttr(hdc);
796 if (pdcattr == NULL)
797 {
798 return NULL;
799 }
800
801 /* Return the LDC pointer */
802 return pdcattr->pvLDC;
803 }
804
805 BOOL
806 FASTCALL
807 GdiSetLDC(HDC hdc, PVOID pvLDC)
808 {
809 PDC_ATTR pdcattr;
810
811 /* Get the DC attribute */
812 pdcattr = GdiGetDcAttr(hdc);
813 if (pdcattr == NULL)
814 {
815 return FALSE;
816 }
817
818 /* Set the LDC pointer */
819 pdcattr->pvLDC = pvLDC;
820 return TRUE;
821 }
822
823
824 VOID GdiSAPCallback(PLDC pldc)
825 {
826 DWORD Time, NewTime = GetTickCount();
827
828 Time = NewTime - pldc->CallBackTick;
829
830 if ( Time < SAPCALLBACKDELAY) return;
831
832 pldc->CallBackTick = NewTime;
833
834 if ( !pldc->pAbortProc(pldc->hDC, 0) )
835 {
836 CancelDC(pldc->hDC);
837 AbortDoc(pldc->hDC);
838 }
839 }
840
841 /*
842 * @implemented
843 */
844 DWORD
845 WINAPI
846 GdiSetBatchLimit(DWORD Limit)
847 {
848 DWORD OldLimit = GDI_BatchLimit;
849
850 if ( (!Limit) ||
851 (Limit >= GDI_BATCH_LIMIT))
852 {
853 return Limit;
854 }
855
856 GdiFlush();
857 GDI_BatchLimit = Limit;
858 return OldLimit;
859 }
860
861
862 /*
863 * @implemented
864 */
865 DWORD
866 WINAPI
867 GdiGetBatchLimit(VOID)
868 {
869 return GDI_BatchLimit;
870 }
871
872
873 /*
874 * @implemented
875 */
876 VOID
877 WINAPI
878 GdiSetLastError(DWORD dwErrCode)
879 {
880 NtCurrentTeb()->LastErrorValue = (ULONG) dwErrCode;
881 }
882
883 HGDIOBJ
884 FASTCALL
885 hGetPEBHandle(HANDLECACHETYPE Type, COLORREF cr)
886 {
887 int Number, Offset, MaxNum, GdiType;
888 HANDLE Lock;
889 HGDIOBJ Handle = NULL;
890
891 Lock = InterlockedCompareExchangePointer( (PVOID*)&GdiHandleCache->ulLock,
892 NtCurrentTeb(),
893 NULL );
894
895 if (Lock) return Handle;
896
897 Number = GdiHandleCache->ulNumHandles[Type];
898
899 if (Type == hctBrushHandle)
900 {
901 Offset = 0;
902 MaxNum = CACHE_BRUSH_ENTRIES;
903 GdiType = GDILoObjType_LO_BRUSH_TYPE;
904 }
905 else if (Type == hctPenHandle)
906 {
907 Offset = CACHE_BRUSH_ENTRIES;
908 MaxNum = CACHE_PEN_ENTRIES;
909 GdiType = GDILoObjType_LO_PEN_TYPE;
910 }
911 else if (Type == hctRegionHandle)
912 {
913 Offset = CACHE_BRUSH_ENTRIES+CACHE_PEN_ENTRIES;
914 MaxNum = CACHE_REGION_ENTRIES;
915 GdiType = GDILoObjType_LO_REGION_TYPE;
916 }
917 else // Font is not supported here.
918 {
919 return Handle;
920 }
921
922 if ( Number && Number <= MaxNum )
923 {
924 PBRUSH_ATTR pBrush_Attr;
925 HGDIOBJ *hPtr;
926 hPtr = GdiHandleCache->Handle + Offset;
927 Handle = hPtr[Number - 1];
928
929 if (GdiGetHandleUserData( Handle, GdiType, (PVOID) &pBrush_Attr))
930 {
931 if (pBrush_Attr->AttrFlags & ATTR_CACHED)
932 {
933 DPRINT("Get Handle! Type %d Count %lu PEB 0x%p\n", Type, GdiHandleCache->ulNumHandles[Type], NtCurrentTeb()->ProcessEnvironmentBlock);
934 pBrush_Attr->AttrFlags &= ~ATTR_CACHED;
935 hPtr[Number - 1] = NULL;
936 GdiHandleCache->ulNumHandles[Type]--;
937 if ( Type == hctBrushHandle ) // Handle only brush.
938 {
939 if ( pBrush_Attr->lbColor != cr )
940 {
941 pBrush_Attr->lbColor = cr ;
942 pBrush_Attr->AttrFlags |= ATTR_NEW_COLOR;
943 }
944 }
945 }
946 }
947 else
948 {
949 Handle = NULL;
950 }
951 }
952 (void)InterlockedExchangePointer((PVOID*)&GdiHandleCache->ulLock, Lock);
953 return Handle;
954 }
955
956 /*
957 * @unimplemented
958 */
959 BOOL
960 WINAPI
961 bMakePathNameW(LPWSTR lpBuffer,LPCWSTR lpFileName,LPWSTR *lpFilePart,DWORD unknown)
962 {
963 UNIMPLEMENTED;
964 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
965 return 0;
966 }
967
968 /*
969 * @implemented
970 */
971 DEVMODEW *
972 WINAPI
973 GdiConvertToDevmodeW(const DEVMODEA *dmA)
974 {
975 DEVMODEW *dmW;
976 WORD dmW_size, dmA_size;
977
978 dmA_size = dmA->dmSize;
979
980 /* this is the minimal dmSize that XP accepts */
981 if (dmA_size < FIELD_OFFSET(DEVMODEA, dmFields))
982 return NULL;
983
984 if (dmA_size > sizeof(DEVMODEA))
985 dmA_size = sizeof(DEVMODEA);
986
987 dmW_size = dmA_size + CCHDEVICENAME;
988 if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME)
989 dmW_size += CCHFORMNAME;
990
991 dmW = HeapAlloc(GetProcessHeap(), 0, dmW_size + dmA->dmDriverExtra);
992 if (!dmW) return NULL;
993
994 MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmDeviceName, CCHDEVICENAME,
995 dmW->dmDeviceName, CCHDEVICENAME);
996 /* copy slightly more, to avoid long computations */
997 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion, dmA_size - CCHDEVICENAME);
998
999 if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME)
1000 {
1001 MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmFormName, CCHFORMNAME,
1002 dmW->dmFormName, CCHFORMNAME);
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 * @unimplemented
1030 */
1031 VOID WINAPI GdiInitializeLanguagePack(DWORD InitParam)
1032 {
1033 UNIMPLEMENTED;
1034 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1035 }
1036
1037 BOOL
1038 WINAPI
1039 GdiAddGlsBounds(HDC hdc,LPRECT prc)
1040 {
1041 return NtGdiSetBoundsRect(hdc, prc, DCB_WINDOWMGR|DCB_ACCUMULATE ) ? TRUE : FALSE;
1042 }
1043
1044 BOOL
1045 WINAPI
1046 GetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags)
1047 {
1048 return NtGdiGetBoundsRect(hdc, prc, flags);
1049 }
1050
1051 BOOL
1052 WINAPI
1053 SetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags)
1054 {
1055 return NtGdiSetBoundsRect(hdc, prc, flags );
1056 }
1057
1058 /*
1059 * @unimplemented
1060 */
1061 BOOL
1062 WINAPI
1063 GdiAddGlsRecord(HDC hdc,
1064 DWORD unknown1,
1065 LPCSTR unknown2,
1066 LPRECT unknown3)
1067 {
1068 UNIMPLEMENTED;
1069 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1070 return 0;
1071 }
1072