aboutsummaryrefslogtreecommitdiff
path: root/src/libdraw/x11-draw.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libdraw/x11-draw.c')
-rw-r--r--src/libdraw/x11-draw.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/libdraw/x11-draw.c b/src/libdraw/x11-draw.c
new file mode 100644
index 00000000..33b92c87
--- /dev/null
+++ b/src/libdraw/x11-draw.c
@@ -0,0 +1,143 @@
+#include "x11-inc.h"
+
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+#include "x11-memdraw.h"
+
+static int xdraw(Memdrawparam*);
+
+/*
+ * 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
+memimagedraw(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;
+
+ if(xdraw(par))
+ return;
+
+ /* only fetch dst data if we need it */
+ if((par->state&(Simplemask|Fullmask)) != (Simplemask|Fullmask))
+ xgetxdata(dst, par->r);
+
+ /* always fetch source and mask */
+ xgetxdata(src, par->sr);
+ xgetxdata(mask, par->mr);
+
+ /* now can run memimagedraw on the in-memory bits */
+ _memimagedraw(par);
+
+ /* put bits back on x server */
+ xputxdata(dst, par->r);
+}
+
+static int
+xdraw(Memdrawparam *par)
+{
+ u32int 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|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 ? _x.gccopy0 : _x.gccopy;
+
+ XCopyArea(_x.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 = _x.gcsimplesrc0;
+ if(_x.gcsimplesrc0color != sdval){
+ XSetForeground(_x.display, gc, sdval);
+ _x.gcsimplesrc0color = sdval;
+ }
+ if(_x.gcsimplesrc0pixmap != xmask->pixmap){
+ XSetStipple(_x.display, gc, xmask->pixmap);
+ _x.gcsimplesrc0pixmap = xmask->pixmap;
+ }
+ }else{
+ /* this doesn't work on rob's mac? */
+ gc = _x.gcsimplesrc;
+ if(dst->chan == CMAP8 && _x.usetable)
+ sdval = _x.tox11[sdval];
+
+ if(_x.gcsimplesrccolor != sdval){
+ XSetForeground(_x.display, gc, sdval);
+ _x.gcsimplesrccolor = sdval;
+ }
+ if(_x.gcsimplesrcpixmap != xmask->pixmap){
+ XSetStipple(_x.display, gc, xmask->pixmap);
+ _x.gcsimplesrcpixmap = xmask->pixmap;
+ }
+ }
+ XSetTSOrigin(_x.display, gc, mp.x, mp.y);
+ XFillRectangle(_x.display, xdst->pixmap, gc, dp.x, dp.y,
+ Dx(r), Dy(r));
+ xdirtyxdata(dst, r);
+ return 1;
+ }
+
+ /*
+ * Can't accelerate.
+ */
+ return 0;
+}
+