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