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