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 */ 526 if (!ppdev->pfn.AssertMode(ppdev->dhpdev, FALSE)) 527 { 528 DPRINT1("DrvAssertMode 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 leave; 539 } 540 541 /* 3. Create a new surface */ 542 pSurface = PDEVOBJ_pSurface(ppdevTmp); 543 if (!pSurface) 544 { 545 DPRINT1("PDEVOBJ_pSurface failed\n"); 546 goto leave; 547 } 548 549 /* 4. Get DirectDraw information */ 550 /* 5. Enable DirectDraw Not traced */ 551 /* 6. Copy old PDEV state to new PDEV instance */ 552 553 /* 7. Switch the PDEVs */ 554 PDEVOBJ_vSwitchPdev(ppdev, ppdevTmp); 555 556 /* 8. Disable DirectDraw */ 557 558 PDEVOBJ_vRelease(ppdevTmp); 559 560 /* Update primary display capabilities */ 561 if(ppdev == gppdevPrimary) 562 { 563 PDEVOBJ_vGetDeviceCaps(ppdev, &GdiHandleTable->DevCaps); 564 } 565 566 /* Success! */ 567 retval = TRUE; 568 leave: 569 /* Unlock PDEV */ 570 EngReleaseSemaphore(ppdev->hsemDevLock); 571 EngReleaseSemaphore(ghsemPDEV); 572 573 DPRINT1("leave, ppdev = %p, pSurface = %p\n", ppdev, ppdev->pSurface); 574 575 return retval; 576 } 577 578 579 PPDEVOBJ 580 NTAPI 581 EngpGetPDEV( 582 _In_opt_ PUNICODE_STRING pustrDeviceName) 583 { 584 UNICODE_STRING ustrCurrent; 585 PPDEVOBJ ppdev; 586 PGRAPHICS_DEVICE pGraphicsDevice; 587 588 /* Acquire PDEV lock */ 589 EngAcquireSemaphore(ghsemPDEV); 590 591 /* Did the caller pass a device name? */ 592 if (pustrDeviceName) 593 { 594 /* Loop all present PDEVs */ 595 for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext) 596 { 597 /* Get a pointer to the GRAPHICS_DEVICE */ 598 pGraphicsDevice = ppdev->pGraphicsDevice; 599 600 /* Compare the name */ 601 RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName); 602 if (RtlEqualUnicodeString(pustrDeviceName, &ustrCurrent, FALSE)) 603 { 604 /* Found! */ 605 break; 606 } 607 } 608 } 609 else 610 { 611 /* Otherwise use the primary PDEV */ 612 ppdev = gppdevPrimary; 613 } 614 615 /* Did we find one? */ 616 if (ppdev) 617 { 618 /* Yes, reference the PDEV */ 619 InterlockedIncrement(&ppdev->cPdevRefs); 620 } 621 else 622 { 623 /* No, create a new PDEV for the given device */ 624 ppdev = EngpCreatePDEV(pustrDeviceName, NULL); 625 if (ppdev) 626 { 627 /* Insert the PDEV into the list */ 628 ppdev->ppdevNext = gppdevList; 629 gppdevList = ppdev; 630 631 /* Set as primary PDEV, if we don't have one yet */ 632 if (!gppdevPrimary) 633 { 634 gppdevPrimary = ppdev; 635 ppdev->pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE; 636 } 637 } 638 } 639 640 /* Release PDEV lock */ 641 EngReleaseSemaphore(ghsemPDEV); 642 643 return ppdev; 644 } 645 646 INT 647 NTAPI 648 PDEVOBJ_iGetColorManagementCaps(PPDEVOBJ ppdev) 649 { 650 INT ret = CM_NONE; 651 652 if (ppdev->flFlags & PDEV_DISPLAY) 653 { 654 if (ppdev->devinfo.iDitherFormat == BMF_8BPP || 655 ppdev->devinfo.flGraphicsCaps2 & GCAPS2_CHANGEGAMMARAMP) 656 ret = CM_GAMMA_RAMP; 657 } 658 659 if (ppdev->devinfo.flGraphicsCaps & GCAPS_CMYKCOLOR) 660 ret |= CM_CMYK_COLOR; 661 if (ppdev->devinfo.flGraphicsCaps & GCAPS_ICM) 662 ret |= CM_DEVICE_ICM; 663 664 return ret; 665 } 666 667 VOID 668 NTAPI 669 PDEVOBJ_vGetDeviceCaps( 670 IN PPDEVOBJ ppdev, 671 OUT PDEVCAPS pDevCaps) 672 { 673 PGDIINFO pGdiInfo = &ppdev->gdiinfo; 674 675 pDevCaps->ulVersion = pGdiInfo->ulVersion; 676 pDevCaps->ulTechnology = pGdiInfo->ulTechnology; 677 pDevCaps->ulHorzSizeM = (pGdiInfo->ulHorzSize + 500) / 1000; 678 pDevCaps->ulVertSizeM = (pGdiInfo->ulVertSize + 500) / 1000; 679 pDevCaps->ulHorzSize = pGdiInfo->ulHorzSize; 680 pDevCaps->ulVertSize = pGdiInfo->ulVertSize; 681 pDevCaps->ulHorzRes = pGdiInfo->ulHorzRes; 682 pDevCaps->ulVertRes = pGdiInfo->ulVertRes; 683 pDevCaps->ulBitsPixel = pGdiInfo->cBitsPixel; 684 if (pDevCaps->ulBitsPixel == 15) pDevCaps->ulBitsPixel = 16; 685 pDevCaps->ulPlanes = pGdiInfo->cPlanes; 686 pDevCaps->ulNumPens = pGdiInfo->ulNumColors; 687 if (pDevCaps->ulNumPens != -1) pDevCaps->ulNumPens *= 5; 688 pDevCaps->ulNumFonts = 0; // PDEVOBJ_cFonts(ppdev); 689 pDevCaps->ulNumColors = pGdiInfo->ulNumColors; 690 pDevCaps->ulRasterCaps = pGdiInfo->flRaster; 691 pDevCaps->ulAspectX = pGdiInfo->ulAspectX; 692 pDevCaps->ulAspectY = pGdiInfo->ulAspectY; 693 pDevCaps->ulAspectXY = pGdiInfo->ulAspectXY; 694 pDevCaps->ulLogPixelsX = pGdiInfo->ulLogPixelsX; 695 pDevCaps->ulLogPixelsY = pGdiInfo->ulLogPixelsY; 696 pDevCaps->ulSizePalette = pGdiInfo->ulNumPalReg; 697 pDevCaps->ulColorRes = pGdiInfo->ulDACRed + 698 pGdiInfo->ulDACGreen + 699 pGdiInfo->ulDACBlue; 700 pDevCaps->ulPhysicalWidth = pGdiInfo->szlPhysSize.cx; 701 pDevCaps->ulPhysicalHeight = pGdiInfo->szlPhysSize.cy; 702 pDevCaps->ulPhysicalOffsetX = pGdiInfo->ptlPhysOffset.x; 703 pDevCaps->ulPhysicalOffsetY = pGdiInfo->ptlPhysOffset.y; 704 pDevCaps->ulTextCaps = pGdiInfo->flTextCaps; 705 pDevCaps->ulTextCaps |= (TC_SO_ABLE|TC_UA_ABLE|TC_CP_STROKE|TC_OP_STROKE|TC_OP_CHARACTER); 706 if (pGdiInfo->ulTechnology != DT_PLOTTER) 707 pDevCaps->ulTextCaps |= TC_VA_ABLE; 708 pDevCaps->ulVRefresh = pGdiInfo->ulVRefresh; 709 pDevCaps->ulDesktopHorzRes = pGdiInfo->ulHorzRes; 710 pDevCaps->ulDesktopVertRes = pGdiInfo->ulVertRes; 711 pDevCaps->ulBltAlignment = pGdiInfo->ulBltAlignment; 712 pDevCaps->ulPanningHorzRes = pGdiInfo->ulPanningHorzRes; 713 pDevCaps->ulPanningVertRes = pGdiInfo->ulPanningVertRes; 714 pDevCaps->xPanningAlignment = pGdiInfo->xPanningAlignment; 715 pDevCaps->yPanningAlignment = pGdiInfo->yPanningAlignment; 716 pDevCaps->ulShadeBlend = pGdiInfo->flShadeBlend; 717 pDevCaps->ulColorMgmtCaps = PDEVOBJ_iGetColorManagementCaps(ppdev); 718 } 719 720 721 /** Exported functions ********************************************************/ 722 723 _Must_inspect_result_ _Ret_z_ 724 LPWSTR 725 APIENTRY 726 EngGetDriverName(_In_ HDEV hdev) 727 { 728 PPDEVOBJ ppdev = (PPDEVOBJ)hdev; 729 730 ASSERT(ppdev); 731 ASSERT(ppdev->pldev); 732 ASSERT(ppdev->pldev->pGdiDriverInfo); 733 ASSERT(ppdev->pldev->pGdiDriverInfo->DriverName.Buffer); 734 735 return ppdev->pldev->pGdiDriverInfo->DriverName.Buffer; 736 } 737 738 739 INT 740 APIENTRY 741 NtGdiGetDeviceCaps( 742 HDC hdc, 743 INT Index) 744 { 745 PDC pdc; 746 DEVCAPS devcaps; 747 748 /* Lock the given DC */ 749 pdc = DC_LockDc(hdc); 750 if (!pdc) 751 { 752 EngSetLastError(ERROR_INVALID_HANDLE); 753 return 0; 754 } 755 756 /* Get the data */ 757 PDEVOBJ_vGetDeviceCaps(pdc->ppdev, &devcaps); 758 759 /* Unlock the DC */ 760 DC_UnlockDc(pdc); 761 762 /* Return capability */ 763 switch (Index) 764 { 765 case DRIVERVERSION: 766 return devcaps.ulVersion; 767 768 case TECHNOLOGY: 769 return devcaps.ulTechnology; 770 771 case HORZSIZE: 772 return devcaps.ulHorzSize; 773 774 case VERTSIZE: 775 return devcaps.ulVertSize; 776 777 case HORZRES: 778 return devcaps.ulHorzRes; 779 780 case VERTRES: 781 return devcaps.ulVertRes; 782 783 case LOGPIXELSX: 784 return devcaps.ulLogPixelsX; 785 786 case LOGPIXELSY: 787 return devcaps.ulLogPixelsY; 788 789 case BITSPIXEL: 790 return devcaps.ulBitsPixel; 791 792 case PLANES: 793 return devcaps.ulPlanes; 794 795 case NUMBRUSHES: 796 return -1; 797 798 case NUMPENS: 799 return devcaps.ulNumPens; 800 801 case NUMFONTS: 802 return devcaps.ulNumFonts; 803 804 case NUMCOLORS: 805 return devcaps.ulNumColors; 806 807 case ASPECTX: 808 return devcaps.ulAspectX; 809 810 case ASPECTY: 811 return devcaps.ulAspectY; 812 813 case ASPECTXY: 814 return devcaps.ulAspectXY; 815 816 case CLIPCAPS: 817 return CP_RECTANGLE; 818 819 case SIZEPALETTE: 820 return devcaps.ulSizePalette; 821 822 case NUMRESERVED: 823 return 20; 824 825 case COLORRES: 826 return devcaps.ulColorRes; 827 828 case DESKTOPVERTRES: 829 return devcaps.ulVertRes; 830 831 case DESKTOPHORZRES: 832 return devcaps.ulHorzRes; 833 834 case BLTALIGNMENT: 835 return devcaps.ulBltAlignment; 836 837 case SHADEBLENDCAPS: 838 return devcaps.ulShadeBlend; 839 840 case COLORMGMTCAPS: 841 return devcaps.ulColorMgmtCaps; 842 843 case PHYSICALWIDTH: 844 return devcaps.ulPhysicalWidth; 845 846 case PHYSICALHEIGHT: 847 return devcaps.ulPhysicalHeight; 848 849 case PHYSICALOFFSETX: 850 return devcaps.ulPhysicalOffsetX; 851 852 case PHYSICALOFFSETY: 853 return devcaps.ulPhysicalOffsetY; 854 855 case VREFRESH: 856 return devcaps.ulVRefresh; 857 858 case RASTERCAPS: 859 return devcaps.ulRasterCaps; 860 861 case CURVECAPS: 862 return (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE | 863 CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT); 864 865 case LINECAPS: 866 return (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE | 867 LC_STYLED | LC_WIDESTYLED | LC_INTERIORS); 868 869 case POLYGONALCAPS: 870 return (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE | 871 PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS); 872 873 case TEXTCAPS: 874 return devcaps.ulTextCaps; 875 876 case CAPS1: 877 case PDEVICESIZE: 878 case SCALINGFACTORX: 879 case SCALINGFACTORY: 880 default: 881 return 0; 882 } 883 884 return 0; 885 } 886 887 _Success_(return!=FALSE) 888 BOOL 889 APIENTRY 890 NtGdiGetDeviceCapsAll( 891 IN HDC hDC, 892 OUT PDEVCAPS pDevCaps) 893 { 894 PDC pdc; 895 DEVCAPS devcaps; 896 BOOL bResult = TRUE; 897 898 /* Lock the given DC */ 899 pdc = DC_LockDc(hDC); 900 if (!pdc) 901 { 902 EngSetLastError(ERROR_INVALID_HANDLE); 903 return FALSE; 904 } 905 906 /* Get the data */ 907 PDEVOBJ_vGetDeviceCaps(pdc->ppdev, &devcaps); 908 909 /* Unlock the DC */ 910 DC_UnlockDc(pdc); 911 912 /* Copy data to caller */ 913 _SEH2_TRY 914 { 915 ProbeForWrite(pDevCaps, sizeof(DEVCAPS), 1); 916 RtlCopyMemory(pDevCaps, &devcaps, sizeof(DEVCAPS)); 917 } 918 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 919 { 920 SetLastNtError(_SEH2_GetExceptionCode()); 921 bResult = FALSE; 922 } 923 _SEH2_END; 924 925 return bResult; 926 } 927 928 DHPDEV 929 APIENTRY 930 NtGdiGetDhpdev( 931 IN HDEV hdev) 932 { 933 PPDEVOBJ ppdev; 934 DHPDEV dhpdev = NULL; 935 936 /* Check parameter */ 937 if (!hdev || (PCHAR)hdev < (PCHAR)MmSystemRangeStart) 938 return NULL; 939 940 /* Lock PDEV list */ 941 EngAcquireSemaphoreShared(ghsemPDEV); 942 943 /* Walk through the list of PDEVs */ 944 for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext) 945 { 946 /* Compare with the given HDEV */ 947 if (ppdev == (PPDEVOBJ)hdev) 948 { 949 /* Found the PDEV! Get it's dhpdev and break */ 950 dhpdev = ppdev->dhpdev; 951 break; 952 } 953 } 954 955 /* Unlock PDEV list */ 956 EngReleaseSemaphore(ghsemPDEV); 957 958 return dhpdev; 959 } 960 961 PSIZEL 962 FASTCALL 963 PDEVOBJ_sizl(PPDEVOBJ ppdev, PSIZEL psizl) 964 { 965 if (ppdev->flFlags & PDEV_META_DEVICE) 966 { 967 psizl->cx = ppdev->ulHorzRes; 968 psizl->cy = ppdev->ulVertRes; 969 } 970 else 971 { 972 psizl->cx = ppdev->gdiinfo.ulHorzRes; 973 psizl->cy = ppdev->gdiinfo.ulVertRes; 974 } 975 return psizl; 976 } 977