/* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include "libgint.h" /* * Libg applications are written assuming that black is ~0 * and white is 0. Some screens use the reverse convention. * We get the effect the application desired by seeing what * happens if both the source and dest are converted to the * black==~0 convention, and then converting the dest back * to whatever convention it uses. * * Offscreen bitmaps of depth 1 use the black==~0 convention. * * Bitmaps of depth > 1 are probably in color. Libg operations that * would produce a 1 should produce the foreground color, and * libg operations that would produce a 0 should produce the background * color. Operations that use bitmaps of depth > 1 as source * should interpret the foreground pixel as "black" (1) and the * background pixel as "white" (0). It is hard to make this work, * but the important cases are Fcodes Zero, F, S, and S^D, so * we make sure that those work. When a fill value is given for * a bitmap of depth > 1, assume ~0 means foreground, but otherwise * take any other value literally (assume it came from rgbpix). * This may be wrong for the case of 0, but libg programmers * usually use Fcode Zero instead of passing 0 with Fcode S. * * We assume there are at most two depths of bitmaps: depth 1 * and depth of the screen. */ /* * gx func code corresponding to libg func code when both * source and dest use 1 for black. This is a straight translation. */ static int gx[16] = { GXclear, /* Zero */ GXnor, /* DnorS */ GXandInverted, /* DandnotS */ GXcopyInverted, /* notS */ GXandReverse, /* notDandS */ GXinvert, /* notD */ GXxor, /* DxorS */ GXnand, /* DnandS */ GXand, /* DandS */ GXequiv, /* DxnorS */ GXnoop, /* D */ GXorInverted, /* DornotS */ GXcopy, /* S */ GXorReverse, /* notDorS */ GXor, /* DorS */ GXset, /* F */ }; /* * gx func code corresponding to libg func code when 0 means black * in dst and 1 means black in src. These means the table has op' * where dst <- dst op' src == not ( not(dst) op src ). * The comment on each line is op, in Fcode terms. */ static int d0s1gx[16] = { GXset, /* Zero */ GXorReverse, /* DnorS */ GXor, /* DandnotS */ GXcopy, /* notS */ GXnand, /* notDandS */ GXinvert, /* notD */ GXxor, /* DxorS */ GXandReverse, /* DnandS */ GXorInverted, /* DandS */ GXequiv, /* DxnorS */ GXnoop, /* D */ GXand, /* DornotS */ GXcopyInverted, /* S */ GXnor, /* notDorS */ GXandInverted, /* DorS */ GXclear, /* F */ }; /* * gx func code corresponding to libg func code when 1 means black * in dst and 0 means black in src. These means the table has op' * where dst <- dst op' src == dst op not(src) ) * The comment on each line is op, in Fcode terms. */ static int d1s0gx[16] = { GXclear, /* Zero */ GXandReverse, /* DnorS */ GXand, /* DandnotS */ GXcopy, /* notS */ GXnor, /* notDandS */ GXinvert, /* notD */ GXequiv, /* DxorS */ GXorReverse, /* DnandS */ GXandInverted, /* DandS */ GXxor, /* DxnorS */ GXnoop, /* D */ GXor, /* DornotS */ GXcopyInverted, /* S */ GXnand, /* notDorS */ GXorInverted, /* DorS */ GXset, /* F */ }; /* * gx func code corresponding to libg func code when 0 means black * in both the src and the dst. These means the table has op' * where dst <- dst op' src == not (not(dst) op not(src)) ) * The comment on each line is op, in Fcode terms. */ static int d0s0gx[16] = { GXset, /* Zero */ GXnand, /* DnorS */ GXorInverted, /* DandnotS */ GXcopyInverted, /* notS */ GXorReverse, /* notDandS */ GXinvert, /* notD */ GXequiv, /* DxorS */ GXnor, /* DnandS */ GXor, /* DandS */ GXxor, /* DxnorS */ GXnoop, /* D */ GXandInverted, /* DornotS */ GXcopy, /* S */ GXandReverse, /* notDorS */ GXand, /* DorS */ GXclear, /* F */ }; /* * 1 for those Fcodes that are degenerate (don't involve src) */ static int degengc[16] = { 1, /* Zero */ 0, /* DnorS */ 0, /* DandnotS */ 0, /* notS */ 0, /* notDandS */ 1, /* notD */ 0, /* DxorS */ 0, /* DnandS */ 0, /* DandS */ 0, /* DxnorS */ 1, /* D */ 0, /* DornotS */ 0, /* S */ 0, /* notDorS */ 0, /* DorS */ 1, /* F */ }; /* * GCs are all for same screen, and depth is either 1 or screen depth. * Return a GC for the depth of b, with values as specified by gcv. * * Also, set (or unset) the clip rectangle if necessary. * (This implementation should be improved if setting a clip rectangle is not rare). */ GC _getgc(Bitmap *b, unsigned long gcvm, XGCValues *pgcv) { static GC gc0, gcn; static clipset = 0; GC g; XRectangle xr; g = (b->ldepth==0)? gc0 : gcn; if(!g){ g = XCreateGC(_dpy, (Drawable)b->id, gcvm, pgcv); if(b->ldepth==0) gc0 = g; else gcn = g; } else XChangeGC(_dpy, g, gcvm, pgcv); if(b->flag&CLIP){ xr.x = b->clipr.min.x; xr.y = b->clipr.min.y; xr.width = Dx(b->clipr); xr.height = Dy(b->clipr); if(b->flag&SHIFT){ xr.x -= b->r.min.x; xr.y -= b->r.min.y; } XSetClipRectangles(_dpy, g, 0, 0, &xr, 1, YXBanded); clipset = 1; }else if(clipset){ pgcv->clip_mask = None; XChangeGC(_dpy, g, GCClipMask, pgcv); clipset = 0; } return g; } /* * Return a GC that will fill bitmap b using a pixel value v and Fcode f. * Pixel value v is according to libg convention, so 0 means * white (or background) and ~0 means black (or foreground). */ GC _getfillgc(Fcode f, Bitmap *b, unsigned long val) { int xf, m; unsigned long v, fg, bg, spix, vmax; XGCValues gcv; f &= F; vmax = _ld2dmask[b->ldepth]; v = val & vmax; spix = v; xf = GXcopy; m = b->flag; if(m & DP1){ xf = (m&BL1)? gx[f] : d0s1gx[f]; }else{ fg = _fgpixel; bg = _bgpixel; switch(f){ case Zero: labZero: spix = bg; break; case F: labF: spix = fg; break; case D: labD: xf = GXnoop; break; case notD: labnotD: xf = GXxor; spix = fg^bg; break; case S: if(val == ~0) spix = fg; else spix = v; break; case notS: if(val == ~0) spix = bg; else spix = v; break; case DxorS: xf = GXxor; if(val == ~0) spix = fg^bg; else spix = v; break; case DxnorS: xf = GXxor; if(val == 0) spix = fg^bg; else spix = v; break; default: /* hard to do anything other than v==0 or v==~0 case */ if(v < vmax-v){ /* v is closer to 0 than vmax */ switch(f&~S){ case D&~S: goto labD; case notD&~S: goto labnotD; case Zero&~S: goto labZero; case F&~S: goto labF; } }else{ /* v is closer to vmax than 0 */ switch(f&S){ case D&S: goto labD; case notD&S: goto labnotD; case Zero&S: goto labZero; case F&S: goto labF; } } } } gcv.foreground = spix; gcv.function = xf; return _getgc(b, GCForeground|GCFunction, &gcv); } /* * Return a GC to be used to copy an area from bitmap sb to * bitmap db. Sometimes the calling function shouldn't use * XCopyArea, but instead should use XCopyPlane or XFillRectangle. * The *bltfunc arg is set to one of UseCopyArea, UseCopyPlane, * UseFillRectangle. */ GC _getcopygc(Fcode f, Bitmap *db, Bitmap *sb, int *bltfunc) { unsigned long spix, bg, fg, df, sf; int xf, c; XGCValues gcv; unsigned long gcvm; f &= F; gcvm = 0; df = db->flag; if(degengc[f]){ *bltfunc = UseFillRectangle; if(df&SCR || !(df&DP1)){ fg = _fgpixel; bg = _bgpixel; }else{ /* must be DP1 and BL1 */ fg = 1; bg = 0; } switch(f){ case Zero: xf = GXcopy; spix = bg; break; case F: xf = GXcopy; spix = fg; break; case D: xf = GXnoop; spix = fg; break; case notD: xf = GXxor; spix = fg^bg; break; } gcv.function = xf; gcv.foreground = spix; gcvm = GCFunction|GCForeground; }else{ /* src is involved in f */ #define code(f1,f2) ((((f1)&(DP1|BL1))<<2)|((f2)&(DP1|BL1))) sf = sb->flag; c = code(df,sf); *bltfunc = UseCopyArea; switch(code(df,sf)){ case code(DP1|BL1,DP1|BL1): case code(BL1,BL1): xf = gx[f]; break; case code(DP1|BL1,DP1): xf = d1s0gx[f]; break; case code(DP1,DP1|BL1): xf = d0s1gx[f]; break; case code(DP1,DP1): case code(0,0): xf = d0s0gx[f]; break; default: /* * One bitmap has depth 1, the other has screen depth. * We know the bitmap must have BL1. * CopyPlane must be used; it won't really work * for more than fcode==S. */ *bltfunc = UseCopyPlane; xf = GXcopy; switch(c){ case code(0,DP1|BL1): case code(BL1,DP1|BL1): fg = _fgpixel; bg = _bgpixel; break; case code(DP1|BL1,0): fg = 0; bg = 1; break; case code(DP1|BL1,BL1): fg = 1; bg = 0; break; default: berror("bad combination of copy bitmaps"); } gcv.foreground = fg; gcv.background = bg; gcvm |= GCForeground|GCBackground; } gcv.function = xf; gcvm |= GCFunction; #undef code } return _getgc(db, gcvm, &gcv); }