- Implement CCM_{GET|SET}COLORSCHEME.
[wine] / objects / clipping.c
1 /*
2  * DC clipping functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdlib.h>
22 #include "windef.h"
23 #include "wingdi.h"
24 #include "wine/winuser16.h"
25 #include "gdi.h"
26 #include "region.h"
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(clipping);
30
31
32 /***********************************************************************
33  *           CLIPPING_UpdateGCRegion
34  *
35  * Update the GC clip region when the ClipRgn or VisRgn have changed.
36  */
37 void CLIPPING_UpdateGCRegion( DC * dc )
38 {
39     if (!dc->hGCClipRgn) dc->hGCClipRgn = CreateRectRgn( 0, 0, 0, 0 );
40
41     if (!dc->hVisRgn)
42     {
43         ERR("hVisRgn is zero. Please report this.\n" );
44         exit(1);
45     }
46
47     if (dc->flags & DC_DIRTY) ERR( "DC is dirty. Please report this.\n" );
48
49     if (!dc->hClipRgn)
50         CombineRgn( dc->hGCClipRgn, dc->hVisRgn, 0, RGN_COPY );
51     else
52         CombineRgn(dc->hGCClipRgn, dc->hClipRgn, dc->hVisRgn, RGN_AND);
53     if (dc->funcs->pSetDeviceClipping) dc->funcs->pSetDeviceClipping( dc );
54 }
55
56
57 /***********************************************************************
58  *           SelectClipRgn    (GDI.44)
59  */
60 INT16 WINAPI SelectClipRgn16( HDC16 hdc, HRGN16 hrgn )
61 {
62     return (INT16)SelectClipRgn( hdc, hrgn );
63 }
64
65
66 /***********************************************************************
67  *           SelectClipRgn    (GDI32.@)
68  */
69 INT WINAPI SelectClipRgn( HDC hdc, HRGN hrgn )
70 {
71     return ExtSelectClipRgn( hdc, hrgn, RGN_COPY );
72 }
73
74 /******************************************************************************
75  *              ExtSelectClipRgn        [GDI.508]
76  */
77 INT16 WINAPI ExtSelectClipRgn16( HDC16 hdc, HRGN16 hrgn, INT16 fnMode )
78 {
79   return (INT16) ExtSelectClipRgn((HDC) hdc, (HRGN) hrgn, fnMode);
80 }
81
82 /******************************************************************************
83  *              ExtSelectClipRgn        [GDI32.@]
84  */
85 INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode )
86 {
87     INT retval;
88     DC * dc = DC_GetDCUpdate( hdc );
89     if (!dc) return ERROR;
90
91     TRACE("%04x %04x %d\n", hdc, hrgn, fnMode );
92
93     if (!hrgn)
94     {
95         if (fnMode == RGN_COPY)
96         {
97             if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
98             dc->hClipRgn = 0;
99             retval = SIMPLEREGION; /* Clip region == whole DC */
100         }
101         else
102         {
103             FIXME("Unimplemented: hrgn NULL in mode: %d\n", fnMode); 
104             GDI_ReleaseObj( hdc );
105             return ERROR;
106         }
107     }
108     else 
109     {
110         if (!dc->hClipRgn)
111         {
112             RECT rect;
113             GetRgnBox( dc->hVisRgn, &rect );
114             dc->hClipRgn = CreateRectRgnIndirect( &rect );
115         }
116
117         OffsetRgn( dc->hClipRgn, -dc->DCOrgX, -dc->DCOrgY );
118         if(fnMode == RGN_COPY)
119             retval = CombineRgn( dc->hClipRgn, hrgn, 0, fnMode );
120         else
121             retval = CombineRgn( dc->hClipRgn, dc->hClipRgn, hrgn, fnMode);
122         OffsetRgn( dc->hClipRgn, dc->DCOrgX, dc->DCOrgY );
123     }
124
125     CLIPPING_UpdateGCRegion( dc );
126     GDI_ReleaseObj( hdc );
127     return retval;
128 }
129
130 /***********************************************************************
131  *           SelectVisRgn    (GDI.105)
132  */
133 INT16 WINAPI SelectVisRgn16( HDC16 hdc, HRGN16 hrgn )
134 {
135     int retval;
136     DC * dc;
137
138     if (!hrgn) return ERROR;
139     if (!(dc = DC_GetDCPtr( hdc ))) return ERROR;
140
141     TRACE("%04x %04x\n", hdc, hrgn );
142
143     dc->flags &= ~DC_DIRTY;
144
145     retval = CombineRgn16( dc->hVisRgn, hrgn, 0, RGN_COPY );
146     CLIPPING_UpdateGCRegion( dc );
147     GDI_ReleaseObj( hdc );
148     return retval;
149 }
150
151
152 /***********************************************************************
153  *           OffsetClipRgn    (GDI.32)
154  */
155 INT16 WINAPI OffsetClipRgn16( HDC16 hdc, INT16 x, INT16 y )
156 {
157     return (INT16)OffsetClipRgn( hdc, x, y );
158 }
159
160
161 /***********************************************************************
162  *           OffsetClipRgn    (GDI32.@)
163  */
164 INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y )
165 {
166     INT ret = SIMPLEREGION;
167     DC *dc = DC_GetDCUpdate( hdc );
168     if (!dc) return ERROR;
169
170     TRACE("%04x %d,%d\n", hdc, x, y );
171
172     if(dc->funcs->pOffsetClipRgn)
173         ret = dc->funcs->pOffsetClipRgn( dc, x, y );
174     else if (dc->hClipRgn) {
175         ret = OffsetRgn( dc->hClipRgn, XLSTODS(dc,x), YLSTODS(dc,y));
176         CLIPPING_UpdateGCRegion( dc );
177     }
178     GDI_ReleaseObj( hdc );
179     return ret;
180 }
181
182
183 /***********************************************************************
184  *           OffsetVisRgn    (GDI.102)
185  */
186 INT16 WINAPI OffsetVisRgn16( HDC16 hdc, INT16 x, INT16 y )
187 {
188     INT16 retval;
189     DC * dc = DC_GetDCUpdate( hdc );
190     if (!dc) return ERROR;    
191     TRACE("%04x %d,%d\n", hdc, x, y );
192     retval = OffsetRgn( dc->hVisRgn, x, y );
193     CLIPPING_UpdateGCRegion( dc );
194     GDI_ReleaseObj( hdc );
195     return retval;
196 }
197
198
199 /***********************************************************************
200  *           CLIPPING_IntersectClipRect
201  *
202  * Helper function for {Intersect,Exclude}ClipRect, can be called from
203  * elsewhere (like ExtTextOut()) to skip redundant metafile update and
204  * coordinate conversion.
205  */
206 INT CLIPPING_IntersectClipRect( DC * dc, INT left, INT top,
207                                   INT right, INT bottom, UINT flags )
208 {
209     HRGN newRgn;
210     INT ret;
211
212     left   += dc->DCOrgX;
213     right  += dc->DCOrgX;
214     top    += dc->DCOrgY;
215     bottom += dc->DCOrgY;
216
217     if (!(newRgn = CreateRectRgn( left, top, right, bottom ))) return ERROR;
218     if (!dc->hClipRgn)
219     {
220        if( flags & CLIP_INTERSECT )
221        {
222            dc->hClipRgn = newRgn;
223            CLIPPING_UpdateGCRegion( dc );
224            return SIMPLEREGION;
225        }
226        else if( flags & CLIP_EXCLUDE )
227        {
228            dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
229            CombineRgn( dc->hClipRgn, dc->hVisRgn, 0, RGN_COPY );
230        }
231        else WARN("No hClipRgn and flags are %x\n",flags);
232     }
233
234     ret = CombineRgn( newRgn, dc->hClipRgn, newRgn, 
235                         (flags & CLIP_EXCLUDE) ? RGN_DIFF : RGN_AND );
236     if (ret != ERROR)
237     {
238         if (!(flags & CLIP_KEEPRGN)) DeleteObject( dc->hClipRgn );
239         dc->hClipRgn = newRgn;    
240         CLIPPING_UpdateGCRegion( dc );
241     }
242     else DeleteObject( newRgn );
243     return ret;
244 }
245
246
247 /***********************************************************************
248  *           ExcludeClipRect    (GDI.21)
249  */
250 INT16 WINAPI ExcludeClipRect16( HDC16 hdc, INT16 left, INT16 top,
251                                 INT16 right, INT16 bottom )
252 {
253     return (INT16)ExcludeClipRect( hdc, left, top, right, bottom );
254 }
255
256
257 /***********************************************************************
258  *           ExcludeClipRect    (GDI32.@)
259  */
260 INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top,
261                                 INT right, INT bottom )
262 {
263     INT ret;
264     DC *dc = DC_GetDCUpdate( hdc );
265     if (!dc) return ERROR;
266
267     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
268
269     if(dc->funcs->pExcludeClipRect)
270         ret = dc->funcs->pExcludeClipRect( dc, left, top, right, bottom );
271     else {
272         left   = XLPTODP( dc, left );
273         right  = XLPTODP( dc, right );
274         top    = YLPTODP( dc, top );
275         bottom = YLPTODP( dc, bottom );
276
277         ret = CLIPPING_IntersectClipRect( dc, left, top, right, bottom, CLIP_EXCLUDE );
278     }
279     GDI_ReleaseObj( hdc );
280     return ret;
281 }
282
283
284 /***********************************************************************
285  *           IntersectClipRect    (GDI.22)
286  */
287 INT16 WINAPI IntersectClipRect16( HDC16 hdc, INT16 left, INT16 top,
288                                   INT16 right, INT16 bottom )
289 {
290     return (INT16)IntersectClipRect( hdc, left, top, right, bottom );
291 }
292
293
294 /***********************************************************************
295  *           IntersectClipRect    (GDI32.@)
296  */
297 INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top,
298                                   INT right, INT bottom )
299 {
300     INT ret;
301     DC *dc = DC_GetDCUpdate( hdc );
302     if (!dc) return ERROR;
303
304     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
305
306     if(dc->funcs->pIntersectClipRect)
307         ret = dc->funcs->pIntersectClipRect( dc, left, top, right, bottom );
308     else {
309         left   = XLPTODP( dc, left );
310         right  = XLPTODP( dc, right );
311         top    = YLPTODP( dc, top );
312         bottom = YLPTODP( dc, bottom );
313
314         ret = CLIPPING_IntersectClipRect( dc, left, top, right, bottom, CLIP_INTERSECT );
315     }
316     GDI_ReleaseObj( hdc );
317     return ret;
318 }
319
320
321 /***********************************************************************
322  *           CLIPPING_IntersectVisRect
323  *
324  * Helper function for {Intersect,Exclude}VisRect, can be called from
325  * elsewhere (like ExtTextOut()) to skip redundant metafile update and
326  * coordinate conversion.
327  */
328 INT CLIPPING_IntersectVisRect( DC * dc, INT left, INT top,
329                                  INT right, INT bottom,
330                                  BOOL exclude )
331 {
332     HRGN tempRgn, newRgn;
333     INT ret;
334
335     left   += dc->DCOrgX;
336     right  += dc->DCOrgX;
337     top    += dc->DCOrgY;
338     bottom += dc->DCOrgY;
339
340     if (!(newRgn = CreateRectRgn( 0, 0, 0, 0 ))) return ERROR;
341     if (!(tempRgn = CreateRectRgn( left, top, right, bottom )))
342     {
343         DeleteObject( newRgn );
344         return ERROR;
345     }
346     ret = CombineRgn( newRgn, dc->hVisRgn, tempRgn,
347                         exclude ? RGN_DIFF : RGN_AND );
348     DeleteObject( tempRgn );
349
350     if (ret != ERROR)
351     {
352         RGNOBJ *newObj  = (RGNOBJ*)GDI_GetObjPtr( newRgn, REGION_MAGIC);
353         if (newObj)
354         {
355             RGNOBJ *prevObj = (RGNOBJ*)GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC);
356             if (prevObj)
357             {
358                 newObj->header.hNext = prevObj->header.hNext;
359                 GDI_ReleaseObj( dc->hVisRgn );
360             }
361             GDI_ReleaseObj( newRgn );
362         }
363         DeleteObject( dc->hVisRgn );
364         dc->hVisRgn = newRgn;    
365         CLIPPING_UpdateGCRegion( dc );
366     }
367     else DeleteObject( newRgn );
368     return ret;
369 }
370
371
372 /***********************************************************************
373  *           ExcludeVisRect    (GDI.73)
374  */
375 INT16 WINAPI ExcludeVisRect16( HDC16 hdc, INT16 left, INT16 top,
376                              INT16 right, INT16 bottom )
377 {
378     INT16 ret;
379     DC * dc = DC_GetDCUpdate( hdc );
380     if (!dc) return ERROR;    
381
382     left   = XLPTODP( dc, left );
383     right  = XLPTODP( dc, right );
384     top    = YLPTODP( dc, top );
385     bottom = YLPTODP( dc, bottom );
386
387     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
388
389     ret = CLIPPING_IntersectVisRect( dc, left, top, right, bottom, TRUE );
390     GDI_ReleaseObj( hdc );
391     return ret;
392 }
393
394
395 /***********************************************************************
396  *           IntersectVisRect    (GDI.98)
397  */
398 INT16 WINAPI IntersectVisRect16( HDC16 hdc, INT16 left, INT16 top,
399                                INT16 right, INT16 bottom )
400 {
401     INT16 ret;
402     DC * dc = DC_GetDCUpdate( hdc );
403     if (!dc) return ERROR;    
404
405     left   = XLPTODP( dc, left );
406     right  = XLPTODP( dc, right );
407     top    = YLPTODP( dc, top );
408     bottom = YLPTODP( dc, bottom );
409
410     TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom );
411
412     ret = CLIPPING_IntersectVisRect( dc, left, top, right, bottom, FALSE );
413     GDI_ReleaseObj( hdc );
414     return ret;
415 }
416
417
418 /***********************************************************************
419  *           PtVisible    (GDI.103)
420  */
421 BOOL16 WINAPI PtVisible16( HDC16 hdc, INT16 x, INT16 y )
422 {
423     return PtVisible( hdc, x, y );
424 }
425
426
427 /***********************************************************************
428  *           PtVisible    (GDI32.@)
429  */
430 BOOL WINAPI PtVisible( HDC hdc, INT x, INT y )
431 {
432     BOOL ret = FALSE;
433     DC *dc = DC_GetDCUpdate( hdc );
434
435     TRACE("%04x %d,%d\n", hdc, x, y );
436     if (!dc) return FALSE;
437     if (dc->hGCClipRgn)
438     {
439         ret = PtInRegion( dc->hGCClipRgn, XLPTODP(dc,x) + dc->DCOrgX, 
440                                            YLPTODP(dc,y) + dc->DCOrgY );
441     }
442     GDI_ReleaseObj( hdc );
443     return ret;
444 }
445
446
447 /***********************************************************************
448  *           RectVisible    (GDI.465)
449  *           RectVisibleOld (GDI.104)
450  */
451 BOOL16 WINAPI RectVisible16( HDC16 hdc, const RECT16* rect16 )
452 {
453     RECT rect;
454     CONV_RECT16TO32( rect16, &rect );
455     return RectVisible( hdc, &rect );
456 }
457
458
459 /***********************************************************************
460  *           RectVisible    (GDI32.@)
461  */
462 BOOL WINAPI RectVisible( HDC hdc, const RECT* rect )
463 {
464     BOOL ret = FALSE;
465     RECT tmpRect;
466     DC *dc = DC_GetDCUpdate( hdc );
467     if (!dc) return FALSE;
468     TRACE("%04x %d,%dx%d,%d\n",
469           hdc, rect->left, rect->top, rect->right, rect->bottom );
470     if (dc->hGCClipRgn)
471     {
472         /* copy rectangle to avoid overwriting by LPtoDP */
473         tmpRect = *rect;
474         LPtoDP( hdc, (LPPOINT)&tmpRect, 2 );
475         tmpRect.left   += dc->DCOrgX;
476         tmpRect.right  += dc->DCOrgX;
477         tmpRect.top    += dc->DCOrgY;
478         tmpRect.bottom += dc->DCOrgY;
479         ret = RectInRegion( dc->hGCClipRgn, &tmpRect );
480     }
481     GDI_ReleaseObj( hdc );
482     return ret;
483 }
484
485
486 /***********************************************************************
487  *           GetClipBox    (GDI.77)
488  */
489 INT16 WINAPI GetClipBox16( HDC16 hdc, LPRECT16 rect )
490 {
491     int ret;
492     DC *dc = DC_GetDCUpdate( hdc );
493     if (!dc) return ERROR;
494     ret = GetRgnBox16( dc->hGCClipRgn, rect );
495     rect->left   -= dc->DCOrgX;
496     rect->right  -= dc->DCOrgX;
497     rect->top    -= dc->DCOrgY;
498     rect->bottom -= dc->DCOrgY;
499     DPtoLP16( hdc, (LPPOINT16)rect, 2 );
500     TRACE("%d,%d-%d,%d\n", rect->left,rect->top,rect->right,rect->bottom );
501     GDI_ReleaseObj( hdc );
502     return ret;
503 }
504
505
506 /***********************************************************************
507  *           GetClipBox    (GDI32.@)
508  */
509 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
510 {
511     INT ret;
512     DC *dc = DC_GetDCUpdate( hdc );
513     if (!dc) return ERROR;
514     ret = GetRgnBox( dc->hGCClipRgn, rect );
515     rect->left   -= dc->DCOrgX;
516     rect->right  -= dc->DCOrgX;
517     rect->top    -= dc->DCOrgY;
518     rect->bottom -= dc->DCOrgY;
519     DPtoLP( hdc, (LPPOINT)rect, 2 );
520     GDI_ReleaseObj( hdc );
521     return ret;
522 }
523
524
525 /***********************************************************************
526  *           GetClipRgn  (GDI32.@)
527  */
528 INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn )
529 {
530     INT ret = -1;
531     DC * dc;
532     if (hRgn && (dc = DC_GetDCPtr( hdc )))
533     {
534       if( dc->hClipRgn )
535       { 
536         /* this assumes that dc->hClipRgn is in coordinates
537            relative to the device (not DC origin) */
538
539         if( CombineRgn(hRgn, dc->hClipRgn, 0, RGN_COPY) != ERROR )
540         {
541             OffsetRgn( hRgn, -dc->DCOrgX, -dc->DCOrgY );
542             ret = 1;
543         }
544       }
545       else ret = 0;
546       GDI_ReleaseObj( hdc );
547     }
548     return ret;
549 }
550
551 /***********************************************************************
552  *           SaveVisRgn    (GDI.129)
553  */
554 HRGN16 WINAPI SaveVisRgn16( HDC16 hdc )
555 {
556     HRGN copy;
557     RGNOBJ *obj, *copyObj;
558     DC *dc = DC_GetDCUpdate( hdc );
559
560     if (!dc) return 0;
561     TRACE("%04x\n", hdc );
562
563     if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC )))
564     {
565         GDI_ReleaseObj( hdc );
566         return 0;
567     }
568     if (!(copy = CreateRectRgn( 0, 0, 0, 0 )))
569     {
570         GDI_ReleaseObj( dc->hVisRgn );
571         GDI_ReleaseObj( hdc );
572         return 0;
573     }  
574     CombineRgn( copy, dc->hVisRgn, 0, RGN_COPY );
575     if (!(copyObj = (RGNOBJ *) GDI_GetObjPtr( copy, REGION_MAGIC )))
576     {
577         DeleteObject( copy );
578         GDI_ReleaseObj( dc->hVisRgn );
579         GDI_ReleaseObj( hdc );
580         return 0;
581     }
582     copyObj->header.hNext = obj->header.hNext;
583     obj->header.hNext = copy;
584     GDI_ReleaseObj( copy );
585     GDI_ReleaseObj( dc->hVisRgn );
586     GDI_ReleaseObj( hdc );
587     return copy;
588 }
589
590
591 /***********************************************************************
592  *           RestoreVisRgn    (GDI.130)
593  */
594 INT16 WINAPI RestoreVisRgn16( HDC16 hdc )
595 {
596     HRGN saved;
597     RGNOBJ *obj, *savedObj;
598     DC *dc = DC_GetDCPtr( hdc );
599     INT16 ret = ERROR;
600
601     if (!dc) return ERROR;    
602     if (!dc->hVisRgn) goto done;
603     TRACE("%04x\n", hdc );
604     if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC ))) goto done;
605
606     saved = obj->header.hNext;
607     GDI_ReleaseObj( dc->hVisRgn );
608     if (!saved || !(savedObj = (RGNOBJ *) GDI_GetObjPtr( saved, REGION_MAGIC ))) goto done;
609
610     DeleteObject( dc->hVisRgn );
611     dc->hVisRgn = saved;
612     dc->flags &= ~DC_DIRTY;
613     CLIPPING_UpdateGCRegion( dc );
614     ret = savedObj->rgn->type; /* FIXME */
615     GDI_ReleaseObj( saved );
616  done:
617     GDI_ReleaseObj( hdc );
618     return ret;
619 }