/* * REGION_FrameRgn * Create a region that is a frame around another region. * Expand all rectangles by +/- x and y, then subtract original region. */ BOOL REGION_FrameRgn( HRGN hDest, HRGN hSrc, INT x, INT y ) { BOOL bRet; MWRGNOBJ *srcObj = (MWRGNOBJ*) GDI_GetObjPtr( hSrc, OBJ_REGION ); if (srcObj->rgn->numRects != 0) { MWRGNOBJ* destObj = (MWRGNOBJ*) GDI_GetObjPtr( hDest, OBJ_REGION ); RECT *pRect, *pEndRect; RECT tempRect; EMPTY_REGION( destObj->rgn ); pEndRect = srcObj->rgn->rects + srcObj->rgn->numRects; for(pRect = srcObj->rgn->rects; pRect < pEndRect; pRect++) { tempRect.left = pRect->left - x; tempRect.top = pRect->top - y; tempRect.right = pRect->right + x; tempRect.bottom = pRect->bottom + y; GdUnionRectWithRegion( &tempRect, destObj->rgn ); } GdSubtractRegion( destObj->rgn, destObj->rgn, srcObj->rgn ); bRet = TRUE; } else bRet = FALSE; return bRet; }
/* * Note: The behavior is correct even if src and dest regions are the same. */ INT WINAPI CombineRgn(HRGN hDest, HRGN hSrc1, HRGN hSrc2, INT mode) { MWRGNOBJ *destObj = (MWRGNOBJ *) GDI_GetObjPtr( hDest, OBJ_REGION); INT result = ERRORREGION; /*TRACE(region, " %04x,%04x -> %04x mode=%x\n", hSrc1, hSrc2, hDest,mode);*/ if (destObj) { MWRGNOBJ *src1Obj = (MWRGNOBJ *) GDI_GetObjPtr( hSrc1, OBJ_REGION); if (src1Obj) { /*TRACE(region, "dump:\n"); if(TRACE_ON(region)) REGION_DumpRegion(src1Obj->rgn);*/ if (mode == RGN_COPY) { GdCopyRegion( destObj->rgn, src1Obj->rgn ); result = destObj->rgn->type; } else { MWRGNOBJ *src2Obj = (MWRGNOBJ *) GDI_GetObjPtr( hSrc2, OBJ_REGION); if (src2Obj) { /*TRACE(region, "dump:\n"); if(TRACE_ON(region)) REGION_DumpRegion(src2Obj->rgn);*/ switch (mode) { case RGN_AND: GdIntersectRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn); break; case RGN_OR: GdUnionRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn ); break; case RGN_XOR: GdXorRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn ); break; case RGN_DIFF: GdSubtractRegion( destObj->rgn, src1Obj->rgn, src2Obj->rgn ); break; } result = destObj->rgn->type; } } } /*TRACE(region, "dump:\n"); if(TRACE_ON(region)) REGION_DumpRegion(destObj->rgn);*/ } return result; }
/* remove region from window update region*/ BOOL WINAPI ValidateRgn(HWND hwnd, HRGN hrgn) { if(hwnd) { if(!hrgn) /* remove client area from update region*/ return ValidateRect(hwnd, NULL); /* passed region is in client coords, convert to screen*/ GdOffsetRegion(((MWRGNOBJ *)hrgn)->rgn, hwnd->clirect.left, hwnd->clirect.top); GdSubtractRegion(hwnd->update, hwnd->update, ((MWRGNOBJ *)hrgn)->rgn); GdOffsetRegion(((MWRGNOBJ *)hrgn)->rgn, -hwnd->clirect.left, -hwnd->clirect.top); /* if update region empty, mark window as painted*/ if(hwnd->update->numRects == 0) if(hwnd->gotPaintMsg == PAINT_NEEDSPAINT) hwnd->gotPaintMsg = PAINT_PAINTED; } return TRUE; }
/* * Set the clip rectangles for a window taking into account other * windows that may be obscuring it. The windows that may be obscuring * this one are the siblings of each direct ancestor which are higher * in priority than those ancestors. Also, each parent limits the visible * area of the window. */ void MwSetClipWindow(HDC hdc) { HWND wp = hdc->hwnd; HWND pwp; /* parent window */ HWND sibwp; /* sibling windows */ MWCOORD diff; /* difference in coordinates */ PRECT prc; /* client or window rectangle*/ MWCLIPREGION *vis, *r; MWCOORD x, y, width, height; /* * Start with the rectangle for the complete window. * We will then cut pieces out of it as needed. */ prc = MwIsClientDC(hdc)? &wp->clirect: &wp->winrect; x = prc->left; y = prc->top; width = prc->right - prc->left; height = prc->bottom - prc->top; /* * First walk upwards through all parent windows, * and restrict the visible part of this window to the part * that shows through all of those parent windows client areas. */ pwp = wp; while (pwp != rootwp) { pwp = pwp->parent; diff = pwp->clirect.left - x; if (diff > 0) { width -= diff; x = pwp->clirect.left; } diff = pwp->clirect.right - (x + width); if (diff < 0) width += diff; diff = pwp->clirect.top - y; if (diff > 0) { height -= diff; y = pwp->clirect.top; } diff = pwp->clirect.bottom - (y + height); if (diff < 0) height += diff; } /* * If the window is completely clipped out of view, then * set the clipping region to indicate that. */ if (width <= 0 || height <= 0) { GdSetClipRegion(hdc->psd, NULL); return; } /* * Allocate initial vis region to parent-clipped size of window */ vis = GdAllocRectRegion(x, y, x+width, y+height); /* * Allocate temp region */ r = GdAllocRegion(); /* * Now examine all windows that obscure this window, and * for each obscuration, break up the clip rectangles into * the smaller pieces that are still visible. The windows * that can obscure us are the earlier siblings of all of * our parents. When clipping the root window, search all children. */ pwp = wp; while (pwp != NULL) { wp = pwp; pwp = wp->parent; if(!pwp) { /* We're clipping the root window*/ if(hdc->flags & DCX_CLIPCHILDREN) /* start with root's children*/ sibwp = rootwp->children; else sibwp = NULL; /* no search*/ wp = NULL; /* search all root's children*/ } else { if(hdc->flags & DCX_CLIPSIBLINGS) sibwp = pwp->children; else sibwp = wp; /* no search*/ } for (; sibwp != wp; sibwp = sibwp->siblings) { if (sibwp->unmapcount) continue; GdSetRectRegionIndirect(r, &sibwp->winrect); GdSubtractRegion(vis, vis, r); } /* if not clipping the root window, stop when you reach it*/ if(pwp == rootwp) break; } /* * If not the root window and we're going to be drawing * in the client area, clip all children. This is * required for non-special paint handling for child windows. * Non-client dc's don't clip children in order to get * proper border clipping in the case of border-clipped children. */ wp = hdc->hwnd; if(wp != rootwp && MwIsClientDC(hdc)) { for (sibwp=wp->children; sibwp; sibwp = sibwp->siblings) { if (sibwp->unmapcount) continue; GdSetRectRegionIndirect(r, &sibwp->winrect); GdSubtractRegion(vis, vis, r); } } #if UPDATEREGIONS /* * Intersect with update region, unless requested not to. */ if(!(hdc->flags & DCX_EXCLUDEUPDATE)) GdIntersectRegion(vis, vis, wp->update); #endif /* * Intersect with user region, if set. */ if (hdc->region) GdIntersectRegion(vis, vis, hdc->region->rgn); /* * Set the clip region (later destroy handled by GdSetClipRegion) */ GdSetClipRegion(hdc->psd, vis); /* * Destroy temp region */ GdDestroyRegion(r); }
/* * Set the clip rectangles for a window taking into account other * windows that may be obscuring it. The windows that may be obscuring * this one are the siblings of each direct ancestor which are higher * in priority than those ancestors. Also, each parent limits the visible * area of the window. The clipping is not done if it is already up to * date of if the window is not outputtable. */ void GsSetClipWindow(GR_WINDOW *wp, MWCLIPREGION *userregion, int flags) { GR_WINDOW *orgwp; /* original window pointer */ GR_WINDOW *pwp; /* parent window */ GR_WINDOW *sibwp; /* sibling windows */ GR_COORD minx; /* minimum clip x coordinate */ GR_COORD miny; /* minimum clip y coordinate */ GR_COORD maxx; /* maximum clip x coordinate */ GR_COORD maxy; /* maximum clip y coordinate */ GR_COORD diff; /* difference in coordinates */ GR_SIZE bs; /* border size */ GR_COORD x, y, width, height; MWCLIPREGION *vis, *r; if (wp->unmapcount || !wp->output) return; clipwp = wp; /* * Start with the rectangle for the complete window. * We will then cut pieces out of it as needed. */ x = wp->x; y = wp->y; width = wp->width; height = wp->height; /* * First walk upwards through all parent windows, * and restrict the visible part of this window to the part * that shows through all of those parent windows. */ pwp = wp; while (pwp != rootwp) { pwp = pwp->parent; diff = pwp->x - x; if (diff > 0) { width -= diff; x = pwp->x; } diff = (pwp->x + pwp->width) - (x + width); if (diff < 0) width += diff; diff = pwp->y - y; if (diff > 0) { height -= diff; y = pwp->y; } diff = (pwp->y + pwp->height) - (y + height); if (diff < 0) height += diff; } /* * If the window is completely clipped out of view, then * set the clipping region to indicate that. */ if (width <= 0 || height <= 0) { GdSetClipRegion(clipwp->psd, NULL); return; } /* * Allocate region to clipped size of window */ vis = GdAllocRectRegion(x, y, x+width, y+height); /* * Allocate temp region */ r = GdAllocRegion(); /* * Now examine all windows that obscure this window, and * for each obscuration, break up the clip rectangles into * the smaller pieces that are still visible. The windows * that can obscure us are the earlier siblings of all of * our parents. */ orgwp = wp; pwp = wp; while (pwp != NULL) { wp = pwp; pwp = wp->parent; if(!pwp) { /* We're clipping the root window*/ if (!(flags & GR_MODE_EXCLUDECHILDREN)) /* start with root's children*/ sibwp = rootwp->children; else sibwp = NULL; /* no search*/ wp = NULL; /* search all root's children*/ } else { sibwp = pwp->children; /* clip siblings*/ } for (; sibwp != wp; sibwp = sibwp->siblings) { if (sibwp->unmapcount || !sibwp->output) continue; bs = sibwp->bordersize; minx = sibwp->x - bs; miny = sibwp->y - bs; maxx = sibwp->x + sibwp->width + bs; maxy = sibwp->y + sibwp->height + bs; GdSetRectRegion(r, minx, miny, maxx, maxy); GdSubtractRegion(vis, vis, r); } /* if not clipping the root window, stop when you reach it*/ if (pwp == rootwp) break; } wp = orgwp; /* * If not the root window, clip all children. * (Root window's children are are clipped above) */ if(wp != rootwp && !(flags & GR_MODE_EXCLUDECHILDREN)) { for (sibwp=wp->children; sibwp; sibwp = sibwp->siblings) { if (sibwp->unmapcount || !sibwp->output) continue; bs = sibwp->bordersize; minx = sibwp->x - bs; miny = sibwp->y - bs; maxx = sibwp->x + sibwp->width + bs; maxy = sibwp->y + sibwp->height + bs; GdSetRectRegion(r, minx, miny, maxx, maxy); GdSubtractRegion(vis, vis, r); } } /* * Intersect with user region, if set. */ if (userregion) { /* temporarily offset region by window coordinates*/ GdOffsetRegion(userregion, wp->x, wp->y); GdIntersectRegion(vis, vis, userregion); GdOffsetRegion(userregion, -wp->x, -wp->y); } /* * Set the clip region (later destroy handled by GdSetClipRegion) */ GdSetClipRegion(clipwp->psd, vis); /* * Destroy temp region */ GdDestroyRegion(r); }