/* /sys/src/libmemlayer/ */ function ldrawop(dst, screenr, clipr, etc, insave){ var p0, p1; var oclipr, srcr, r, mr; var ok; if(insave && etc.dst.save == undefined) return; p0 = addpt(screenr.min, etc.deltas); p1 = addpt(screenr.min, etc.deltam); if(insave){ r = rectsubpt(screenr, etc.dst.delta); clipr = rectsubpt(clipr, etc.dst.delta); }else{ r = Rect.copy(screenr); } /* now in logical coordinates */ if(!rectinrect(r, clipr)){ oclipr = Rect.copy(dst.clipr); dst.clipr = Rect.copy(clipr); ok = drawclip(dst, r, etc.src, p0, etc.mask, p1, srcr, mr); dst.clipr = oclipr; if(!ok) return; } memdraw(dst, r, etc.src, p0, etc.mask, p1, etc.op); } function memdraw(dst, r, src, p0, mask, p1, op){ var d; var srcr, tr, mr; if(mask == undefined){ mask = memopaque; p1 = new Point(0, 0); } r = Rect.copy(r); p0 = Point.copy(p0); p1 = Point.copy(p1); srcr = new Rect(new Point(0, 0), new Point(0, 0)); mr = new Rect(new Point(0, 0), new Point(0, 0)); if(mask.screen != undefined) throw("mask is a screenimage"); Top: do{ if(dst.screen == undefined && src.screen == undefined) return drawmasked(dst, r, src, p0, mask, p1, op); if(drawclip(dst, r, src, p0, mask, p1, srcr, mr) == 0) return; /* convert to screen coordinates */ if(dst.screen) r = rectaddpt(r, dst.delta); Clearlayer: do{ if(dst.screen && dst.clear){ if(src == dst){ p0 = addpt(p0, dst.delta); src = dst.screen.backimg; } dst = dst.screen.backimg; continue Top; } if(src.screen){ p0 = addpt(p0, src.delta); srcr = rectaddpt(srcr, src.delta); } /* Now everything is in screen coordinates. */ if(dst.screen != undefined && dst == src){ if(dst.save == undefined) return; if(rectXrect(r, srcr)){ tr = Rect.copy(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.y - srcr.min.y; 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(dst.save, rectsubpt(r, dst.delta), dst.save, subpt(srcr.min, src.delta), mask, p1, op); memlexpose(dst, r); return; } if(src.screen){ if(src.clear){ src = src.screen.backimg; if(dst.screen) r = rectsubpt(r, dst.delta); continue Top; } /* relatively rare case; use save area */ if(src.save == undefined) return; memlhide(src, srcr); /* convert back to logical coordinates */ p0 = subpt(p0, src.delta); srcr = rectsubpt(srcr, src.delta); src = src.save; } /* src is now an image. dst may be an image or a clear layer. */ if(dst.screen == undefined) continue Top; if(dst.clear) continue Clearlayer; /* dst is an obscured layer */ d = { deltas: subpt(p0, r.min), deltam: subpt(p1, r.min), dst: dst, src: src, op: op, mask: mask }; memlayerop(ldrawop, dst, r, r, d); break; }while(true); break; }while(true); } function layerop(fn, img, r, clipr, etc, front){ var fr; var RECUR = function(a, b, c, d){ return layerop(fn, img, new Rect(new Point(a.x, b.y), new Point(c.x, d.y)), clipr, etc, front.rear); } r = Rect.copy(r); for(;;){ if(front == img){ fn(img.screen.backimg, r, clipr, etc, 0); return; } fr = front.screenr; if(rectXrect(r, fr) == 0) front = front.rear; else break; } 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; } fn(img.save, r, clipr, etc, 1); } function memlayerop(fn, img, screenr, clipr, etc){ var r, scr; screenr = Rect.copy(screenr); if(!rectclip(screenr, img.screenr)) return; if(img.clear){ fn(img.screen.backimg, screenr, clipr, etc, 0); return; } r = screenr; scr = img.screen.backimg.clipr; if(rectclip(screenr, scr)) layerop(fn, img, screenr, clipr, etc, img.screen.frontmost); if(rectinrect(r, scr)) return; if(!rectXrect(r, scr)){ /* completely offscreen */ fn(img.save, r, clipr, etc, 1); return; } if(r.min.y < scr.min.y){ /* above screen */ fn(img.save, new Rect(r.min, new Point(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(img.save, new Rect(new Point(r.min.x, scr.max.y), r.max), clipr, etc, 1); r.max.y = scr.max.y; } if(r.min.x < scr.min.x){ /* left of screen */ fn(img.save, new Rect(r.min, new Point(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(img.save, new Rect(new Point(scr.max.x, r.min.y), r.max), clipr, etc, 1); } } function memldelete(img){ var screen; delete img.save; img.save = undefined; img.refreshptr = undefined; memltorear(img); screen = img.screen; if(screen.fill){ img.clipr = img.r; memdraw(img, img.r, screen.fill, img.r.min, undefined, img.r.min, Memdraw.Opdefs.S.key); } if(img.front){ img.front.rear = undefined; screen.rearmost = img.front; }else{ screen.frontmost = undefined; screen.rearmost = undefined; } delete img; } function memltofront(img, front, fill){ var s; var f, ff, rr; var x; var overlap; s = img.screen; while(img.front != front){ f = img.front; x = Rect.copy(img.screenr); overlap = rectclip(x, f.screenr); if(overlap){ memlhide(f, x); f.clear = false; } /* swap img and f in screen's list */ ff = f.front; rr = img.rear; if(ff == undefined) s.frontmost = img; else ff.rear = img; if(rr == undefined) s.rearmost = f; else rr.front = f; img.front = ff; img.rear = f; f.front = img; f.rear = rr; if(overlap && fill) memlexpose(img, x); } } function memltofrontfill(img, fill){ memltofront(img, undefined, fill); memlsetclear(img.screen); } function memltofrontn(imgs){ var i; var front; if(imgs.length == 0) return; front = undefined; for(i = 0; i < imgs.length; ++i){ memltofront(imgs[i], front, 1); front = imgs[i]; } memlsetclear(front.screen); } function memltorear(img, rear){ var s; var f, r, rr; var x; var overlap; s = img.screen; while(img.rear != rear){ r = img.rear; x = Rect.copy(img.screenr); overlap = rectclip(x, r.screenr); if(overlap){ memlhide(img, x); img.clear = false; } /* swap img and r in screen's list */ rr = r.rear; f = img.front; if(rr == undefined) s.rearmost = img; else rr.front = img; if(f == undefined) s.frontmost = r; else f.rear = r; img.rear = rr; img.front = r; r.rear = img; r.front = f; if(overlap) memlexpose(r, x); } } function memltorearn(imgs){ var i; var rear; if(imgs.length == 0) return; rear = undefined; for(i = 0; i < imgs.length; ++i){ memltorear(imgs[i], rear); rear = i; } memlsetclear(rear.screen); } function memlsetrefresh(img, fn, ptr){ throw("memlsetrefresh is unimplemented"); } function lhideop(src, screenr, clipr, img, insave){ var r; if(src != img.save){ r = rectsubpt(screenr, img.delta); memdraw(img.save, r, src, screenr.min, undefined, screenr.min, Memdraw.Opdefs.S.key); } } function memlhide(img, screenr){ screenr = Rect.copy(screenr); if(img.save == undefined) return; if(rectclip(screenr, img.screen.backimg.r) == 0) return; memlayerop(lhideop, img, screenr, screenr, img); } function lexposeop(dst, screenr, clipr, img, insave){ var r; if(insave) return; r = rectsubpt(screenr, img.delta); if(img.save != undefined) memdraw(dst, screenr, img.save, r.min, undefined, r.min, Memdraw.Opdefs.S); else img.refreshfn(dst, r, img.refreshptr); } function memlexpose(img, screenr){ screenr = Rect.copy(screenr); if(rectclip(screenr, img.screen.backimg.r) == 0) return; memlayerop(lexposeop, img, screenr, screenr, img); } function memlsetclear(screen){ var i, j; for(i = screen.rearmost; i != undefined; i = i.front){ i.clear = rectinrect(i.screenr, i.screen.backimg.clipr); if(i.clear){ for(j = i.front; j != undefined; j = j.front){ if(rectXrect(i.screenr, j.screenr)){ i.clear = 0; break; } } } } } function memlnorefresh(){ ; } function memlorigin(img, log, scr){ var s; var t; var x, newr, oldr; var delta; var overlap, eqlog, eqscr, wasclear; var nsave, nsaver; var shad; s = img.screen; oldr = Rect.copy(img.screenr); newr = new Rect(new Point(scr.x, scr.y), new Point(scr.x+Dx(oldr), scr.y+Dy(oldr))); eqsqr = eqpt(scr, oldr.min); eqlog = eqpt(log, img.r.min); if(eqscr && eqlog) return 0; nsave = undefined; if(eqlog == 0 && img.save != undefined){ nsaver = new Rect(log, new Point(log.x + Dx(oldr), log.y + Dy(oldr))); nsave = new Draw9p.Image(0, img.chan, 0, nsaver, nsaver, DNofill); } memltofront(img); wasclear = img.clear; if(nsave){ if(!wasclear) drawmasked(nsave, nsave.r, img.save, img.save.r.min, undefined, undefined, Memdraw.Opdefs.S.key); img.save = nsave; } delta = subpt(log, img.r.min); img.r = rectaddpt(img.r, delta); img.clipr = rectaddpt(img.clipr, delta); img.delta = subpt(img.screenr.min, img.r.min); if(eqscr) return 0; /* clean up background with shadow window. */ shad = new Draw9p.ScreenImage(s, 1, img.chan, 0, oldr, oldr, DNofill); /* XXX use memlsetrefresh */ shad.save = undefined; shad.refreshfn = memlnorefresh; s.frontmost = img; if(s.rearmost == img) s.rearmost = shad; else img.rear.front = shad; shad.front = img; shad.rear = img.rear; img.rear = shad; img.front = undefined; shad.clear = 0; for(t = img.rear.rear; t != undefined; t = t.rear){ x = Rect.copy(newr); overlap = rectclip(x, t.screenr); if(overlap){ memlhide(t, x); t.clear = 0; } } img.screenr = newr; img.delta = subpt(scr, img.r.min); img.clear = rectinrect(newr, img.screen.backimg.clipr); if(wasclear) memdraw(s.backimg, newr, s.backimg, oldr.min, undefined, undefined, Memdraw.Opdefs.S.key); else memlexpose(img, newr); memldelete(shad); return 1; }