5847f3bd2e45c1b93f935b1036a936fd62a4074b
[reactos.git] / reactos / win32ss / gdi / eng / pdevobj.c
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 /* Unlock PDEV */
297 EngReleaseSemaphore(ppdev->hsemDevLock);
298 }
299
300 PDEVMODEW
301 NTAPI
302 PDEVOBJ_pdmMatchDevMode(
303 PPDEVOBJ ppdev,
304 PDEVMODEW pdm)
305 {
306 PGRAPHICS_DEVICE pGraphicsDevice;
307 PDEVMODEW pdmCurrent;
308 ULONG i;
309 DWORD dwFields;
310
311 pGraphicsDevice = ppdev->pGraphicsDevice;
312
313 for (i = 0; i < pGraphicsDevice->cDevModes; i++)
314 {
315 pdmCurrent = pGraphicsDevice->pDevModeList[i].pdm;
316
317 /* Compare asked DEVMODE fields
318 * Only compare those that are valid in both DEVMODE structs */
319 dwFields = pdmCurrent->dmFields & pdm->dmFields ;
320
321 /* For now, we only need those */
322 if ((dwFields & DM_BITSPERPEL) &&
323 (pdmCurrent->dmBitsPerPel != pdm->dmBitsPerPel)) continue;
324 if ((dwFields & DM_PELSWIDTH) &&
325 (pdmCurrent->dmPelsWidth != pdm->dmPelsWidth)) continue;
326 if ((dwFields & DM_PELSHEIGHT) &&
327 (pdmCurrent->dmPelsHeight != pdm->dmPelsHeight)) continue;
328 if ((dwFields & DM_DISPLAYFREQUENCY) &&
329 (pdmCurrent->dmDisplayFrequency != pdm->dmDisplayFrequency)) continue;
330
331 /* Match! Return the DEVMODE */
332 return pdmCurrent;
333 }
334
335 /* Nothing found */
336 return NULL;
337 }
338
339 static
340 PPDEVOBJ
341 EngpCreatePDEV(
342 PUNICODE_STRING pustrDeviceName,
343 PDEVMODEW pdm)
344 {
345 PGRAPHICS_DEVICE pGraphicsDevice;
346 PPDEVOBJ ppdev;
347 DPRINT("EngpCreatePDEV(%wZ, %p)\n", pustrDeviceName, pdm);
348
349 /* Try to find the GRAPHICS_DEVICE */
350 if (pustrDeviceName)
351 {
352 pGraphicsDevice = EngpFindGraphicsDevice(pustrDeviceName, 0, 0);
353 if (!pGraphicsDevice)
354 {
355 DPRINT1("No GRAPHICS_DEVICE found for %ls!\n",
356 pustrDeviceName ? pustrDeviceName->Buffer : 0);
357 return NULL;
358 }
359 }
360 else
361 {
362 pGraphicsDevice = gpPrimaryGraphicsDevice;
363 }
364
365 /* Allocate a new PDEVOBJ */
366 ppdev = PDEVOBJ_AllocPDEV();
367 if (!ppdev)
368 {
369 DPRINT1("failed to allocate a PDEV\n");
370 return NULL;
371 }
372
373 /* If no DEVMODEW is given, ... */
374 if (!pdm)
375 {
376 /* ... use the device's default one */
377 pdm = pGraphicsDevice->pDevModeList[pGraphicsDevice->iDefaultMode].pdm;
378 DPRINT("Using iDefaultMode = %lu\n", pGraphicsDevice->iDefaultMode);
379 }
380
381 /* Try to get a diplay driver */
382 ppdev->pldev = EngLoadImageEx(pdm->dmDeviceName, LDEV_DEVICE_DISPLAY);
383 if (!ppdev->pldev)
384 {
385 DPRINT1("Could not load display driver '%ls', '%ls'\n",
386 pGraphicsDevice->pDiplayDrivers,
387 pdm->dmDeviceName);
388 PDEVOBJ_vRelease(ppdev);
389 return NULL;
390 }
391
392 /* Copy the function table */
393 ppdev->pfn = ppdev->pldev->pfn;
394
395 /* Set MovePointer function */
396 ppdev->pfnMovePointer = ppdev->pfn.MovePointer;
397 if (!ppdev->pfnMovePointer)
398 ppdev->pfnMovePointer = EngMovePointer;
399
400 ppdev->pGraphicsDevice = pGraphicsDevice;
401
402 // DxEngGetHdevData asks for Graphics DeviceObject in hSpooler field
403 ppdev->hSpooler = ppdev->pGraphicsDevice->DeviceObject;
404
405 // Should we change the ative mode of pGraphicsDevice ?
406 ppdev->pdmwDev = PDEVOBJ_pdmMatchDevMode(ppdev, pdm) ;
407
408 /* FIXME! */
409 ppdev->flFlags = PDEV_DISPLAY;
410
411 /* HACK: Don't use the pointer */
412 ppdev->Pointer.Exclude.right = -1;
413
414 /* Call the driver to enable the PDEV */
415 if (!PDEVOBJ_bEnablePDEV(ppdev, pdm, NULL))
416 {
417 DPRINT1("Failed to enable PDEV!\n");
418 PDEVOBJ_vRelease(ppdev);
419 return NULL;
420 }
421
422 /* FIXME: this must be done in a better way */
423 pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
424
425 /* Tell the driver that the PDEV is ready */
426 PDEVOBJ_vCompletePDEV(ppdev);
427
428 /* Return the PDEV */
429 return ppdev;
430 }
431
432 FORCEINLINE
433 VOID
434 SwitchPointer(
435 _Inout_ PVOID pvPointer1,
436 _Inout_ PVOID pvPointer2)
437 {
438 PVOID *ppvPointer1 = pvPointer1;
439 PVOID *ppvPointer2 = pvPointer2;
440 PVOID pvTemp;
441
442 pvTemp = *ppvPointer1;
443 *ppvPointer1 = *ppvPointer2;
444 *ppvPointer2 = pvTemp;
445 }
446
447 VOID
448 NTAPI
449 PDEVOBJ_vSwitchPdev(
450 PPDEVOBJ ppdev,
451 PPDEVOBJ ppdev2)
452 {
453 union
454 {
455 DRIVER_FUNCTIONS pfn;
456 GDIINFO gdiinfo;
457 DEVINFO devinfo;
458 DWORD StateFlags;
459 } temp;
460
461 /* Exchange driver functions */
462 temp.pfn = ppdev->pfn;
463 ppdev->pfn = ppdev2->pfn;
464 ppdev2->pfn = temp.pfn;
465
466 /* Exchange LDEVs */
467 SwitchPointer(&ppdev->pldev, &ppdev2->pldev);
468
469 /* Exchange DHPDEV */
470 SwitchPointer(&ppdev->dhpdev, &ppdev2->dhpdev);
471
472 /* Exchange surfaces and associate them with their new PDEV */
473 SwitchPointer(&ppdev->pSurface, &ppdev2->pSurface);
474 ppdev->pSurface->SurfObj.hdev = (HDEV)ppdev;
475 ppdev2->pSurface->SurfObj.hdev = (HDEV)ppdev2;
476
477 /* Exchange devinfo */
478 temp.devinfo = ppdev->devinfo;
479 ppdev->devinfo = ppdev2->devinfo;
480 ppdev2->devinfo = temp.devinfo;
481
482 /* Exchange gdiinfo */
483 temp.gdiinfo = ppdev->gdiinfo;
484 ppdev->gdiinfo = ppdev2->gdiinfo;
485 ppdev2->gdiinfo = temp.gdiinfo;
486
487 /* Exchange DEVMODE */
488 SwitchPointer(&ppdev->pdmwDev, &ppdev2->pdmwDev);
489
490 /* Exchange state flags */
491 temp.StateFlags = ppdev->pGraphicsDevice->StateFlags;
492 ppdev->pGraphicsDevice->StateFlags = ppdev2->pGraphicsDevice->StateFlags;
493 ppdev2->pGraphicsDevice->StateFlags = temp.StateFlags;
494
495 /* Notify each driver instance of its new HDEV association */
496 ppdev->pfn.CompletePDEV(ppdev->dhpdev, (HDEV)ppdev);
497 ppdev2->pfn.CompletePDEV(ppdev2->dhpdev, (HDEV)ppdev2);
498 }
499
500
501 BOOL
502 NTAPI
503 PDEVOBJ_bSwitchMode(
504 PPDEVOBJ ppdev,
505 PDEVMODEW pdm)
506 {
507 UNICODE_STRING ustrDevice;
508 PPDEVOBJ ppdevTmp;
509 PSURFACE pSurface;
510 BOOL retval = FALSE;
511
512 /* Lock the PDEV */
513 EngAcquireSemaphore(ppdev->hsemDevLock);
514
515 /* And everything else */
516 EngAcquireSemaphore(ghsemPDEV);
517
518 DPRINT1("PDEVOBJ_bSwitchMode, ppdev = %p, pSurface = %p\n", ppdev, ppdev->pSurface);
519
520 // Lookup the GraphicsDevice + select DEVMODE
521 // pdm = PDEVOBJ_pdmMatchDevMode(ppdev, pdm);
522
523 /* 1. Temporarily disable the current PDEV */
524 if (!ppdev->pfn.AssertMode(ppdev->dhpdev, FALSE))
525 {
526 DPRINT1("DrvAssertMode failed\n");
527 goto leave;
528 }
529
530 /* 2. Create new PDEV */
531 RtlInitUnicodeString(&ustrDevice, ppdev->pGraphicsDevice->szWinDeviceName);
532 ppdevTmp = EngpCreatePDEV(&ustrDevice, pdm);
533 if (!ppdevTmp)
534 {
535 DPRINT1("Failed to create a new PDEV\n");
536 goto leave;
537 }
538
539 /* 3. Create a new surface */
540 pSurface = PDEVOBJ_pSurface(ppdevTmp);
541 if (!pSurface)
542 {
543 DPRINT1("PDEVOBJ_pSurface failed\n");
544 goto leave;
545 }
546
547 /* 4. Get DirectDraw information */
548 /* 5. Enable DirectDraw Not traced */
549 /* 6. Copy old PDEV state to new PDEV instance */
550
551 /* 7. Switch the PDEVs */
552 PDEVOBJ_vSwitchPdev(ppdev, ppdevTmp);
553
554 /* 8. Disable DirectDraw */
555
556 PDEVOBJ_vRelease(ppdevTmp);
557
558 /* Update primary display capabilities */
559 if(ppdev == gppdevPrimary)
560 {
561 PDEVOBJ_vGetDeviceCaps(ppdev, &GdiHandleTable->DevCaps);
562 }
563
564 /* Success! */
565 retval = TRUE;
566 leave:
567 /* Unlock PDEV */
568 EngReleaseSemaphore(ppdev->hsemDevLock);
569 EngReleaseSemaphore(ghsemPDEV);
570
571 DPRINT1("leave, ppdev = %p, pSurface = %p\n", ppdev, ppdev->pSurface);
572
573 return retval;
574 }
575
576
577 PPDEVOBJ
578 NTAPI
579 EngpGetPDEV(
580 _In_opt_ PUNICODE_STRING pustrDeviceName)
581 {
582 UNICODE_STRING ustrCurrent;
583 PPDEVOBJ ppdev;
584 PGRAPHICS_DEVICE pGraphicsDevice;
585
586 /* Acquire PDEV lock */
587 EngAcquireSemaphore(ghsemPDEV);
588
589 /* Did the caller pass a device name? */
590 if (pustrDeviceName)
591 {
592 /* Loop all present PDEVs */
593 for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext)
594 {
595 /* Get a pointer to the GRAPHICS_DEVICE */
596 pGraphicsDevice = ppdev->pGraphicsDevice;
597
598 /* Compare the name */
599 RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName);
600 if (RtlEqualUnicodeString(pustrDeviceName, &ustrCurrent, FALSE))
601 {
602 /* Found! */
603 break;
604 }
605 }
606 }
607 else
608 {
609 /* Otherwise use the primary PDEV */
610 ppdev = gppdevPrimary;
611 }
612
613 /* Did we find one? */
614 if (ppdev)
615 {
616 /* Yes, reference the PDEV */
617 InterlockedIncrement(&ppdev->cPdevRefs);
618 }
619 else
620 {
621 /* No, create a new PDEV for the given device */
622 ppdev = EngpCreatePDEV(pustrDeviceName, NULL);
623 if (ppdev)
624 {
625 /* Insert the PDEV into the list */
626 ppdev->ppdevNext = gppdevList;
627 gppdevList = ppdev;
628
629 /* Set as primary PDEV, if we don't have one yet */
630 if (!gppdevPrimary)
631 {
632 gppdevPrimary = ppdev;
633 ppdev->pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
634 }
635 }
636 }
637
638 /* Release PDEV lock */
639 EngReleaseSemaphore(ghsemPDEV);
640
641 return ppdev;
642 }
643
644 INT
645 NTAPI
646 PDEVOBJ_iGetColorManagementCaps(PPDEVOBJ ppdev)
647 {
648 INT ret = CM_NONE;
649
650 if (ppdev->flFlags & PDEV_DISPLAY)
651 {
652 if (ppdev->devinfo.iDitherFormat == BMF_8BPP ||
653 ppdev->devinfo.flGraphicsCaps2 & GCAPS2_CHANGEGAMMARAMP)
654 ret = CM_GAMMA_RAMP;
655 }
656
657 if (ppdev->devinfo.flGraphicsCaps & GCAPS_CMYKCOLOR)
658 ret |= CM_CMYK_COLOR;
659 if (ppdev->devinfo.flGraphicsCaps & GCAPS_ICM)
660 ret |= CM_DEVICE_ICM;
661
662 return ret;
663 }
664
665 VOID
666 NTAPI
667 PDEVOBJ_vGetDeviceCaps(
668 IN PPDEVOBJ ppdev,
669 OUT PDEVCAPS pDevCaps)
670 {
671 PGDIINFO pGdiInfo = &ppdev->gdiinfo;
672
673 pDevCaps->ulVersion = pGdiInfo->ulVersion;
674 pDevCaps->ulTechnology = pGdiInfo->ulTechnology;
675 pDevCaps->ulHorzSizeM = (pGdiInfo->ulHorzSize + 500) / 1000;
676 pDevCaps->ulVertSizeM = (pGdiInfo->ulVertSize + 500) / 1000;
677 pDevCaps->ulHorzSize = pGdiInfo->ulHorzSize;
678 pDevCaps->ulVertSize = pGdiInfo->ulVertSize;
679 pDevCaps->ulHorzRes = pGdiInfo->ulHorzRes;
680 pDevCaps->ulVertRes = pGdiInfo->ulVertRes;
681 pDevCaps->ulBitsPixel = pGdiInfo->cBitsPixel;
682 if (pDevCaps->ulBitsPixel == 15) pDevCaps->ulBitsPixel = 16;
683 pDevCaps->ulPlanes = pGdiInfo->cPlanes;
684 pDevCaps->ulNumPens = pGdiInfo->ulNumColors;
685 if (pDevCaps->ulNumPens != -1) pDevCaps->ulNumPens *= 5;
686 pDevCaps->ulNumFonts = 0; // PDEVOBJ_cFonts(ppdev);
687 pDevCaps->ulNumColors = pGdiInfo->ulNumColors;
688 pDevCaps->ulRasterCaps = pGdiInfo->flRaster;
689 pDevCaps->ulAspectX = pGdiInfo->ulAspectX;
690 pDevCaps->ulAspectY = pGdiInfo->ulAspectY;
691 pDevCaps->ulAspectXY = pGdiInfo->ulAspectXY;
692 pDevCaps->ulLogPixelsX = pGdiInfo->ulLogPixelsX;
693 pDevCaps->ulLogPixelsY = pGdiInfo->ulLogPixelsY;
694 pDevCaps->ulSizePalette = pGdiInfo->ulNumPalReg;
695 pDevCaps->ulColorRes = pGdiInfo->ulDACRed +
696 pGdiInfo->ulDACGreen +
697 pGdiInfo->ulDACBlue;
698 pDevCaps->ulPhysicalWidth = pGdiInfo->szlPhysSize.cx;
699 pDevCaps->ulPhysicalHeight = pGdiInfo->szlPhysSize.cy;
700 pDevCaps->ulPhysicalOffsetX = pGdiInfo->ptlPhysOffset.x;
701 pDevCaps->ulPhysicalOffsetY = pGdiInfo->ptlPhysOffset.y;
702 pDevCaps->ulTextCaps = pGdiInfo->flTextCaps;
703 pDevCaps->ulTextCaps |= (TC_SO_ABLE|TC_UA_ABLE|TC_CP_STROKE|TC_OP_STROKE|TC_OP_CHARACTER);
704 if (pGdiInfo->ulTechnology != DT_PLOTTER)
705 pDevCaps->ulTextCaps |= TC_VA_ABLE;
706 pDevCaps->ulVRefresh = pGdiInfo->ulVRefresh;
707 pDevCaps->ulDesktopHorzRes = pGdiInfo->ulHorzRes;
708 pDevCaps->ulDesktopVertRes = pGdiInfo->ulVertRes;
709 pDevCaps->ulBltAlignment = pGdiInfo->ulBltAlignment;
710 pDevCaps->ulPanningHorzRes = pGdiInfo->ulPanningHorzRes;
711 pDevCaps->ulPanningVertRes = pGdiInfo->ulPanningVertRes;
712 pDevCaps->xPanningAlignment = pGdiInfo->xPanningAlignment;
713 pDevCaps->yPanningAlignment = pGdiInfo->yPanningAlignment;
714 pDevCaps->ulShadeBlend = pGdiInfo->flShadeBlend;
715 pDevCaps->ulColorMgmtCaps = PDEVOBJ_iGetColorManagementCaps(ppdev);
716 }
717
718
719 /** Exported functions ********************************************************/
720
721 _Must_inspect_result_ _Ret_z_
722 LPWSTR
723 APIENTRY
724 EngGetDriverName(_In_ HDEV hdev)
725 {
726 PPDEVOBJ ppdev = (PPDEVOBJ)hdev;
727
728 ASSERT(ppdev);
729 ASSERT(ppdev->pldev);
730 ASSERT(ppdev->pldev->pGdiDriverInfo);
731 ASSERT(ppdev->pldev->pGdiDriverInfo->DriverName.Buffer);
732
733 return ppdev->pldev->pGdiDriverInfo->DriverName.Buffer;
734 }
735
736
737 INT
738 APIENTRY
739 NtGdiGetDeviceCaps(
740 HDC hdc,
741 INT Index)
742 {
743 PDC pdc;
744 DEVCAPS devcaps;
745
746 /* Lock the given DC */
747 pdc = DC_LockDc(hdc);
748 if (!pdc)
749 {
750 EngSetLastError(ERROR_INVALID_HANDLE);
751 return 0;
752 }
753
754 /* Get the data */
755 PDEVOBJ_vGetDeviceCaps(pdc->ppdev, &devcaps);
756
757 /* Unlock the DC */
758 DC_UnlockDc(pdc);
759
760 /* Return capability */
761 switch (Index)
762 {
763 case DRIVERVERSION:
764 return devcaps.ulVersion;
765
766 case TECHNOLOGY:
767 return devcaps.ulTechnology;
768
769 case HORZSIZE:
770 return devcaps.ulHorzSize;
771
772 case VERTSIZE:
773 return devcaps.ulVertSize;
774
775 case HORZRES:
776 return devcaps.ulHorzRes;
777
778 case VERTRES:
779 return devcaps.ulVertRes;
780
781 case LOGPIXELSX:
782 return devcaps.ulLogPixelsX;
783
784 case LOGPIXELSY:
785 return devcaps.ulLogPixelsY;
786
787 case BITSPIXEL:
788 return devcaps.ulBitsPixel;
789
790 case PLANES:
791 return devcaps.ulPlanes;
792
793 case NUMBRUSHES:
794 return -1;
795
796 case NUMPENS:
797 return devcaps.ulNumPens;
798
799 case NUMFONTS:
800 return devcaps.ulNumFonts;
801
802 case NUMCOLORS:
803 return devcaps.ulNumColors;
804
805 case ASPECTX:
806 return devcaps.ulAspectX;
807
808 case ASPECTY:
809 return devcaps.ulAspectY;
810
811 case ASPECTXY:
812 return devcaps.ulAspectXY;
813
814 case CLIPCAPS:
815 return CP_RECTANGLE;
816
817 case SIZEPALETTE:
818 return devcaps.ulSizePalette;
819
820 case NUMRESERVED:
821 return 20;
822
823 case COLORRES:
824 return devcaps.ulColorRes;
825
826 case DESKTOPVERTRES:
827 return devcaps.ulVertRes;
828
829 case DESKTOPHORZRES:
830 return devcaps.ulHorzRes;
831
832 case BLTALIGNMENT:
833 return devcaps.ulBltAlignment;
834
835 case SHADEBLENDCAPS:
836 return devcaps.ulShadeBlend;
837
838 case COLORMGMTCAPS:
839 return devcaps.ulColorMgmtCaps;
840
841 case PHYSICALWIDTH:
842 return devcaps.ulPhysicalWidth;
843
844 case PHYSICALHEIGHT:
845 return devcaps.ulPhysicalHeight;
846
847 case PHYSICALOFFSETX:
848 return devcaps.ulPhysicalOffsetX;
849
850 case PHYSICALOFFSETY:
851 return devcaps.ulPhysicalOffsetY;
852
853 case VREFRESH:
854 return devcaps.ulVRefresh;
855
856 case RASTERCAPS:
857 return devcaps.ulRasterCaps;
858
859 case CURVECAPS:
860 return (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE |
861 CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT);
862
863 case LINECAPS:
864 return (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE |
865 LC_STYLED | LC_WIDESTYLED | LC_INTERIORS);
866
867 case POLYGONALCAPS:
868 return (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE |
869 PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS);
870
871 case TEXTCAPS:
872 return devcaps.ulTextCaps;
873
874 case CAPS1:
875 case PDEVICESIZE:
876 case SCALINGFACTORX:
877 case SCALINGFACTORY:
878 default:
879 return 0;
880 }
881
882 return 0;
883 }
884
885 _Success_(return!=FALSE)
886 BOOL
887 APIENTRY
888 NtGdiGetDeviceCapsAll(
889 IN HDC hDC,
890 OUT PDEVCAPS pDevCaps)
891 {
892 PDC pdc;
893 DEVCAPS devcaps;
894 BOOL bResult = TRUE;
895
896 /* Lock the given DC */
897 pdc = DC_LockDc(hDC);
898 if (!pdc)
899 {
900 EngSetLastError(ERROR_INVALID_HANDLE);
901 return FALSE;
902 }
903
904 /* Get the data */
905 PDEVOBJ_vGetDeviceCaps(pdc->ppdev, &devcaps);
906
907 /* Unlock the DC */
908 DC_UnlockDc(pdc);
909
910 /* Copy data to caller */
911 _SEH2_TRY
912 {
913 ProbeForWrite(pDevCaps, sizeof(DEVCAPS), 1);
914 RtlCopyMemory(pDevCaps, &devcaps, sizeof(DEVCAPS));
915 }
916 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
917 {
918 SetLastNtError(_SEH2_GetExceptionCode());
919 bResult = FALSE;
920 }
921 _SEH2_END;
922
923 return bResult;
924 }
925
926 DHPDEV
927 APIENTRY
928 NtGdiGetDhpdev(
929 IN HDEV hdev)
930 {
931 PPDEVOBJ ppdev;
932 DHPDEV dhpdev = NULL;
933
934 /* Check parameter */
935 if (!hdev || (PCHAR)hdev < (PCHAR)MmSystemRangeStart)
936 return NULL;
937
938 /* Lock PDEV list */
939 EngAcquireSemaphoreShared(ghsemPDEV);
940
941 /* Walk through the list of PDEVs */
942 for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext)
943 {
944 /* Compare with the given HDEV */
945 if (ppdev == (PPDEVOBJ)hdev)
946 {
947 /* Found the PDEV! Get it's dhpdev and break */
948 dhpdev = ppdev->dhpdev;
949 break;
950 }
951 }
952
953 /* Unlock PDEV list */
954 EngReleaseSemaphore(ghsemPDEV);
955
956 return dhpdev;
957 }
958
959 PSIZEL
960 FASTCALL
961 PDEVOBJ_sizl(PPDEVOBJ ppdev, PSIZEL psizl)
962 {
963 if (ppdev->flFlags & PDEV_META_DEVICE)
964 {
965 psizl->cx = ppdev->ulHorzRes;
966 psizl->cy = ppdev->ulVertRes;
967 }
968 else
969 {
970 psizl->cx = ppdev->gdiinfo.ulHorzRes;
971 psizl->cy = ppdev->gdiinfo.ulVertRes;
972 }
973 return psizl;
974 }