Synchronize with trunk's revision r57599.
[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 int FASTCALL
15 CLIPPING_UpdateGCRegion(DC* Dc)
16 {
17 PROSRGNDATA CombinedRegion;
18 //HRGN hRgnVis;
19 PREGION prgnClip, prgnGCClip;
20
21 /* Would prefer this, but the rest of the code sucks... */
22 //ASSERT(Dc->rosdc.hGCClipRgn);
23 //ASSERT(Dc->rosdc.hClipRgn);
24 ASSERT(Dc->prgnVis);
25 //hRgnVis = Dc->prgnVis->BaseObject.hHmgr;
26
27 if (Dc->rosdc.hGCClipRgn == NULL)
28 Dc->rosdc.hGCClipRgn = IntSysCreateRectRgn(0, 0, 0, 0);
29
30 prgnGCClip = REGION_LockRgn(Dc->rosdc.hGCClipRgn);
31 ASSERT(prgnGCClip);
32
33 if (Dc->rosdc.hClipRgn == NULL)
34 IntGdiCombineRgn(prgnGCClip, Dc->prgnVis, NULL, RGN_COPY);
35 else
36 {
37 prgnClip = REGION_LockRgn(Dc->rosdc.hClipRgn); // FIXME: Locking order, ugh!
38 IntGdiCombineRgn(prgnGCClip, Dc->prgnVis, prgnClip, RGN_AND);
39 REGION_UnlockRgn(prgnClip);
40 }
41 REGION_UnlockRgn(prgnGCClip);
42
43 NtGdiOffsetRgn(Dc->rosdc.hGCClipRgn, Dc->ptlDCOrig.x, Dc->ptlDCOrig.y);
44
45 if((CombinedRegion = RGNOBJAPI_Lock(Dc->rosdc.hGCClipRgn, NULL)))
46 {
47 CLIPOBJ *CombinedClip;
48
49 CombinedClip = IntEngCreateClipRegion(CombinedRegion->rdh.nCount,
50 CombinedRegion->Buffer,
51 &CombinedRegion->rdh.rcBound);
52
53 RGNOBJAPI_Unlock(CombinedRegion);
54
55 if ( !CombinedClip )
56 {
57 DPRINT1("IntEngCreateClipRegion() failed\n");
58 return ERROR;
59 }
60
61 if(Dc->rosdc.CombinedClip != NULL)
62 IntEngDeleteClipRegion(Dc->rosdc.CombinedClip);
63
64 Dc->rosdc.CombinedClip = CombinedClip ;
65 }
66
67 return NtGdiOffsetRgn(Dc->rosdc.hGCClipRgn, -Dc->ptlDCOrig.x, -Dc->ptlDCOrig.y);
68 }
69
70 INT FASTCALL
71 GdiSelectVisRgn(HDC hdc, HRGN hrgn)
72 {
73 int retval;
74 DC *dc;
75 PREGION prgn;
76
77 if (!hrgn)
78 {
79 EngSetLastError(ERROR_INVALID_PARAMETER);
80 return ERROR;
81 }
82 if (!(dc = DC_LockDc(hdc)))
83 {
84 EngSetLastError(ERROR_INVALID_HANDLE);
85 return ERROR;
86 }
87
88 dc->fs &= ~DC_FLAG_DIRTY_RAO;
89
90 ASSERT (dc->prgnVis != NULL);
91
92 prgn = RGNOBJAPI_Lock(hrgn, NULL);
93 retval = prgn ? IntGdiCombineRgn(dc->prgnVis, prgn, NULL, RGN_COPY) : ERROR;
94 RGNOBJAPI_Unlock(prgn);
95 if ( retval != ERROR )
96 {
97 IntGdiOffsetRgn(dc->prgnVis, -dc->ptlDCOrig.x, -dc->ptlDCOrig.y);
98 CLIPPING_UpdateGCRegion(dc);
99 }
100 DC_UnlockDc(dc);
101
102 return retval;
103 }
104
105
106 int FASTCALL GdiExtSelectClipRgn(PDC dc,
107 HRGN hrgn,
108 int fnMode)
109 {
110 // dc->fs &= ~DC_FLAG_DIRTY_RAO;
111
112 if (!hrgn)
113 {
114 if (fnMode == RGN_COPY)
115 {
116 if (dc->rosdc.hClipRgn != NULL)
117 {
118 GreDeleteObject(dc->rosdc.hClipRgn);
119 dc->rosdc.hClipRgn = NULL;
120 }
121 }
122 else
123 {
124 EngSetLastError(ERROR_INVALID_PARAMETER);
125 return ERROR;
126 }
127 }
128 else
129 {
130 if (!dc->rosdc.hClipRgn)
131 {
132 RECTL rect;
133 if(dc->prgnVis)
134 {
135 REGION_GetRgnBox(dc->prgnVis, &rect);
136 dc->rosdc.hClipRgn = IntSysCreateRectRgnIndirect(&rect);
137 }
138 else
139 {
140 dc->rosdc.hClipRgn = IntSysCreateRectRgn(0, 0, 0, 0);
141 }
142 }
143 if(fnMode == RGN_COPY)
144 {
145 NtGdiCombineRgn(dc->rosdc.hClipRgn, hrgn, 0, fnMode);
146 }
147 else
148 NtGdiCombineRgn(dc->rosdc.hClipRgn, dc->rosdc.hClipRgn, hrgn, fnMode);
149 }
150
151 return CLIPPING_UpdateGCRegion(dc);
152 }
153
154
155 int APIENTRY NtGdiExtSelectClipRgn(HDC hDC,
156 HRGN hrgn,
157 int fnMode)
158 {
159 int retval;
160 DC *dc;
161
162 if (!(dc = DC_LockDc(hDC)))
163 {
164 EngSetLastError(ERROR_INVALID_HANDLE);
165 return ERROR;
166 }
167
168 retval = GdiExtSelectClipRgn ( dc, hrgn, fnMode );
169
170 DC_UnlockDc(dc);
171 return retval;
172 }
173
174 INT FASTCALL
175 GdiGetClipBox(HDC hDC, PRECTL rc)
176 {
177 INT retval;
178 PDC dc;
179 PROSRGNDATA pRgnNew, pRgn = NULL;
180 BOOL Unlock = FALSE; // Small HACK
181
182 if (!(dc = DC_LockDc(hDC)))
183 {
184 return ERROR;
185 }
186
187 /* FIXME: Rao and Vis only! */
188 if (dc->prgnAPI) // APIRGN
189 {
190 pRgn = dc->prgnAPI;
191 }
192 else if (dc->dclevel.prgnMeta) // METARGN
193 {
194 pRgn = dc->dclevel.prgnMeta;
195 }
196 else if (dc->rosdc.hClipRgn)
197 {
198 Unlock = TRUE ;
199 pRgn = REGION_LockRgn(dc->rosdc.hClipRgn); // CLIPRGN
200 }
201
202 if (pRgn)
203 {
204 pRgnNew = IntSysCreateRectpRgn( 0, 0, 0, 0 );
205
206 if (!pRgnNew)
207 {
208 DC_UnlockDc(dc);
209 if(Unlock) REGION_UnlockRgn(pRgn);
210 return ERROR;
211 }
212
213 IntGdiCombineRgn(pRgnNew, dc->prgnVis, pRgn, RGN_AND);
214
215 retval = REGION_GetRgnBox(pRgnNew, rc);
216
217 REGION_Delete(pRgnNew);
218
219 DC_UnlockDc(dc);
220 if(Unlock) REGION_UnlockRgn(pRgn);
221 return retval;
222 }
223
224 retval = REGION_GetRgnBox(dc->prgnVis, rc);
225 IntDPtoLP(dc, (LPPOINT)rc, 2);
226 DC_UnlockDc(dc);
227
228 return retval;
229 }
230
231 INT APIENTRY
232 NtGdiGetAppClipBox(HDC hDC, PRECTL rc)
233 {
234 INT Ret;
235 NTSTATUS Status = STATUS_SUCCESS;
236 RECTL Saferect;
237
238 Ret = GdiGetClipBox(hDC, &Saferect);
239
240 _SEH2_TRY
241 {
242 ProbeForWrite(rc,
243 sizeof(RECT),
244 1);
245 *rc = Saferect;
246 }
247 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
248 {
249 Status = _SEH2_GetExceptionCode();
250 }
251 _SEH2_END;
252
253 if(!NT_SUCCESS(Status))
254 {
255 SetLastNtError(Status);
256 return ERROR;
257 }
258
259 return Ret;
260 }
261
262 int APIENTRY NtGdiExcludeClipRect(HDC hDC,
263 int LeftRect,
264 int TopRect,
265 int RightRect,
266 int BottomRect)
267 {
268 INT Result;
269 RECTL Rect;
270 PREGION prgnNew, prgnClip;
271 PDC dc = DC_LockDc(hDC);
272
273 if (!dc)
274 {
275 EngSetLastError(ERROR_INVALID_HANDLE);
276 return ERROR;
277 }
278
279 Rect.left = LeftRect;
280 Rect.top = TopRect;
281 Rect.right = RightRect;
282 Rect.bottom = BottomRect;
283
284 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
285
286 prgnNew = IntSysCreateRectpRgnIndirect(&Rect);
287 if (!prgnNew)
288 {
289 Result = ERROR;
290 }
291 else
292 {
293 if (!dc->rosdc.hClipRgn)
294 {
295 dc->rosdc.hClipRgn = IntSysCreateRectRgn(0, 0, 0, 0);
296 prgnClip = REGION_LockRgn(dc->rosdc.hClipRgn);
297 IntGdiCombineRgn(prgnClip, dc->prgnVis, prgnNew, RGN_DIFF);
298 REGION_UnlockRgn(prgnClip);
299 Result = SIMPLEREGION;
300 }
301 else
302 {
303 prgnClip = REGION_LockRgn(dc->rosdc.hClipRgn);
304 Result = IntGdiCombineRgn(prgnClip, prgnClip, prgnNew, RGN_DIFF);
305 REGION_UnlockRgn(prgnClip);
306 }
307 REGION_Delete(prgnNew);
308 }
309 if (Result != ERROR)
310 CLIPPING_UpdateGCRegion(dc);
311
312 DC_UnlockDc(dc);
313
314 return Result;
315 }
316
317 int APIENTRY NtGdiIntersectClipRect(HDC hDC,
318 int LeftRect,
319 int TopRect,
320 int RightRect,
321 int BottomRect)
322 {
323 INT Result;
324 RECTL Rect;
325 HRGN NewRgn;
326 PDC dc = DC_LockDc(hDC);
327
328 DPRINT("NtGdiIntersectClipRect(%p, %d,%d-%d,%d)\n",
329 hDC, LeftRect, TopRect, RightRect, BottomRect);
330
331 if (!dc)
332 {
333 EngSetLastError(ERROR_INVALID_HANDLE);
334 return ERROR;
335 }
336
337 Rect.left = LeftRect;
338 Rect.top = TopRect;
339 Rect.right = RightRect;
340 Rect.bottom = BottomRect;
341
342 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
343
344 NewRgn = IntSysCreateRectRgnIndirect(&Rect);
345 if (!NewRgn)
346 {
347 Result = ERROR;
348 }
349 else if (!dc->rosdc.hClipRgn)
350 {
351 dc->rosdc.hClipRgn = NewRgn;
352 Result = SIMPLEREGION;
353 }
354 else
355 {
356 Result = NtGdiCombineRgn(dc->rosdc.hClipRgn, dc->rosdc.hClipRgn, NewRgn, RGN_AND);
357 GreDeleteObject(NewRgn);
358 }
359 if (Result != ERROR)
360 CLIPPING_UpdateGCRegion(dc);
361
362 DC_UnlockDc(dc);
363
364 return Result;
365 }
366
367 int APIENTRY NtGdiOffsetClipRgn(HDC hDC,
368 int XOffset,
369 int YOffset)
370 {
371 INT Result;
372 DC *dc;
373
374 if(!(dc = DC_LockDc(hDC)))
375 {
376 EngSetLastError(ERROR_INVALID_HANDLE);
377 return ERROR;
378 }
379
380 if(dc->rosdc.hClipRgn != NULL)
381 {
382 Result = NtGdiOffsetRgn(dc->rosdc.hClipRgn,
383 XOffset,
384 YOffset);
385 CLIPPING_UpdateGCRegion(dc);
386 }
387 else
388 {
389 Result = NULLREGION;
390 }
391
392 DC_UnlockDc(dc);
393 return Result;
394 }
395
396 BOOL APIENTRY NtGdiPtVisible(HDC hDC,
397 int X,
398 int Y)
399 {
400 HRGN rgn;
401 DC *dc;
402
403 if(!(dc = DC_LockDc(hDC)))
404 {
405 EngSetLastError(ERROR_INVALID_HANDLE);
406 return FALSE;
407 }
408
409 rgn = dc->rosdc.hGCClipRgn;
410 DC_UnlockDc(dc);
411
412 return (rgn ? NtGdiPtInRegion(rgn, X, Y) : FALSE);
413 }
414
415 BOOL APIENTRY NtGdiRectVisible(HDC hDC,
416 LPRECT UnsafeRect)
417 {
418 NTSTATUS Status = STATUS_SUCCESS;
419 PROSRGNDATA Rgn;
420 PDC dc = DC_LockDc(hDC);
421 BOOL Result = FALSE;
422 RECTL Rect;
423
424 if (!dc)
425 {
426 EngSetLastError(ERROR_INVALID_HANDLE);
427 return FALSE;
428 }
429
430 _SEH2_TRY
431 {
432 ProbeForRead(UnsafeRect,
433 sizeof(RECT),
434 1);
435 Rect = *UnsafeRect;
436 }
437 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
438 {
439 Status = _SEH2_GetExceptionCode();
440 }
441 _SEH2_END;
442
443 if(!NT_SUCCESS(Status))
444 {
445 DC_UnlockDc(dc);
446 SetLastNtError(Status);
447 return FALSE;
448 }
449
450 if (dc->rosdc.hGCClipRgn)
451 {
452 if((Rgn = (PROSRGNDATA)RGNOBJAPI_Lock(dc->rosdc.hGCClipRgn, NULL)))
453 {
454 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
455 Result = REGION_RectInRegion(Rgn, &Rect);
456 RGNOBJAPI_Unlock(Rgn);
457 }
458 }
459 DC_UnlockDc(dc);
460
461 return Result;
462 }
463
464 int
465 FASTCALL
466 IntGdiSetMetaRgn(PDC pDC)
467 {
468 INT Ret = ERROR;
469 PROSRGNDATA TempRgn;
470
471 if ( pDC->dclevel.prgnMeta )
472 {
473 if ( pDC->dclevel.prgnClip )
474 {
475 TempRgn = IntSysCreateRectpRgn(0,0,0,0);
476 if (TempRgn)
477 {
478 Ret = IntGdiCombineRgn( TempRgn,
479 pDC->dclevel.prgnMeta,
480 pDC->dclevel.prgnClip,
481 RGN_AND);
482 if ( Ret )
483 {
484 GDIOBJ_vDereferenceObject(&pDC->dclevel.prgnMeta->BaseObject);
485 if (!((PROSRGNDATA)pDC->dclevel.prgnMeta)->BaseObject.ulShareCount)
486 REGION_Delete(pDC->dclevel.prgnMeta);
487
488 pDC->dclevel.prgnMeta = TempRgn;
489
490 GDIOBJ_vDereferenceObject(&pDC->dclevel.prgnClip->BaseObject);
491 if (!((PROSRGNDATA)pDC->dclevel.prgnClip)->BaseObject.ulShareCount)
492 REGION_Delete(pDC->dclevel.prgnClip);
493
494 pDC->dclevel.prgnClip = NULL;
495
496 IntGdiReleaseRaoRgn(pDC);
497 }
498 else
499 REGION_Delete(TempRgn);
500 }
501 }
502 else
503 Ret = REGION_Complexity(pDC->dclevel.prgnMeta);
504 }
505 else
506 {
507 if ( pDC->dclevel.prgnClip )
508 {
509 Ret = REGION_Complexity(pDC->dclevel.prgnClip);
510 pDC->dclevel.prgnMeta = pDC->dclevel.prgnClip;
511 pDC->dclevel.prgnClip = NULL;
512 }
513 else
514 Ret = SIMPLEREGION;
515 }
516 return Ret;
517 }
518
519
520 int APIENTRY NtGdiSetMetaRgn(HDC hDC)
521 {
522 INT Ret;
523 PDC pDC = DC_LockDc(hDC);
524
525 if (!pDC)
526 {
527 EngSetLastError(ERROR_INVALID_PARAMETER);
528 return ERROR;
529 }
530 Ret = IntGdiSetMetaRgn(pDC);
531
532 DC_UnlockDc(pDC);
533 return Ret;
534 }
535
536 INT FASTCALL
537 NEW_CLIPPING_UpdateGCRegion(PDC pDC)
538 {
539 CLIPOBJ * co;
540
541 /* Must have VisRgn set to a valid state! */
542 ASSERT (pDC->prgnVis);
543
544 // FIXME: this seems to be broken!
545
546 if (pDC->prgnAPI)
547 {
548 REGION_Delete(pDC->prgnAPI);
549 pDC->prgnAPI = IntSysCreateRectpRgn(0,0,0,0);
550 }
551
552 if (pDC->prgnRao)
553 {
554 REGION_Delete(pDC->prgnRao);
555 pDC->prgnRao = IntSysCreateRectpRgn(0,0,0,0);
556 }
557
558 if (pDC->dclevel.prgnMeta && pDC->dclevel.prgnClip)
559 {
560 IntGdiCombineRgn( pDC->prgnAPI,
561 pDC->dclevel.prgnClip,
562 pDC->dclevel.prgnMeta,
563 RGN_AND);
564 }
565 else
566 {
567 if (pDC->dclevel.prgnClip)
568 {
569 IntGdiCombineRgn( pDC->prgnAPI,
570 pDC->dclevel.prgnClip,
571 NULL,
572 RGN_COPY);
573 }
574 else if (pDC->dclevel.prgnMeta)
575 {
576 IntGdiCombineRgn( pDC->prgnAPI,
577 pDC->dclevel.prgnMeta,
578 NULL,
579 RGN_COPY);
580 }
581 }
582
583 IntGdiCombineRgn( pDC->prgnRao,
584 pDC->prgnVis,
585 pDC->prgnAPI,
586 RGN_AND);
587
588 // FIXME: pDC->prgnRao may be NULL
589 RtlCopyMemory(&pDC->erclClip,
590 &pDC->prgnRao->rdh.rcBound,
591 sizeof(RECTL));
592
593 pDC->fs &= ~DC_FLAG_DIRTY_RAO;
594
595 IntGdiOffsetRgn(pDC->prgnRao, pDC->ptlDCOrig.x, pDC->ptlDCOrig.y);
596
597 // pDC->co should be used. Example, CLIPOBJ_cEnumStart uses XCLIPOBJ to build
598 // the rects from region objects rects in pClipRgn->Buffer.
599 // With pDC->co.pClipRgn->Buffer,
600 // pDC->co.pClipRgn = pDC->prgnRao ? pDC->prgnRao : pDC->prgnVis;
601
602 co = IntEngCreateClipRegion( ((PROSRGNDATA)pDC->prgnRao)->rdh.nCount,
603 ((PROSRGNDATA)pDC->prgnRao)->Buffer,
604 &pDC->erclClip);
605 if (co)
606 {
607 if (pDC->rosdc.CombinedClip != NULL)
608 IntEngDeleteClipRegion(pDC->rosdc.CombinedClip);
609
610 pDC->rosdc.CombinedClip = co;
611 }
612
613 return IntGdiOffsetRgn(pDC->prgnRao, -pDC->ptlDCOrig.x, -pDC->ptlDCOrig.y);
614 }
615
616 /* EOF */