/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ /* * region.c --- FE specific region operations */ #include "mozilla.h" #include "xfe.h" #include "fe_rgn.h" #include "region.h" /* Internal X region structures. We need these to */ /* iterate over rect lists in FE_ForEachRectInRegion(). */ /* Creates an empty region. Returns NULL if region can't be created */ FE_Region FE_CreateRegion() { return (FE_Region)XCreateRegion(); } /* Creates a region from a rectangle. Returns NULL if region can't be created */ FE_Region FE_CreateRectRegion(XP_Rect *rect) { XPoint points[4]; points[0].x = points[3].x = (short)rect->left; /* points[] corresponds to */ points[0].y = points[1].y = (short)rect->top; /* top-left, top-right, */ points[1].x = points[2].x = (short)rect->right; /* bot-left and bot-right */ points[3].y = points[2].y = (short)rect->bottom;/* respectively. */ return (FE_Region)XPolygonRegion(points, 4, EvenOddRule); /* Fill rule is irrelevant since there */ /* should be no self overlap. */ } /* Set an existing region to a rectangle. */ /* The purpose of this routine is to avoid the overhead of destroying and */ /* recreating a region on the Windows platform. Unfortunately, it doesn't */ /* do much for X. */ FE_Region FE_SetRectRegion(FE_Region region, XP_Rect *rect) { XRectangle rectangle; XP_ASSERT(region); if (!XEmptyRegion((Region)region)) /* If region is not empty. */ XSubtractRegion((Region)region, (Region)region, (Region)region); /* Subtract region from itself. */ XP_ASSERT(XEmptyRegion((Region)region)); rectangle.x = (short)rect->left; rectangle.y = (short)rect->top; rectangle.width = (unsigned short)(rect->right - rect->left); rectangle.height = (unsigned short)(rect->bottom - rect->top); return (FE_Region)XUnionRectWithRegion(&rectangle, (Region)region, (Region)region); } /* Destroys region */ void FE_DestroyRegion(FE_Region region) { XP_ASSERT(region); XDestroyRegion((Region)region); } /* Make a copy of a region */ FE_Region FE_CopyRegion(FE_Region src, FE_Region dst) { Region copyRegion; XP_ASSERT(src); if (dst != NULL) { copyRegion = (Region)dst; } else { /* Create an empty region */ copyRegion = XCreateRegion(); if (copyRegion == NULL) return NULL; } /* Copy the region */ XUnionRegion((Region)src, (Region)src, (Region)copyRegion); return (FE_Region)copyRegion; } /* dst = src1 intersect sr2 */ /* dst can be one of src1 or src2 */ void FE_IntersectRegion(FE_Region src1, FE_Region src2, FE_Region dst) { XP_ASSERT(src1); XP_ASSERT(src2); XP_ASSERT(dst); XIntersectRegion((Region)src1, (Region)src2, (Region)dst); } /* dst = src1 union src2 */ /* dst can be one of src1 or src2 */ void FE_UnionRegion(FE_Region src1, FE_Region src2, FE_Region dst) { XP_ASSERT(src1); XP_ASSERT(src2); XP_ASSERT(dst); XUnionRegion((Region)src1, (Region)src2, (Region)dst); } /* dst = src1 - src2 */ /* dst can be one of src1 or src2 */ void FE_SubtractRegion(FE_Region src1, FE_Region src2, FE_Region dst) { XP_ASSERT(src1); XP_ASSERT(src2); XP_ASSERT(dst); XSubtractRegion((Region)src1, (Region)src2, (Region)dst); } /* Returns TRUE if the region contains no pixels */ XP_Bool FE_IsEmptyRegion(FE_Region region) { XP_ASSERT(region); return (XP_Bool)XEmptyRegion((Region)region); } /* Returns the bounding rectangle of the region */ void FE_GetRegionBoundingBox(FE_Region region, XP_Rect *bbox) { XRectangle rect; XP_ASSERT(region); XP_ASSERT(bbox); XClipBox((Region)region, &rect); bbox->left = (int32)rect.x; bbox->top = (int32)rect.y; bbox->right = (int32)(rect.x + rect.width); bbox->bottom = (int32)(rect.y + rect.height); } /* TRUE if rgn1 == rgn2 */ XP_Bool FE_IsEqualRegion(FE_Region rgn1, FE_Region rgn2) { XP_ASSERT(rgn1); XP_ASSERT(rgn2); return (XP_Bool)XEqualRegion((Region)rgn1, (Region)rgn2); } /* Moves a region by the specified offsets */ void FE_OffsetRegion(FE_Region region, int32 x_offset, int32 y_offset) { XOffsetRegion((Region)region, x_offset, y_offset); } /* Returns TRUE if any part of the rectangle is in the specified region */ XP_Bool FE_RectInRegion(FE_Region region, XP_Rect *rect) { int result; XRectangle box; XP_ASSERT(region); XP_ASSERT(rect); box.x = (short)rect->left; box.y = (short)rect->top; box.width = (unsigned short)(rect->right - rect->left); box.height = (unsigned short)(rect->bottom - rect->top); result = XRectInRegion((Region)region, box.x, box.y, box.width, box.height); if (result == RectangleOut) return FALSE; else /* result == RectangleIn || result == RectanglePart */ return TRUE; } /* Calls the specified function for each rectangle that makes up the region */ void FE_ForEachRectInRegion(FE_Region region, FE_RectInRegionFunc func, void *closure) { Region pRegion; register int nbox; register BOX *pbox; XP_Rect rect; XP_ASSERT(region); XP_ASSERT(func); pRegion = (Region)region; pbox = pRegion->rects; nbox = pRegion->numRects; while(nbox--) { rect.left = pbox->x1; rect.right = pbox->x2; rect.top = pbox->y1; rect.bottom = pbox->y2; (*func)(closure, &rect); pbox++; } } #ifdef DEBUG #include "X11/X.h" #include static void wait_usec(long usec) { struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = usec; select(0, NULL, NULL, NULL, &timeout); } static void fe_InvertRect(MWContext *context, XP_Rect *rect) { Widget wid; Display *dpy; Window win; Screen *screen; XGCValues gcv; GC gc; uint32 x, y, w, h; x = rect->left; y = rect->top; w = rect->right - rect->left; h = rect->bottom - rect->top; wid = CONTEXT_DATA (context)->drawing_area; if (wid == NULL) return; XtVaGetValues (wid, XmNscreen, &screen, 0); dpy = XtDisplay (wid); win = XtWindow (wid); gcv.function = GXxor; gcv.foreground = 0xFFFFFF; gc = XCreateGC (dpy, win, GCForeground | GCFunction, &gcv); XFillRectangle (dpy, win, gc, x, y, w, h); XFreeGC (dpy, gc); } void FE_HighlightRect(void *c, XP_Rect *rect, int how_much) { MWContext *context = (MWContext*)c; while (how_much--) { fe_InvertRect(context, rect); wait_usec(1000 * how_much); fe_InvertRect(context, rect); } } void fe_HighlightRegion(MWContext *context, FE_Region region) { FE_ForEachRectInRegion(region, (FE_RectInRegionFunc)fe_InvertRect, (void *)context); } void FE_HighlightRegion(void *c, FE_Region region, int how_much) { Widget wid; Display *dpy; MWContext *context = (MWContext*)c; wid = CONTEXT_DATA (context)->drawing_area; if (wid == NULL) return; dpy = XtDisplay (wid); fe_HighlightRegion(context, region); XSync(dpy, 0); wait_usec(1000 * how_much); fe_HighlightRegion(context, region); XSync(dpy, 0); } #endif /* DEBUG */