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