2011-03-30 15:46:40 +03:00
|
|
|
#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;
|
draw: fix drawing of replicated source image on memlayer with a clip rectangle
when a replicated source image with a clipr with clipr.min > Pt(0, 0),
drawclip() would properly translate the src->clipr on the dstr
but then clamp the source rectangle back on src->r.
while traversing down multiple layers, this would cause the translation to
be applied multiple times to the dst rectangle giving the wrong image result.
this change adds a new drawclipnorepl() function that avoids the clamping
of source and mask rectangles to src->r and mask->r. this is then used in
libmemlayer.
the final memimagedraw() call will call drawclip() which will do the final
claming.
a testcase is provided:
#include <u.h>
#include <libc.h>
#include <draw.h>
Image *blue;
Image *red;
void
main(int, char *argv[])
{
Image *i;
if(initdraw(nil, nil, argv[0]) < 0)
sysfatal("initdraw: %r");
i = allocimage(display, screen->r, screen->chan, 1, DWhite);
red = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DRed);
blue = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPaleblue);
replclipr(red, 1, Rect(10, 10, 110, 110));
replclipr(blue, 1, Rect(11, 11, 111, 111));
/* draw on non-layer, works correctly */
draw(i, i->r, red, nil, ZP);
draw(i, i->r, blue, nil, ZP);
draw(screen, screen->r, i, nil, i->r.min);
flushimage(display, 1);
/* draw on (screen) layer is too far to the right */
draw(screen, screen->r, red, nil, ZP);
draw(screen, screen->r, blue, nil, ZP);
flushimage(display, 1);
for(;;){
sleep(1000);
}
}
2013-12-09 03:35:01 +01:00
|
|
|
ok = drawclipnorepl(dst, &r, d->src, &p0, d->mask, &p1, &srcr, &mr);
|
2011-03-30 15:46:40 +03:00
|
|
|
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(mask == nil)
|
|
|
|
mask = memopaque;
|
|
|
|
|
2017-04-29 21:10:28 +02:00
|
|
|
if(mask->layer)
|
2011-03-30 15:46:40 +03:00
|
|
|
return; /* too hard, at least for now */
|
|
|
|
|
|
|
|
Top:
|
|
|
|
if(dst->layer==nil && src->layer==nil){
|
|
|
|
memimagedraw(dst, r, src, p0, mask, p1, op);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-04-29 21:10:28 +02:00
|
|
|
if(drawclipnorepl(dst, &r, src, &p0, mask, &p1, &srcr, &mr) == 0)
|
2011-03-30 15:46:40 +03:00
|
|
|
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);
|
|
|
|
}
|