[gnu.gcc.bug] possible bug in GXxor copy area under mfb

adam@UUNET.UU.NET (Adam de Boor) (05/03/89)

			  X Window System Bug Report
			    xbugs@expo.lcs.mit.edu




VERSION:
    R3

CLIENT MACHINE and OPERATING SYSTEM:
	Sun 3/50 running SunOS 3.5 (gcc version 1.34)

DISPLAY:
	Sun BW2

WINDOW MANAGER:
	awm

AREA:
    server/mfb

SYNOPSIS:
    a CopyArea with function == GXxor doesn't work -- the combination
    of bits happens with the longword to the right of the dest, rather than
    with the destination itself.

DESCRIPTION:
    I'm not sure if this is a compiler artifact or a real bug. However, running
    gremlin (available for X11 from ucbvax.berkeley.edu, if you're interested)
    reveals that a CopyArea from a pixmap to a window using XOR doesn't
    work right. The results are sometimes entertaining, however. 

    In addition, given that many compilers today perform switches with
    calculated branches, and even if a compiler doesn't, a single switch
    on the function followed by unwound loops with the alu employed directly
    is bound to be faster than 6 compares per longword as currently used in
    the macros for mfbBitBlt, I have changed the longRop macro to
    switch on the alu. In places that don't employ putbitsrop, I've also
    changed DoRop to BltRop, which is the same except there's no compare
    against GXcopy at the front, since GXcopy is special-cased.

    I've no empirical data for these changes, just common sense.

    Anyway, with these changes, the problem with the XOR copy goes away.

REPEAT BY:

to be linked with wsimple.o from the xfd directory. Give -X to perform
the copy in XOR mode. If you place the small window on top of another window
with text in it, and the problem I had wasn't just a compiler artifact, pieces
of the text will find their way into the right half of the window when you
bring the beastie to the top.

/* Copyright 1987, Massachusetts Institute of Technology */

/*
 * xfd: program to display a font for perusal by the user.
 *
 * Written by Mark Lillibridge
 *
 */

#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/cursorfont.h>
#include <stdio.h>

#define BUFFERSIZE 10
#define VERBOSE_LINES 4         /* Number of lines in verbose display */
#define	GRAY_PAD	2	/* padding for gray mode		*/


    /* Global variables */

int space_per_line;             /* How much space to reserve per line */
int line_offset;                /* Where to start writting (base line) */
int number_of_lines=1;          /* number of lines in bottom area display */
int verbose = 0;                /* verbose mode? */
int box_x = 0;                  /* The size of one box in grid */
int box_y = 0;
int x_offset = 0;               /* Point in box to display character from */
int y_offset = 0;
int x_boxes = 0;                /* Current size of window in # of boxes */
int y_boxes = 0;
int bottom = 0;                 /* Size of grid in pixels */
int right = 0;
int first_char = 0;             /* Character # of first character displayed on
				   the grid */
int gray = 0;                   /* use gray background ? */
GC body_gc, real_gc;            /* Graphics contexts */
XFontStruct *real_font;         /* The font we are to display */

/* Gray pattern for use as background */
#include "X11/bitmaps/light_gray"

/* Include routines to handle parsing defaults */
#define TITLE_DEFAULT "xfd"     /* Our name... */
#define DEFX_DEFAULT 300        /* Default window pop-up location */
#define DEFY_DEFAULT 300
#define RESIZE_X_INC 1          /* We will specify a resize inc later ... */
#define RESIZE_Y_INC 1
#define MIN_X_SIZE 1            /* Ditto for minimum window size */
#define MIN_Y_SIZE 1

#include "wsimple.h"

/*
 * usage: routine to show usage then exit.
 */
usage()
{
	fprintf(stderr, 
	        "%s: usage: %s %s [-v[erbose]] [-gray] [-start <char number>] -fn fontname\n", program_name,
		program_name, X_USAGE);
	exit(1);
}


/*
 * The main program:
 */
main(argc, argv) 

     int argc;
     char **argv;
{
	register int i;
	GC gc;
	XGCValues gc_init;
	XEvent event;
	char *fontname = NULL;		        /* Display default body font */
	char buffer[BUFFERSIZE];                /* buffer for XLookupString */
	Cursor cursor;
	Pixmap pix;
	int xor = 0;

	INIT_NAME;

	/* Handle command line arguments, open the display */
	Get_X_Options(&argc, argv);
	for (i = 1; i < argc; i++) {
		if (!strcmp("-help", argv[i])) usage ();
		if (!strcmp("-X", argv[i])) { xor=1; continue; }
		if (!strcmp("-", argv[i]))
		  continue;
		if (argv[i][0] == '-') usage();
		if (fontname) usage();
		fontname = argv[i];
	} 


	/* Resolve the X options */
	Resolve_X_Options();

	line_offset = 2 + body_font->ascent;
	space_per_line = body_font->descent + line_offset + 2;

	/* Get minimun perfered size */
	Calc_Default_Size();

	/* Create the window */
	Create_Default_Window();

	pix = XCreatePixmap(dpy, wind, 64, 32, 1);

	gc_init.foreground = BlackPixel(dpy, 0);
	gc_init.background = WhitePixel(dpy, 0);
	gc = XCreateGC(dpy, pix, GCForeground|GCBackground, &gc_init);
	XDrawLine(dpy, pix, gc, 0, 0, 64, 32);

	XFreeGC(dpy, gc);

	gc_init.function = xor ? GXxor : GXcopy;
	gc = XCreateGC(dpy, wind, GCFunction, &gc_init);

	/* Start main loop by selecting events then mapping window */
	XSelectInput(dpy, wind, ExposureMask);
	XMapWindow(dpy, wind);

	/* Main event loop */
	for (;;) {
		XNextEvent(dpy, &event);
		if (event.type == Expose && !event.xexpose.count) {
		    XClearArea(dpy, wind, 0, 0, 0, 0, False);
		    XCopyArea(dpy, pix, wind, DefaultGC(dpy, 0), 
				0, 0, 64, 32, 0, 0);
		    XCopyArea(dpy, pix, wind, gc,
				0, 0, 64, 32, 0, 0);
		}
	}
}

char short_format[] = "%d (0x%x)";
char line1_alt[] = "%s bounds:";
char line1_format[] = "character # = %d (0x%x):";
char line2_format[] = "left bearing = %d, right bearing = %d";
char line3_format[] = "ascent = %d, descent = %d";
char line4_format[] = "width = %d";
char buf[80*2];

/*
 * Calc_Default_Size: This routine calculates the size of a box in the grid
 * and where to write a character from so that every character will fit
 * in a box.  The size of an ideal window (16 boxes by 16 boxes with room
 * for the bottom text) is then calculated.
 */
Calc_Default_Size()
{
	size_hints.min_width = size_hints.max_width = 64;
	size_hints.min_height = size_hints.max_height = 32;
	size_hints.flags = USSize|USPosition;
	size_hints.height = 32;
	size_hints.width = 64;
	size_hints.x = size_hints.y = 0;
}

char s[4] = { 0, 0, 0, 0 };

SAMPLE FIX:

*** /tmp/,RCSt1a20453	Tue May  2 15:10:13 1989
--- mfbbitblt.c	Tue May  2 14:59:29 1989
***************
*** 243,273 ****
      } \
  }
  
