#include #include #include #include #include #include "dat.h" #include "fns.h" #include "inc.h" #include "x.h" enum { Fullsrc=1<<5, }; static int xdraw(Memdrawparam*); Memdrawparam par; Memdrawparam* memimagedrawsetup(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op) { if(mask == nil) mask = memopaque; if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0) return nil; if(op < Clear || op > SoverD) return nil; par.op = op; par.dst = dst; par.r = r; par.src = src; /* par.sr set by drawclip */ par.mask = mask; /* par.mr set by drawclip */ par.state = 0; if(src->flags&Frepl){ par.state |= Replsrc; if(Dx(src->r)==1 && Dy(src->r)==1){ par.sval = pixelbits(src, src->r.min); par.state |= Simplesrc; par.srgba = imgtorgba(src, par.sval); par.sdval = rgbatoimg(dst, par.srgba); if((par.srgba&0xFF) == 0 && (op&DoutS)) return nil; /* no-op successfully handled */ if((par.srgba&0xFF) == 0xFF) par.state |= Fullsrc; } } if(mask->flags & Frepl){ par.state |= Replmask; if(Dx(mask->r)==1 && Dy(mask->r)==1){ par.mval = pixelbits(mask, mask->r.min); if(par.mval == 0 && (op&DoutS)) return nil; /* no-op successfully handled */ par.state |= Simplemask; if(par.mval == ~0) par.state |= Fullmask; par.mrgba = imgtorgba(mask, par.mval); } } return ∥ } /* * The X acceleration doesn't fit into the standard hwaccel * model because we have the extra steps of pulling the image * data off the server and putting it back when we're done. */ void xmemimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op) { Memdrawparam *par; if((par = memimagedrawsetup(dst, r, src, sp, mask, mp, op)) == nil) return; /* only fetch dst data if we need it */ if((par->state&(Simplemask|Fullmask)) != (Simplemask|Fullmask)) xgetxdata(par->dst, par->r); /* always fetch source and mask */ xgetxdata(par->src, par->sr); xgetxdata(par->mask, par->mr); /* now can run memimagedraw on the in-memory bits */ _memimagedraw(dst, r, src, sp, mask, mp, op); if(xdraw(par)) return; /* put bits back on x server */ xputxdata(par->dst, par->r); } static int xdraw(Memdrawparam *par) { ulong sdval; uint m, state; Memimage *src, *dst, *mask; Point dp, mp, sp; Rectangle r; Xmem *xdst, *xmask, *xsrc; XGC gc; if(par->dst->X == nil) return 0; dst = par->dst; mask = par->mask; r = par->r; src = par->src; state = par->state; /* * If we have an opaque mask and source is one opaque pixel, * we can convert to the destination format and just XFillRectangle. */ m = Simplesrc|Fullsrc|Simplemask|Fullmask; if((state&m) == m){ xfillcolor(dst, r, par->sdval); /* xdirtyxdata(dst, r); */ return 1; } /* * If no source alpha and an opaque mask, we can just copy * the source onto the destination. If the channels are the * same and the source is not replicated, XCopyArea works. */ m = Simplemask|Fullmask; if((state&(m|Replsrc))==m && src->chan==dst->chan && src->X){ xdst = dst->X; xsrc = src->X; dp = subpt(r.min, dst->r.min); sp = subpt(par->sr.min, src->r.min); gc = dst->chan==GREY1 ? xconn.gccopy0 : xconn.gccopy; XCopyArea(xconn.display, xsrc->pixmap, xdst->pixmap, gc, sp.x, sp.y, Dx(r), Dy(r), dp.x, dp.y); /* xdirtyxdata(dst, r); */ return 1; } /* * If no source alpha, a 1-bit mask, and a simple source, * we can copy through the mask onto the destination. */ if(dst->X && mask->X && !(mask->flags&Frepl) && mask->chan==GREY1 && (state&Simplesrc)){ xdst = dst->X; xmask = mask->X; sdval = par->sdval; dp = subpt(r.min, dst->r.min); mp = subpt(r.min, subpt(par->mr.min, mask->r.min)); if(dst->chan == GREY1){ gc = xconn.gcsimplesrc0; if(xconn.gcsimplesrc0color != sdval){ XSetForeground(xconn.display, gc, sdval); xconn.gcsimplesrc0color = sdval; } if(xconn.gcsimplesrc0pixmap != xmask->pixmap){ XSetStipple(xconn.display, gc, xmask->pixmap); xconn.gcsimplesrc0pixmap = xmask->pixmap; } }else{ /* this doesn't work on rob's mac? */ return 0; /* gc = xconn.gcsimplesrc; if(dst->chan == CMAP8 && xconn.usetable) sdval = xconn.tox11[sdval]; if(xconn.gcsimplesrccolor != sdval){ XSetForeground(xconn.display, gc, sdval); xconn.gcsimplesrccolor = sdval; } if(xconn.gcsimplesrcpixmap != xmask->pixmap){ XSetStipple(xconn.display, gc, xmask->pixmap); xconn.gcsimplesrcpixmap = xmask->pixmap; } */ } XSetTSOrigin(xconn.display, gc, mp.x, mp.y); XFillRectangle(xconn.display, xdst->pixmap, gc, dp.x, dp.y, Dx(r), Dy(r)); /* xdirtyxdata(dst, r); */ return 1; } /* * Can't accelerate. */ return 0; } int xloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) { int n; n = _loadmemimage(i, r, data, ndata); if(n > 0 && i->X) xputxdata(i, r); return n; } int xunloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata) { if(i->X) xgetxdata(i, r); return _unloadmemimage(i, r, data, ndata); } ulong xpixelbits(Memimage *m, Point p) { if(m->X) xgetxdata(m, Rect(p.x, p.y, p.x+1, p.y+1)); return _pixelbits(m, p); }