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