! #define longRop(alu,from,to,count)    \
  { \
      switch (count & 7) { \
! 	  case 0:   *to = DoRop (alu, *from++, *to); to++; \
! 	  case 7:   *to = DoRop (alu, *from++, *to); to++; \
! 	  case 6:   *to = DoRop (alu, *from++, *to); to++; \
! 	  case 5:   *to = DoRop (alu, *from++, *to); to++; \
! 	  case 4:   *to = DoRop (alu, *from++, *to); to++; \
! 	  case 3:   *to = DoRop (alu, *from++, *to); to++; \
! 	  case 2:   *to = DoRop (alu, *from++, *to); to++; \
! 	  case 1:   *to = DoRop (alu, *from++, *to); to++; \
      } \
!     while ((count -= 8) > 0) { \
! 	  *to = DoRop (alu, *from++, *to); to++; \
! 	  *to = DoRop (alu, *from++, *to); to++; \
! 	  *to = DoRop (alu, *from++, *to); to++; \
! 	  *to = DoRop (alu, *from++, *to); to++; \
! 	  *to = DoRop (alu, *from++, *to); to++; \
! 	  *to = DoRop (alu, *from++, *to); to++; \
! 	  *to = DoRop (alu, *from++, *to); to++; \
! 	  *to = DoRop (alu, *from++, *to); to++; \
!     } \
  }
  
  
  #define getunalignedword(psrc, x, dst) \
  { \
      int m; \
--- 243,295 ----
      } \
  }
  
! #define longDoRop(fn,from,to,count) \
  { \
      switch (count & 7) { \
! 	  case 0:   *to = fn(*from++, *to); to++;\
! 	  case 7:   *to = fn(*from++, *to); to++;\
! 	  case 6:   *to = fn(*from++, *to); to++;\
! 	  case 5:   *to = fn(*from++, *to); to++;\
! 	  case 4:   *to = fn(*from++, *to); to++;\
! 	  case 3:   *to = fn(*from++, *to); to++;\
! 	  case 2:   *to = fn(*from++, *to); to++;\
! 	  case 1:   *to = fn(*from++, *to); to++;\
      } \
!     while ((count -= 8) > 0) {\
! 	*to = fn(*from++, *to); to++;\
! 	*to = fn(*from++, *to); to++;\
! 	*to = fn(*from++, *to); to++;\
! 	*to = fn(*from++, *to); to++;\
! 	*to = fn(*from++, *to); to++;\
! 	*to = fn(*from++, *to); to++;\
! 	*to = fn(*from++, *to); to++;\
! 	*to = fn(*from++, *to); to++;\
!     }\
  }
  
