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