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