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