Improvement on the code that deals with setting the color map in
[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 <stdarg.h>
22 #include <stdlib.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "wownt32.h"
27 #include "wine/winuser16.h"
28 #include "gdi.h"
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(clipping);
32
33
34 /***********************************************************************
35  *           CLIPPING_UpdateGCRegion
36  *
37  * Update the GC clip region when the ClipRgn or VisRgn have changed.
38  */
39 void CLIPPING_UpdateGCRegion( DC * dc )
40 {
41     if (!dc->hGCClipRgn) dc->hGCClipRgn = CreateRectRgn( 0, 0, 0, 0 );
42
43     if (!dc->hVisRgn)
44     {
45         ERR("hVisRgn is zero. Please report this.\n" );
46         exit(1);
47     }
48
49     if (dc->flags & DC_DIRTY) ERR( "DC is dirty. Please report this.\n" );
50
51     if (!dc->hClipRgn)
52         CombineRgn( dc->hGCClipRgn, dc->hVisRgn, 0, RGN_COPY );
53     else
54         CombineRgn(dc->hGCClipRgn, dc->hClipRgn, dc->hVisRgn, RGN_AND);
55     if (dc->funcs->pSetDeviceClipping)
56         dc->funcs->pSetDeviceClipping( dc->physDev, dc->hGCClipRgn );
57 }
58
59
60 /***********************************************************************
61  *           SelectClipRgn    (GDI32.@)
62  */
63 INT WINAPI SelectClipRgn( HDC hdc, HRGN hrgn )
64 {
65     return ExtSelectClipRgn( hdc, hrgn, RGN_COPY );
66 }
67
68
69 /******************************************************************************
70  *              ExtSelectClipRgn        [GDI32.@]
71  */
72 INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode )
73 {
74     INT retval;
75     RECT rect;
76     DC * dc = DC_GetDCUpdate( hdc );
77     if (!dc) return ERROR;
78
79     TRACE("%p %p %d\n", hdc, hrgn, fnMode );
80
81     if (dc->funcs->pExtSelectClipRgn)
82     {
83         retval = dc->funcs->pExtSelectClipRgn( dc->physDev, hrgn, fnMode );
84         GDI_ReleaseObj( hdc );
85         return retval;
86     }
87
88     if (!hrgn)
89     {
90         if (fnMode == RGN_COPY)
91         {
92             if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
93             dc->hClipRgn = 0;
94         }
95         else
96         {
97             FIXME("Unimplemented: hrgn NULL in mode: %d\n", fnMode);
98             GDI_ReleaseObj( hdc );
99             return ERROR;
100         }
101     }
102     else
103     {
104         if (!dc->hClipRgn)
105         {
106             RECT rect;
107             GetRgnBox( dc->hVisRgn, &rect );
108             dc->hClipRgn = CreateRectRgnIndirect( &rect );
109         }
110
111         if(fnMode == RGN_COPY)
112             CombineRgn( dc->hClipRgn, hrgn, 0, fnMode );
113         else
114             CombineRgn( dc->hClipRgn, dc->hClipRgn, hrgn, fnMode);
115     }
116
117     CLIPPING_UpdateGCRegion( dc );
118     GDI_ReleaseObj( hdc );
119
120     return GetClipBox(hdc, &rect);
121 }
122
123 /***********************************************************************
124  *           SelectVisRgn   (GDI.105)
125  */
126 INT16 WINAPI SelectVisRgn16( HDC16 hdc16, HRGN16 hrgn )
127 {
128     int retval;
129     HDC hdc = HDC_32( hdc16 );
130     DC * dc;
131
132     if (!hrgn) return ERROR;
133     if (!(dc = DC_GetDCPtr( hdc ))) return ERROR;
134
135     TRACE("%p %04x\n", hdc, hrgn );
136
137     dc->flags &= ~DC_DIRTY;
138
139     retval = CombineRgn( dc->hVisRgn, HRGN_32(hrgn), 0, RGN_COPY );
140     CLIPPING_UpdateGCRegion( dc );
141     GDI_ReleaseObj( hdc );
142     return retval;
143 }
144
145
146 /***********************************************************************
147  *           OffsetClipRgn    (GDI32.@)
148  */
149 INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y )
150 {
151     INT ret = SIMPLEREGION;
152     DC *dc = DC_GetDCUpdate( hdc );
153     if (!dc) return ERROR;
154
155     TRACE("%p %d,%d\n", hdc, x, y );
156
157     if(dc->funcs->pOffsetClipRgn)
158         ret = dc->funcs->pOffsetClipRgn( dc->physDev, x, y );
159     else if (dc->hClipRgn) {
160         ret = OffsetRgn( dc->hClipRgn, XLSTODS(dc,x), YLSTODS(dc,y));
161         CLIPPING_UpdateGCRegion( dc );
162     }
163     GDI_ReleaseObj( hdc );
164     return ret;
165 }
166
167
168 /***********************************************************************
169  *           OffsetVisRgn    (GDI.102)
170  */
171 INT16 WINAPI OffsetVisRgn16( HDC16 hdc16, INT16 x, INT16 y )
172 {
173     INT16 retval;
174     HDC hdc = HDC_32( hdc16 );
175     DC * dc = DC_GetDCUpdate( hdc );
176     if (!dc) return ERROR;
177     TRACE("%p %d,%d\n", hdc, x, y );
178     retval = OffsetRgn( dc->hVisRgn, x, y );
179     CLIPPING_UpdateGCRegion( dc );
180     GDI_ReleaseObj( hdc );
181     return retval;
182 }
183
184
185 /***********************************************************************
186  *           ExcludeClipRect    (GDI32.@)
187  */
188 INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top,
189                                 INT right, INT bottom )
190 {
191     HRGN newRgn;
192     INT ret;
193     DC *dc = DC_GetDCUpdate( hdc );
194     if (!dc) return ERROR;
195
196     TRACE("%p %dx%d,%dx%d\n", hdc, left, top, right, bottom );
197
198     if(dc->funcs->pExcludeClipRect)
199         ret = dc->funcs->pExcludeClipRect( dc->physDev, left, top, right, bottom );
200     else
201     {
202         POINT pt[2];
203
204         pt[0].x = left;
205         pt[0].y = top;
206         pt[1].x = right;
207         pt[1].y = bottom;
208         LPtoDP( hdc, pt, 2 );
209         if (!(newRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
210         else
211         {
212             if (!dc->hClipRgn)
213             {
214                 dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
215                 CombineRgn( dc->hClipRgn, dc->hVisRgn, 0, RGN_COPY );
216             }
217             ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_DIFF );
218             DeleteObject( newRgn );
219         }
220         if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
221     }
222     GDI_ReleaseObj( hdc );
223     return ret;
224 }
225
226
227 /***********************************************************************
228  *           IntersectClipRect    (GDI32.@)
229  */
230 INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top, INT right, INT bottom )
231 {
232     INT ret;
233     DC *dc = DC_GetDCUpdate( hdc );
234     if (!dc) return ERROR;
235
236     TRACE("%p %d,%d - %d,%d\n", hdc, left, top, right, bottom );
237
238     if(dc->funcs->pIntersectClipRect)
239         ret = dc->funcs->pIntersectClipRect( dc->physDev, left, top, right, bottom );
240     else
241     {
242         POINT pt[2];
243
244         pt[0].x = left;
245         pt[0].y = top;
246         pt[1].x = right;
247         pt[1].y = bottom;
248
249         LPtoDP( hdc, pt, 2 );
250
251         if (!dc->hClipRgn)
252         {
253             dc->hClipRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y );
254             ret = SIMPLEREGION;
255         }
256         else
257         {
258             HRGN newRgn;
259
260             if (!(newRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
261             else
262             {
263                 ret = CombineRgn( dc->hClipRgn, dc->hClipRgn, newRgn, RGN_AND );
264                 DeleteObject( newRgn );
265             }
266         }
267         if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
268     }
269     GDI_ReleaseObj( hdc );
270     return ret;
271 }
272
273
274 /***********************************************************************
275  *           ExcludeVisRect   (GDI.73)
276  */
277 INT16 WINAPI ExcludeVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, INT16 bottom )
278 {
279     HRGN tempRgn;
280     INT16 ret;
281     POINT pt[2];
282     HDC hdc = HDC_32( hdc16 );
283     DC * dc = DC_GetDCUpdate( hdc );
284     if (!dc) return ERROR;
285
286     pt[0].x = left;
287     pt[0].y = top;
288     pt[1].x = right;
289     pt[1].y = bottom;
290
291     LPtoDP( hdc, pt, 2 );
292
293     TRACE("%p %ld,%ld - %ld,%ld\n", hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
294
295     if (!(tempRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
296     else
297     {
298         ret = CombineRgn( dc->hVisRgn, dc->hVisRgn, tempRgn, RGN_DIFF );
299         DeleteObject( tempRgn );
300     }
301     if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
302     GDI_ReleaseObj( hdc );
303     return ret;
304 }
305
306
307 /***********************************************************************
308  *           IntersectVisRect   (GDI.98)
309  */
310 INT16 WINAPI IntersectVisRect16( HDC16 hdc16, INT16 left, INT16 top, INT16 right, INT16 bottom )
311 {
312     HRGN tempRgn;
313     INT16 ret;
314     POINT pt[2];
315     HDC hdc = HDC_32( hdc16 );
316     DC * dc = DC_GetDCUpdate( hdc );
317     if (!dc) return ERROR;
318
319     pt[0].x = left;
320     pt[0].y = top;
321     pt[1].x = right;
322     pt[1].y = bottom;
323
324     LPtoDP( hdc, pt, 2 );
325
326     TRACE("%p %ld,%ld - %ld,%ld\n", hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
327
328
329     if (!(tempRgn = CreateRectRgn( pt[0].x, pt[0].y, pt[1].x, pt[1].y ))) ret = ERROR;
330     else
331     {
332         ret = CombineRgn( dc->hVisRgn, dc->hVisRgn, tempRgn, RGN_AND );
333         DeleteObject( tempRgn );
334     }
335     if (ret != ERROR) CLIPPING_UpdateGCRegion( dc );
336     GDI_ReleaseObj( hdc );
337     return ret;
338 }
339
340
341 /***********************************************************************
342  *           PtVisible    (GDI32.@)
343  */
344 BOOL WINAPI PtVisible( HDC hdc, INT x, INT y )
345 {
346     BOOL ret = FALSE;
347     DC *dc = DC_GetDCUpdate( hdc );
348
349     TRACE("%p %d,%d\n", hdc, x, y );
350     if (!dc) return FALSE;
351     if (dc->hGCClipRgn)
352     {
353         POINT pt;
354
355         pt.x = x;
356         pt.y = y;
357         LPtoDP( hdc, &pt, 1 );
358         ret = PtInRegion( dc->hGCClipRgn, pt.x, pt.y );
359     }
360     GDI_ReleaseObj( hdc );
361     return ret;
362 }
363
364
365 /***********************************************************************
366  *           RectVisible    (GDI32.@)
367  */
368 BOOL WINAPI RectVisible( HDC hdc, const RECT* rect )
369 {
370     BOOL ret = FALSE;
371     DC *dc = DC_GetDCUpdate( hdc );
372     if (!dc) return FALSE;
373     TRACE("%p %ld,%ldx%ld,%ld\n", hdc, rect->left, rect->top, rect->right, rect->bottom );
374     if (dc->hGCClipRgn)
375     {
376         POINT pt[2];
377         RECT tmpRect;
378
379         pt[0].x = rect->left;
380         pt[0].y = rect->top;
381         pt[1].x = rect->right;
382         pt[1].y = rect->bottom;
383         LPtoDP( hdc, pt, 2 );
384         tmpRect.left    = pt[0].x;
385         tmpRect.top     = pt[0].y;
386         tmpRect.right   = pt[1].x;
387         tmpRect.bottom  = pt[1].y;
388         ret = RectInRegion( dc->hGCClipRgn, &tmpRect );
389     }
390     GDI_ReleaseObj( hdc );
391     return ret;
392 }
393
394
395 /***********************************************************************
396  *           GetClipBox    (GDI32.@)
397  */
398 INT WINAPI GetClipBox( HDC hdc, LPRECT rect )
399 {
400     INT ret;
401     DC *dc = DC_GetDCUpdate( hdc );
402     if (!dc) return ERROR;
403     ret = GetRgnBox( dc->hGCClipRgn, rect );
404     DPtoLP( hdc, (LPPOINT)rect, 2 );
405     GDI_ReleaseObj( hdc );
406     return ret;
407 }
408
409
410 /***********************************************************************
411  *           GetClipRgn  (GDI32.@)
412  */
413 INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn )
414 {
415     INT ret = -1;
416     DC * dc;
417     if (hRgn && (dc = DC_GetDCPtr( hdc )))
418     {
419       if( dc->hClipRgn )
420       {
421           if( CombineRgn(hRgn, dc->hClipRgn, 0, RGN_COPY) != ERROR ) ret = 1;
422       }
423       else ret = 0;
424       GDI_ReleaseObj( hdc );
425     }
426     return ret;
427 }
428
429 /***********************************************************************
430  *           SaveVisRgn   (GDI.129)
431  */
432 HRGN16 WINAPI SaveVisRgn16( HDC16 hdc16 )
433 {
434     HRGN copy;
435     GDIOBJHDR *obj, *copyObj;
436     HDC hdc = HDC_32( hdc16 );
437     DC *dc = DC_GetDCUpdate( hdc );
438
439     if (!dc) return 0;
440     TRACE("%p\n", hdc );
441
442     if (!(obj = GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC )))
443     {
444         GDI_ReleaseObj( hdc );
445         return 0;
446     }
447     if (!(copy = CreateRectRgn( 0, 0, 0, 0 )))
448     {
449         GDI_ReleaseObj( dc->hVisRgn );
450         GDI_ReleaseObj( hdc );
451         return 0;
452     }
453     CombineRgn( copy, dc->hVisRgn, 0, RGN_COPY );
454     if (!(copyObj = GDI_GetObjPtr( copy, REGION_MAGIC )))
455     {
456         DeleteObject( copy );
457         GDI_ReleaseObj( dc->hVisRgn );
458         GDI_ReleaseObj( hdc );
459         return 0;
460     }
461     copyObj->hNext = obj->hNext;
462     obj->hNext = HRGN_16(copy);
463     GDI_ReleaseObj( copy );
464     GDI_ReleaseObj( dc->hVisRgn );
465     GDI_ReleaseObj( hdc );
466     return HRGN_16(copy);
467 }
468
469
470 /***********************************************************************
471  *           RestoreVisRgn   (GDI.130)
472  */
473 INT16 WINAPI RestoreVisRgn16( HDC16 hdc16 )
474 {
475     HRGN saved;
476     GDIOBJHDR *obj, *savedObj;
477     HDC hdc = HDC_32( hdc16 );
478     DC *dc = DC_GetDCPtr( hdc );
479     INT16 ret = ERROR;
480
481     if (!dc) return ERROR;
482
483     TRACE("%p\n", hdc );
484
485     if (!(obj = GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC ))) goto done;
486     saved = HRGN_32(obj->hNext);
487
488     if ((savedObj = GDI_GetObjPtr( saved, REGION_MAGIC )))
489     {
490         ret = CombineRgn( dc->hVisRgn, saved, 0, RGN_COPY );
491         obj->hNext = savedObj->hNext;
492         GDI_ReleaseObj( saved );
493         DeleteObject( saved );
494         dc->flags &= ~DC_DIRTY;
495         CLIPPING_UpdateGCRegion( dc );
496     }
497     GDI_ReleaseObj( dc->hVisRgn );
498  done:
499     GDI_ReleaseObj( hdc );
500     return ret;
501 }
502
503
504 /***********************************************************************
505  * GetRandomRgn [GDI32.@]
506  *
507  * NOTES
508  *     This function is documented in MSDN online for the case of
509  *     dwCode == SYSRGN (4).
510  *
511  *     For dwCode == 1 it should return the clip region
512  *                   2 "    "       "   the meta region
513  *                   3 "    "       "   the intersection of the clip with
514  *                                      the meta region (== 'Rao' region).
515  *
516  *     See http://www.codeproject.com/gdi/cliprgnguide.asp
517  */
518 INT WINAPI GetRandomRgn(HDC hDC, HRGN hRgn, DWORD dwCode)
519 {
520     switch (dwCode)
521     {
522     case SYSRGN: /* == 4 */
523         {
524             DC *dc = DC_GetDCPtr (hDC);
525             if (!dc) return -1;
526
527             CombineRgn (hRgn, dc->hVisRgn, 0, RGN_COPY);
528             GDI_ReleaseObj( hDC );
529             /*
530              *     On Windows NT/2000,
531              *           the region returned is in screen coordinates.
532              *     On Windows 95/98,
533              *           the region returned is in window coordinates
534              */
535             if (!(GetVersion() & 0x80000000))
536             {
537                 POINT org;
538                 GetDCOrgEx(hDC, &org);
539                 OffsetRgn(hRgn, org.x, org.y);
540             }
541             return 1;
542         }
543
544     case 1: /* clip region */
545             return GetClipRgn (hDC, hRgn);
546
547     default:
548         WARN("Unknown dwCode %ld\n", dwCode);
549         return -1;
550     }
551
552     return -1;
553 }
554
555
556 /***********************************************************************
557  *           GetMetaRgn    (GDI32.@)
558  */
559 INT WINAPI GetMetaRgn( HDC hdc, HRGN hRgn )
560 {
561     FIXME( "stub\n" );
562
563     return 0;
564 }
565
566
567 /***********************************************************************
568  *           SetMetaRgn    (GDI32.@)
569  */
570 INT WINAPI SetMetaRgn( HDC hdc )
571 {
572     FIXME( "stub\n" );
573
574     return ERROR;
575 }