2f4f53c5254986515a70b0facc0f6d83ad07b70e
[reactos.git] / win32ss / gdi / ntgdi / cliprgn.c
1 /*
2 * COPYRIGHT: GNU GPL, See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Clip region functions
5 * FILE: win32ss/gdi/ntgdi/cliprgn.c
6 * PROGRAMER: Unknown
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 VOID
15 FASTCALL
16 IntGdiReleaseRaoRgn(PDC pDC)
17 {
18 INT Index = GDI_HANDLE_GET_INDEX(pDC->BaseObject.hHmgr);
19 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
20 pDC->fs |= DC_FLAG_DIRTY_RAO;
21 Entry->Flags |= GDI_ENTRY_VALIDATE_VIS;
22 RECTL_vSetEmptyRect(&pDC->erclClip);
23 REGION_Delete(pDC->prgnRao);
24 pDC->prgnRao = NULL;
25 }
26
27 VOID
28 FASTCALL
29 IntGdiReleaseVisRgn(PDC pDC)
30 {
31 INT Index = GDI_HANDLE_GET_INDEX(pDC->BaseObject.hHmgr);
32 PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
33 pDC->fs |= DC_FLAG_DIRTY_RAO;
34 Entry->Flags |= GDI_ENTRY_VALIDATE_VIS;
35 RECTL_vSetEmptyRect(&pDC->erclClip);
36 REGION_Delete(pDC->prgnVis);
37 pDC->prgnVis = prgnDefault;
38 }
39
40 VOID
41 FASTCALL
42 GdiSelectVisRgn(
43 HDC hdc,
44 PREGION prgn)
45 {
46 DC *dc;
47
48 if (!(dc = DC_LockDc(hdc)))
49 {
50 EngSetLastError(ERROR_INVALID_HANDLE);
51 return;
52 }
53
54 dc->fs |= DC_FLAG_DIRTY_RAO;
55
56 ASSERT(dc->prgnVis != NULL);
57 ASSERT(prgn != NULL);
58
59 IntGdiCombineRgn(dc->prgnVis, prgn, NULL, RGN_COPY);
60 REGION_bOffsetRgn(dc->prgnVis, -dc->ptlDCOrig.x, -dc->ptlDCOrig.y);
61
62 DC_UnlockDc(dc);
63 }
64
65
66 int
67 FASTCALL
68 IntGdiExtSelectClipRgn(
69 PDC dc,
70 PREGION prgn,
71 int fnMode)
72 {
73 if (fnMode == RGN_COPY)
74 {
75 if (!prgn)
76 {
77 if (dc->dclevel.prgnClip != NULL)
78 {
79 REGION_Delete(dc->dclevel.prgnClip);
80 dc->dclevel.prgnClip = NULL;
81 dc->fs |= DC_FLAG_DIRTY_RAO;
82 }
83 return SIMPLEREGION;
84 }
85
86 if (!dc->dclevel.prgnClip)
87 dc->dclevel.prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0);
88
89 dc->fs |= DC_FLAG_DIRTY_RAO;
90
91 return IntGdiCombineRgn(dc->dclevel.prgnClip, prgn, NULL, RGN_COPY);
92 }
93
94 ASSERT(prgn != NULL);
95
96 if (!dc->dclevel.prgnClip)
97 {
98 RECTL rect;
99
100 REGION_GetRgnBox(dc->prgnVis, &rect);
101 dc->dclevel.prgnClip = IntSysCreateRectpRgnIndirect(&rect);
102 }
103
104 dc->fs |= DC_FLAG_DIRTY_RAO;
105
106 return IntGdiCombineRgn(dc->dclevel.prgnClip, dc->dclevel.prgnClip, prgn, fnMode);
107 }
108
109
110 int
111 APIENTRY
112 NtGdiExtSelectClipRgn(
113 HDC hDC,
114 HRGN hrgn,
115 int fnMode)
116 {
117 int retval;
118 DC *dc;
119 PREGION prgn;
120
121 if (!(dc = DC_LockDc(hDC)))
122 {
123 EngSetLastError(ERROR_INVALID_HANDLE);
124 return ERROR;
125 }
126
127 prgn = REGION_LockRgn(hrgn);
128
129 if ((prgn == NULL) && (fnMode != RGN_COPY))
130 {
131 EngSetLastError(ERROR_INVALID_HANDLE);
132 retval = ERROR;
133 }
134 else
135 {
136 retval = IntGdiExtSelectClipRgn(dc, prgn, fnMode);
137 }
138
139 if (prgn)
140 REGION_UnlockRgn(prgn);
141
142 DC_UnlockDc(dc);
143 return retval;
144 }
145
146 _Success_(return!=ERROR)
147 INT
148 FASTCALL
149 GdiGetClipBox(
150 _In_ HDC hdc,
151 _Out_ LPRECT prc)
152 {
153 PDC pdc;
154 INT iComplexity;
155
156 /* Lock the DC */
157 pdc = DC_LockDc(hdc);
158 if (!pdc)
159 {
160 return ERROR;
161 }
162
163 /* Update RAO region if necessary */
164 if (pdc->fs & DC_FLAG_DIRTY_RAO)
165 CLIPPING_UpdateGCRegion(pdc);
166
167 /* Check if we have a RAO region (intersection of API and VIS region) */
168 if (pdc->prgnRao)
169 {
170 /* We have a RAO region, use it */
171 iComplexity = REGION_GetRgnBox(pdc->prgnRao, prc);
172 }
173 else
174 {
175 /* No RAO region means no API region, so use the VIS region */
176 ASSERT(pdc->prgnVis);
177 iComplexity = REGION_GetRgnBox(pdc->prgnVis, prc);
178 }
179
180 /* Unlock the DC */
181 DC_UnlockDc(pdc);
182
183 /* Convert the rect to logical coordinates */
184 IntDPtoLP(pdc, (LPPOINT)prc, 2);
185
186 /* Return the complexity */
187 return iComplexity;
188 }
189
190 _Success_(return!=ERROR)
191 INT
192 APIENTRY
193 NtGdiGetAppClipBox(
194 _In_ HDC hdc,
195 _Out_ LPRECT prc)
196 {
197 RECT rect;
198 INT iComplexity;
199
200 /* Call the internal function */
201 iComplexity = GdiGetClipBox(hdc, &rect);
202
203 if (iComplexity != ERROR)
204 {
205 _SEH2_TRY
206 {
207 ProbeForWrite(prc, sizeof(RECT), 1);
208 *prc = rect;
209 }
210 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
211 {
212 iComplexity = ERROR;
213 }
214 _SEH2_END
215 }
216
217 /* Return the complexity */
218 return iComplexity;
219 }
220
221 INT
222 APIENTRY
223 NtGdiExcludeClipRect(
224 _In_ HDC hdc,
225 _In_ INT xLeft,
226 _In_ INT yTop,
227 _In_ INT xRight,
228 _In_ INT yBottom)
229 {
230 INT iComplexity;
231 RECTL rect;
232 PDC pdc;
233
234 /* Lock the DC */
235 pdc = DC_LockDc(hdc);
236 if (pdc == NULL)
237 {
238 EngSetLastError(ERROR_INVALID_HANDLE);
239 return ERROR;
240 }
241
242 /* Convert coordinates to device space */
243 rect.left = xLeft;
244 rect.top = yTop;
245 rect.right = xRight;
246 rect.bottom = yBottom;
247 RECTL_vMakeWellOrdered(&rect);
248 IntLPtoDP(pdc, (LPPOINT)&rect, 2);
249
250 /* Check if we already have a clip region */
251 if (pdc->dclevel.prgnClip != NULL)
252 {
253 /* We have a region, subtract the rect */
254 iComplexity = REGION_SubtractRectFromRgn(pdc->dclevel.prgnClip,
255 pdc->dclevel.prgnClip,
256 &rect);
257 }
258 else
259 {
260 /* We don't have a clip region yet, create an empty region */
261 pdc->dclevel.prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0);
262 if (pdc->dclevel.prgnClip == NULL)
263 {
264 iComplexity = ERROR;
265 }
266 else
267 {
268 /* Subtract the rect from the VIS region */
269 iComplexity = REGION_SubtractRectFromRgn(pdc->dclevel.prgnClip,
270 pdc->prgnVis,
271 &rect);
272 }
273 }
274
275 /* Emulate Windows behavior */
276 if (iComplexity == SIMPLEREGION)
277 iComplexity = COMPLEXREGION;
278
279 /* If we succeeded, mark the RAO region as dirty */
280 if (iComplexity != ERROR)
281 pdc->fs |= DC_FLAG_DIRTY_RAO;
282
283 /* Unlock the DC */
284 DC_UnlockDc(pdc);
285
286 return iComplexity;
287 }
288
289 INT
290 APIENTRY
291 NtGdiIntersectClipRect(
292 _In_ HDC hdc,
293 _In_ INT xLeft,
294 _In_ INT yTop,
295 _In_ INT xRight,
296 _In_ INT yBottom)
297 {
298 INT iComplexity;
299 RECTL rect;
300 PREGION prgnNew;
301 PDC pdc;
302
303 DPRINT("NtGdiIntersectClipRect(%p, %d,%d-%d,%d)\n",
304 hdc, xLeft, yTop, xRight, yBottom);
305
306 /* Lock the DC */
307 pdc = DC_LockDc(hdc);
308 if (!pdc)
309 {
310 EngSetLastError(ERROR_INVALID_HANDLE);
311 return ERROR;
312 }
313
314 /* Convert coordinates to device space */
315 rect.left = xLeft;
316 rect.top = yTop;
317 rect.right = xRight;
318 rect.bottom = yBottom;
319 IntLPtoDP(pdc, (LPPOINT)&rect, 2);
320
321 /* Check if we already have a clip region */
322 if (pdc->dclevel.prgnClip != NULL)
323 {
324 /* We have a region, crop it */
325 iComplexity = REGION_CropRegion(pdc->dclevel.prgnClip,
326 pdc->dclevel.prgnClip,
327 &rect);
328 }
329 else
330 {
331 /* We don't have a region yet, allocate a new one */
332 prgnNew = IntSysCreateRectpRgnIndirect(&rect);
333 if (prgnNew == NULL)
334 {
335 iComplexity = ERROR;
336 }
337 else
338 {
339 /* Set the new region */
340 pdc->dclevel.prgnClip = prgnNew;
341 iComplexity = SIMPLEREGION;
342 }
343 }
344
345 /* If we succeeded, mark the RAO region as dirty */
346 if (iComplexity != ERROR)
347 pdc->fs |= DC_FLAG_DIRTY_RAO;
348
349 /* Unlock the DC */
350 DC_UnlockDc(pdc);
351
352 return iComplexity;
353 }
354
355 INT
356 APIENTRY
357 NtGdiOffsetClipRgn(
358 _In_ HDC hdc,
359 _In_ INT xOffset,
360 _In_ INT yOffset)
361 {
362 INT iComplexity;
363 PDC pdc;
364 POINTL apt[2];
365
366 /* Lock the DC */
367 pdc = DC_LockDc(hdc);
368 if (pdc == NULL)
369 {
370 return ERROR;
371 }
372
373 /* Check if we have a clip region */
374 if (pdc->dclevel.prgnClip != NULL)
375 {
376 /* Convert coordinates into device space. Note that we need to convert
377 2 coordinates to account for rotation / shear / offset */
378 apt[0].x = 0;
379 apt[0].y = 0;
380 apt[1].x = xOffset;
381 apt[1].y = yOffset;
382 IntLPtoDP(pdc, &apt, 2);
383
384 /* Offset the clip region */
385 if (!REGION_bOffsetRgn(pdc->dclevel.prgnClip,
386 apt[1].x - apt[0].x,
387 apt[1].y - apt[0].y))
388 {
389 iComplexity = ERROR;
390 }
391 else
392 {
393 iComplexity = REGION_Complexity(pdc->dclevel.prgnClip);
394 }
395
396 /* Mark the RAO region as dirty */
397 pdc->fs |= DC_FLAG_DIRTY_RAO;
398 }
399 else
400 {
401 /* NULL means no clipping, i.e. the "whole" region */
402 iComplexity = SIMPLEREGION;
403 }
404
405 /* Unlock the DC and return the complexity */
406 DC_UnlockDc(pdc);
407 return iComplexity;
408 }
409
410 BOOL APIENTRY NtGdiPtVisible(HDC hDC,
411 int X,
412 int Y)
413 {
414 BOOL ret = FALSE;
415 PDC dc;
416
417 if(!(dc = DC_LockDc(hDC)))
418 {
419 EngSetLastError(ERROR_INVALID_HANDLE);
420 return FALSE;
421 }
422
423 if (dc->prgnRao)
424 {
425 POINT pt = {X, Y};
426 IntLPtoDP(dc, &pt, 1);
427 ret = REGION_PtInRegion(dc->prgnRao, pt.x, pt.y);
428 }
429
430 DC_UnlockDc(dc);
431
432 return ret;
433 }
434
435 BOOL
436 APIENTRY
437 NtGdiRectVisible(
438 HDC hDC,
439 LPRECT UnsafeRect)
440 {
441 NTSTATUS Status = STATUS_SUCCESS;
442 PDC dc = DC_LockDc(hDC);
443 BOOL Result = FALSE;
444 RECTL Rect;
445
446 if (!dc)
447 {
448 EngSetLastError(ERROR_INVALID_HANDLE);
449 return FALSE;
450 }
451
452 _SEH2_TRY
453 {
454 ProbeForRead(UnsafeRect,
455 sizeof(RECT),
456 1);
457 Rect = *UnsafeRect;
458 }
459 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
460 {
461 Status = _SEH2_GetExceptionCode();
462 }
463 _SEH2_END;
464
465 if(!NT_SUCCESS(Status))
466 {
467 DC_UnlockDc(dc);
468 SetLastNtError(Status);
469 return FALSE;
470 }
471
472 if (dc->fs & DC_FLAG_DIRTY_RAO)
473 CLIPPING_UpdateGCRegion(dc);
474
475 if (dc->prgnRao)
476 {
477 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
478 Result = REGION_RectInRegion(dc->prgnRao, &Rect);
479 }
480 DC_UnlockDc(dc);
481
482 return Result;
483 }
484
485 int
486 FASTCALL
487 IntGdiSetMetaRgn(PDC pDC)
488 {
489 INT Ret = ERROR;
490
491 if ( pDC->dclevel.prgnMeta )
492 {
493 if ( pDC->dclevel.prgnClip )
494 {
495 // preferably REGION_IntersectRegion
496 Ret = IntGdiCombineRgn(pDC->dclevel.prgnMeta, pDC->dclevel.prgnMeta, pDC->dclevel.prgnClip, RGN_AND);
497 if (Ret != ERROR)
498 {
499 REGION_Delete(pDC->dclevel.prgnClip);
500 pDC->dclevel.prgnClip = NULL;
501 IntGdiReleaseRaoRgn(pDC);
502 }
503 }
504 else
505 Ret = REGION_Complexity(pDC->dclevel.prgnMeta);
506 }
507 else
508 {
509 if ( pDC->dclevel.prgnClip )
510 {
511 Ret = REGION_Complexity(pDC->dclevel.prgnClip);
512 pDC->dclevel.prgnMeta = pDC->dclevel.prgnClip;
513 pDC->dclevel.prgnClip = NULL;
514 }
515 else
516 Ret = SIMPLEREGION;
517 }
518
519 if (Ret != ERROR)
520 pDC->fs |= DC_FLAG_DIRTY_RAO;
521
522 return Ret;
523 }
524
525
526 int APIENTRY NtGdiSetMetaRgn(HDC hDC)
527 {
528 INT Ret;
529 PDC pDC = DC_LockDc(hDC);
530
531 if (!pDC)
532 {
533 EngSetLastError(ERROR_INVALID_PARAMETER);
534 return ERROR;
535 }
536 Ret = IntGdiSetMetaRgn(pDC);
537
538 DC_UnlockDc(pDC);
539 return Ret;
540 }
541
542 VOID
543 FASTCALL
544 CLIPPING_UpdateGCRegion(PDC pDC)
545 {
546 /* Must have VisRgn set to a valid state! */
547 ASSERT (pDC->prgnVis);
548
549 if (pDC->prgnAPI)
550 {
551 REGION_Delete(pDC->prgnAPI);
552 pDC->prgnAPI = NULL;
553 }
554
555 if (pDC->prgnRao)
556 REGION_Delete(pDC->prgnRao);
557
558 pDC->prgnRao = IntSysCreateRectpRgn(0,0,0,0);
559
560 ASSERT(pDC->prgnRao);
561
562 if (pDC->dclevel.prgnMeta || pDC->dclevel.prgnClip)
563 {
564 pDC->prgnAPI = IntSysCreateRectpRgn(0,0,0,0);
565 if (!pDC->dclevel.prgnMeta)
566 {
567 IntGdiCombineRgn(pDC->prgnAPI,
568 pDC->dclevel.prgnClip,
569 NULL,
570 RGN_COPY);
571 }
572 else if (!pDC->dclevel.prgnClip)
573 {
574 IntGdiCombineRgn(pDC->prgnAPI,
575 pDC->dclevel.prgnMeta,
576 NULL,
577 RGN_COPY);
578 }
579 else
580 {
581 IntGdiCombineRgn(pDC->prgnAPI,
582 pDC->dclevel.prgnClip,
583 pDC->dclevel.prgnMeta,
584 RGN_AND);
585 }
586 }
587
588 if (pDC->prgnAPI)
589 {
590 IntGdiCombineRgn(pDC->prgnRao,
591 pDC->prgnVis,
592 pDC->prgnAPI,
593 RGN_AND);
594 }
595 else
596 {
597 IntGdiCombineRgn(pDC->prgnRao,
598 pDC->prgnVis,
599 NULL,
600 RGN_COPY);
601 }
602
603
604 REGION_bOffsetRgn(pDC->prgnRao, pDC->ptlDCOrig.x, pDC->ptlDCOrig.y);
605
606 RtlCopyMemory(&pDC->erclClip,
607 &pDC->prgnRao->rdh.rcBound,
608 sizeof(RECTL));
609
610 pDC->fs &= ~DC_FLAG_DIRTY_RAO;
611
612 // pDC->co should be used. Example, CLIPOBJ_cEnumStart uses XCLIPOBJ to build
613 // the rects from region objects rects in pClipRgn->Buffer.
614 // With pDC->co.pClipRgn->Buffer,
615 // pDC->co.pClipRgn = pDC->prgnRao ? pDC->prgnRao : pDC->prgnVis;
616
617 IntEngUpdateClipRegion(&pDC->co,
618 pDC->prgnRao->rdh.nCount,
619 pDC->prgnRao->Buffer,
620 &pDC->erclClip);
621
622 REGION_bOffsetRgn(pDC->prgnRao, -pDC->ptlDCOrig.x, -pDC->ptlDCOrig.y);
623 }
624
625 /* EOF */