Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <memlayer.h>

struct Draw
{
        Point   deltas;
        Point   deltam;
        Memlayer                *dstlayer;
        Memimage        *src;
        Memimage        *mask;
        int     op;
};

static
void
ldrawop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave)
{
        struct Draw *d;
        Point p0, p1;
        Rectangle oclipr, srcr, r, mr;
        int ok;

        d = etc;
        if(insave && d->dstlayer->save==nil)
                return;

        p0 = addpt(screenr.min, d->deltas);
        p1 = addpt(screenr.min, d->deltam);

        if(insave){
                r = rectsubpt(screenr, d->dstlayer->delta);
                clipr = rectsubpt(clipr, d->dstlayer->delta);
        }else
                r = screenr;

        /* now in logical coordinates */

        /* clipr may have narrowed what we should draw on, so clip if necessary */
        if(!rectinrect(r, clipr)){
                oclipr = dst->clipr;
                dst->clipr = clipr;
                ok = drawclip(dst, &r, d->src, &p0, d->mask, &p1, &srcr, &mr);
                dst->clipr = oclipr;
                if(!ok)
                        return;
        }
        memdraw(dst, r, d->src, p0, d->mask, p1, d->op);
}

void
memdraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op)
{
        struct Draw d;
        Rectangle srcr, tr, mr;
        Memlayer *dl, *sl;

        if(drawdebug)
                iprint("memdraw %p %R %p %P %p %P\n", dst, r, src, p0, mask, p1);

        if(mask == nil)
                mask = memopaque;

        if(mask->layer){
if(drawdebug)   iprint("mask->layer != nil\n");
                return; /* too hard, at least for now */
        }

    Top:
        if(dst->layer==nil && src->layer==nil){
                memimagedraw(dst, r, src, p0, mask, p1, op);
                return;
        }

        if(drawclip(dst, &r, src, &p0, mask, &p1, &srcr, &mr) == 0){
if(drawdebug)   iprint("drawclip dstcr %R srccr %R maskcr %R\n", dst->clipr, src->clipr, mask->clipr);
                return;
        }

        /*
         * Convert to screen coordinates.
         */
        dl = dst->layer;
        if(dl != nil){
                r.min.x += dl->delta.x;
                r.min.y += dl->delta.y;
                r.max.x += dl->delta.x;
                r.max.y += dl->delta.y;
        }
    Clearlayer:
        if(dl!=nil && dl->clear){
                if(src == dst){
                        p0.x += dl->delta.x;
                        p0.y += dl->delta.y;
                        src = dl->screen->image;
                }
                dst = dl->screen->image;
                goto Top;
        }

        sl = src->layer;
        if(sl != nil){
                p0.x += sl->delta.x;
                p0.y += sl->delta.y;
                srcr.min.x += sl->delta.x;
                srcr.min.y += sl->delta.y;
                srcr.max.x += sl->delta.x;
                srcr.max.y += sl->delta.y;
        }

        /*
         * Now everything is in screen coordinates.
         * mask is an image.  dst and src are images or obscured layers.
         */

        /*
         * if dst and src are the same layer, just draw in save area and expose.
         */
        if(dl!=nil && dst==src){
                if(dl->save == nil)
                        return; /* refresh function makes this case unworkable */
                if(rectXrect(r, srcr)){
                        tr = r;
                        if(srcr.min.x < tr.min.x){
                                p1.x += tr.min.x - srcr.min.x;
                                tr.min.x = srcr.min.x;
                        }
                        if(srcr.min.y < tr.min.y){
                                p1.y += tr.min.x - srcr.min.x;
                                tr.min.y = srcr.min.y;
                        }
                        if(srcr.max.x > tr.max.x)
                                tr.max.x = srcr.max.x;
                        if(srcr.max.y > tr.max.y)
                                tr.max.y = srcr.max.y;
                        memlhide(dst, tr);
                }else{
                        memlhide(dst, r);
                        memlhide(dst, srcr);
                }
                memdraw(dl->save, rectsubpt(r, dl->delta), dl->save,
                        subpt(srcr.min, src->layer->delta), mask, p1, op);
                memlexpose(dst, r);
                return;
        }

        if(sl){
                if(sl->clear){
                        src = sl->screen->image;
                        if(dl != nil){
                                r.min.x -= dl->delta.x;
                                r.min.y -= dl->delta.y;
                                r.max.x -= dl->delta.x;
                                r.max.y -= dl->delta.y;
                        }
                        goto Top;
                }
                /* relatively rare case; use save area */
                if(sl->save == nil)
                        return; /* refresh function makes this case unworkable */
                memlhide(src, srcr);
                /* convert back to logical coordinates */
                p0.x -= sl->delta.x;
                p0.y -= sl->delta.y;
                srcr.min.x -= sl->delta.x;
                srcr.min.y -= sl->delta.y;
                srcr.max.x -= sl->delta.x;
                srcr.max.y -= sl->delta.y;
                src = src->layer->save;
        }

        /*
         * src is now an image.  dst may be an image or a clear layer
         */
        if(dst->layer==nil)
                goto Top;
        if(dst->layer->clear)
                goto Clearlayer;

        /*
         * dst is an obscured layer
         */
        d.deltas = subpt(p0, r.min);
        d.deltam = subpt(p1, r.min);
        d.dstlayer = dl;
        d.src = src;
        d.op = op;
        d.mask = mask;
        _memlayerop(ldrawop, dst, r, r, &d);
}