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