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