Sync up with trunk r61578.
[reactos.git] / win32ss / gdi / ntgdi / dcutil.c
1 #include <win32k.h>
2
3 #define NDEBUG
4 #include <debug.h>
5
6 int FASTCALL
7 GreGetBkMode(HDC hdc)
8 {
9 PDC dc;
10 if (!(dc = DC_LockDc(hdc)))
11 {
12 EngSetLastError(ERROR_INVALID_HANDLE);
13 return CLR_INVALID;
14 }
15 return dc->pdcattr->lBkMode;
16 }
17
18 int FASTCALL
19 GreGetMapMode(HDC hdc)
20 {
21 PDC dc;
22 if (!(dc = DC_LockDc(hdc)))
23 {
24 EngSetLastError(ERROR_INVALID_HANDLE);
25 return CLR_INVALID;
26 }
27 return dc->pdcattr->iMapMode;
28 }
29
30 COLORREF FASTCALL
31 GreGetTextColor(HDC hdc)
32 {
33 PDC dc;
34 if (!(dc = DC_LockDc(hdc)))
35 {
36 EngSetLastError(ERROR_INVALID_HANDLE);
37 return CLR_INVALID;
38 }
39 return dc->pdcattr->ulForegroundClr;
40 }
41
42 COLORREF FASTCALL
43 IntGdiSetBkColor(HDC hDC, COLORREF color)
44 {
45 COLORREF oldColor;
46 PDC dc;
47 PDC_ATTR pdcattr;
48 HBRUSH hBrush;
49
50 if (!(dc = DC_LockDc(hDC)))
51 {
52 EngSetLastError(ERROR_INVALID_HANDLE);
53 return CLR_INVALID;
54 }
55 pdcattr = dc->pdcattr;
56 oldColor = pdcattr->crBackgroundClr;
57 pdcattr->crBackgroundClr = color;
58 pdcattr->ulBackgroundClr = (ULONG)color;
59 pdcattr->ulDirty_ |= DIRTY_BACKGROUND|DIRTY_LINE|DIRTY_FILL; // Clear Flag if set.
60 hBrush = pdcattr->hbrush;
61 DC_UnlockDc(dc);
62 NtGdiSelectBrush(hDC, hBrush);
63 return oldColor;
64 }
65
66 INT FASTCALL
67 IntGdiSetBkMode(HDC hDC, INT Mode)
68 {
69 COLORREF oldMode;
70 PDC dc;
71 PDC_ATTR pdcattr;
72
73 if (!(dc = DC_LockDc(hDC)))
74 {
75 EngSetLastError(ERROR_INVALID_HANDLE);
76 return CLR_INVALID;
77 }
78 pdcattr = dc->pdcattr;
79 oldMode = pdcattr->lBkMode;
80 pdcattr->jBkMode = Mode;
81 pdcattr->lBkMode = Mode;
82 DC_UnlockDc(dc);
83 return oldMode;
84 }
85
86 UINT
87 FASTCALL
88 IntGdiSetTextAlign(HDC hDC,
89 UINT Mode)
90 {
91 UINT prevAlign;
92 DC *dc;
93 PDC_ATTR pdcattr;
94
95 dc = DC_LockDc(hDC);
96 if (!dc)
97 {
98 EngSetLastError(ERROR_INVALID_HANDLE);
99 return GDI_ERROR;
100 }
101 pdcattr = dc->pdcattr;
102 prevAlign = pdcattr->lTextAlign;
103 pdcattr->lTextAlign = Mode;
104 DC_UnlockDc(dc);
105 return prevAlign;
106 }
107
108 COLORREF
109 FASTCALL
110 IntGdiSetTextColor(HDC hDC,
111 COLORREF color)
112 {
113 COLORREF crOldColor;
114 PDC pdc;
115 PDC_ATTR pdcattr;
116
117 pdc = DC_LockDc(hDC);
118 if (!pdc)
119 {
120 EngSetLastError(ERROR_INVALID_HANDLE);
121 return CLR_INVALID;
122 }
123 pdcattr = pdc->pdcattr;
124
125 // What about ulForegroundClr, like in gdi32?
126 crOldColor = pdcattr->crForegroundClr;
127 pdcattr->crForegroundClr = color;
128 DC_vUpdateTextBrush(pdc);
129
130 DC_UnlockDc(pdc);
131
132 return crOldColor;
133 }
134
135 COLORREF FASTCALL
136 IntSetDCBrushColor(HDC hdc, COLORREF crColor)
137 {
138 COLORREF OldColor = CLR_INVALID;
139 PDC dc;
140 if (!(dc = DC_LockDc(hdc)))
141 {
142 EngSetLastError(ERROR_INVALID_HANDLE);
143 return CLR_INVALID;
144 }
145 else
146 {
147 OldColor = (COLORREF) dc->pdcattr->ulBrushClr;
148 dc->pdcattr->ulBrushClr = (ULONG) crColor;
149
150 if ( dc->pdcattr->crBrushClr != crColor )
151 {
152 dc->pdcattr->ulDirty_ |= DIRTY_FILL;
153 dc->pdcattr->crBrushClr = crColor;
154 }
155 }
156 return OldColor;
157 }
158
159 COLORREF FASTCALL
160 IntSetDCPenColor(HDC hdc, COLORREF crColor)
161 {
162 COLORREF OldColor;
163 PDC dc;
164 if (!(dc = DC_LockDc(hdc)))
165 {
166 EngSetLastError(ERROR_INVALID_PARAMETER);
167 return CLR_INVALID;
168 }
169
170 OldColor = (COLORREF)dc->pdcattr->ulPenClr;
171 dc->pdcattr->ulPenClr = (ULONG)crColor;
172
173 if (dc->pdcattr->crPenClr != crColor)
174 {
175 dc->pdcattr->ulDirty_ |= DIRTY_LINE;
176 dc->pdcattr->crPenClr = crColor;
177 }
178
179 return OldColor;
180 }
181
182 int
183 FASTCALL
184 GreSetStretchBltMode(HDC hDC, int iStretchMode)
185 {
186 PDC pdc;
187 PDC_ATTR pdcattr;
188 INT oSMode = 0;
189
190 pdc = DC_LockDc(hDC);
191 if (pdc)
192 {
193 pdcattr = pdc->pdcattr;
194 oSMode = pdcattr->lStretchBltMode;
195 pdcattr->lStretchBltMode = iStretchMode;
196
197 // Wine returns an error here. We set the default.
198 if ((iStretchMode <= 0) || (iStretchMode > MAXSTRETCHBLTMODE)) iStretchMode = WHITEONBLACK;
199
200 pdcattr->jStretchBltMode = iStretchMode;
201 }
202 return oSMode;
203 }
204
205 VOID
206 FASTCALL
207 DCU_SetDcUndeletable(HDC hDC)
208 {
209 PDC dc = DC_LockDc(hDC);
210 if (!dc)
211 {
212 EngSetLastError(ERROR_INVALID_HANDLE);
213 return;
214 }
215
216 dc->fs |= DC_FLAG_PERMANENT;
217 DC_UnlockDc(dc);
218 return;
219 }
220
221 #if 0
222 BOOL FASTCALL
223 IntIsPrimarySurface(SURFOBJ *SurfObj)
224 {
225 if (PrimarySurface.pSurface == NULL)
226 {
227 return FALSE;
228 }
229 return SurfObj->hsurf == PrimarySurface.pSurface; // <- FIXME: WTF?
230 }
231 #endif
232
233 BOOL
234 FASTCALL
235 IntSetDefaultRegion(PDC pdc)
236 {
237 PSURFACE pSurface;
238 PROSRGNDATA prgn;
239 RECTL rclWnd, rclClip;
240
241 IntGdiReleaseRaoRgn(pdc);
242
243 rclWnd.left = 0;
244 rclWnd.top = 0;
245 rclWnd.right = pdc->dclevel.sizl.cx;
246 rclWnd.bottom = pdc->dclevel.sizl.cy;
247 rclClip = rclWnd;
248
249 //EngAcquireSemaphoreShared(pdc->ppdev->hsemDevLock);
250 if (pdc->ppdev->flFlags & PDEV_META_DEVICE)
251 {
252 pSurface = pdc->dclevel.pSurface;
253 if (pSurface && pSurface->flags & PDEV_SURFACE)
254 {
255 rclClip.left += pdc->ppdev->ptlOrigion.x;
256 rclClip.top += pdc->ppdev->ptlOrigion.y;
257 rclClip.right += pdc->ppdev->ptlOrigion.x;
258 rclClip.bottom += pdc->ppdev->ptlOrigion.y;
259 }
260 }
261 //EngReleaseSemaphore(pdc->ppdev->hsemDevLock);
262
263 prgn = pdc->prgnVis;
264
265 if (prgn && prgn != prgnDefault)
266 {
267 REGION_SetRectRgn( prgn,
268 rclClip.left,
269 rclClip.top,
270 rclClip.right ,
271 rclClip.bottom );
272 }
273 else
274 {
275 prgn = IntSysCreateRectpRgn( rclClip.left,
276 rclClip.top,
277 rclClip.right ,
278 rclClip.bottom );
279 pdc->prgnVis = prgn;
280 }
281
282 if (prgn)
283 {
284 pdc->ptlDCOrig.x = 0;
285 pdc->ptlDCOrig.y = 0;
286 pdc->erclWindow = rclWnd;
287 pdc->erclClip = rclClip;
288 /* Might be an InitDC or DCE... */
289 pdc->ptlFillOrigin.x = pdc->dcattr.VisRectRegion.Rect.right;
290 pdc->ptlFillOrigin.y = pdc->dcattr.VisRectRegion.Rect.bottom;
291 return TRUE;
292 }
293
294 pdc->prgnVis = prgnDefault;
295 return FALSE;
296 }
297
298
299 BOOL APIENTRY
300 NtGdiCancelDC(HDC hDC)
301 {
302 UNIMPLEMENTED;
303 return FALSE;
304 }
305
306
307 WORD APIENTRY
308 IntGdiSetHookFlags(HDC hDC, WORD Flags)
309 {
310 WORD wRet;
311 DC *dc = DC_LockDc(hDC);
312
313 if (NULL == dc)
314 {
315 EngSetLastError(ERROR_INVALID_HANDLE);
316 return 0;
317 }
318
319 wRet = dc->fs & DC_FLAG_DIRTY_RAO; // FIXME: Wrong flag!
320
321 /* Info in "Undocumented Windows" is slightly confusing. */
322 DPRINT("DC %p, Flags %04x\n", hDC, Flags);
323
324 if (Flags & DCHF_INVALIDATEVISRGN)
325 {
326 /* hVisRgn has to be updated */
327 dc->fs |= DC_FLAG_DIRTY_RAO;
328 }
329 else if (Flags & DCHF_VALIDATEVISRGN || 0 == Flags)
330 {
331 dc->fs &= ~DC_FLAG_DIRTY_RAO;
332 }
333
334 DC_UnlockDc(dc);
335
336 return wRet;
337 }
338
339
340 BOOL
341 APIENTRY
342 NtGdiGetDCDword(
343 HDC hDC,
344 UINT u,
345 DWORD *Result)
346 {
347 BOOL Ret = TRUE;
348 PDC pdc;
349 PDC_ATTR pdcattr;
350
351 DWORD SafeResult = 0;
352 NTSTATUS Status = STATUS_SUCCESS;
353
354 if (!Result)
355 {
356 EngSetLastError(ERROR_INVALID_PARAMETER);
357 return FALSE;
358 }
359
360 pdc = DC_LockDc(hDC);
361 if (!pdc)
362 {
363 EngSetLastError(ERROR_INVALID_HANDLE);
364 return FALSE;
365 }
366 pdcattr = pdc->pdcattr;
367
368 switch (u)
369 {
370 case GdiGetJournal:
371 break;
372
373 case GdiGetRelAbs:
374 SafeResult = pdcattr->lRelAbs;
375 break;
376
377 case GdiGetBreakExtra:
378 SafeResult = pdcattr->lBreakExtra;
379 break;
380
381 case GdiGerCharBreak:
382 SafeResult = pdcattr->cBreak;
383 break;
384
385 case GdiGetArcDirection:
386 if (pdcattr->dwLayout & LAYOUT_RTL)
387 SafeResult = AD_CLOCKWISE - ((pdc->dclevel.flPath & DCPATH_CLOCKWISE) != 0);
388 else
389 SafeResult = ((pdc->dclevel.flPath & DCPATH_CLOCKWISE) != 0) + AD_COUNTERCLOCKWISE;
390 break;
391
392 case GdiGetEMFRestorDc:
393 break;
394
395 case GdiGetFontLanguageInfo:
396 SafeResult = IntGetFontLanguageInfo(pdc);
397 break;
398
399 case GdiGetIsMemDc:
400 SafeResult = pdc->dctype;
401 break;
402
403 case GdiGetMapMode:
404 SafeResult = pdcattr->iMapMode;
405 break;
406
407 case GdiGetTextCharExtra:
408 SafeResult = pdcattr->lTextExtra;
409 break;
410
411 default:
412 EngSetLastError(ERROR_INVALID_PARAMETER);
413 Ret = FALSE;
414 break;
415 }
416
417 if (Ret)
418 {
419 _SEH2_TRY
420 {
421 ProbeForWrite(Result, sizeof(DWORD), 1);
422 *Result = SafeResult;
423 }
424 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
425 {
426 Status = _SEH2_GetExceptionCode();
427 }
428 _SEH2_END;
429
430 if (!NT_SUCCESS(Status))
431 {
432 SetLastNtError(Status);
433 Ret = FALSE;
434 }
435 }
436
437 DC_UnlockDc(pdc);
438 return Ret;
439 }
440
441 _Success_(return != FALSE)
442 BOOL
443 APIENTRY
444 NtGdiGetAndSetDCDword(
445 _In_ HDC hdc,
446 _In_ UINT u,
447 _In_ DWORD dwIn,
448 _Out_ DWORD *pdwResult)
449 {
450 BOOL Ret = TRUE;
451 PDC pdc;
452 PDC_ATTR pdcattr;
453
454 DWORD SafeResult = 0;
455 NTSTATUS Status = STATUS_SUCCESS;
456
457 if (!pdwResult)
458 {
459 EngSetLastError(ERROR_INVALID_PARAMETER);
460 return FALSE;
461 }
462
463 pdc = DC_LockDc(hdc);
464 if (!pdc)
465 {
466 EngSetLastError(ERROR_INVALID_HANDLE);
467 return FALSE;
468 }
469 pdcattr = pdc->pdcattr;
470
471 switch (u)
472 {
473 case GdiGetSetCopyCount:
474 SafeResult = pdc->ulCopyCount;
475 pdc->ulCopyCount = dwIn;
476 break;
477
478 case GdiGetSetTextAlign:
479 SafeResult = pdcattr->lTextAlign;
480 pdcattr->lTextAlign = dwIn;
481 // pdcattr->flTextAlign = dwIn; // Flags!
482 break;
483
484 case GdiGetSetRelAbs:
485 SafeResult = pdcattr->lRelAbs;
486 pdcattr->lRelAbs = dwIn;
487 break;
488
489 case GdiGetSetTextCharExtra:
490 SafeResult = pdcattr->lTextExtra;
491 pdcattr->lTextExtra = dwIn;
492 break;
493
494 case GdiGetSetSelectFont:
495 break;
496
497 case GdiGetSetMapperFlagsInternal:
498 if (dwIn & ~1)
499 {
500 EngSetLastError(ERROR_INVALID_PARAMETER);
501 Ret = FALSE;
502 break;
503 }
504 SafeResult = pdcattr->flFontMapper;
505 pdcattr->flFontMapper = dwIn;
506 break;
507
508 case GdiGetSetMapMode:
509 SafeResult = IntGdiSetMapMode(pdc, dwIn);
510 break;
511
512 case GdiGetSetArcDirection:
513 if (dwIn != AD_COUNTERCLOCKWISE && dwIn != AD_CLOCKWISE)
514 {
515 EngSetLastError(ERROR_INVALID_PARAMETER);
516 Ret = FALSE;
517 break;
518 }
519 if (pdcattr->dwLayout & LAYOUT_RTL) // Right to Left
520 {
521 SafeResult = AD_CLOCKWISE - ((pdc->dclevel.flPath & DCPATH_CLOCKWISE) != 0);
522 if (dwIn == AD_CLOCKWISE)
523 {
524 pdc->dclevel.flPath &= ~DCPATH_CLOCKWISE;
525 break;
526 }
527 pdc->dclevel.flPath |= DCPATH_CLOCKWISE;
528 }
529 else // Left to Right
530 {
531 SafeResult = ((pdc->dclevel.flPath & DCPATH_CLOCKWISE) != 0) +
532 AD_COUNTERCLOCKWISE;
533 if (dwIn == AD_COUNTERCLOCKWISE)
534 {
535 pdc->dclevel.flPath &= ~DCPATH_CLOCKWISE;
536 break;
537 }
538 pdc->dclevel.flPath |= DCPATH_CLOCKWISE;
539 }
540 break;
541
542 default:
543 EngSetLastError(ERROR_INVALID_PARAMETER);
544 Ret = FALSE;
545 break;
546 }
547
548 if (Ret)
549 {
550 _SEH2_TRY
551 {
552 ProbeForWrite(pdwResult, sizeof(DWORD), 1);
553 *pdwResult = SafeResult;
554 }
555 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
556 {
557 Status = _SEH2_GetExceptionCode();
558 }
559 _SEH2_END;
560
561 if (!NT_SUCCESS(Status))
562 {
563 SetLastNtError(Status);
564 Ret = FALSE;
565 }
566 }
567
568 DC_UnlockDc(pdc);
569 return Ret;
570 }
571
572 DWORD
573 APIENTRY
574 NtGdiGetBoundsRect(
575 IN HDC hdc,
576 OUT LPRECT prc,
577 IN DWORD flags)
578 {
579 DWORD ret;
580 PDC pdc;
581
582 /* Lock the DC */
583 if (!(pdc = DC_LockDc(hdc))) return 0;
584
585 /* Get the return value */
586 ret = pdc->fs & DC_ACCUM_APP ? DCB_ENABLE : DCB_DISABLE;
587 ret |= RECTL_bIsEmptyRect(&pdc->erclBoundsApp) ? DCB_RESET : DCB_SET;
588
589 /* Copy the rect to the caller */
590 _SEH2_TRY
591 {
592 ProbeForWrite(prc, sizeof(RECT), 1);
593 *prc = pdc->erclBoundsApp;
594 }
595 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
596 {
597 ret = 0;
598 }
599 _SEH2_END;
600
601 if (flags & DCB_RESET)
602 {
603 RECTL_vSetEmptyRect(&pdc->erclBoundsApp);
604 }
605
606 DC_UnlockDc(pdc);
607 return ret;
608 }
609
610
611 DWORD
612 APIENTRY
613 NtGdiSetBoundsRect(
614 IN HDC hdc,
615 IN LPRECT prc,
616 IN DWORD flags)
617 {
618 DWORD ret;
619 PDC pdc;
620 RECTL rcl;
621
622 /* Verify arguments */
623 if ((flags & DCB_ENABLE) && (flags & DCB_DISABLE)) return 0;
624
625 /* Lock the DC */
626 if (!(pdc = DC_LockDc(hdc))) return 0;
627
628 /* Get the return value */
629 ret = pdc->fs & DC_ACCUM_APP ? DCB_ENABLE : DCB_DISABLE;
630 ret |= RECTL_bIsEmptyRect(&pdc->erclBoundsApp) ? DCB_RESET : DCB_SET;
631
632 if (flags & DCB_RESET)
633 {
634 RECTL_vSetEmptyRect(&pdc->erclBoundsApp);
635 }
636
637 if (flags & DCB_ACCUMULATE)
638 {
639 /* Capture the rect */
640 _SEH2_TRY
641 {
642 ProbeForRead(prc, sizeof(RECT), 1);
643 rcl = *prc;
644 }
645 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
646 {
647 DC_UnlockDc(pdc);
648 _SEH2_YIELD(return 0;)
649 }
650 _SEH2_END;
651
652 RECTL_vMakeWellOrdered(&rcl);
653 RECTL_bUnionRect(&pdc->erclBoundsApp, &pdc->erclBoundsApp, &rcl);
654 }
655
656 if (flags & DCB_ENABLE) pdc->fs |= DC_ACCUM_APP;
657 if (flags & DCB_DISABLE) pdc->fs &= ~DC_ACCUM_APP;
658 DC_UnlockDc(pdc);
659 return ret;
660 }
661
662 /* Translates a COLORREF to the right color in the specified DC color space */
663 ULONG
664 TranslateCOLORREF(PDC pdc, COLORREF crColor)
665 {
666 PSURFACE psurfDC;
667 PPALETTE ppalDC;
668 ULONG index, ulColor, iBitmapFormat;
669 EXLATEOBJ exlo;
670
671 /* Get the DC surface */
672 psurfDC = pdc->dclevel.pSurface;
673
674 /* If no surface is selected, use the default bitmap */
675 if (!psurfDC)
676 psurfDC = psurfDefaultBitmap;
677
678 /* Check what color type this is */
679 switch (crColor >> 24)
680 {
681 case 0x00: /* RGB color */
682 break;
683
684 case 0x01: /* PALETTEINDEX */
685 index = crColor & 0xFFFFFF;
686 ppalDC = pdc->dclevel.ppal;
687 if (index >= ppalDC->NumColors) index = 0;
688
689 /* Get the RGB value */
690 crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, index);
691 break;
692
693 case 0x02: /* PALETTERGB */
694
695 if (pdc->dclevel.hpal != StockObjects[DEFAULT_PALETTE])
696 {
697 /* First find the nearest index in the dc palette */
698 ppalDC = pdc->dclevel.ppal;
699 index = PALETTE_ulGetNearestIndex(ppalDC, crColor & 0xFFFFFF);
700
701 /* Get the RGB value */
702 crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, index);
703 }
704 else
705 {
706 /* Use the pure color */
707 crColor = crColor & 0x00FFFFFF;
708 }
709 break;
710
711 case 0x10: /* DIBINDEX */
712 /* Mask the value to match the target bpp */
713 iBitmapFormat = psurfDC->SurfObj.iBitmapFormat;
714 if (iBitmapFormat == BMF_1BPP) index = crColor & 0x1;
715 else if (iBitmapFormat == BMF_4BPP) index = crColor & 0xf;
716 else if (iBitmapFormat == BMF_8BPP) index = crColor & 0xFF;
717 else if (iBitmapFormat == BMF_16BPP) index = crColor & 0xFFFF;
718 else index = crColor & 0xFFFFFF;
719 return index;
720
721 default:
722 DPRINT("Unsupported color type %u passed\n", crColor >> 24);
723 crColor &= 0xFFFFFF;
724 }
725
726 /* Initialize an XLATEOBJ from RGB to the target surface */
727 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, psurfDC->ppal, 0xFFFFFF, 0, 0);
728
729 /* Translate the color to the target format */
730 ulColor = XLATEOBJ_iXlate(&exlo.xlo, crColor);
731
732 /* Cleanup the XLATEOBJ */
733 EXLATEOBJ_vCleanup(&exlo);
734
735 return ulColor;
736 }
737
738