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