Sync with trunk r63786.
[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: 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 return IntGdiCombineRgn(dc->dclevel.prgnClip, prgn, NULL, RGN_COPY);
64 }
65
66 ASSERT(prgn != NULL);
67
68 if (!dc->dclevel.prgnClip)
69 {
70 RECTL rect;
71
72 REGION_GetRgnBox(dc->prgnVis, &rect);
73 dc->dclevel.prgnClip = IntSysCreateRectpRgnIndirect(&rect);
74 }
75
76 dc->fs |= DC_FLAG_DIRTY_RAO;
77
78 return IntGdiCombineRgn(dc->dclevel.prgnClip, dc->dclevel.prgnClip, prgn, fnMode);
79 }
80
81
82 int
83 APIENTRY
84 NtGdiExtSelectClipRgn(
85 HDC hDC,
86 HRGN hrgn,
87 int fnMode)
88 {
89 int retval;
90 DC *dc;
91 PREGION prgn;
92
93 if (!(dc = DC_LockDc(hDC)))
94 {
95 EngSetLastError(ERROR_INVALID_HANDLE);
96 return ERROR;
97 }
98
99 prgn = REGION_LockRgn(hrgn);
100
101 if ((prgn == NULL) && (fnMode != RGN_COPY))
102 {
103 EngSetLastError(ERROR_INVALID_HANDLE);
104 retval = ERROR;
105 }
106 else
107 {
108 retval = IntGdiExtSelectClipRgn(dc, prgn, fnMode);
109 }
110
111 if (prgn)
112 REGION_UnlockRgn(prgn);
113
114 DC_UnlockDc(dc);
115 return retval;
116 }
117
118 INT FASTCALL
119 GdiGetClipBox(HDC hDC, PRECTL rc)
120 {
121 INT retval;
122 PDC dc;
123 PROSRGNDATA pRgnNew, pRgn = NULL;
124
125 if (!(dc = DC_LockDc(hDC)))
126 {
127 return ERROR;
128 }
129
130 if (dc->fs & DC_FLAG_DIRTY_RAO)
131 CLIPPING_UpdateGCRegion(dc);
132
133 /* FIXME: Rao and Vis only! */
134 if (dc->prgnAPI) // APIRGN
135 {
136 pRgn = dc->prgnAPI;
137 }
138 else if (dc->dclevel.prgnMeta) // METARGN
139 {
140 pRgn = dc->dclevel.prgnMeta;
141 }
142 else if (dc->dclevel.prgnClip) // CLIPRGN
143 {
144 pRgn = dc->dclevel.prgnClip;
145 }
146
147 if (pRgn)
148 {
149 pRgnNew = IntSysCreateRectpRgn( 0, 0, 0, 0 );
150
151 if (!pRgnNew)
152 {
153 DC_UnlockDc(dc);
154 return ERROR;
155 }
156
157 IntGdiCombineRgn(pRgnNew, dc->prgnVis, pRgn, RGN_AND);
158
159 retval = REGION_GetRgnBox(pRgnNew, rc);
160
161 REGION_Delete(pRgnNew);
162
163 DC_UnlockDc(dc);
164 return retval;
165 }
166
167 retval = REGION_GetRgnBox(dc->prgnVis, rc);
168
169 DC_UnlockDc(dc);
170
171 return retval;
172 }
173
174 INT APIENTRY
175 NtGdiGetAppClipBox(HDC hDC, PRECTL rc)
176 {
177 INT Ret;
178 NTSTATUS Status = STATUS_SUCCESS;
179 RECTL Saferect;
180
181 Ret = GdiGetClipBox(hDC, &Saferect);
182
183 _SEH2_TRY
184 {
185 ProbeForWrite(rc,
186 sizeof(RECT),
187 1);
188 *rc = Saferect;
189 }
190 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
191 {
192 Status = _SEH2_GetExceptionCode();
193 }
194 _SEH2_END;
195
196 if(!NT_SUCCESS(Status))
197 {
198 SetLastNtError(Status);
199 return ERROR;
200 }
201
202 return Ret;
203 }
204
205 int APIENTRY NtGdiExcludeClipRect(HDC hDC,
206 int LeftRect,
207 int TopRect,
208 int RightRect,
209 int BottomRect)
210 {
211 INT Result;
212 RECTL Rect;
213 PREGION prgnNew;
214 PDC dc = DC_LockDc(hDC);
215
216 if (!dc)
217 {
218 EngSetLastError(ERROR_INVALID_HANDLE);
219 return ERROR;
220 }
221
222 Rect.left = LeftRect;
223 Rect.top = TopRect;
224 Rect.right = RightRect;
225 Rect.bottom = BottomRect;
226
227 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
228
229 prgnNew = IntSysCreateRectpRgnIndirect(&Rect);
230 if (!prgnNew)
231 {
232 Result = ERROR;
233 }
234 else
235 {
236 if (!dc->dclevel.prgnClip)
237 {
238 dc->dclevel.prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0);
239 IntGdiCombineRgn(dc->dclevel.prgnClip, dc->prgnVis, prgnNew, RGN_DIFF);
240 Result = SIMPLEREGION;
241 }
242 else
243 {
244 Result = IntGdiCombineRgn(dc->dclevel.prgnClip, dc->dclevel.prgnClip, prgnNew, RGN_DIFF);
245 }
246 REGION_Delete(prgnNew);
247 }
248 if (Result != ERROR)
249 dc->fs |= DC_FLAG_DIRTY_RAO;
250
251 DC_UnlockDc(dc);
252
253 return Result;
254 }
255
256 int APIENTRY NtGdiIntersectClipRect(HDC hDC,
257 int LeftRect,
258 int TopRect,
259 int RightRect,
260 int BottomRect)
261 {
262 INT Result;
263 RECTL Rect;
264 PREGION pNewRgn;
265 PDC dc = DC_LockDc(hDC);
266
267 DPRINT("NtGdiIntersectClipRect(%p, %d,%d-%d,%d)\n",
268 hDC, LeftRect, TopRect, RightRect, BottomRect);
269
270 if (!dc)
271 {
272 EngSetLastError(ERROR_INVALID_HANDLE);
273 return ERROR;
274 }
275
276 Rect.left = LeftRect;
277 Rect.top = TopRect;
278 Rect.right = RightRect;
279 Rect.bottom = BottomRect;
280
281 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
282
283 pNewRgn = IntSysCreateRectpRgnIndirect(&Rect);
284 if (!pNewRgn)
285 {
286 Result = ERROR;
287 }
288 else if (!dc->dclevel.prgnClip)
289 {
290 dc->dclevel.prgnClip = pNewRgn;
291 Result = SIMPLEREGION;
292 }
293 else
294 {
295 Result = IntGdiCombineRgn(dc->dclevel.prgnClip, dc->dclevel.prgnClip, pNewRgn, RGN_AND);
296 REGION_Delete(pNewRgn);
297 }
298 if (Result != ERROR)
299 dc->fs |= DC_FLAG_DIRTY_RAO;
300
301 DC_UnlockDc(dc);
302
303 return Result;
304 }
305
306 int APIENTRY NtGdiOffsetClipRgn(HDC hDC,
307 int XOffset,
308 int YOffset)
309 {
310 INT Result;
311 DC *dc;
312
313 if(!(dc = DC_LockDc(hDC)))
314 {
315 EngSetLastError(ERROR_INVALID_HANDLE);
316 return ERROR;
317 }
318
319 if(dc->dclevel.prgnClip != NULL)
320 {
321 Result = IntGdiOffsetRgn(dc->dclevel.prgnClip,
322 XOffset,
323 YOffset);
324 dc->fs |= DC_FLAG_DIRTY_RAO;
325 }
326 else
327 {
328 Result = NULLREGION;
329 }
330
331 DC_UnlockDc(dc);
332 return Result;
333 }
334
335 BOOL APIENTRY NtGdiPtVisible(HDC hDC,
336 int X,
337 int Y)
338 {
339 BOOL ret = FALSE;
340 PDC dc;
341
342 if(!(dc = DC_LockDc(hDC)))
343 {
344 EngSetLastError(ERROR_INVALID_HANDLE);
345 return FALSE;
346 }
347
348 if (dc->prgnRao)
349 {
350 POINT pt = {X, Y};
351 IntLPtoDP(dc, &pt, 1);
352 ret = REGION_PtInRegion(dc->prgnRao, pt.x, pt.y);
353 }
354
355 DC_UnlockDc(dc);
356
357 return ret;
358 }
359
360 BOOL
361 APIENTRY
362 NtGdiRectVisible(
363 HDC hDC,
364 LPRECT UnsafeRect)
365 {
366 NTSTATUS Status = STATUS_SUCCESS;
367 PDC dc = DC_LockDc(hDC);
368 BOOL Result = FALSE;
369 RECTL Rect;
370
371 if (!dc)
372 {
373 EngSetLastError(ERROR_INVALID_HANDLE);
374 return FALSE;
375 }
376
377 _SEH2_TRY
378 {
379 ProbeForRead(UnsafeRect,
380 sizeof(RECT),
381 1);
382 Rect = *UnsafeRect;
383 }
384 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
385 {
386 Status = _SEH2_GetExceptionCode();
387 }
388 _SEH2_END;
389
390 if(!NT_SUCCESS(Status))
391 {
392 DC_UnlockDc(dc);
393 SetLastNtError(Status);
394 return FALSE;
395 }
396
397 if (dc->fs & DC_FLAG_DIRTY_RAO)
398 CLIPPING_UpdateGCRegion(dc);
399
400 if (dc->prgnRao)
401 {
402 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
403 Result = REGION_RectInRegion(dc->prgnRao, &Rect);
404 }
405 DC_UnlockDc(dc);
406
407 return Result;
408 }
409
410 int
411 FASTCALL
412 IntGdiSetMetaRgn(PDC pDC)
413 {
414 INT Ret = ERROR;
415
416 if ( pDC->dclevel.prgnMeta )
417 {
418 if ( pDC->dclevel.prgnClip )
419 {
420 Ret = IntGdiCombineRgn(pDC->dclevel.prgnMeta, pDC->dclevel.prgnMeta, pDC->dclevel.prgnClip, RGN_AND);
421 if (Ret != ERROR)
422 {
423 REGION_Delete(pDC->dclevel.prgnClip);
424 pDC->dclevel.prgnClip = NULL;
425 IntGdiReleaseRaoRgn(pDC);
426 }
427 }
428 else
429 Ret = REGION_Complexity(pDC->dclevel.prgnMeta);
430 }
431 else
432 {
433 if ( pDC->dclevel.prgnClip )
434 {
435 Ret = REGION_Complexity(pDC->dclevel.prgnClip);
436 pDC->dclevel.prgnMeta = pDC->dclevel.prgnClip;
437 pDC->dclevel.prgnClip = NULL;
438 }
439 else
440 Ret = SIMPLEREGION;
441 }
442
443 if (Ret != ERROR)
444 pDC->fs |= DC_FLAG_DIRTY_RAO;
445
446 return Ret;
447 }
448
449
450 int APIENTRY NtGdiSetMetaRgn(HDC hDC)
451 {
452 INT Ret;
453 PDC pDC = DC_LockDc(hDC);
454
455 if (!pDC)
456 {
457 EngSetLastError(ERROR_INVALID_PARAMETER);
458 return ERROR;
459 }
460 Ret = IntGdiSetMetaRgn(pDC);
461
462 DC_UnlockDc(pDC);
463 return Ret;
464 }
465
466 VOID
467 FASTCALL
468 CLIPPING_UpdateGCRegion(PDC pDC)
469 {
470 /* Must have VisRgn set to a valid state! */
471 ASSERT (pDC->prgnVis);
472
473 if (pDC->prgnAPI)
474 {
475 REGION_Delete(pDC->prgnAPI);
476 pDC->prgnAPI = NULL;
477 }
478
479 if (pDC->prgnRao)
480 REGION_Delete(pDC->prgnRao);
481
482 pDC->prgnRao = IntSysCreateRectpRgn(0,0,0,0);
483
484 ASSERT(pDC->prgnRao);
485
486 if (pDC->dclevel.prgnMeta || pDC->dclevel.prgnClip)
487 {
488 pDC->prgnAPI = IntSysCreateRectpRgn(0,0,0,0);
489 if (!pDC->dclevel.prgnMeta)
490 {
491 IntGdiCombineRgn(pDC->prgnAPI,
492 pDC->dclevel.prgnClip,
493 NULL,
494 RGN_COPY);
495 }
496 else if (!pDC->dclevel.prgnClip)
497 {
498 IntGdiCombineRgn(pDC->prgnAPI,
499 pDC->dclevel.prgnMeta,
500 NULL,
501 RGN_COPY);
502 }
503 else
504 {
505 IntGdiCombineRgn(pDC->prgnAPI,
506 pDC->dclevel.prgnClip,
507 pDC->dclevel.prgnMeta,
508 RGN_AND);
509 }
510 }
511
512 if (pDC->prgnAPI)
513 {
514 IntGdiCombineRgn(pDC->prgnRao,
515 pDC->prgnVis,
516 pDC->prgnAPI,
517 RGN_AND);
518 }
519 else
520 {
521 IntGdiCombineRgn(pDC->prgnRao,
522 pDC->prgnVis,
523 NULL,
524 RGN_COPY);
525 }
526
527
528 IntGdiOffsetRgn(pDC->prgnRao, pDC->ptlDCOrig.x, pDC->ptlDCOrig.y);
529
530 RtlCopyMemory(&pDC->erclClip,
531 &pDC->prgnRao->rdh.rcBound,
532 sizeof(RECTL));
533
534 pDC->fs &= ~DC_FLAG_DIRTY_RAO;
535
536 // pDC->co should be used. Example, CLIPOBJ_cEnumStart uses XCLIPOBJ to build
537 // the rects from region objects rects in pClipRgn->Buffer.
538 // With pDC->co.pClipRgn->Buffer,
539 // pDC->co.pClipRgn = pDC->prgnRao ? pDC->prgnRao : pDC->prgnVis;
540
541 IntEngUpdateClipRegion(&pDC->co,
542 pDC->prgnRao->rdh.nCount,
543 pDC->prgnRao->Buffer,
544 &pDC->erclClip);
545
546 IntGdiOffsetRgn(pDC->prgnRao, -pDC->ptlDCOrig.x, -pDC->ptlDCOrig.y);
547 }
548
549 /* EOF */