f6a89e382ddeccc385149a65e4fd61ed9f6e950d
[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 APIENTRY NtGdiExcludeClipRect(HDC hDC,
194 int LeftRect,
195 int TopRect,
196 int RightRect,
197 int BottomRect)
198 {
199 INT Result;
200 RECTL Rect;
201 PREGION prgnNew;
202 PDC dc = DC_LockDc(hDC);
203
204 if (!dc)
205 {
206 EngSetLastError(ERROR_INVALID_HANDLE);
207 return ERROR;
208 }
209
210 Rect.left = LeftRect;
211 Rect.top = TopRect;
212 Rect.right = RightRect;
213 Rect.bottom = BottomRect;
214
215 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
216
217 prgnNew = IntSysCreateRectpRgnIndirect(&Rect);
218 if (!prgnNew)
219 {
220 Result = ERROR;
221 }
222 else
223 {
224 if (!dc->dclevel.prgnClip)
225 {
226 dc->dclevel.prgnClip = IntSysCreateRectpRgn(0, 0, 0, 0);
227 IntGdiCombineRgn(dc->dclevel.prgnClip, dc->prgnVis, prgnNew, RGN_DIFF);
228 Result = SIMPLEREGION;
229 }
230 else
231 {
232 Result = IntGdiCombineRgn(dc->dclevel.prgnClip, dc->dclevel.prgnClip, prgnNew, RGN_DIFF);
233 }
234 REGION_Delete(prgnNew);
235 }
236 if (Result != ERROR)
237 dc->fs |= DC_FLAG_DIRTY_RAO;
238
239 DC_UnlockDc(dc);
240
241 return Result;
242 }
243
244 int APIENTRY NtGdiIntersectClipRect(HDC hDC,
245 int LeftRect,
246 int TopRect,
247 int RightRect,
248 int BottomRect)
249 {
250 INT Result;
251 RECTL Rect;
252 PREGION pNewRgn;
253 PDC dc = DC_LockDc(hDC);
254
255 DPRINT("NtGdiIntersectClipRect(%p, %d,%d-%d,%d)\n",
256 hDC, LeftRect, TopRect, RightRect, BottomRect);
257
258 if (!dc)
259 {
260 EngSetLastError(ERROR_INVALID_HANDLE);
261 return ERROR;
262 }
263
264 Rect.left = LeftRect;
265 Rect.top = TopRect;
266 Rect.right = RightRect;
267 Rect.bottom = BottomRect;
268
269 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
270
271 pNewRgn = IntSysCreateRectpRgnIndirect(&Rect);
272 if (!pNewRgn)
273 {
274 Result = ERROR;
275 }
276 else if (!dc->dclevel.prgnClip)
277 {
278 dc->dclevel.prgnClip = pNewRgn;
279 Result = SIMPLEREGION;
280 }
281 else
282 {
283 Result = IntGdiCombineRgn(dc->dclevel.prgnClip, dc->dclevel.prgnClip, pNewRgn, RGN_AND);
284 REGION_Delete(pNewRgn);
285 }
286 if (Result != ERROR)
287 dc->fs |= DC_FLAG_DIRTY_RAO;
288
289 DC_UnlockDc(dc);
290
291 return Result;
292 }
293
294 int APIENTRY NtGdiOffsetClipRgn(HDC hDC,
295 int XOffset,
296 int YOffset)
297 {
298 INT Result;
299 DC *dc;
300
301 if(!(dc = DC_LockDc(hDC)))
302 {
303 EngSetLastError(ERROR_INVALID_HANDLE);
304 return ERROR;
305 }
306
307 if(dc->dclevel.prgnClip != NULL)
308 {
309 Result = IntGdiOffsetRgn(dc->dclevel.prgnClip,
310 XOffset,
311 YOffset);
312 dc->fs |= DC_FLAG_DIRTY_RAO;
313 }
314 else
315 {
316 Result = NULLREGION;
317 }
318
319 DC_UnlockDc(dc);
320 return Result;
321 }
322
323 BOOL APIENTRY NtGdiPtVisible(HDC hDC,
324 int X,
325 int Y)
326 {
327 BOOL ret = FALSE;
328 PDC dc;
329
330 if(!(dc = DC_LockDc(hDC)))
331 {
332 EngSetLastError(ERROR_INVALID_HANDLE);
333 return FALSE;
334 }
335
336 if (dc->prgnRao)
337 {
338 POINT pt = {X, Y};
339 IntLPtoDP(dc, &pt, 1);
340 ret = REGION_PtInRegion(dc->prgnRao, pt.x, pt.y);
341 }
342
343 DC_UnlockDc(dc);
344
345 return ret;
346 }
347
348 BOOL
349 APIENTRY
350 NtGdiRectVisible(
351 HDC hDC,
352 LPRECT UnsafeRect)
353 {
354 NTSTATUS Status = STATUS_SUCCESS;
355 PDC dc = DC_LockDc(hDC);
356 BOOL Result = FALSE;
357 RECTL Rect;
358
359 if (!dc)
360 {
361 EngSetLastError(ERROR_INVALID_HANDLE);
362 return FALSE;
363 }
364
365 _SEH2_TRY
366 {
367 ProbeForRead(UnsafeRect,
368 sizeof(RECT),
369 1);
370 Rect = *UnsafeRect;
371 }
372 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
373 {
374 Status = _SEH2_GetExceptionCode();
375 }
376 _SEH2_END;
377
378 if(!NT_SUCCESS(Status))
379 {
380 DC_UnlockDc(dc);
381 SetLastNtError(Status);
382 return FALSE;
383 }
384
385 if (dc->fs & DC_FLAG_DIRTY_RAO)
386 CLIPPING_UpdateGCRegion(dc);
387
388 if (dc->prgnRao)
389 {
390 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
391 Result = REGION_RectInRegion(dc->prgnRao, &Rect);
392 }
393 DC_UnlockDc(dc);
394
395 return Result;
396 }
397
398 int
399 FASTCALL
400 IntGdiSetMetaRgn(PDC pDC)
401 {
402 INT Ret = ERROR;
403
404 if ( pDC->dclevel.prgnMeta )
405 {
406 if ( pDC->dclevel.prgnClip )
407 {
408 Ret = IntGdiCombineRgn(pDC->dclevel.prgnMeta, pDC->dclevel.prgnMeta, pDC->dclevel.prgnClip, RGN_AND);
409 if (Ret != ERROR)
410 {
411 REGION_Delete(pDC->dclevel.prgnClip);
412 pDC->dclevel.prgnClip = NULL;
413 IntGdiReleaseRaoRgn(pDC);
414 }
415 }
416 else
417 Ret = REGION_Complexity(pDC->dclevel.prgnMeta);
418 }
419 else
420 {
421 if ( pDC->dclevel.prgnClip )
422 {
423 Ret = REGION_Complexity(pDC->dclevel.prgnClip);
424 pDC->dclevel.prgnMeta = pDC->dclevel.prgnClip;
425 pDC->dclevel.prgnClip = NULL;
426 }
427 else
428 Ret = SIMPLEREGION;
429 }
430
431 if (Ret != ERROR)
432 pDC->fs |= DC_FLAG_DIRTY_RAO;
433
434 return Ret;
435 }
436
437
438 int APIENTRY NtGdiSetMetaRgn(HDC hDC)
439 {
440 INT Ret;
441 PDC pDC = DC_LockDc(hDC);
442
443 if (!pDC)
444 {
445 EngSetLastError(ERROR_INVALID_PARAMETER);
446 return ERROR;
447 }
448 Ret = IntGdiSetMetaRgn(pDC);
449
450 DC_UnlockDc(pDC);
451 return Ret;
452 }
453
454 VOID
455 FASTCALL
456 CLIPPING_UpdateGCRegion(PDC pDC)
457 {
458 /* Must have VisRgn set to a valid state! */
459 ASSERT (pDC->prgnVis);
460
461 if (pDC->prgnAPI)
462 {
463 REGION_Delete(pDC->prgnAPI);
464 pDC->prgnAPI = NULL;
465 }
466
467 if (pDC->prgnRao)
468 REGION_Delete(pDC->prgnRao);
469
470 pDC->prgnRao = IntSysCreateRectpRgn(0,0,0,0);
471
472 ASSERT(pDC->prgnRao);
473
474 if (pDC->dclevel.prgnMeta || pDC->dclevel.prgnClip)
475 {
476 pDC->prgnAPI = IntSysCreateRectpRgn(0,0,0,0);
477 if (!pDC->dclevel.prgnMeta)
478 {
479 IntGdiCombineRgn(pDC->prgnAPI,
480 pDC->dclevel.prgnClip,
481 NULL,
482 RGN_COPY);
483 }
484 else if (!pDC->dclevel.prgnClip)
485 {
486 IntGdiCombineRgn(pDC->prgnAPI,
487 pDC->dclevel.prgnMeta,
488 NULL,
489 RGN_COPY);
490 }
491 else
492 {
493 IntGdiCombineRgn(pDC->prgnAPI,
494 pDC->dclevel.prgnClip,
495 pDC->dclevel.prgnMeta,
496 RGN_AND);
497 }
498 }
499
500 if (pDC->prgnAPI)
501 {
502 IntGdiCombineRgn(pDC->prgnRao,
503 pDC->prgnVis,
504 pDC->prgnAPI,
505 RGN_AND);
506 }
507 else
508 {
509 IntGdiCombineRgn(pDC->prgnRao,
510 pDC->prgnVis,
511 NULL,
512 RGN_COPY);
513 }
514
515
516 IntGdiOffsetRgn(pDC->prgnRao, pDC->ptlDCOrig.x, pDC->ptlDCOrig.y);
517
518 RtlCopyMemory(&pDC->erclClip,
519 &pDC->prgnRao->rdh.rcBound,
520 sizeof(RECTL));
521
522 pDC->fs &= ~DC_FLAG_DIRTY_RAO;
523
524 // pDC->co should be used. Example, CLIPOBJ_cEnumStart uses XCLIPOBJ to build
525 // the rects from region objects rects in pClipRgn->Buffer.
526 // With pDC->co.pClipRgn->Buffer,
527 // pDC->co.pClipRgn = pDC->prgnRao ? pDC->prgnRao : pDC->prgnVis;
528
529 IntEngUpdateClipRegion(&pDC->co,
530 pDC->prgnRao->rdh.nCount,
531 pDC->prgnRao->Buffer,
532 &pDC->erclClip);
533
534 IntGdiOffsetRgn(pDC->prgnRao, -pDC->ptlDCOrig.x, -pDC->ptlDCOrig.y);
535 }
536
537 /* EOF */