Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

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

#define RECUR(a,b,c,d)  _layerop(fn, i, Rect(a.x, b.y, c.x, d.y), clipr, etc, front->layer->rear);

static void
_layerop(
        void (*fn)(Memimage*, Rectangle, Rectangle, void*, int),
        Memimage *i,
        Rectangle r,
        Rectangle clipr,
        void *etc,
        Memimage *front)
{
        Rectangle fr;

    Top:
        if(front == i){
                /* no one is in front of this part of window; use the screen */
                fn(i->layer->screen->image, r, clipr, etc, 0);
                return;
        }
        fr = front->layer->screenr;
        if(rectXrect(r, fr) == 0){
                /* r doesn't touch this window; continue on next rearmost */
                // assert(front && front->layer && front->layer->screen && front->layer->rear);
                front = front->layer->rear;
                goto Top;
        }
        if(fr.max.y < r.max.y){
                RECUR(r.min, fr.max, r.max, r.max);
                r.max.y = fr.max.y;
        }
        if(r.min.y < fr.min.y){
                RECUR(r.min, r.min, r.max, fr.min);
                r.min.y = fr.min.y;
        }
        if(fr.max.x < r.max.x){
                RECUR(fr.max, r.min, r.max, r.max);
                r.max.x = fr.max.x;
        }
        if(r.min.x < fr.min.x){
                RECUR(r.min, r.min, fr.min, r.max);
                r.min.x = fr.min.x;
        }
        /* r is covered by front, so put in save area */
        (*fn)(i->layer->save, r, clipr, etc, 1);
}

/*
 * Assumes incoming rectangle has already been clipped to i's logical r and clipr
 */
void
_memlayerop(
        void (*fn)(Memimage*, Rectangle, Rectangle, void*, int),
        Memimage *i,
        Rectangle screenr,      /* clipped to window boundaries */
        Rectangle clipr,                /* clipped also to clipping rectangles of hierarchy */
        void *etc)
{
        Memlayer *l;
        Rectangle r, scr;

        l = i->layer;
        if(!rectclip(&screenr, l->screenr))
                return;
        if(l->clear){
                fn(l->screen->image, screenr, clipr, etc, 0);
                return;
        }
        r = screenr;
        scr = l->screen->image->clipr;

        /*
         * Do the piece on the screen
         */
        if(rectclip(&screenr, scr))
                _layerop(fn, i, screenr, clipr, etc, l->screen->frontmost);
        if(rectinrect(r, scr))
                return;

        /*
         * Do the piece off the screen
        */
        if(!rectXrect(r, scr)){
                /* completely offscreen; easy */
                fn(l->save, r, clipr, etc, 1);
                return;
        }
        if(r.min.y < scr.min.y){
                /* above screen */
                fn(l->save, Rect(r.min.x, r.min.y, r.max.x, scr.min.y), clipr, etc, 1);
                r.min.y = scr.min.y;
        }
        if(r.max.y > scr.max.y){
                /* below screen */
                fn(l->save, Rect(r.min.x, scr.max.y, r.max.x, r.max.y), clipr, etc, 1);
                r.max.y = scr.max.y;
        }
        if(r.min.x < scr.min.x){
                /* left of screen */
                fn(l->save, Rect(r.min.x, r.min.y, scr.min.x, r.max.y), clipr, etc, 1);
                r.min.x = scr.min.x;
        }
        if(r.max.x > scr.max.x){
                /* right of screen */
                fn(l->save, Rect(scr.max.x, r.min.y, r.max.x, r.max.y), clipr, etc, 1);
        }
}