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