[WIN32K]
[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
245 APIENTRY
246 NtGdiIntersectClipRect(
247 _In_ HDC hdc,
248 _In_ INT xLeft,
249 _In_ INT yTop,
250 _In_ INT xRight,
251 _In_ INT yBottom)
252 {
253 INT iComplexity;
254 RECTL rect;
255 PREGION prgnNew;
256 PDC pdc;
257
258 DPRINT("NtGdiIntersectClipRect(%p, %d,%d-%d,%d)\n",
259 hdc, xLeft, yTop, xRight, yBottom);
260
261 /* Lock the DC */
262 pdc = DC_LockDc(hdc);
263 if (!pdc)
264 {
265 EngSetLastError(ERROR_INVALID_HANDLE);
266 return ERROR;
267 }
268
269 /* Convert coordinates to device space */
270 rect.left = xLeft;
271 rect.top = yTop;
272 rect.right = xRight;
273 rect.bottom = yBottom;
274 IntLPtoDP(pdc, (LPPOINT)&rect, 2);
275
276 /* Check if we already have a clip region */
277 if (pdc->dclevel.prgnClip != NULL)
278 {
279 /* We have a region, crop it */
280 iComplexity = REGION_CropAndOffsetRegion(pdc->dclevel.prgnClip,
281 pdc->dclevel.prgnClip,
282 &rect,
283 NULL);
284 }
285 else
286 {
287 /* We don't have a region yet, allocate a new one */
288 prgnNew = IntSysCreateRectpRgnIndirect(&rect);
289 if (prgnNew == NULL)
290 {
291 iComplexity = ERROR;
292 }
293 else
294 {
295 /* Set the new region */
296 pdc->dclevel.prgnClip = prgnNew;
297 iComplexity = SIMPLEREGION;
298 }
299 }
300
301 /* If we succeeded, mark the RAO region as dirty */
302 if (iComplexity != ERROR)
303 pdc->fs |= DC_FLAG_DIRTY_RAO;
304
305 /* Unlock the DC */
306 DC_UnlockDc(pdc);
307
308 return iComplexity;
309 }
310
311 int APIENTRY NtGdiOffsetClipRgn(HDC hDC,
312 int XOffset,
313 int YOffset)
314 {
315 INT Result;
316 DC *dc;
317
318 if(!(dc = DC_LockDc(hDC)))
319 {
320 EngSetLastError(ERROR_INVALID_HANDLE);
321 return ERROR;
322 }
323
324 if(dc->dclevel.prgnClip != NULL)
325 {
326 Result = IntGdiOffsetRgn(dc->dclevel.prgnClip,
327 XOffset,
328 YOffset);
329 dc->fs |= DC_FLAG_DIRTY_RAO;
330 }
331 else
332 {
333 Result = NULLREGION;
334 }
335
336 DC_UnlockDc(dc);
337 return Result;
338 }
339
340 BOOL APIENTRY NtGdiPtVisible(HDC hDC,
341 int X,
342 int Y)
343 {
344 BOOL ret = FALSE;
345 PDC dc;
346
347 if(!(dc = DC_LockDc(hDC)))
348 {
349 EngSetLastError(ERROR_INVALID_HANDLE);
350 return FALSE;
351 }
352
353 if (dc->prgnRao)
354 {
355 POINT pt = {X, Y};
356 IntLPtoDP(dc, &pt, 1);
357 ret = REGION_PtInRegion(dc->prgnRao, pt.x, pt.y);
358 }
359
360 DC_UnlockDc(dc);
361
362 return ret;
363 }
364
365 BOOL
366 APIENTRY
367 NtGdiRectVisible(
368 HDC hDC,
369 LPRECT UnsafeRect)
370 {
371 NTSTATUS Status = STATUS_SUCCESS;
372 PDC dc = DC_LockDc(hDC);
373 BOOL Result = FALSE;
374 RECTL Rect;
375
376 if (!dc)
377 {
378 EngSetLastError(ERROR_INVALID_HANDLE);
379 return FALSE;
380 }
381
382 _SEH2_TRY
383 {
384 ProbeForRead(UnsafeRect,
385 sizeof(RECT),
386 1);
387 Rect = *UnsafeRect;
388 }
389 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
390 {
391 Status = _SEH2_GetExceptionCode();
392 }
393 _SEH2_END;
394
395 if(!NT_SUCCESS(Status))
396 {
397 DC_UnlockDc(dc);
398 SetLastNtError(Status);
399 return FALSE;
400 }
401
402 if (dc->fs & DC_FLAG_DIRTY_RAO)
403 CLIPPING_UpdateGCRegion(dc);
404
405 if (dc->prgnRao)
406 {
407 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
408 Result = REGION_RectInRegion(dc->prgnRao, &Rect);
409 }
410 DC_UnlockDc(dc);
411
412 return Result;
413 }
414
415 int
416 FASTCALL
417 IntGdiSetMetaRgn(PDC pDC)
418 {
419 INT Ret = ERROR;
420
421 if ( pDC->dclevel.prgnMeta )
422 {
423 if ( pDC->dclevel.prgnClip )
424 {
425 Ret = IntGdiCombineRgn(pDC->dclevel.prgnMeta, pDC->dclevel.prgnMeta, pDC->dclevel.prgnClip, RGN_AND);
426 if (Ret != ERROR)
427 {
428 REGION_Delete(pDC->dclevel.prgnClip);
429 pDC->dclevel.prgnClip = NULL;
430 IntGdiReleaseRaoRgn(pDC);
431 }
432 }
433 else
434 Ret = REGION_Complexity(pDC->dclevel.prgnMeta);
435 }
436 else
437 {
438 if ( pDC->dclevel.prgnClip )
439 {
440 Ret = REGION_Complexity(pDC->dclevel.prgnClip);
441 pDC->dclevel.prgnMeta = pDC->dclevel.prgnClip;
442 pDC->dclevel.prgnClip = NULL;
443 }
444 else
445 Ret = SIMPLEREGION;
446 }
447
448 if (Ret != ERROR)
449 pDC->fs |= DC_FLAG_DIRTY_RAO;
450
451 return Ret;
452 }
453
454
455 int APIENTRY NtGdiSetMetaRgn(HDC hDC)
456 {
457 INT Ret;
458 PDC pDC = DC_LockDc(hDC);
459
460 if (!pDC)
461 {
462 EngSetLastError(ERROR_INVALID_PARAMETER);
463 return ERROR;
464 }
465 Ret = IntGdiSetMetaRgn(pDC);
466
467 DC_UnlockDc(pDC);
468 return Ret;
469 }
470
471 VOID
472 FASTCALL
473 CLIPPING_UpdateGCRegion(PDC pDC)
474 {
475 /* Must have VisRgn set to a valid state! */
476 ASSERT (pDC->prgnVis);
477
478 if (pDC->prgnAPI)
479 {
480 REGION_Delete(pDC->prgnAPI);
481 pDC->prgnAPI = NULL;
482 }
483
484 if (pDC->prgnRao)
485 REGION_Delete(pDC->prgnRao);
486
487 pDC->prgnRao = IntSysCreateRectpRgn(0,0,0,0);
488
489 ASSERT(pDC->prgnRao);
490
491 if (pDC->dclevel.prgnMeta || pDC->dclevel.prgnClip)
492 {
493 pDC->prgnAPI = IntSysCreateRectpRgn(0,0,0,0);
494 if (!pDC->dclevel.prgnMeta)
495 {
496 IntGdiCombineRgn(pDC->prgnAPI,
497 pDC->dclevel.prgnClip,
498 NULL,
499 RGN_COPY);
500 }
501 else if (!pDC->dclevel.prgnClip)
502 {
503 IntGdiCombineRgn(pDC->prgnAPI,
504 pDC->dclevel.prgnMeta,
505 NULL,
506 RGN_COPY);
507 }
508 else
509 {
510 IntGdiCombineRgn(pDC->prgnAPI,
511 pDC->dclevel.prgnClip,
512 pDC->dclevel.prgnMeta,
513 RGN_AND);
514 }
515 }
516
517 if (pDC->prgnAPI)
518 {
519 IntGdiCombineRgn(pDC->prgnRao,
520 pDC->prgnVis,
521 pDC->prgnAPI,
522 RGN_AND);
523 }
524 else
525 {
526 IntGdiCombineRgn(pDC->prgnRao,
527 pDC->prgnVis,
528 NULL,
529 RGN_COPY);
530 }
531
532
533 IntGdiOffsetRgn(pDC->prgnRao, pDC->ptlDCOrig.x, pDC->ptlDCOrig.y);
534
535 RtlCopyMemory(&pDC->erclClip,
536 &pDC->prgnRao->rdh.rcBound,
537 sizeof(RECTL));
538
539 pDC->fs &= ~DC_FLAG_DIRTY_RAO;
540
541 // pDC->co should be used. Example, CLIPOBJ_cEnumStart uses XCLIPOBJ to build
542 // the rects from region objects rects in pClipRgn->Buffer.
543 // With pDC->co.pClipRgn->Buffer,
544 // pDC->co.pClipRgn = pDC->prgnRao ? pDC->prgnRao : pDC->prgnVis;
545
546 IntEngUpdateClipRegion(&pDC->co,
547 pDC->prgnRao->rdh.nCount,
548 pDC->prgnRao->Buffer,
549 &pDC->erclClip);
550
551 IntGdiOffsetRgn(pDC->prgnRao, -pDC->ptlDCOrig.x, -pDC->ptlDCOrig.y);
552 }
553
554 /* EOF */