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 METADC_ExtEscape(hdc, nEscape, cbInput, lpvInData, 0, lpvOutData); 70 } 71 72 switch (nEscape) 73 { 74 case ABORTDOC: 75 /* Note: Windows checks if the handle has any user data for the ABORTDOC command 76 * ReactOS copies this behavior to be compatible with windows 2003 77 */ 78 if (GdiGetDcAttr(hdc) == NULL) 79 { 80 GdiSetLastError(ERROR_INVALID_HANDLE); 81 retValue = FALSE; 82 } 83 else 84 { 85 retValue = AbortDoc(hdc); 86 } 87 break; 88 89 case DRAFTMODE: 90 case FLUSHOUTPUT: 91 case SETCOLORTABLE: 92 /* Note 1: DRAFTMODE, FLUSHOUTPUT, SETCOLORTABLE are outdated */ 93 /* Note 2: Windows checks if the handle has any user data for the DRAFTMODE, FLUSHOUTPUT, SETCOLORTABLE commands 94 * ReactOS copies this behavior to be compatible with windows 2003 95 */ 96 if (GdiGetDcAttr(hdc) == NULL) 97 { 98 GdiSetLastError(ERROR_INVALID_HANDLE); 99 } 100 retValue = FALSE; 101 break; 102 103 case SETABORTPROC: 104 /* Note: Windows checks if the handle has any user data for the SETABORTPROC command 105 * ReactOS copies this behavior to be compatible with windows 2003 106 */ 107 if (GdiGetDcAttr(hdc) == NULL) 108 { 109 GdiSetLastError(ERROR_INVALID_HANDLE); 110 retValue = FALSE; 111 } 112 retValue = SetAbortProc(hdc, (ABORTPROC)lpvInData); 113 break; 114 115 case GETCOLORTABLE: 116 retValue = GetSystemPaletteEntries(hdc, (UINT)*lpvInData, 1, (LPPALETTEENTRY)lpvOutData); 117 if (!retValue) 118 { 119 retValue = SP_ERROR; 120 } 121 break; 122 123 case ENDDOC: 124 /* Note: Windows checks if the handle has any user data for the ENDDOC command 125 * ReactOS copies this behavior to be compatible with windows 2003 126 */ 127 if (GdiGetDcAttr(hdc) == NULL) 128 { 129 GdiSetLastError(ERROR_INVALID_HANDLE); 130 retValue = FALSE; 131 } 132 retValue = EndDoc(hdc); 133 break; 134 135 case GETSCALINGFACTOR: 136 /* Note GETSCALINGFACTOR is outdated have been replace by GetDeviceCaps */ 137 if (ulObjType == GDI_OBJECT_TYPE_DC) 138 { 139 if (lpvOutData) 140 { 141 PPOINT ptr = (PPOINT)lpvOutData; 142 ptr->x = 0; 143 ptr->y = 0; 144 } 145 } 146 retValue = FALSE; 147 break; 148 149 case GETEXTENDEDTEXTMETRICS: 150 retValue = GetETM(hdc, (EXTTEXTMETRIC *)lpvOutData) != 0; 151 break; 152 153 case STARTDOC: 154 { 155 DOCINFOA di; 156 157 /* Note: Windows checks if the handle has any user data for the STARTDOC command 158 * ReactOS copies this behavior to be compatible with windows 2003 159 */ 160 if (GdiGetDcAttr(hdc) == NULL) 161 { 162 GdiSetLastError(ERROR_INVALID_HANDLE); 163 retValue = FALSE; 164 } 165 166 di.cbSize = sizeof(DOCINFOA); 167 di.lpszOutput = 0; 168 di.lpszDatatype = 0; 169 di.fwType = 0; 170 di.lpszDocName = lpvInData; 171 172 /* NOTE : doc for StartDocA/W at msdn http://msdn2.microsoft.com/en-us/library/ms535793(VS.85).aspx */ 173 retValue = StartDocA(hdc, &di); 174 175 /* Check if StartDocA failed */ 176 if (retValue < 0) 177 { 178 { 179 retValue = GetLastError(); 180 181 /* Translate StartDocA error code to STARTDOC error code 182 * see msdn http://msdn2.microsoft.com/en-us/library/ms535472.aspx 183 */ 184 switch(retValue) 185 { 186 case ERROR_NOT_ENOUGH_MEMORY: 187 retValue = SP_OUTOFMEMORY; 188 break; 189 190 case ERROR_PRINT_CANCELLED: 191 retValue = SP_USERABORT; 192 break; 193 194 case ERROR_DISK_FULL: 195 retValue = SP_OUTOFDISK; 196 break; 197 198 default: 199 retValue = SP_ERROR; 200 break; 201 } 202 } 203 } 204 } 205 break; 206 207 default: 208 UNIMPLEMENTED; 209 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 210 } 211 212 return retValue; 213 } 214 215 INT 216 WINAPI 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 (GDI_HANDLE_GET_UPPER(hGdiObj)) 739 { 740 return hGdiObj; 741 } 742 743 /* FIXME is this right ?? */ 744 745 Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hGdiObj); 746 747 /* Rebuild handle for Object */ 748 return (HGDIOBJ)(((ULONG_PTR)(hGdiObj)) | (Entry->Type << GDI_ENTRY_UPPER_SHIFT)); 749 } 750 751 /* 752 * @implemented 753 */ 754 PVOID 755 WINAPI 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 * Synchronized with WINE dlls/gdi32/driver.c 966 */ 967 DEVMODEW * 968 WINAPI 969 GdiConvertToDevmodeW(const DEVMODEA *dmA) 970 { 971 DEVMODEW *dmW; 972 WORD dmW_size, dmA_size; 973 974 dmA_size = dmA->dmSize; 975 976 /* this is the minimal dmSize that XP accepts */ 977 if (dmA_size < FIELD_OFFSET(DEVMODEA, dmFields)) 978 return NULL; 979 980 if (dmA_size > sizeof(DEVMODEA)) 981 dmA_size = sizeof(DEVMODEA); 982 983 dmW_size = dmA_size + CCHDEVICENAME; 984 if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME) 985 dmW_size += CCHFORMNAME; 986 987 dmW = HeapAlloc(GetProcessHeap(), 0, dmW_size + dmA->dmDriverExtra); 988 if (!dmW) return NULL; 989 990 MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmDeviceName, -1, 991 dmW->dmDeviceName, CCHDEVICENAME); 992 /* copy slightly more, to avoid long computations */ 993 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion, dmA_size - CCHDEVICENAME); 994 995 if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME) 996 { 997 if (dmA->dmFields & DM_FORMNAME) 998 MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmFormName, -1, 999 dmW->dmFormName, CCHFORMNAME); 1000 else 1001 dmW->dmFormName[0] = 0; 1002 1003 if (dmA_size > FIELD_OFFSET(DEVMODEA, dmLogPixels)) 1004 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA_size - FIELD_OFFSET(DEVMODEA, dmLogPixels)); 1005 } 1006 1007 if (dmA->dmDriverExtra) 1008 memcpy((char *)dmW + dmW_size, (const char *)dmA + dmA_size, dmA->dmDriverExtra); 1009 1010 dmW->dmSize = dmW_size; 1011 1012 return dmW; 1013 } 1014 1015 /* 1016 * @unimplemented 1017 */ 1018 BOOL 1019 WINAPI 1020 GdiRealizationInfo(HDC hdc, 1021 PREALIZATION_INFO pri) 1022 { 1023 // ATM we do not support local font data and Language Pack. 1024 return NtGdiGetRealizationInfo(hdc, pri, (HFONT) NULL); 1025 } 1026 1027 1028 /* 1029 * @halfplemented 1030 */ 1031 VOID WINAPI GdiInitializeLanguagePack(DWORD InitParam) 1032 { 1033 /* Lpk function pointers to be passed to user32 */ 1034 #if 0 1035 FARPROC hookfuncs[4]; 1036 #endif 1037 1038 #ifdef LANGPACK 1039 if (!LoadLPK(LPK_INIT)) // no lpk found! 1040 #endif 1041 return; 1042 1043 /* Call InitializeLpkHooks with 4 procedure addresses 1044 loaded from lpk.dll but currently only one of them is currently implemented. 1045 Then InitializeLpkHooks (in user32) uses these to replace certain internal functions 1046 and ORs a DWORD being used also by ClientThreadSetup and calls 1047 NtUserOneParam with parameter 54 which is ONEPARAM_ROUTINE_REGISTERLPK 1048 which most likely changes the value of dwLpkEntryPoints in the 1049 PROCESSINFO struct */ 1050 1051 #if 0 1052 hookfuncs[0] = GetProcAddress(hLpk, "LpkPSMTextOut"); 1053 InitializeLpkHooks(hookfuncs); 1054 #endif 1055 1056 gbLpk = TRUE; 1057 } 1058 1059 BOOL 1060 WINAPI 1061 GdiAddGlsBounds(HDC hdc,LPRECT prc) 1062 { 1063 return NtGdiSetBoundsRect(hdc, prc, DCB_WINDOWMGR|DCB_ACCUMULATE ) ? TRUE : FALSE; 1064 } 1065 1066 BOOL 1067 WINAPI 1068 GetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags) 1069 { 1070 return NtGdiGetBoundsRect(hdc, prc, flags); 1071 } 1072 1073 BOOL 1074 WINAPI 1075 SetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags) 1076 { 1077 return NtGdiSetBoundsRect(hdc, prc, flags ); 1078 } 1079 1080 /* 1081 * @unimplemented 1082 */ 1083 BOOL 1084 WINAPI 1085 GdiAddGlsRecord(HDC hdc, 1086 DWORD unknown1, 1087 LPCSTR unknown2, 1088 LPRECT unknown3) 1089 { 1090 UNIMPLEMENTED; 1091 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1092 return 0; 1093 } 1094 1095