Merge trunk HEAD (r46369)
[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 <w32k.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 if (dc->prgnAPI) // APIRGN
206 {
207 hRgn = ((PROSRGNDATA)dc->prgnAPI)->BaseObject.hHmgr;
208 }
209 else if (dc->dclevel.prgnMeta) // METARGN
210 {
211 hRgn = ((PROSRGNDATA)dc->dclevel.prgnMeta)->BaseObject.hHmgr;
212 }
213 else
214 {
215 hRgn = dc->rosdc.hClipRgn; // CLIPRGN
216 }
217
218 if (hRgn)
219 {
220 hRgnNew = IntSysCreateRectRgn( 0, 0, 0, 0 );
221
222 NtGdiCombineRgn(hRgnNew, dc->rosdc.hVisRgn, hRgn, RGN_AND);
223
224 if (!(Rgn = RGNOBJAPI_Lock(hRgnNew, NULL)))
225 {
226 DC_UnlockDc(dc);
227 return ERROR;
228 }
229
230 retval = REGION_GetRgnBox(Rgn, rc);
231
232 REGION_FreeRgnByHandle(hRgnNew);
233 RGNOBJAPI_Unlock(Rgn);
234 DC_UnlockDc(dc);
235 return retval;
236 }
237
238 if (!(Rgn = RGNOBJAPI_Lock(dc->rosdc.hVisRgn, NULL)))
239 {
240 DC_UnlockDc(dc);
241 return ERROR;
242 }
243 retval = REGION_GetRgnBox(Rgn, rc);
244 RGNOBJAPI_Unlock(Rgn);
245 IntDPtoLP(dc, (LPPOINT)rc, 2);
246 DC_UnlockDc(dc);
247
248 return retval;
249 }
250
251 INT APIENTRY
252 NtGdiGetAppClipBox(HDC hDC, PRECTL rc)
253 {
254 INT Ret;
255 NTSTATUS Status = STATUS_SUCCESS;
256 RECTL Saferect;
257
258 Ret = GdiGetClipBox(hDC, &Saferect);
259
260 _SEH2_TRY
261 {
262 ProbeForWrite(rc,
263 sizeof(RECT),
264 1);
265 *rc = Saferect;
266 }
267 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
268 {
269 Status = _SEH2_GetExceptionCode();
270 }
271 _SEH2_END;
272
273 if(!NT_SUCCESS(Status))
274 {
275 SetLastNtError(Status);
276 return ERROR;
277 }
278
279 return Ret;
280 }
281
282 int APIENTRY NtGdiExcludeClipRect(HDC hDC,
283 int LeftRect,
284 int TopRect,
285 int RightRect,
286 int BottomRect)
287 {
288 INT Result;
289 RECTL Rect;
290 HRGN NewRgn;
291 PDC dc = DC_LockDc(hDC);
292
293 if (!dc)
294 {
295 SetLastWin32Error(ERROR_INVALID_HANDLE);
296 return ERROR;
297 }
298
299 Rect.left = LeftRect;
300 Rect.top = TopRect;
301 Rect.right = RightRect;
302 Rect.bottom = BottomRect;
303
304 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
305
306 NewRgn = IntSysCreateRectRgnIndirect(&Rect);
307 if (!NewRgn)
308 {
309 Result = ERROR;
310 }
311 else
312 {
313 if (!dc->rosdc.hClipRgn)
314 {
315 dc->rosdc.hClipRgn = IntSysCreateRectRgn(0, 0, 0, 0);
316 NtGdiCombineRgn(dc->rosdc.hClipRgn, dc->rosdc.hVisRgn, NewRgn, RGN_DIFF);
317 Result = SIMPLEREGION;
318 }
319 else
320 {
321 Result = NtGdiCombineRgn(dc->rosdc.hClipRgn, dc->rosdc.hClipRgn, NewRgn, RGN_DIFF);
322 }
323 REGION_FreeRgnByHandle(NewRgn);
324 }
325 if (Result != ERROR)
326 CLIPPING_UpdateGCRegion(dc);
327
328 DC_UnlockDc(dc);
329
330 return Result;
331 }
332
333 int APIENTRY NtGdiIntersectClipRect(HDC hDC,
334 int LeftRect,
335 int TopRect,
336 int RightRect,
337 int BottomRect)
338 {
339 INT Result;
340 RECTL Rect;
341 HRGN NewRgn;
342 PDC dc = DC_LockDc(hDC);
343
344 DPRINT("NtGdiIntersectClipRect(%x, %d,%d-%d,%d)\n",
345 hDC, LeftRect, TopRect, RightRect, BottomRect);
346
347 if (!dc)
348 {
349 SetLastWin32Error(ERROR_INVALID_HANDLE);
350 return ERROR;
351 }
352
353 Rect.left = LeftRect;
354 Rect.top = TopRect;
355 Rect.right = RightRect;
356 Rect.bottom = BottomRect;
357
358 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
359
360 NewRgn = IntSysCreateRectRgnIndirect(&Rect);
361 if (!NewRgn)
362 {
363 Result = ERROR;
364 }
365 else if (!dc->rosdc.hClipRgn)
366 {
367 dc->rosdc.hClipRgn = NewRgn;
368 Result = SIMPLEREGION;
369 }
370 else
371 {
372 Result = NtGdiCombineRgn(dc->rosdc.hClipRgn, dc->rosdc.hClipRgn, NewRgn, RGN_AND);
373 REGION_FreeRgnByHandle(NewRgn);
374 }
375 if (Result != ERROR)
376 CLIPPING_UpdateGCRegion(dc);
377
378 DC_UnlockDc(dc);
379
380 return Result;
381 }
382
383 int APIENTRY NtGdiOffsetClipRgn(HDC hDC,
384 int XOffset,
385 int YOffset)
386 {
387 INT Result;
388 DC *dc;
389
390 if(!(dc = DC_LockDc(hDC)))
391 {
392 SetLastWin32Error(ERROR_INVALID_HANDLE);
393 return ERROR;
394 }
395
396 if(dc->rosdc.hClipRgn != NULL)
397 {
398 Result = NtGdiOffsetRgn(dc->rosdc.hClipRgn,
399 XOffset,
400 YOffset);
401 CLIPPING_UpdateGCRegion(dc);
402 }
403 else
404 {
405 Result = NULLREGION;
406 }
407
408 DC_UnlockDc(dc);
409 return Result;
410 }
411
412 BOOL APIENTRY NtGdiPtVisible(HDC hDC,
413 int X,
414 int Y)
415 {
416 HRGN rgn;
417 DC *dc;
418
419 if(!(dc = DC_LockDc(hDC)))
420 {
421 SetLastWin32Error(ERROR_INVALID_HANDLE);
422 return FALSE;
423 }
424
425 rgn = dc->rosdc.hGCClipRgn;
426 DC_UnlockDc(dc);
427
428 return (rgn ? NtGdiPtInRegion(rgn, X, Y) : FALSE);
429 }
430
431 BOOL APIENTRY NtGdiRectVisible(HDC hDC,
432 LPRECT UnsafeRect)
433 {
434 NTSTATUS Status = STATUS_SUCCESS;
435 PROSRGNDATA Rgn;
436 PDC dc = DC_LockDc(hDC);
437 BOOL Result = FALSE;
438 RECTL Rect;
439
440 if (!dc)
441 {
442 SetLastWin32Error(ERROR_INVALID_HANDLE);
443 return FALSE;
444 }
445
446 _SEH2_TRY
447 {
448 ProbeForRead(UnsafeRect,
449 sizeof(RECT),
450 1);
451 Rect = *UnsafeRect;
452 }
453 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
454 {
455 Status = _SEH2_GetExceptionCode();
456 }
457 _SEH2_END;
458
459 if(!NT_SUCCESS(Status))
460 {
461 DC_UnlockDc(dc);
462 SetLastNtError(Status);
463 return FALSE;
464 }
465
466 if (dc->rosdc.hGCClipRgn)
467 {
468 if((Rgn = (PROSRGNDATA)RGNOBJAPI_Lock(dc->rosdc.hGCClipRgn, NULL)))
469 {
470 IntLPtoDP(dc, (LPPOINT)&Rect, 2);
471 Result = REGION_RectInRegion(Rgn, &Rect);
472 RGNOBJAPI_Unlock(Rgn);
473 }
474 }
475 DC_UnlockDc(dc);
476
477 return Result;
478 }
479
480 int
481 FASTCALL
482 IntGdiSetMetaRgn(PDC pDC)
483 {
484 INT Ret = ERROR;
485 PROSRGNDATA TempRgn;
486
487 if ( pDC->dclevel.prgnMeta )
488 {
489 if ( pDC->dclevel.prgnClip )
490 {
491 TempRgn = IntSysCreateRectpRgn(0,0,0,0);
492 if (TempRgn)
493 {
494 Ret = IntGdiCombineRgn( TempRgn,
495 pDC->dclevel.prgnMeta,
496 pDC->dclevel.prgnClip,
497 RGN_AND);
498 if ( Ret )
499 {
500 GDIOBJ_ShareUnlockObjByPtr(pDC->dclevel.prgnMeta);
501 if (!((PROSRGNDATA)pDC->dclevel.prgnMeta)->BaseObject.ulShareCount)
502 REGION_Delete(pDC->dclevel.prgnMeta);
503
504 pDC->dclevel.prgnMeta = TempRgn;
505
506 GDIOBJ_ShareUnlockObjByPtr(pDC->dclevel.prgnClip);
507 if (!((PROSRGNDATA)pDC->dclevel.prgnClip)->BaseObject.ulShareCount)
508 REGION_Delete(pDC->dclevel.prgnClip);
509
510 pDC->dclevel.prgnClip = NULL;
511
512 IntGdiReleaseRaoRgn(pDC);
513 }
514 else
515 REGION_Delete(TempRgn);
516 }
517 }
518 else
519 Ret = REGION_Complexity(pDC->dclevel.prgnMeta);
520 }
521 else
522 {
523 if ( pDC->dclevel.prgnClip )
524 {
525 Ret = REGION_Complexity(pDC->dclevel.prgnClip);
526 pDC->dclevel.prgnMeta = pDC->dclevel.prgnClip;
527 pDC->dclevel.prgnClip = NULL;
528 }
529 else
530 Ret = SIMPLEREGION;
531 }
532 return Ret;
533 }
534
535 int APIENTRY NtGdiSetMetaRgn(HDC hDC)
536 {
537 INT Ret;
538 PDC pDC = DC_LockDc(hDC);
539
540 if (!pDC)
541 {
542 SetLastWin32Error(ERROR_INVALID_PARAMETER);
543 return ERROR;
544 }
545 Ret = IntGdiSetMetaRgn(pDC);
546
547 DC_UnlockDc(pDC);
548 return Ret;
549 }
550
551 INT FASTCALL
552 NEW_CLIPPING_UpdateGCRegion(PDC pDC)
553 {
554 CLIPOBJ * co;
555
556 /* Must have VisRgn set to a valid state! */
557 if (!pDC->prgnVis) return ERROR;
558
559 if (pDC->prgnAPI)
560 {
561 REGION_Delete(pDC->prgnAPI);
562 pDC->prgnAPI = IntSysCreateRectpRgn(0,0,0,0);
563 }
564
565 if (pDC->prgnRao)
566 {
567 REGION_Delete(pDC->prgnRao);
568 pDC->prgnRao = IntSysCreateRectpRgn(0,0,0,0);
569 }
570
571 if (pDC->dclevel.prgnMeta && pDC->dclevel.prgnClip)
572 {
573 IntGdiCombineRgn( pDC->prgnAPI,
574 pDC->dclevel.prgnClip,
575 pDC->dclevel.prgnMeta,
576 RGN_AND );
577 }
578 else
579 {
580 if (pDC->dclevel.prgnClip)
581 {
582 IntGdiCombineRgn( pDC->prgnAPI,
583 pDC->dclevel.prgnClip,
584 NULL,
585 RGN_COPY );
586 }
587 else if (pDC->dclevel.prgnMeta)
588 {
589 IntGdiCombineRgn( pDC->prgnAPI,
590 pDC->dclevel.prgnMeta,
591 NULL,
592 RGN_COPY );
593 }
594 }
595
596 IntGdiCombineRgn( pDC->prgnRao,
597 pDC->prgnVis,
598 pDC->prgnAPI,
599 RGN_AND );
600
601 RtlCopyMemory( &pDC->erclClip,
602 &((PROSRGNDATA)pDC->prgnRao)->rdh.rcBound,
603 sizeof(RECTL));
604
605 pDC->fs &= ~DC_FLAG_DIRTY_RAO;
606
607 IntGdiOffsetRgn(pDC->prgnRao, pDC->ptlDCOrig.x, pDC->ptlDCOrig.y);
608
609 if (pDC->rosdc.CombinedClip != NULL)
610 IntEngDeleteClipRegion(pDC->rosdc.CombinedClip);
611
612 // pDC->co should be used. Example, CLIPOBJ_cEnumStart uses XCLIPOBJ to build
613 // the rects from region objects rects in pClipRgn->Buffer.
614 // With pDC->co.pClipRgn->Buffer,
615 // pDC->co.pClipRgn = pDC->prgnRao ? pDC->prgnRao : pDC->prgnVis;
616
617 co = IntEngCreateClipRegion( ((PROSRGNDATA)pDC->prgnRao)->rdh.nCount,
618 ((PROSRGNDATA)pDC->prgnRao)->Buffer,
619 &pDC->erclClip);
620
621 pDC->rosdc.CombinedClip = co;
622
623 return IntGdiOffsetRgn(pDC->prgnRao, -pDC->ptlDCOrig.x, -pDC->ptlDCOrig.y);
624 }
625
626 /* EOF */