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