85098a5843702b2e741e0cc76bd2b1611bc1eb52
[reactos.git] / 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 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 }