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.
11 * Macro to distinguish cases of clipping.
13 #define GAPVAL(leftgap, rightgap, topgap, bottomgap) \
14 (((leftgap) << 3) + ((rightgap) << 2) + ((topgap) << 1) + (bottomgap))
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);
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
29 MwSetClipWindow(HDC hdc)
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 */
45 * Start with the rectangle for the complete window.
46 * We will then cut pieces out of it as needed.
48 prc = MwIsClientDC(hdc)? &wp->clirect: &wp->winrect;
53 clip->width = prc->right - prc->left;
54 clip->height = prc->bottom - prc->top;
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.
62 while (pwp != rootwp) {
65 diff = pwp->clirect.left - clip->x;
68 clip->x = pwp->clirect.left;
71 diff = pwp->clirect.right - (clip->x + clip->width);
75 diff = pwp->clirect.top - clip->y;
78 clip->y = pwp->clirect.top;
81 diff = pwp->clirect.bottom - (clip->y + clip->height);
87 * If the window is completely clipped out of view, then
88 * set the clipping region to indicate that.
90 if (clip->width <= 0 || clip->height <= 0) {
91 GdSetClipRects(hdc->psd, 1, cliprects);
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.
104 while (pwp != NULL) {
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*/
115 if(hdc->flags & DCX_CLIPSIBLINGS)
116 sibwp = pwp->children;
117 else sibwp = wp; /* no search*/
119 for (; sibwp != wp; sibwp = sibwp->siblings) {
120 if (sibwp->unmapcount)
123 toomany |= MwExcludeClipRect(sibwp->winrect.left,
124 sibwp->winrect.top, sibwp->winrect.right-1,
125 sibwp->winrect.bottom-1, &count, cliprects);
129 /* if not clipping the root window, stop when you reach it*/
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.
142 if(wp != rootwp && MwIsClientDC(hdc)) {
143 for (sibwp=wp->children; sibwp; sibwp = sibwp->siblings) {
144 if (sibwp->unmapcount)
147 toomany |= MwExcludeClipRect(sibwp->winrect.left,
148 sibwp->winrect.top, sibwp->winrect.right-1,
149 sibwp->winrect.bottom-1, &count, cliprects);
154 /*GsError(GR_ERROR_TOO_MUCH_CLIPPING, wp->id);*/
163 * Set the clip rectangles.
165 GdSetClipRects(hdc->psd, count, cliprects);
169 MwExcludeClipRect(int minx,int miny,int maxx,int maxy,int *count,
170 MWCLIPRECT *cliprects)
172 int i; /* current index */
173 int newcount; /* number of new rectangles */
174 BOOL toomany = FALSE;/* TRUE if too many clip rects */
177 for (i = 0; i < *count; i++) {
178 if (newcount > MAX_CLIPRECTS - 3) {
182 newcount += MwSplitClipRect(&cliprects[i],
183 &cliprects[newcount],
184 minx, miny, maxx, maxy);
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.
203 MwSplitClipRect(MWCLIPRECT *srcrect, MWCLIPRECT *destrect, MWCOORD minx,
204 MWCOORD miny, MWCOORD maxx, MWCOORD maxy)
215 * First see if there is any overlap at all.
216 * If not, then nothing to do.
220 width = srcrect->width;
221 height = srcrect->height;
223 if ((minx > maxx) || (miny > maxy) || (maxx < x) || (maxy < y) ||
224 (x + width <= minx) || (y + height <= miny))
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.
235 gaps |= GAPVAL(1, 0, 0, 0);
236 if (x + width - 1 > maxx)
237 gaps |= GAPVAL(0, 1, 0, 0);
239 gaps |= GAPVAL(0, 0, 1, 0);
240 if (y + height - 1 > maxy)
241 gaps |= GAPVAL(0, 0, 0, 1);
244 case GAPVAL(0, 0, 0, 0): /* no gaps at all */
251 case GAPVAL(0, 0, 0, 1): /* gap on bottom */
254 srcrect->height -= dy;
257 case GAPVAL(0, 0, 1, 0): /* gap on top */
258 srcrect->height = miny - y;
261 case GAPVAL(0, 0, 1, 1): /* gap on top, bottom */
262 srcrect->height = miny - y;
264 destrect->width = width;
265 destrect->y = maxy + 1;
266 destrect->height = y + height - maxy - 1;
269 case GAPVAL(0, 1, 0, 0): /* gap on right */
272 srcrect->width -= dx;
275 case GAPVAL(0, 1, 0, 1): /* gap on right, bottom */
278 srcrect->width -= dx;
279 srcrect->height = maxy - y + 1;
281 destrect->width = width;
282 destrect->y = maxy + 1;
283 destrect->height = y + height - maxy - 1;
286 case GAPVAL(0, 1, 1, 0): /* gap on right, top */
288 srcrect->height = miny - y;
289 destrect->x = x + dx;
290 destrect->width = width - dx;
292 destrect->height = y + height - miny;
295 case GAPVAL(0, 1, 1, 1): /* gap on right, top, bottom */
297 srcrect->height = miny - y;
299 destrect->width = width;
300 destrect->y = maxy + 1;
301 destrect->height = y + height - maxy - 1;
303 destrect->x = x + dx;
304 destrect->width = width - dx;
306 destrect->height = maxy - miny + 1;
309 case GAPVAL(1, 0, 0, 0): /* gap on left */
310 srcrect->width = minx - x;
313 case GAPVAL(1, 0, 0, 1): /* gap on left, bottom */
314 srcrect->width = minx - x;
315 srcrect->height = maxy - y + 1;
317 destrect->width = width;
318 destrect->y = maxy + 1;
319 destrect->height = y + height - maxy - 1;
322 case GAPVAL(1, 0, 1, 0): /* gap on left, top */
323 srcrect->height = miny - y;
325 destrect->width = minx - x;
327 destrect->height = y + height - miny;
330 case GAPVAL(1, 0, 1, 1): /* gap on left, top, bottom */
331 srcrect->height = miny - y;
333 destrect->width = minx - x;
335 destrect->height = maxy - miny + 1;
338 destrect->width = width;
339 destrect->y = maxy + 1;
340 destrect->height = y + height - maxy - 1;
343 case GAPVAL(1, 1, 0, 0): /* gap on left, right */
344 destrect->x = maxx + 1;
345 destrect->width = x + width - maxx - 1;
347 destrect->height = height;
348 srcrect->width = minx - x;
351 case GAPVAL(1, 1, 0, 1): /* gap on left, right, bottom */
354 srcrect->height -= dy;
356 destrect->width = minx - x;
358 destrect->height = dy;
360 destrect->x = maxx + 1;
361 destrect->width = x + width - maxx - 1;
363 destrect->height = dy;
366 case GAPVAL(1, 1, 1, 0): /* gap on left, right, top */
367 srcrect->height = miny - y;
369 destrect->width = minx - x;
371 destrect->height = y + height - miny;
373 destrect->x = maxx + 1;
374 destrect->width = x + width - maxx - 1;
376 destrect->height = y + height - miny;
379 case GAPVAL(1, 1, 1, 1): /* gap on all sides */
380 srcrect->height = miny - y;
382 destrect->width = minx - x;
384 destrect->height = maxy - miny + 1;
386 destrect->x = maxx + 1;
387 destrect->width = x + width - maxx - 1;
389 destrect->height = maxy - miny + 1;
392 destrect->width = width;
393 destrect->y = maxy + 1;
394 destrect->height = y + height - maxy - 1;
397 return 0; /* NOTREACHED */