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