+ #define longRop(alu,from,to,count)    \
+ {\
+     switch(alu) {\
+ 	case GXclear:	    	longDoRop(fnCLEAR,from,to,count); break;\
+ 	case GXand: 	    	longDoRop(fnAND,from,to,count); break;\
+ 	case GXandReverse:  	longDoRop(fnANDREVERSE,from,to,count); break;\
+ 	case GXcopy:	    	/* Never happens */ break;\
+ 	case GXandInverted: 	longDoRop(fnANDINVERTED,from,to,count); break;\
+ 	case GXnoop:	    	from += count; to += count; break;\
+ 	case GXxor: 	    	longDoRop(fnXOR,from,to,count); break;\
+ 	case GXor:  	    	longDoRop(fnOR,from,to,count); break;\
+ 	case GXnor: 	    	longDoRop(fnNOR,from,to,count); break;\
+ 	case GXequiv:	    	longDoRop(fnEQUIV,from,to,count); break;\
+ 	case GXinvert:	    	longDoRop(fnINVERT,from,to,count); break;\
+ 	case GXorReverse:   	longDoRop(fnORREVERSE,from,to,count); break;\
+ 	case GXcopyInverted:	longDoRop(fnCOPYINVERTED,from,to,count); break;\
+ 	case GXorInverted:  	longDoRop(fnORINVERTED,from,to,count); break;\
+ 	case GXnand:	    	longDoRop(fnNAND,from,to,count); break;\
+ 	case GXset: 	    	longDoRop(fnSET,from,to,count); break;\
+     }\
+ }
  
+ 
  #define getunalignedword(psrc, x, dst) \
  { \
      int m; \
***************
*** 276,281 ****
--- 298,323 ----
          (SCRRIGHT(*((psrc)+1), m) & starttab[m]); \
  }
  
+ /* Like DoRop, but no compare for GXcopy, since this is never used for
+  * GXcopy.
+  */
+ #define BltRop(alu, src, dst) \
+ ( (((alu) >= GXnor) ? \
+      (((alu) >= GXcopyInverted) ? \
+        (((alu) >= GXnand) ? \
+          (((alu) == GXnand) ? ~((src) & (dst)) : ~0) : \
+          (((alu) == GXcopyInverted) ? ~(src) : (~(src) | (dst)))) : \
+        (((alu) >= GXinvert) ? \
+ 	 (((alu) == GXinvert) ? ~(dst) : ((src) | ~(dst))) : \
+ 	 (((alu) == GXnor) ? ~((src) | (dst)) : (~(src) ^ (dst)))) ) : \
+      (((alu) >= GXandInverted) ? \
+        (((alu) >= GXxor) ? \
+ 	 (((alu) == GXxor) ? ((src) ^ (dst)) : ((src) | (dst))) : \
+ 	 (((alu) == GXnoop) ? (dst) : (~(src) & (dst)))) : \
+        (((alu) >= GXandReverse) ? \
+ 	 (((alu) == GXandReverse) ? ((src) & ~(dst)) : (src)) : \
+ 	 (((alu) == GXand) ? ((src) & (dst)) : 0)))  ) )
+ 
  mfbDoBitblt(pSrcDrawable, pDstDrawable, alu, prgnDst, pptSrc)
  DrawablePtr pSrcDrawable;
  DrawablePtr pDstDrawable;
***************
*** 509,515 ****
  	        else
  		    nend = 0;
  
! 	        xoffSrc = ((pptSrc->x & 0x1f) + nstart) & 0x1f;
  	        srcStartOver = ((pptSrc->x & 0x1f) + nstart) > 31;
  
  	        if (xdir == 1) /* move left to right */
--- 551,557 ----
  	        else
  		    nend = 0;
  
! 	        xoffSrc = (pptSrc->x + nstart) & 0x1f;
  	        srcStartOver = ((pptSrc->x & 0x1f) + nstart) > 31;
  
  	        if (xdir == 1) /* move left to right */
***************
*** 657,663 ****
  	        else
  		    nend = 0;
  
! 	        xoffSrc = ((pptSrc->x & 0x1f) + nstart) & 0x1f;
  	        srcStartOver = ((pptSrc->x & 0x1f) + nstart) > 31;
  
  	        if (xdir == 1) /* move left to right */
--- 699,705 ----
  	        else
  		    nend = 0;
  
! 	        xoffSrc = (pptSrc->x + nstart) & 0x1f;
  	        srcStartOver = ((pptSrc->x & 0x1f) + nstart) > 31;
  
  	        if (xdir == 1) /* move left to right */
***************
*** 694,701 ****
  			    while (--nl)
  		            {
  				getunalignedword (psrc, xoffSrc, tmpSrc)
! 				*pdst++ = DoRop (alu, tmpSrc, *pdst);
! 				psrc++;
  			    }
  			}
  
--- 736,743 ----
  			    while (--nl)
  		            {
  				getunalignedword (psrc, xoffSrc, tmpSrc)
! 				*pdst = BltRop (alu, tmpSrc, *pdst);
! 				psrc++, pdst++;
  			    }
  			}