]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/services/gfx/mw/v2_0/src/mwin/winclip1.c
Initial revision
[karo-tx-redboot.git] / packages / services / gfx / mw / v2_0 / src / mwin / winclip1.c
1 /*
2  * Copyright (c) 1999 Greg Haerr <greg@censoft.com>
3  * Copyright (c) 1991 David I. Bell
4  * Permission is granted to use, distribute, or modify this source,
5  * provided that this copyright notice remains intact.
6  */
7 #include "windows.h"
8 #include "wintern.h"
9
10 /*
11  * Macro to distinguish cases of clipping.
12  */
13 #define GAPVAL(leftgap, rightgap, topgap, bottomgap) \
14         (((leftgap) << 3) + ((rightgap) << 2) + ((topgap) << 1) + (bottomgap))
15
16 static BOOL MwExcludeClipRect(int minx,int miny,int maxx,int maxy,int *count,
17                 MWCLIPRECT *cliprects);
18 static int  MwSplitClipRect(MWCLIPRECT *srcrect, MWCLIPRECT *destrect,
19                 MWCOORD minx, MWCOORD miny, MWCOORD maxx, MWCOORD maxy);
20
21 /*
22  * Set the clip rectangles for a window taking into account other
23  * windows that may be obscuring it.  The windows that may be obscuring
24  * this one are the siblings of each direct ancestor which are higher
25  * in priority than those ancestors.  Also, each parent limits the visible
26  * area of the window.
27  */
28 void
29 MwSetClipWindow(HDC hdc)
30 {
31         HWND            wp = hdc->hwnd;
32         HWND            pwp;            /* parent window */
33         HWND            sibwp;          /* sibling windows */
34         MWCLIPRECT      *clip;          /* first clip rectangle */
35         int             count;          /* number of clip rectangles */
36         MWCOORD         diff;           /* difference in coordinates */
37         BOOL            toomany;        /* TRUE if too many clip rects */
38         PRECT           prc;            /* client or window rectangle*/
39         MWCLIPRECT      cliprects[MAX_CLIPRECTS];       /* clip rectangles */
40
41         if (wp->unmapcount)
42                 return;
43
44         /*
45          * Start with the rectangle for the complete window.
46          * We will then cut pieces out of it as needed.
47          */
48         prc = MwIsClientDC(hdc)? &wp->clirect: &wp->winrect;
49         count = 1;
50         clip = cliprects;
51         clip->x = prc->left;
52         clip->y = prc->top;
53         clip->width = prc->right - prc->left;
54         clip->height = prc->bottom - prc->top;
55
56         /*
57          * First walk upwards through all parent windows,
58          * and restrict the visible part of this window to the part
59          * that shows through all of those parent windows client areas.
60          */
61         pwp = wp;
62         while (pwp != rootwp) {
63                 pwp = pwp->parent;
64
65                 diff = pwp->clirect.left - clip->x;
66                 if (diff > 0) {
67                         clip->width -= diff;
68                         clip->x = pwp->clirect.left;
69                 }
70
71                 diff = pwp->clirect.right - (clip->x + clip->width);
72                 if (diff < 0)
73                         clip->width += diff;
74
75                 diff = pwp->clirect.top - clip->y;
76                 if (diff > 0) {
77                         clip->height -= diff;
78                         clip->y = pwp->clirect.top;
79                 }
80
81                 diff = pwp->clirect.bottom - (clip->y + clip->height);
82                 if (diff < 0)
83                         clip->height += diff;
84         }
85
86         /*
87          * If the window is completely clipped out of view, then
88          * set the clipping region to indicate that.
89          */
90         if (clip->width <= 0 || clip->height <= 0) {
91                 GdSetClipRects(hdc->psd, 1, cliprects);
92                 return;
93         } 
94
95         /*
96          * Now examine all windows that obscure this window, and
97          * for each obscuration, break up the clip rectangles into
98          * the smaller pieces that are still visible.  The windows
99          * that can obscure us are the earlier siblings of all of
100          * our parents. When clipping the root window, search all children.
101          */
102         toomany = FALSE;
103         pwp = wp;
104         while (pwp != NULL) {
105                 wp = pwp;
106                 pwp = wp->parent;
107                 if(!pwp) {
108                         /* We're clipping the root window*/
109                         if(hdc->flags & DCX_CLIPCHILDREN)
110                                 /* start with root's children*/
111                                 sibwp = rootwp->children;
112                         else sibwp = NULL;      /* no search*/
113                         wp = NULL;              /* search all root's children*/
114                 } else {
115                         if(hdc->flags & DCX_CLIPSIBLINGS)
116                                 sibwp = pwp->children;
117                         else sibwp = wp;        /* no search*/
118                 }
119                 for (; sibwp != wp; sibwp = sibwp->siblings) {
120                         if (sibwp->unmapcount)
121                                 continue;
122
123                         toomany |= MwExcludeClipRect(sibwp->winrect.left,
124                                 sibwp->winrect.top, sibwp->winrect.right-1,
125                                 sibwp->winrect.bottom-1, &count, cliprects);
126
127                 }
128
129                 /* if not clipping the root window, stop when you reach it*/
130                 if(pwp == rootwp)
131                         break;
132         }
133
134         /*
135          * If not the root window and we're going to be drawing
136          * in the client area, clip all children.  This is
137          * required for non-special paint handling for child windows.
138          * Non-client dc's don't clip children in order to get
139          * proper border clipping in the case of border-clipped children.
140          */
141         wp = hdc->hwnd;
142         if(wp != rootwp && MwIsClientDC(hdc)) {
143                 for (sibwp=wp->children; sibwp; sibwp = sibwp->siblings) {
144                         if (sibwp->unmapcount)
145                                 continue;
146
147                         toomany |= MwExcludeClipRect(sibwp->winrect.left,
148                                 sibwp->winrect.top, sibwp->winrect.right-1,
149                                 sibwp->winrect.bottom-1, &count, cliprects);
150                 }
151         }
152
153         if (toomany) {
154                 /*GsError(GR_ERROR_TOO_MUCH_CLIPPING, wp->id);*/
155                 clip->x = 0;
156                 clip->y = 0;
157                 clip->width = -1;
158                 clip->height = -1;
159                 count = 1;
160         }
161
162         /*
163          * Set the clip rectangles.
164          */
165         GdSetClipRects(hdc->psd, count, cliprects);
166 }
167
168 static BOOL
169 MwExcludeClipRect(int minx,int miny,int maxx,int maxy,int *count,
170         MWCLIPRECT *cliprects)
171 {
172         int     i;              /* current index */
173         int     newcount;       /* number of new rectangles */
174         BOOL    toomany = FALSE;/* TRUE if too many clip rects */
175
176         newcount = *count;
177         for (i = 0; i < *count; i++) {
178                 if (newcount > MAX_CLIPRECTS - 3) {
179                         toomany = TRUE;
180                         break;
181                 }
182                 newcount += MwSplitClipRect(&cliprects[i],
183                         &cliprects[newcount],
184                         minx, miny, maxx, maxy);
185         }
186         *count = newcount;
187         return toomany;
188 }
189
190 /*
191  * Check the specified clip rectangle against the specified rectangular
192  * region, and reduce it or split it up into multiple clip rectangles
193  * such that the specified region is not contained in any of the clip
194  * rectangles.  The source clip rectangle can be modified in place, and
195  * in addition more clip rectangles can be generated, which are placed in
196  * the indicated destination location.  The maximum number of new clip
197  * rectangles needed is 3.  Returns the number of clip rectangles added.
198  * If the source clip rectangle is totally obliterated, it is set to an
199  * impossible region and 0 is returned.  When splits are done, we prefer
200  * to create wide regions instead of high regions.
201  */
202 static int
203 MwSplitClipRect(MWCLIPRECT *srcrect, MWCLIPRECT *destrect, MWCOORD minx,
204         MWCOORD miny, MWCOORD maxx, MWCOORD maxy)
205 {
206         MWCOORD         x;
207         MWCOORD         y;
208         MWCOORD         width;
209         MWCOORD         height;
210         MWCOORD         dx;
211         MWCOORD         dy;
212         int             gaps;
213
214         /*
215          * First see if there is any overlap at all.
216          * If not, then nothing to do.
217          */
218         x = srcrect->x;
219         y = srcrect->y;
220         width = srcrect->width;
221         height = srcrect->height;
222
223         if ((minx > maxx) || (miny > maxy) || (maxx < x) || (maxy < y) ||
224                 (x + width <= minx) || (y + height <= miny))
225                         return 0;
226
227         /*
228          * There is an overlap.  Calculate a value to differentiate
229          * various cases, and then handle each case separately.  The
230          * cases are classified on whether there are gaps on the left,
231          * right, top, and bottom sides of the clip rectangle.
232          */
233         gaps = 0;
234         if (x < minx)
235                 gaps |= GAPVAL(1, 0, 0, 0);
236         if (x + width - 1 > maxx)
237                 gaps |= GAPVAL(0, 1, 0, 0);
238         if (y < miny)
239                 gaps |= GAPVAL(0, 0, 1, 0);
240         if (y + height - 1 > maxy)
241                 gaps |= GAPVAL(0, 0, 0, 1);
242
243         switch (gaps) {
244                 case GAPVAL(0, 0, 0, 0):        /* no gaps at all */
245                         srcrect->x = 0;
246                         srcrect->y = 0;
247                         srcrect->width = 0;
248                         srcrect->height = 0;
249                         return 0;
250
251                 case GAPVAL(0, 0, 0, 1):        /* gap on bottom */
252                         dy = maxy - y + 1;
253                         srcrect->y += dy;
254                         srcrect->height -= dy;
255                         return 0;
256
257                 case GAPVAL(0, 0, 1, 0):        /* gap on top */
258                         srcrect->height = miny - y;
259                         return 0;
260
261                 case GAPVAL(0, 0, 1, 1):        /* gap on top, bottom */
262                         srcrect->height = miny - y;
263                         destrect->x = x;
264                         destrect->width = width;
265                         destrect->y = maxy + 1;
266                         destrect->height = y + height - maxy - 1;
267                         return 1;
268
269                 case GAPVAL(0, 1, 0, 0):        /* gap on right */
270                         dx = maxx - x + 1;
271                         srcrect->x += dx;
272                         srcrect->width -= dx;
273                         return 0;
274
275                 case GAPVAL(0, 1, 0, 1):        /* gap on right, bottom */
276                         dx = maxx - x + 1;
277                         srcrect->x += dx;
278                         srcrect->width -= dx;
279                         srcrect->height = maxy - y + 1;
280                         destrect->x = x;
281                         destrect->width = width;
282                         destrect->y = maxy + 1;
283                         destrect->height = y + height - maxy - 1;
284                         return 1;
285
286                 case GAPVAL(0, 1, 1, 0):        /* gap on right, top */
287                         dx = maxx - x + 1;
288                         srcrect->height = miny - y;
289                         destrect->x = x + dx;
290                         destrect->width = width - dx;
291                         destrect->y = miny;
292                         destrect->height = y + height - miny;
293                         return 1;
294
295                 case GAPVAL(0, 1, 1, 1):        /* gap on right, top, bottom */
296                         dx = maxx - x + 1;
297                         srcrect->height = miny - y;
298                         destrect->x = x;
299                         destrect->width = width;
300                         destrect->y = maxy + 1;
301                         destrect->height = y + height - maxy - 1;
302                         destrect++;
303                         destrect->x = x + dx;
304                         destrect->width = width - dx;
305                         destrect->y = miny;
306                         destrect->height = maxy - miny + 1;
307                         return 2;
308
309                 case GAPVAL(1, 0, 0, 0):        /* gap on left */
310                         srcrect->width = minx - x;
311                         return 0;
312
313                 case GAPVAL(1, 0, 0, 1):        /* gap on left, bottom */
314                         srcrect->width = minx - x;
315                         srcrect->height = maxy - y + 1;
316                         destrect->x = x;
317                         destrect->width = width;
318                         destrect->y = maxy + 1;
319                         destrect->height = y + height - maxy - 1;
320                         return 1;
321
322                 case GAPVAL(1, 0, 1, 0):        /* gap on left, top */
323                         srcrect->height = miny - y;
324                         destrect->x = x;
325                         destrect->width = minx - x;
326                         destrect->y = miny;
327                         destrect->height = y + height - miny;
328                         return 1;
329
330                 case GAPVAL(1, 0, 1, 1):        /* gap on left, top, bottom */
331                         srcrect->height = miny - y;
332                         destrect->x = x;
333                         destrect->width = minx - x;
334                         destrect->y = miny;
335                         destrect->height = maxy - miny + 1;
336                         destrect++;
337                         destrect->x = x;
338                         destrect->width = width;
339                         destrect->y = maxy + 1;
340                         destrect->height = y + height - maxy - 1;
341                         return 2;
342
343                 case GAPVAL(1, 1, 0, 0):        /* gap on left, right */
344                         destrect->x = maxx + 1;
345                         destrect->width = x + width - maxx - 1;
346                         destrect->y = y;
347                         destrect->height = height;
348                         srcrect->width = minx - x;
349                         return 1;
350
351                 case GAPVAL(1, 1, 0, 1):        /* gap on left, right, bottom */
352                         dy = maxy - y + 1;
353                         srcrect->y += dy;
354                         srcrect->height -= dy;
355                         destrect->x = x;
356                         destrect->width = minx - x;
357                         destrect->y = y;
358                         destrect->height = dy;
359                         destrect++;
360                         destrect->x = maxx + 1;
361                         destrect->width = x + width - maxx - 1;
362                         destrect->y = y;
363                         destrect->height = dy;
364                         return 2;
365
366                 case GAPVAL(1, 1, 1, 0):        /* gap on left, right, top */
367                         srcrect->height = miny - y;
368                         destrect->x = x;
369                         destrect->width = minx - x;
370                         destrect->y = miny;
371                         destrect->height = y + height - miny;
372                         destrect++;
373                         destrect->x = maxx + 1;
374                         destrect->width = x + width - maxx - 1;
375                         destrect->y = miny;
376                         destrect->height = y + height - miny;
377                         return 2;
378
379                 case GAPVAL(1, 1, 1, 1):        /* gap on all sides */
380                         srcrect->height = miny - y;
381                         destrect->x = x;
382                         destrect->width = minx - x;
383                         destrect->y = miny;
384                         destrect->height = maxy - miny + 1;
385                         destrect++;
386                         destrect->x = maxx + 1;
387                         destrect->width = x + width - maxx - 1;
388                         destrect->y = miny;
389                         destrect->height = maxy - miny + 1;
390                         destrect++;
391                         destrect->x = x;
392                         destrect->width = width;
393                         destrect->y = maxy + 1;
394                         destrect->height = y + height - maxy - 1;
395                         return 3;
396         }
397         return 0; /* NOTREACHED */
398 }