1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Support for physical devices 5 * FILE: win32ss/gdi/eng/pdevobj.c 6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org) 7 */ 8 9 #include <win32k.h> 10 #define NDEBUG 11 #include <debug.h> 12 13 PPDEVOBJ gppdevPrimary = NULL; 14 15 static PPDEVOBJ gppdevList = NULL; 16 static HSEMAPHORE ghsemPDEV; 17 18 INIT_FUNCTION 19 NTSTATUS 20 NTAPI 21 InitPDEVImpl(VOID) 22 { 23 ghsemPDEV = EngCreateSemaphore(); 24 if (!ghsemPDEV) return STATUS_INSUFFICIENT_RESOURCES; 25 return STATUS_SUCCESS; 26 } 27 28 #if DBG 29 PPDEVOBJ 30 NTAPI 31 DbgLookupDHPDEV(DHPDEV dhpdev) 32 { 33 PPDEVOBJ ppdev; 34 35 /* Lock PDEV list */ 36 EngAcquireSemaphoreShared(ghsemPDEV); 37 38 /* Walk through the list of PDEVs */ 39 for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext) 40 { 41 /* Compare with the given DHPDEV */ 42 if (ppdev->dhpdev == dhpdev) break; 43 } 44 45 /* Unlock PDEV list */ 46 EngReleaseSemaphore(ghsemPDEV); 47 48 return ppdev; 49 } 50 #endif 51 52 PPDEVOBJ 53 PDEVOBJ_AllocPDEV(VOID) 54 { 55 PPDEVOBJ ppdev; 56 57 ppdev = ExAllocatePoolWithTag(PagedPool, sizeof(PDEVOBJ), GDITAG_PDEV); 58 if (!ppdev) 59 return NULL; 60 61 RtlZeroMemory(ppdev, sizeof(PDEVOBJ)); 62 63 ppdev->hsemDevLock = EngCreateSemaphore(); 64 if (ppdev->hsemDevLock == NULL) 65 { 66 ExFreePoolWithTag(ppdev, GDITAG_PDEV); 67 return NULL; 68 } 69 70 /* Allocate EDD_DIRECTDRAW_GLOBAL for our ReactX driver */ 71 ppdev->pEDDgpl = ExAllocatePoolWithTag(PagedPool, sizeof(EDD_DIRECTDRAW_GLOBAL), GDITAG_PDEV); 72 if (ppdev->pEDDgpl) 73 RtlZeroMemory(ppdev->pEDDgpl, sizeof(EDD_DIRECTDRAW_GLOBAL)); 74 75 ppdev->cPdevRefs = 1; 76 77 return ppdev; 78 } 79 80 static 81 VOID 82 PDEVOBJ_vDeletePDEV( 83 PPDEVOBJ ppdev) 84 { 85 EngDeleteSemaphore(ppdev->hsemDevLock); 86 if (ppdev->pEDDgpl) 87 ExFreePoolWithTag(ppdev->pEDDgpl, GDITAG_PDEV); 88 ExFreePoolWithTag(ppdev, GDITAG_PDEV); 89 } 90 91 VOID 92 NTAPI 93 PDEVOBJ_vRelease(PPDEVOBJ ppdev) 94 { 95 /* Lock loader */ 96 EngAcquireSemaphore(ghsemPDEV); 97 98 /* Decrease reference count */ 99 --ppdev->cPdevRefs; 100 101 ASSERT(ppdev->cPdevRefs >= 0) ; 102 103 /* Check if references are left */ 104 if (ppdev->cPdevRefs == 0) 105 { 106 /* Do we have a surface? */ 107 if (ppdev->pSurface) 108 { 109 /* Release the surface and let the driver free it */ 110 SURFACE_ShareUnlockSurface(ppdev->pSurface); 111 ppdev->pfn.DisableSurface(ppdev->dhpdev); 112 } 113 114 /* Do we have a palette? */ 115 if(ppdev->ppalSurf) 116 { 117 PALETTE_ShareUnlockPalette(ppdev->ppalSurf); 118 } 119 120 /* Check if the PDEV was enabled */ 121 if (ppdev->dhpdev != NULL) 122 { 123 /* Disable the PDEV */ 124 ppdev->pfn.DisablePDEV(ppdev->dhpdev); 125 } 126 127 /* Remove it from list */ 128 if( ppdev == gppdevList ) 129 gppdevList = ppdev->ppdevNext ; 130 else 131 { 132 PPDEVOBJ ppdevCurrent = gppdevList; 133 BOOL found = FALSE ; 134 while (!found && ppdevCurrent->ppdevNext) 135 { 136 if (ppdevCurrent->ppdevNext == ppdev) 137 found = TRUE; 138 else 139 ppdevCurrent = ppdevCurrent->ppdevNext ; 140 } 141 if(found) 142 ppdevCurrent->ppdevNext = ppdev->ppdevNext; 143 } 144 145 /* Is this the primary one ? */ 146 if (ppdev == gppdevPrimary) 147 gppdevPrimary = NULL; 148 149 /* Free it */ 150 PDEVOBJ_vDeletePDEV(ppdev); 151 } 152 153 /* Unlock loader */ 154 EngReleaseSemaphore(ghsemPDEV); 155 156 } 157 158 BOOL 159 NTAPI 160 PDEVOBJ_bEnablePDEV( 161 PPDEVOBJ ppdev, 162 PDEVMODEW pdevmode, 163 PWSTR pwszLogAddress) 164 { 165 PFN_DrvEnablePDEV pfnEnablePDEV; 166 ULONG i; 167 168 DPRINT("PDEVOBJ_bEnablePDEV()\n"); 169 170 /* Get the DrvEnablePDEV function */ 171 pfnEnablePDEV = ppdev->pldev->pfn.EnablePDEV; 172 173 /* Call the drivers DrvEnablePDEV function */ 174 ppdev->dhpdev = pfnEnablePDEV(pdevmode, 175 pwszLogAddress, 176 HS_DDI_MAX, 177 ppdev->ahsurf, 178 sizeof(GDIINFO), 179 (PULONG)&ppdev->gdiinfo, 180 sizeof(DEVINFO), 181 &ppdev->devinfo, 182 (HDEV)ppdev, 183 ppdev->pGraphicsDevice->pwszDescription, 184 ppdev->pGraphicsDevice->DeviceObject); 185 if (ppdev->dhpdev == NULL) 186 { 187 DPRINT1("Failed to enable PDEV\n"); 188 return FALSE; 189 } 190 191 /* Fix up some values */ 192 if (ppdev->gdiinfo.ulLogPixelsX == 0) 193 ppdev->gdiinfo.ulLogPixelsX = 96; 194 195 if (ppdev->gdiinfo.ulLogPixelsY == 0) 196 ppdev->gdiinfo.ulLogPixelsY = 96; 197 198 /* Set raster caps */ 199 ppdev->gdiinfo.flRaster = RC_OP_DX_OUTPUT | RC_GDI20_OUTPUT | RC_BIGFONT; 200 if ((ppdev->gdiinfo.ulTechnology != DT_PLOTTER) && (ppdev->gdiinfo.ulTechnology != DT_CHARSTREAM)) 201 ppdev->gdiinfo.flRaster |= RC_STRETCHDIB | RC_STRETCHBLT | RC_DIBTODEV | RC_DI_BITMAP | RC_BITMAP64 | RC_BITBLT; 202 if (ppdev->gdiinfo.ulTechnology == DT_RASDISPLAY) 203 ppdev->gdiinfo.flRaster |= RC_FLOODFILL; 204 if (ppdev->devinfo.flGraphicsCaps & GCAPS_PALMANAGED) 205 ppdev->gdiinfo.flRaster |= RC_PALETTE; 206 207 /* Setup Palette */ 208 ppdev->ppalSurf = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault); 209 210 /* Setup hatch brushes */ 211 for (i = 0; i < HS_DDI_MAX; i++) 212 { 213 if (ppdev->ahsurf[i] == NULL) 214 ppdev->ahsurf[i] = gahsurfHatch[i]; 215 } 216 217 DPRINT("PDEVOBJ_bEnablePDEV - dhpdev = %p\n", ppdev->dhpdev); 218 219 return TRUE; 220 } 221 222 VOID 223 NTAPI 224 PDEVOBJ_vCompletePDEV( 225 PPDEVOBJ ppdev) 226 { 227 /* Call the drivers DrvCompletePDEV function */ 228 ppdev->pldev->pfn.CompletePDEV(ppdev->dhpdev, (HDEV)ppdev); 229 } 230 231 PSURFACE 232 NTAPI 233 PDEVOBJ_pSurface( 234 PPDEVOBJ ppdev) 235 { 236 HSURF hsurf; 237 238 /* Check if there is no surface for this PDEV yet */ 239 if (ppdev->pSurface == NULL) 240 { 241 /* Call the drivers DrvEnableSurface */ 242 hsurf = ppdev->pldev->pfn.EnableSurface(ppdev->dhpdev); 243 if (hsurf== NULL) 244 { 245 DPRINT1("Failed to create PDEV surface!\n"); 246 return NULL; 247 } 248 249 /* Get a reference to the surface */ 250 ppdev->pSurface = SURFACE_ShareLockSurface(hsurf); 251 NT_ASSERT(ppdev->pSurface != NULL); 252 } 253 254 /* Increment reference count */ 255 GDIOBJ_vReferenceObjectByPointer(&ppdev->pSurface->BaseObject); 256 257 DPRINT("PDEVOBJ_pSurface() returning %p\n", ppdev->pSurface); 258 return ppdev->pSurface; 259 } 260 261 VOID 262 NTAPI 263 PDEVOBJ_vRefreshModeList( 264 PPDEVOBJ ppdev) 265 { 266 PGRAPHICS_DEVICE pGraphicsDevice; 267 PDEVMODEINFO pdminfo, pdmiNext; 268 DEVMODEW dmDefault; 269 270 /* Lock the PDEV */ 271 EngAcquireSemaphore(ppdev->hsemDevLock); 272 273 pGraphicsDevice = ppdev->pGraphicsDevice; 274 275 /* Remember our default mode */ 276 dmDefault = *pGraphicsDevice->pDevModeList[pGraphicsDevice->iDefaultMode].pdm; 277 278 /* Clear out the modes */ 279 for (pdminfo = pGraphicsDevice->pdevmodeInfo; 280 pdminfo; 281 pdminfo = pdmiNext) 282 { 283 pdmiNext = pdminfo->pdmiNext; 284 ExFreePoolWithTag(pdminfo, GDITAG_DEVMODE); 285 } 286 pGraphicsDevice->pdevmodeInfo = NULL; 287 ExFreePoolWithTag(pGraphicsDevice->pDevModeList, GDITAG_GDEVICE); 288 pGraphicsDevice->pDevModeList = NULL; 289 290 /* Now re-populate the list */ 291 if (!EngpPopulateDeviceModeList(pGraphicsDevice, &dmDefault)) 292 { 293 DPRINT1("FIXME: EngpPopulateDeviceModeList failed, we just destroyed a perfectly good mode list\n"); 294 } 295 296 ppdev->pdmwDev = pGraphicsDevice->pDevModeList[pGraphicsDevice->iCurrentMode].pdm; 297 298 /* Unlock PDEV */ 299 EngReleaseSemaphore(ppdev->hsemDevLock); 300 } 301 302 PDEVMODEW 303 NTAPI 304 PDEVOBJ_pdmMatchDevMode( 305 PPDEVOBJ ppdev, 306 PDEVMODEW pdm) 307 { 308 PGRAPHICS_DEVICE pGraphicsDevice; 309 PDEVMODEW pdmCurrent; 310 ULONG i; 311 DWORD dwFields; 312 313 pGraphicsDevice = ppdev->pGraphicsDevice; 314 315 for (i = 0; i < pGraphicsDevice->cDevModes; i++) 316 { 317 pdmCurrent = pGraphicsDevice->pDevModeList[i].pdm; 318 319 /* Compare asked DEVMODE fields 320 * Only compare those that are valid in both DEVMODE structs */ 321 dwFields = pdmCurrent->dmFields & pdm->dmFields ; 322 323 /* For now, we only need those */ 324 if ((dwFields & DM_BITSPERPEL) && 325 (pdmCurrent->dmBitsPerPel != pdm->dmBitsPerPel)) continue; 326 if ((dwFields & DM_PELSWIDTH) && 327 (pdmCurrent->dmPelsWidth != pdm->dmPelsWidth)) continue; 328 if ((dwFields & DM_PELSHEIGHT) && 329 (pdmCurrent->dmPelsHeight != pdm->dmPelsHeight)) continue; 330 if ((dwFields & DM_DISPLAYFREQUENCY) && 331 (pdmCurrent->dmDisplayFrequency != pdm->dmDisplayFrequency)) continue; 332 333 /* Match! Return the DEVMODE */ 334 return pdmCurrent; 335 } 336 337 /* Nothing found */ 338 return NULL; 339 } 340 341 static 342 PPDEVOBJ 343 EngpCreatePDEV( 344 PUNICODE_STRING pustrDeviceName, 345 PDEVMODEW pdm) 346 { 347 PGRAPHICS_DEVICE pGraphicsDevice; 348 PPDEVOBJ ppdev; 349 DPRINT("EngpCreatePDEV(%wZ, %p)\n", pustrDeviceName, pdm); 350 351 /* Try to find the GRAPHICS_DEVICE */ 352 if (pustrDeviceName) 353 { 354 pGraphicsDevice = EngpFindGraphicsDevice(pustrDeviceName, 0, 0); 355 if (!pGraphicsDevice) 356 { 357 DPRINT1("No GRAPHICS_DEVICE found for %ls!\n", 358 pustrDeviceName ? pustrDeviceName->Buffer : 0); 359 return NULL; 360 } 361 } 362 else 363 { 364 pGraphicsDevice = gpPrimaryGraphicsDevice; 365 } 366 367 /* Allocate a new PDEVOBJ */ 368 ppdev = PDEVOBJ_AllocPDEV(); 369 if (!ppdev) 370 { 371 DPRINT1("failed to allocate a PDEV\n"); 372 return NULL; 373 } 374 375 /* If no DEVMODEW is given, ... */ 376 if (!pdm) 377 { 378 /* ... use the device's default one */ 379 pdm = pGraphicsDevice->pDevModeList[pGraphicsDevice->iDefaultMode].pdm; 380 DPRINT("Using iDefaultMode = %lu\n", pGraphicsDevice->iDefaultMode); 381 } 382 383 /* Try to get a diplay driver */ 384 ppdev->pldev = EngLoadImageEx(pdm->dmDeviceName, LDEV_DEVICE_DISPLAY); 385 if (!ppdev->pldev) 386 { 387 DPRINT1("Could not load display driver '%ls', '%ls'\n", 388 pGraphicsDevice->pDiplayDrivers, 389 pdm->dmDeviceName); 390 PDEVOBJ_vRelease(ppdev); 391 return NULL; 392 } 393 394 /* Copy the function table */ 395 ppdev->pfn = ppdev->pldev->pfn; 396 397 /* Set MovePointer function */ 398 ppdev->pfnMovePointer = ppdev->pfn.MovePointer; 399 if (!ppdev->pfnMovePointer) 400 ppdev->pfnMovePointer = EngMovePointer; 401 402 ppdev->pGraphicsDevice = pGraphicsDevice; 403 404 // DxEngGetHdevData asks for Graphics DeviceObject in hSpooler field 405 ppdev->hSpooler = ppdev->pGraphicsDevice->DeviceObject; 406 407 // Should we change the ative mode of pGraphicsDevice ? 408 ppdev->pdmwDev = PDEVOBJ_pdmMatchDevMode(ppdev, pdm) ; 409 410 /* FIXME! */ 411 ppdev->flFlags = PDEV_DISPLAY; 412 413 /* HACK: Don't use the pointer */ 414 ppdev->Pointer.Exclude.right = -1; 415 416 /* Call the driver to enable the PDEV */ 417 if (!PDEVOBJ_bEnablePDEV(ppdev, pdm, NULL)) 418 { 419 DPRINT1("Failed to enable PDEV!\n"); 420 PDEVOBJ_vRelease(ppdev); 421 return NULL; 422 } 423 424 /* FIXME: this must be done in a better way */ 425 pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP; 426 427 /* Tell the driver that the PDEV is ready */ 428 PDEVOBJ_vCompletePDEV(ppdev); 429 430 /* Return the PDEV */ 431 return ppdev; 432 } 433 434 FORCEINLINE 435 VOID 436 SwitchPointer( 437 _Inout_ PVOID pvPointer1, 438 _Inout_ PVOID pvPointer2) 439 { 440 PVOID *ppvPointer1 = pvPointer1; 441 PVOID *ppvPointer2 = pvPointer2; 442 PVOID pvTemp; 443 444 pvTemp = *ppvPointer1; 445 *ppvPointer1 = *ppvPointer2; 446 *ppvPointer2 = pvTemp; 447 } 448 449 VOID 450 NTAPI 451 PDEVOBJ_vSwitchPdev( 452 PPDEVOBJ ppdev, 453 PPDEVOBJ ppdev2) 454 { 455 union 456 { 457 DRIVER_FUNCTIONS pfn; 458 GDIINFO gdiinfo; 459 DEVINFO devinfo; 460 DWORD StateFlags; 461 } temp; 462 463 /* Exchange driver functions */ 464 temp.pfn = ppdev->pfn; 465 ppdev->pfn = ppdev2->pfn; 466 ppdev2->pfn = temp.pfn; 467 468 /* Exchange LDEVs */ 469 SwitchPointer(&ppdev->pldev, &ppdev2->pldev); 470 471 /* Exchange DHPDEV */ 472 SwitchPointer(&ppdev->dhpdev, &ppdev2->dhpdev); 473 474 /* Exchange surfaces and associate them with their new PDEV */ 475 SwitchPointer(&ppdev->pSurface, &ppdev2->pSurface); 476 ppdev->pSurface->SurfObj.hdev = (HDEV)ppdev; 477 ppdev2->pSurface->SurfObj.hdev = (HDEV)ppdev2; 478 479 /* Exchange devinfo */ 480 temp.devinfo = ppdev->devinfo; 481 ppdev->devinfo = ppdev2->devinfo; 482 ppdev2->devinfo = temp.devinfo; 483 484 /* Exchange gdiinfo */ 485 temp.gdiinfo = ppdev->gdiinfo; 486 ppdev->gdiinfo = ppdev2->gdiinfo; 487 ppdev2->gdiinfo = temp.gdiinfo; 488 489 /* Exchange DEVMODE */ 490 SwitchPointer(&ppdev->pdmwDev, &ppdev2->pdmwDev); 491 492 /* Exchange state flags */ 493 temp.StateFlags = ppdev->pGraphicsDevice->StateFlags; 494 ppdev->pGraphicsDevice->StateFlags = ppdev2->pGraphicsDevice->StateFlags; 495 ppdev2->pGraphicsDevice->StateFlags = temp.StateFlags; 496 497 /* Notify each driver instance of its new HDEV association */ 498 ppdev->pfn.CompletePDEV(ppdev->dhpdev, (HDEV)ppdev); 499 ppdev2->pfn.CompletePDEV(ppdev2->dhpdev, (HDEV)ppdev2); 500 } 501 502 503 BOOL 504 NTAPI 505 PDEVOBJ_bSwitchMode( 506 PPDEVOBJ ppdev, 507 PDEVMODEW pdm) 508 { 509 UNICODE_STRING ustrDevice; 510 PPDEVOBJ ppdevTmp; 511 PSURFACE pSurface; 512 BOOL retval = FALSE; 513 514 /* Lock the PDEV */ 515 EngAcquireSemaphore(ppdev->hsemDevLock); 516 517 /* And everything else */ 518 EngAcquireSemaphore(ghsemPDEV); 519 520 DPRINT1("PDEVOBJ_bSwitchMode, ppdev = %p, pSurface = %p\n", ppdev, ppdev->pSurface); 521 522 // Lookup the GraphicsDevice + select DEVMODE 523 // pdm = PDEVOBJ_pdmMatchDevMode(ppdev, pdm); 524 525 /* 1. Temporarily disable the current PDEV and reset video to its default mode */ 526 if (!ppdev->pfn.AssertMode(ppdev->dhpdev, FALSE)) 527 { 528 DPRINT1("DrvAssertMode(FALSE) failed\n"); 529 goto leave; 530 } 531 532 /* 2. Create new PDEV */ 533 RtlInitUnicodeString(&ustrDevice, ppdev->pGraphicsDevice->szWinDeviceName); 534 ppdevTmp = EngpCreatePDEV(&ustrDevice, pdm); 535 if (!ppdevTmp) 536 { 537 DPRINT1("Failed to create a new PDEV\n"); 538 goto leave2; 539 } 540 541 /* 3. Create a new surface */ 542 pSurface = PDEVOBJ_pSurface(ppdevTmp); 543 if (!pSurface) 544 { 545 DPRINT1("PDEVOBJ_pSurface failed\n"); 546 PDEVOBJ_vRelease(ppdevTmp); 547 goto leave2; 548 } 549 550 /* 4. Get DirectDraw information */ 551 /* 5. Enable DirectDraw Not traced */ 552 /* 6. Copy old PDEV state to new PDEV instance */ 553 554 /* 7. Switch the PDEVs */ 555 PDEVOBJ_vSwitchPdev(ppdev, ppdevTmp); 556 557 /* 8. Disable DirectDraw */ 558 559 PDEVOBJ_vRelease(ppdevTmp); 560 561 /* Update primary display capabilities */ 562 if(ppdev == gppdevPrimary) 563 { 564 PDEVOBJ_vGetDeviceCaps(ppdev, &GdiHandleTable->DevCaps); 565 } 566 567 /* Success! */ 568 retval = TRUE; 569 570 leave2: 571 /* Set the new video mode, or restore the original one in case of failure */ 572 if (!ppdev->pfn.AssertMode(ppdev->dhpdev, TRUE)) 573 { 574 DPRINT1("DrvAssertMode(TRUE) failed\n"); 575 } 576 577 leave: 578 /* Unlock everything else */ 579 EngReleaseSemaphore(ghsemPDEV); 580 /* Unlock the PDEV */ 581 EngReleaseSemaphore(ppdev->hsemDevLock); 582 583 DPRINT1("leave, ppdev = %p, pSurface = %p\n", ppdev, ppdev->pSurface); 584 585 return retval; 586 } 587 588 589 PPDEVOBJ 590 NTAPI 591 EngpGetPDEV( 592 _In_opt_ PUNICODE_STRING pustrDeviceName) 593 { 594 UNICODE_STRING ustrCurrent; 595 PPDEVOBJ ppdev; 596 PGRAPHICS_DEVICE pGraphicsDevice; 597 598 /* Acquire PDEV lock */ 599 EngAcquireSemaphore(ghsemPDEV); 600 601 /* Did the caller pass a device name? */ 602 if (pustrDeviceName) 603 { 604 /* Loop all present PDEVs */ 605 for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext) 606 { 607 /* Get a pointer to the GRAPHICS_DEVICE */ 608 pGraphicsDevice = ppdev->pGraphicsDevice; 609 610 /* Compare the name */ 611 RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName); 612 if (RtlEqualUnicodeString(pustrDeviceName, &ustrCurrent, FALSE)) 613 { 614 /* Found! */ 615 break; 616 } 617 } 618 } 619 else 620 { 621 /* Otherwise use the primary PDEV */ 622 ppdev = gppdevPrimary; 623 } 624 625 /* Did we find one? */ 626 if (ppdev) 627 { 628 /* Yes, reference the PDEV */ 629 InterlockedIncrement(&ppdev->cPdevRefs); 630 } 631 else 632 { 633 /* No, create a new PDEV for the given device */ 634 ppdev = EngpCreatePDEV(pustrDeviceName, NULL); 635 if (ppdev) 636 { 637 /* Insert the PDEV into the list */ 638 ppdev->ppdevNext = gppdevList; 639 gppdevList = ppdev; 640 641 /* Set as primary PDEV, if we don't have one yet */ 642 if (!gppdevPrimary) 643 { 644 gppdevPrimary = ppdev; 645 ppdev->pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE; 646 } 647 } 648 } 649 650 /* Release PDEV lock */ 651 EngReleaseSemaphore(ghsemPDEV); 652 653 return ppdev; 654 } 655 656 INT 657 NTAPI 658 PDEVOBJ_iGetColorManagementCaps(PPDEVOBJ ppdev) 659 { 660 INT ret = CM_NONE; 661 662 if (ppdev->flFlags & PDEV_DISPLAY) 663 { 664 if (ppdev->devinfo.iDitherFormat == BMF_8BPP || 665 ppdev->devinfo.flGraphicsCaps2 & GCAPS2_CHANGEGAMMARAMP) 666 ret = CM_GAMMA_RAMP; 667 } 668 669 if (ppdev->devinfo.flGraphicsCaps & GCAPS_CMYKCOLOR) 670 ret |= CM_CMYK_COLOR; 671 if (ppdev->devinfo.flGraphicsCaps & GCAPS_ICM) 672 ret |= CM_DEVICE_ICM; 673 674 return ret; 675 } 676 677 VOID 678 NTAPI 679 PDEVOBJ_vGetDeviceCaps( 680 IN PPDEVOBJ ppdev, 681 OUT PDEVCAPS pDevCaps) 682 { 683 PGDIINFO pGdiInfo = &ppdev->gdiinfo; 684 685 pDevCaps->ulVersion = pGdiInfo->ulVersion; 686 pDevCaps->ulTechnology = pGdiInfo->ulTechnology; 687 pDevCaps->ulHorzSizeM = (pGdiInfo->ulHorzSize + 500) / 1000; 688 pDevCaps->ulVertSizeM = (pGdiInfo->ulVertSize + 500) / 1000; 689 pDevCaps->ulHorzSize = pGdiInfo->ulHorzSize; 690 pDevCaps->ulVertSize = pGdiInfo->ulVertSize; 691 pDevCaps->ulHorzRes = pGdiInfo->ulHorzRes; 692 pDevCaps->ulVertRes = pGdiInfo->ulVertRes; 693 pDevCaps->ulBitsPixel = pGdiInfo->cBitsPixel; 694 if (pDevCaps->ulBitsPixel == 15) pDevCaps->ulBitsPixel = 16; 695 pDevCaps->ulPlanes = pGdiInfo->cPlanes; 696 pDevCaps->ulNumPens = pGdiInfo->ulNumColors; 697 if (pDevCaps->ulNumPens != -1) pDevCaps->ulNumPens *= 5; 698 pDevCaps->ulNumFonts = 0; // PDEVOBJ_cFonts(ppdev); 699 pDevCaps->ulNumColors = pGdiInfo->ulNumColors; 700 pDevCaps->ulRasterCaps = pGdiInfo->flRaster; 701 pDevCaps->ulAspectX = pGdiInfo->ulAspectX; 702 pDevCaps->ulAspectY = pGdiInfo->ulAspectY; 703 pDevCaps->ulAspectXY = pGdiInfo->ulAspectXY; 704 pDevCaps->ulLogPixelsX = pGdiInfo->ulLogPixelsX; 705 pDevCaps->ulLogPixelsY = pGdiInfo->ulLogPixelsY; 706 pDevCaps->ulSizePalette = pGdiInfo->ulNumPalReg; 707 pDevCaps->ulColorRes = pGdiInfo->ulDACRed + 708 pGdiInfo->ulDACGreen + 709 pGdiInfo->ulDACBlue; 710 pDevCaps->ulPhysicalWidth = pGdiInfo->szlPhysSize.cx; 711 pDevCaps->ulPhysicalHeight = pGdiInfo->szlPhysSize.cy; 712 pDevCaps->ulPhysicalOffsetX = pGdiInfo->ptlPhysOffset.x; 713 pDevCaps->ulPhysicalOffsetY = pGdiInfo->ptlPhysOffset.y; 714 pDevCaps->ulTextCaps = pGdiInfo->flTextCaps; 715 pDevCaps->ulTextCaps |= (TC_SO_ABLE|TC_UA_ABLE|TC_CP_STROKE|TC_OP_STROKE|TC_OP_CHARACTER); 716 if (pGdiInfo->ulTechnology != DT_PLOTTER) 717 pDevCaps->ulTextCaps |= TC_VA_ABLE; 718 pDevCaps->ulVRefresh = pGdiInfo->ulVRefresh; 719 pDevCaps->ulDesktopHorzRes = pGdiInfo->ulHorzRes; 720 pDevCaps->ulDesktopVertRes = pGdiInfo->ulVertRes; 721 pDevCaps->ulBltAlignment = pGdiInfo->ulBltAlignment; 722 pDevCaps->ulPanningHorzRes = pGdiInfo->ulPanningHorzRes; 723 pDevCaps->ulPanningVertRes = pGdiInfo->ulPanningVertRes; 724 pDevCaps->xPanningAlignment = pGdiInfo->xPanningAlignment; 725 pDevCaps->yPanningAlignment = pGdiInfo->yPanningAlignment; 726 pDevCaps->ulShadeBlend = pGdiInfo->flShadeBlend; 727 pDevCaps->ulColorMgmtCaps = PDEVOBJ_iGetColorManagementCaps(ppdev); 728 } 729 730 731 /** Exported functions ********************************************************/ 732 733 _Must_inspect_result_ _Ret_z_ 734 LPWSTR 735 APIENTRY 736 EngGetDriverName(_In_ HDEV hdev) 737 { 738 PPDEVOBJ ppdev = (PPDEVOBJ)hdev; 739 740 ASSERT(ppdev); 741 ASSERT(ppdev->pldev); 742 ASSERT(ppdev->pldev->pGdiDriverInfo); 743 ASSERT(ppdev->pldev->pGdiDriverInfo->DriverName.Buffer); 744 745 return ppdev->pldev->pGdiDriverInfo->DriverName.Buffer; 746 } 747 748 749 INT 750 APIENTRY 751 NtGdiGetDeviceCaps( 752 HDC hdc, 753 INT Index) 754 { 755 PDC pdc; 756 DEVCAPS devcaps; 757 758 /* Lock the given DC */ 759 pdc = DC_LockDc(hdc); 760 if (!pdc) 761 { 762 EngSetLastError(ERROR_INVALID_HANDLE); 763 return 0; 764 } 765 766 /* Get the data */ 767 PDEVOBJ_vGetDeviceCaps(pdc->ppdev, &devcaps); 768 769 /* Unlock the DC */ 770 DC_UnlockDc(pdc); 771 772 /* Return capability */ 773 switch (Index) 774 { 775 case DRIVERVERSION: 776 return devcaps.ulVersion; 777 778 case TECHNOLOGY: 779 return devcaps.ulTechnology; 780 781 case HORZSIZE: 782 return devcaps.ulHorzSize; 783 784 case VERTSIZE: 785 return devcaps.ulVertSize; 786 787 case HORZRES: 788 return devcaps.ulHorzRes; 789 790 case VERTRES: 791 return devcaps.ulVertRes; 792 793 case LOGPIXELSX: 794 return devcaps.ulLogPixelsX; 795 796 case LOGPIXELSY: 797 return devcaps.ulLogPixelsY; 798 799 case BITSPIXEL: 800 return devcaps.ulBitsPixel; 801 802 case PLANES: 803 return devcaps.ulPlanes; 804 805 case NUMBRUSHES: 806 return -1; 807 808 case NUMPENS: 809 return devcaps.ulNumPens; 810 811 case NUMFONTS: 812 return devcaps.ulNumFonts; 813 814 case NUMCOLORS: 815 return devcaps.ulNumColors; 816 817 case ASPECTX: 818 return devcaps.ulAspectX; 819 820 case ASPECTY: 821 return devcaps.ulAspectY; 822 823 case ASPECTXY: 824 return devcaps.ulAspectXY; 825 826 case CLIPCAPS: 827 return CP_RECTANGLE; 828 829 case SIZEPALETTE: 830 return devcaps.ulSizePalette; 831 832 case NUMRESERVED: 833 return 20; 834 835 case COLORRES: 836 return devcaps.ulColorRes; 837 838 case DESKTOPVERTRES: 839 return devcaps.ulVertRes; 840 841 case DESKTOPHORZRES: 842 return devcaps.ulHorzRes; 843 844 case BLTALIGNMENT: 845 return devcaps.ulBltAlignment; 846 847 case SHADEBLENDCAPS: 848 return devcaps.ulShadeBlend; 849 850 case COLORMGMTCAPS: 851 return devcaps.ulColorMgmtCaps; 852 853 case PHYSICALWIDTH: 854 return devcaps.ulPhysicalWidth; 855 856 case PHYSICALHEIGHT: 857 return devcaps.ulPhysicalHeight; 858 859 case PHYSICALOFFSETX: 860 return devcaps.ulPhysicalOffsetX; 861 862 case PHYSICALOFFSETY: 863 return devcaps.ulPhysicalOffsetY; 864 865 case VREFRESH: 866 return devcaps.ulVRefresh; 867 868 case RASTERCAPS: 869 return devcaps.ulRasterCaps; 870 871 case CURVECAPS: 872 return (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE | 873 CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT); 874 875 case LINECAPS: 876 return (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE | 877 LC_STYLED | LC_WIDESTYLED | LC_INTERIORS); 878 879 case POLYGONALCAPS: 880 return (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE | 881 PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS); 882 883 case TEXTCAPS: 884 return devcaps.ulTextCaps; 885 886 case CAPS1: 887 case PDEVICESIZE: 888 case SCALINGFACTORX: 889 case SCALINGFACTORY: 890 default: 891 return 0; 892 } 893 894 return 0; 895 } 896 897 _Success_(return!=FALSE) 898 BOOL 899 APIENTRY 900 NtGdiGetDeviceCapsAll( 901 IN HDC hDC, 902 OUT PDEVCAPS pDevCaps) 903 { 904 PDC pdc; 905 DEVCAPS devcaps; 906 BOOL bResult = TRUE; 907 908 /* Lock the given DC */ 909 pdc = DC_LockDc(hDC); 910 if (!pdc) 911 { 912 EngSetLastError(ERROR_INVALID_HANDLE); 913 return FALSE; 914 } 915 916 /* Get the data */ 917 PDEVOBJ_vGetDeviceCaps(pdc->ppdev, &devcaps); 918 919 /* Unlock the DC */ 920 DC_UnlockDc(pdc); 921 922 /* Copy data to caller */ 923 _SEH2_TRY 924 { 925 ProbeForWrite(pDevCaps, sizeof(DEVCAPS), 1); 926 RtlCopyMemory(pDevCaps, &devcaps, sizeof(DEVCAPS)); 927 } 928 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 929 { 930 SetLastNtError(_SEH2_GetExceptionCode()); 931 bResult = FALSE; 932 } 933 _SEH2_END; 934 935 return bResult; 936 } 937 938 DHPDEV 939 APIENTRY 940 NtGdiGetDhpdev( 941 IN HDEV hdev) 942 { 943 PPDEVOBJ ppdev; 944 DHPDEV dhpdev = NULL; 945 946 /* Check parameter */ 947 if (!hdev || (PCHAR)hdev < (PCHAR)MmSystemRangeStart) 948 return NULL; 949 950 /* Lock PDEV list */ 951 EngAcquireSemaphoreShared(ghsemPDEV); 952 953 /* Walk through the list of PDEVs */ 954 for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext) 955 { 956 /* Compare with the given HDEV */ 957 if (ppdev == (PPDEVOBJ)hdev) 958 { 959 /* Found the PDEV! Get it's dhpdev and break */ 960 dhpdev = ppdev->dhpdev; 961 break; 962 } 963 } 964 965 /* Unlock PDEV list */ 966 EngReleaseSemaphore(ghsemPDEV); 967 968 return dhpdev; 969 } 970 971 PSIZEL 972 FASTCALL 973 PDEVOBJ_sizl(PPDEVOBJ ppdev, PSIZEL psizl) 974 { 975 if (ppdev->flFlags & PDEV_META_DEVICE) 976 { 977 psizl->cx = ppdev->ulHorzRes; 978 psizl->cy = ppdev->ulVertRes; 979 } 980 else 981 { 982 psizl->cx = ppdev->gdiinfo.ulHorzRes; 983 psizl->cy = ppdev->gdiinfo.ulVertRes; 984 } 985 return psizl; 986 } 987