diff packages/services/gfx/mw/current/src/engine/devclip1.c @ 208:e0c0827131d1 ecos

Merge from eCos master repository on 2002-05-20-20:11:54-BST
author jlarmour
date Mon, 20 May 2002 22:19:26 +0000
parents
children
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/services/gfx/mw/current/src/engine/devclip1.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 1999 Greg Haerr <greg@censoft.com>
+ * Copyright (c) 1991 David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * Device-independent routines to determine clipping regions.
+ */
+#include "device.h"
+
+/* Clip cache rectangle information.
+ * After calling GdClipPoint, this rectangle is guaranteed to contain the
+ * specified point (among others), and all points in the rectangle are
+ * plottable or not according to the value of clipresult.
+ */
+MWCOORD clipminx;		/* minimum x value of cache rectangle */
+MWCOORD clipminy;		/* minimum y value of cache rectangle */
+MWCOORD clipmaxx;		/* maximum x value of cache rectangle */
+MWCOORD clipmaxy;		/* maximum y value of cache rectangle */
+
+static MWBOOL	clipresult;	/* whether clip rectangle is plottable */
+int 	clipcount;		/* number of clip rectangles */
+MWCLIPRECT cliprects[MAX_CLIPRECTS];	/* clip rectangles */
+
+/*
+ * Set an array of clip rectangles for future drawing actions.
+ * Each pixel will be drawn only if lies in one or more of the specified
+ * clip rectangles.  As a special case, specifying no rectangles implies
+ * clipping is for the complete screen.  All clip rectangles are modified
+ * if necessary to lie within the device area.  Call only after device
+ * has been initialized.
+ */
+void
+GdSetClipRects(PSD psd,int count, MWCLIPRECT *table)
+{
+  register MWCLIPRECT *rp;		/* current rectangle */
+
+  /* If there are no clip rectangles, then default to the full device area. */
+  if (count <= 0) {
+	clipminx = 0;
+	clipminy = 0;
+	clipmaxx = psd->xvirtres - 1;
+	clipmaxy = psd->yvirtres - 1;
+	clipcount = 0;
+	clipresult = TRUE;
+	return;
+  }
+
+  /* Copy the clip table to our own static array, modifying each
+   * rectangle as necesary to fit within the device area.  If the clip
+   * rectangle lies entirely outside of the device area, then skip it.
+   */
+  rp = cliprects;
+  clipcount = 0;
+  if (count > MAX_CLIPRECTS) count = MAX_CLIPRECTS;
+  while (count-- > 0) {
+	*rp = *table++;
+	if (rp->x < 0) {
+		rp->width += rp->x;
+		rp->x = 0;
+	}
+	if (rp->y < 0) {
+		rp->height += rp->y;
+		rp->y = 0;
+	}
+	if ((rp->x >= psd->xvirtres) || (rp->width <= 0) ||
+	    (rp->y >= psd->yvirtres) || (rp->height <= 0))
+		continue;
+	if (rp->x + rp->width > psd->xvirtres)
+		rp->width = psd->xvirtres - rp->x;
+	if (rp->y + rp->height > psd->yvirtres)
+		rp->height = psd->yvirtres - rp->y;
+	rp++;
+	clipcount++;
+  }
+
+  /* If there were no surviving clip rectangles, then set the clip
+   * cache to prevent all drawing.
+   */
+  if (clipcount == 0) {
+	clipminx = MIN_MWCOORD;
+	clipminy = MIN_MWCOORD;
+	clipmaxx = MAX_MWCOORD;
+	clipmaxy = MAX_MWCOORD;
+	clipresult = FALSE;
+	return;
+  }
+
+  /* There was at least one valid clip rectangle. Default the clip
+   * cache to be the first clip rectangle.
+   */
+  clipminx = cliprects[0].x;
+  clipminy = cliprects[0].y;
+  clipmaxx = clipminx + cliprects[0].width - 1;
+  clipmaxy = clipminy + cliprects[0].height - 1;
+  clipresult = TRUE;
+}
+
+
+/* Check a point against the list of clip rectangles.
+ * Returns TRUE if the point is within one or more rectangles and thus
+ * can be plotted, or FALSE if the point is not within any rectangle and
+ * thus cannot be plotted.  Also remembers the coordinates of a clip cache
+ * rectangle containing the specified point such that every point in the
+ * rectangle would give the same result.  By examining this clip cache
+ * rectangle after a call to this routine, the caller can efficiently
+ * check many nearby points without needing any further calls.  If the
+ * point lies within the cursor, then the cursor is removed.
+ */
+MWBOOL
+GdClipPoint(PSD psd,MWCOORD x,MWCOORD y)
+{
+  int count;
+  MWCLIPRECT *rp;
+  MWCOORD temp;
+
+  /* First see whether the point lies within the current clip cache
+   * rectangle.  If so, then we already know the result.
+   */
+  if ((x >= clipminx) && (x <= clipmaxx) &&
+      (y >= clipminy) && (y <= clipmaxy)) {
+	if (clipresult) GdCheckCursor(psd, x, y, x, y);
+	return clipresult;
+  }
+
+  /* If the point is outside of the screen area, then it is not
+   * plottable, and the clip cache rectangle is the whole half-plane
+   * outside of the screen area.
+   */
+  if (x < 0) {
+	clipminx = MIN_MWCOORD;
+	clipmaxx = -1;
+	clipminy = MIN_MWCOORD;
+	clipmaxy = MAX_MWCOORD;
+	clipresult = FALSE;
+	return FALSE;
+  }
+  if (y < 0) {
+	clipminx = MIN_MWCOORD;
+	clipmaxx = MAX_MWCOORD;
+	clipminy = MIN_MWCOORD;
+	clipmaxy = -1;
+	clipresult = FALSE;
+	return FALSE;
+  }
+  if (x >= psd->xvirtres) {
+	clipminx = psd->xvirtres;
+	clipmaxx = MAX_MWCOORD;
+	clipminy = MIN_MWCOORD;
+	clipmaxy = MAX_MWCOORD;
+	clipresult = FALSE;
+	return FALSE;
+  }
+  if (y >= psd->yvirtres) {
+	clipminx = MIN_MWCOORD;
+	clipmaxx = MAX_MWCOORD;
+	clipminy = psd->yvirtres;
+	clipmaxy = MAX_MWCOORD;
+	clipresult = FALSE;
+	return FALSE;
+  }
+
+  /* The point is within the screen area. If there are no clip
+   * rectangles, then the point is plottable and the rectangle is the
+   * whole screen.
+   */
+  count = clipcount;
+  if (count <= 0) {
+	clipminx = 0;
+	clipmaxx = psd->xvirtres - 1;
+	clipminy = 0;
+	clipmaxy = psd->yvirtres - 1;
+	clipresult = TRUE;
+	GdCheckCursor(psd, x, y, x, y);
+	return TRUE;
+  }
+
+  /* We need to scan the list of clip rectangles to calculate a new
+   * clip cache rectangle containing this point, and the result. First
+   * see if the point lies within any of the clip rectangles. If so,
+   * then it is plottable and use that clip rectangle as the cache
+   * rectangle.  This is not necessarily the best result, but works ok
+   * and is fast.
+   */
+  for (rp = cliprects; count-- > 0; rp++) {
+	if ((x >= rp->x) && (y >= rp->y) && (x < rp->x + rp->width)
+	    && (y < rp->y + rp->height)) {
+		clipminx = rp->x;
+		clipminy = rp->y;
+		clipmaxx = rp->x + rp->width - 1;
+		clipmaxy = rp->y + rp->height - 1;
+		clipresult = TRUE;
+		GdCheckCursor(psd, x, y, x, y);
+		return TRUE;
+	}
+  }
+
+  /* The point is not plottable. Scan the clip rectangles again to
+   * determine a rectangle containing more non-plottable points.
+   * Simply pick the largest rectangle whose area doesn't contain any
+   * of the same coordinates as appropriate sides of the clip
+   * rectangles.  This is not necessarily the best result, but works ok
+   * and is fast.
+   */
+  clipminx = MIN_MWCOORD;
+  clipminy = MIN_MWCOORD;
+  clipmaxx = MAX_MWCOORD;
+  clipmaxy = MAX_MWCOORD;
+  count = clipcount;
+  for (rp = cliprects; count-- > 0; rp++) {
+	if ((x < rp->x) && (rp->x <= clipmaxx)) clipmaxx = rp->x - 1;
+	temp = rp->x + rp->width - 1;
+	if ((x > temp) && (temp >= clipminx)) clipminx = temp + 1;
+	if ((y < rp->y) && (rp->y <= clipmaxy)) clipmaxy = rp->y - 1;
+	temp = rp->y + rp->height - 1;
+	if ((y > temp) && (temp >= clipminy)) clipminy = temp + 1;
+  }
+  clipresult = FALSE;
+  return FALSE;
+}
+
+
+/* Check the area determined by the specified pair of points against the
+ * list of clip rectangles.  The area will either be totally visible,
+ * totally visible, or possibly partially visible.  This routine updates
+ * the clip cache rectangle, and returns one of the following values:
+ *	CLIP_VISIBLE		The whole rectangle is visible
+ *	CLIP_INVISIBLE		The whole rectangle is invisible
+ *	CLIP_PARTIAL		The rectangle may be partially visible
+ * In the case that the area is totally visible, the cursor is removed
+ * if it overlaps the clip area.
+ */
+int
+GdClipArea(PSD psd,MWCOORD x1, MWCOORD y1, MWCOORD x2, MWCOORD y2)
+{
+  if ((x1 < clipminx) || (x1 > clipmaxx) ||
+      (y1 < clipminy) || (y1 > clipmaxy))
+	GdClipPoint(psd, x1, y1);
+
+  if ((x2 >= clipminx) && (x2 <= clipmaxx) &&
+      (y2 >= clipminy) && (y2 <= clipmaxy)) {
+	if (!clipresult) return CLIP_INVISIBLE;
+	GdCheckCursor(psd, x1, y1, x2, y2);
+	return CLIP_VISIBLE;
+  }
+  return CLIP_PARTIAL;
+}