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