mirror of
https://github.com/gnustep/libs-back.git
synced 2025-04-22 23:42:16 +00:00
Move compositing code to its own file. Pick the right blitter for plusl_oo. Handle inline alpha in compositerect.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@14339 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
a008e3d919
commit
b52e7ce404
4 changed files with 679 additions and 659 deletions
|
@ -1,3 +1,10 @@
|
|||
2002-08-27 10:23 Alexander Malmberg <alexander@malmberg.org>
|
||||
|
||||
* Source/art/ARTContext.m, Source/art/composite.m: Move compositing
|
||||
code to its own file. Reformat.
|
||||
(-_composite_func::::::): Handle the plusl_oo case correctly.
|
||||
(-compositerect:op:): Handle inline alpha in the general case.
|
||||
|
||||
2002-08-26 16:36 Alexander Malmberg <alexander@malmberg.org>
|
||||
|
||||
* Source/art/image.m: Assume that input isn't premultiplied in
|
||||
|
|
|
@ -222,664 +222,6 @@ static void dump_vpath(ArtVpath *vp)
|
|||
@implementation ARTGState
|
||||
|
||||
|
||||
/* Figure out what blit function we should use. If one or both of the
|
||||
windows are known to be totally opaque, we can optimize in many ways
|
||||
(see big table at the end of blit.m). Will set dst_need_alpha and blit_func
|
||||
if necessary. Returns new operation, op==-1 means noop. */
|
||||
-(int) _composite_func: (BOOL)src_opaque : (BOOL)src_transparent
|
||||
: (BOOL)dst_opaque : (BOOL *)dst_needs_alpha
|
||||
: (int)op : (void (**)(composite_run_t *c,int num))blit_func_r
|
||||
{
|
||||
void (*blit_func)(composite_run_t *c,int num);
|
||||
|
||||
*dst_needs_alpha=NO;
|
||||
*blit_func_r=blit_func=NULL;
|
||||
|
||||
if (src_transparent) /* only happens with compositerect */
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case NSCompositeCopy:
|
||||
case NSCompositeSourceIn:
|
||||
case NSCompositeSourceOut:
|
||||
case NSCompositeDestinationIn:
|
||||
case NSCompositeDestinationAtop:
|
||||
case NSCompositePlusDarker:
|
||||
return NSCompositeClear;
|
||||
|
||||
case NSCompositeSourceOver:
|
||||
case NSCompositeSourceAtop:
|
||||
case NSCompositeDestinationOver:
|
||||
case NSCompositeDestinationOut:
|
||||
case NSCompositeXOR:
|
||||
case NSCompositePlusLighter:
|
||||
return -1; /* noop */
|
||||
}
|
||||
}
|
||||
else
|
||||
if (src_opaque && dst_opaque)
|
||||
{ /* both source and destination are totally opaque */
|
||||
switch (op)
|
||||
{
|
||||
case NSCompositeSourceOver:
|
||||
case NSCompositeSourceIn:
|
||||
case NSCompositeSourceAtop:
|
||||
return NSCompositeCopy;
|
||||
|
||||
case NSCompositeSourceOut:
|
||||
case NSCompositeDestinationOut:
|
||||
case NSCompositeXOR:
|
||||
return NSCompositeClear;
|
||||
|
||||
case NSCompositeDestinationOver:
|
||||
case NSCompositeDestinationIn:
|
||||
case NSCompositeDestinationAtop:
|
||||
return -1; /* noop */
|
||||
|
||||
case NSCompositePlusLighter:
|
||||
blit_func=DI.composite_plusd_oo;
|
||||
break;
|
||||
case NSCompositePlusDarker:
|
||||
blit_func=DI.composite_plusd_oo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (src_opaque)
|
||||
{ /* source is opaque, destination has alpha */
|
||||
switch (op)
|
||||
{
|
||||
case NSCompositeSourceOver:
|
||||
return NSCompositeCopy;
|
||||
|
||||
case NSCompositeSourceIn:
|
||||
case NSCompositeSourceAtop:
|
||||
blit_func=DI.composite_sin_oa;
|
||||
break;
|
||||
|
||||
case NSCompositeSourceOut:
|
||||
case NSCompositeXOR:
|
||||
blit_func=DI.composite_sout_oa;
|
||||
break;
|
||||
|
||||
case NSCompositeDestinationOver:
|
||||
case NSCompositeDestinationAtop:
|
||||
blit_func=DI.composite_dover_oa;
|
||||
break;
|
||||
|
||||
case NSCompositeDestinationIn:
|
||||
return -1; /* noop */
|
||||
|
||||
case NSCompositeDestinationOut:
|
||||
return NSCompositeClear;
|
||||
|
||||
case NSCompositePlusLighter:
|
||||
blit_func=DI.composite_plusl_oa;
|
||||
break;
|
||||
case NSCompositePlusDarker:
|
||||
blit_func=DI.composite_plusd_oa;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (dst_opaque)
|
||||
{ /* source has alpha, destination is opaque */
|
||||
switch (op)
|
||||
{
|
||||
case NSCompositeSourceOver:
|
||||
case NSCompositeSourceAtop:
|
||||
blit_func=DI.composite_sover_ao;
|
||||
break;
|
||||
|
||||
case NSCompositeSourceIn:
|
||||
return NSCompositeCopy;
|
||||
|
||||
case NSCompositeSourceOut:
|
||||
return NSCompositeClear;
|
||||
|
||||
case NSCompositeDestinationOver:
|
||||
return -1; /* noop */
|
||||
|
||||
case NSCompositeDestinationIn:
|
||||
case NSCompositeDestinationOut:
|
||||
case NSCompositeDestinationAtop:
|
||||
case NSCompositeXOR:
|
||||
*dst_needs_alpha=YES;
|
||||
goto both_have_alpha;
|
||||
|
||||
case NSCompositePlusLighter:
|
||||
blit_func=DI.composite_plusl_ao;
|
||||
break;
|
||||
case NSCompositePlusDarker:
|
||||
blit_func=DI.composite_plusd_ao;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* both source and destination have alpha */
|
||||
both_have_alpha:
|
||||
switch (op)
|
||||
{
|
||||
case NSCompositeSourceOver:
|
||||
blit_func=DI.composite_sover_aa;
|
||||
break;
|
||||
case NSCompositeSourceIn:
|
||||
blit_func=DI.composite_sin_aa;
|
||||
break;
|
||||
case NSCompositeSourceOut:
|
||||
blit_func=DI.composite_sout_aa;
|
||||
break;
|
||||
case NSCompositeSourceAtop:
|
||||
blit_func=DI.composite_satop_aa;
|
||||
break;
|
||||
case NSCompositeDestinationOver:
|
||||
blit_func=DI.composite_dover_aa;
|
||||
break;
|
||||
case NSCompositeDestinationIn:
|
||||
blit_func=DI.composite_din_aa;
|
||||
break;
|
||||
case NSCompositeDestinationOut:
|
||||
blit_func=DI.composite_dout_aa;
|
||||
break;
|
||||
case NSCompositeDestinationAtop:
|
||||
blit_func=DI.composite_datop_aa;
|
||||
break;
|
||||
case NSCompositeXOR:
|
||||
blit_func=DI.composite_xor_aa;
|
||||
break;
|
||||
case NSCompositePlusLighter:
|
||||
blit_func=DI.composite_plusl_aa;
|
||||
break;
|
||||
case NSCompositePlusDarker:
|
||||
blit_func=DI.composite_plusd_aa;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*blit_func_r=blit_func;
|
||||
return op;
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (void) compositeGState: (GSGState *)source
|
||||
fromRect: (NSRect)aRect
|
||||
toPoint: (NSPoint)aPoint
|
||||
op: (NSCompositingOperation)op
|
||||
{
|
||||
ARTGState *ags=(ARTGState *)source;
|
||||
NSRect sr,dr;
|
||||
unsigned char *dst,*dst_alpha,*src,*src_alpha;
|
||||
|
||||
void (*blit_func)(composite_run_t *c,int num)=NULL;
|
||||
|
||||
int sx,sy;
|
||||
int x0,y0,x1,y1;
|
||||
|
||||
int sbpl,dbpl;
|
||||
int asbpl,adbpl;
|
||||
|
||||
/* 0=top->down, 1=bottom->up */
|
||||
/*
|
||||
TODO: this does not handle the horizontal case
|
||||
either 0=top->down, left->right, 2=top->down, right->left
|
||||
or keep 0 and add 2=top->down, make temporary copy of source
|
||||
could allocate a temporary array on the stack large enough to hold
|
||||
one row and do the operations on it
|
||||
*/
|
||||
/* currently 2=top->down, be careful with overlapping rows */
|
||||
/* order=1 is handled generically by flipping sbpl and dbpl and
|
||||
adjusting the pointers. only order=2 needs to be handled for
|
||||
each operator */
|
||||
int order;
|
||||
|
||||
|
||||
if (!wi || !wi->data || !ags->wi || !ags->wi->data) return;
|
||||
if (all_clipped) return;
|
||||
|
||||
// NSLog(@"op=%i %i %i\n",op,ags->wi->has_alpha,wi->has_alpha);
|
||||
|
||||
|
||||
{
|
||||
BOOL dst_needs_alpha;
|
||||
op=[self _composite_func: !ags->wi->has_alpha : NO
|
||||
: !wi->has_alpha : &dst_needs_alpha
|
||||
: op : &blit_func];
|
||||
if (op==-1)
|
||||
return;
|
||||
|
||||
if (dst_needs_alpha)
|
||||
{
|
||||
[wi needsAlpha];
|
||||
if (!wi->has_alpha)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NSLog(@" got %i %08x",op,blit_func);
|
||||
|
||||
/* these ignore the source window, so we send them off to
|
||||
compositerect: op: */
|
||||
if (op==NSCompositeClear || op==NSCompositeHighlight)
|
||||
{
|
||||
[self compositerect: NSMakeRect(aPoint.x,aPoint.y,
|
||||
aRect.size.width,aRect.size.height)
|
||||
op: op];
|
||||
return;
|
||||
}
|
||||
|
||||
/* NSLog(@"compositeGState: %p fromRect: (%g %g)+(%g %g) toPoint: (%g %g) op: %i",
|
||||
source,
|
||||
aRect.origin.x,aRect.origin.y,
|
||||
aRect.size.width,aRect.size.height,
|
||||
aPoint.x,aPoint.y,
|
||||
op);*/
|
||||
|
||||
/* NSLog(@"composite op=%i from %p %ix%i to %p %ix%i\n",
|
||||
op,ags,ags->wi->sx,ags->wi->sy,
|
||||
wi,wi->sx,wi->sy);*/
|
||||
|
||||
// printf("src->wi=%ix%i dst->wi=%ix%i\n",ags->wi->sx,ags->wi->sy,wi->sx,wi->sy);
|
||||
|
||||
|
||||
/* Set up all the pointers and clip things */
|
||||
|
||||
dbpl=wi->bytes_per_line;
|
||||
sbpl=ags->wi->bytes_per_line;
|
||||
|
||||
sr=aRect;
|
||||
sr=[ags->ctm rectInMatrixSpace: sr];
|
||||
/* printf("sr=(%g %g)+(%g %g)\n",
|
||||
sr.origin.x,sr.origin.y,
|
||||
sr.size.width,sr.size.height);*/
|
||||
sr.origin.y=ags->wi->sy-sr.origin.y-sr.size.height;
|
||||
sx=sr.origin.x;
|
||||
sy=sr.origin.y;
|
||||
|
||||
dr=aRect;
|
||||
dr.origin=aPoint;
|
||||
dr=[ctm rectInMatrixSpace: dr];
|
||||
/* printf("dr=(%g %g)+(%g %g)\n",
|
||||
dr.origin.x,dr.origin.y,
|
||||
dr.size.width,dr.size.height);*/
|
||||
dr.origin.y=wi->sy-dr.origin.y-dr.size.height;
|
||||
// printf("%g=%i-y-%g\n",dr.origin.y,sy,dr.size.height);
|
||||
|
||||
x0=dr.origin.x;
|
||||
y0=dr.origin.y;
|
||||
x1=dr.origin.x+dr.size.width;
|
||||
y1=dr.origin.y+dr.size.height;
|
||||
|
||||
// printf("s=(%i %i) (%i %i)-(%i %i)\n",sx,sy,x0,y0,x1,y1);
|
||||
|
||||
// printf("clip=(%i %i)-(%i %i)\n",clip_x0,clip_y0,clip_x1,clip_y1);
|
||||
if (clip_x0>x0) /* TODO: ??? */
|
||||
{
|
||||
sx+=clip_x0-x0;
|
||||
x0=clip_x0;
|
||||
}
|
||||
if (clip_y0>y0)
|
||||
{
|
||||
sy+=clip_y0-y0;
|
||||
y0=clip_y0;
|
||||
}
|
||||
|
||||
if (x1>clip_x1)
|
||||
x1=clip_x1;
|
||||
if (y1>clip_y1)
|
||||
y1=clip_y1;
|
||||
|
||||
if (x0>=x1 || y0>=y1) return;
|
||||
|
||||
/* TODO: clip source? how?
|
||||
we should at least clip the source to the source window to avoid
|
||||
crashes */
|
||||
|
||||
// printf("clipped s=(%i %i) (%i %i)-(%i %i)\n",sx,sy,x0,y0,x1,y1);
|
||||
|
||||
dst=wi->data+x0*DI.bytes_per_pixel+y0*dbpl;
|
||||
src=ags->wi->data+sx*DI.bytes_per_pixel+sy*sbpl;
|
||||
|
||||
if (ags->wi->has_alpha && op==NSCompositeCopy)
|
||||
{
|
||||
[wi needsAlpha];
|
||||
if (!wi->has_alpha)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ags->wi->has_alpha)
|
||||
{
|
||||
if (DI.inline_alpha)
|
||||
src_alpha=src;
|
||||
else
|
||||
src_alpha=ags->wi->alpha+sx+sy*ags->wi->sx;
|
||||
asbpl=ags->wi->sx;
|
||||
}
|
||||
else
|
||||
{
|
||||
src_alpha=NULL;
|
||||
asbpl=0;
|
||||
}
|
||||
|
||||
if (wi->has_alpha)
|
||||
{
|
||||
if (DI.inline_alpha)
|
||||
dst_alpha=dst;
|
||||
else
|
||||
dst_alpha=wi->alpha+x0+y0*wi->sx;
|
||||
adbpl=wi->sx;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst_alpha=NULL;
|
||||
adbpl=0;
|
||||
}
|
||||
|
||||
y1-=y0;
|
||||
x1-=x0;
|
||||
|
||||
// printf("fixed %p -> %p s=(%i %i) (%i %i)-(%i %i)\n",src,dst,sx,sy,x0,y0,x1,y1);
|
||||
|
||||
/* To handle overlapping areas properly, we sometimes need to do
|
||||
things bottom-up instead of top-down. If so, we flip the
|
||||
coordinates here. */
|
||||
order=0;
|
||||
if (ags==self && sy<=y0)
|
||||
{
|
||||
order=1;
|
||||
dst+=dbpl*(y1-1);
|
||||
src+=sbpl*(y1-1);
|
||||
dst_alpha+=adbpl*(y1-1);
|
||||
src_alpha+=asbpl*(y1-1);
|
||||
dbpl=-dbpl;
|
||||
sbpl=-sbpl;
|
||||
adbpl=-adbpl;
|
||||
asbpl=-asbpl;
|
||||
if (sy==y0)
|
||||
{ /* TODO: pure horizontal, not handled properly in all
|
||||
cases */
|
||||
if ((sx>=x0 && sx<=x0+x1) || (x0>=sx && x0<=x0+x1))
|
||||
order=2;
|
||||
}
|
||||
}
|
||||
|
||||
if (op==NSCompositeCopy)
|
||||
{ /* TODO: for inline alpha, make sure even opaque destinations have
|
||||
alpha properly filled in */
|
||||
int y;
|
||||
|
||||
if (!DI.inline_alpha && wi->has_alpha)
|
||||
{
|
||||
if (ags->wi->has_alpha)
|
||||
for (y=0;y<y1;y++,dst_alpha+=adbpl,src_alpha+=asbpl)
|
||||
memmove(dst_alpha,src_alpha,x1);
|
||||
else
|
||||
for (y=0;y<y1;y++,dst_alpha+=adbpl)
|
||||
memset(dst_alpha,0xff,x1);
|
||||
}
|
||||
|
||||
x1*=DI.bytes_per_pixel;
|
||||
for (y=0;y<y1;y++,dst+=dbpl,src+=sbpl)
|
||||
memmove(dst,src,x1);
|
||||
/* TODO: worth the complexity? */
|
||||
/* {
|
||||
int y;
|
||||
x1*=DI.bytes_per_pixel;
|
||||
for (y=0;y<y1;y++,dst+=dbpl,src+=sbpl)
|
||||
memcpy(dst,src,x1);
|
||||
}*/
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!blit_func)
|
||||
{
|
||||
NSLog(@"unimplemented: compositeGState: %p fromRect: (%g %g)+(%g %g) toPoint: (%g %g) op: %i",
|
||||
source,
|
||||
aRect.origin.x,aRect.origin.y,
|
||||
aRect.size.width,aRect.size.height,
|
||||
aPoint.x,aPoint.y,
|
||||
op);
|
||||
return;
|
||||
}
|
||||
|
||||
/* this breaks the alpha pointer in some, but that's ok since in
|
||||
all those cases, the alpha pointer isn't used (inline alpha or
|
||||
no alpha) */
|
||||
if (order==2)
|
||||
{
|
||||
unsigned char tmpbuf[x1*DI.bytes_per_pixel];
|
||||
int y;
|
||||
composite_run_t c;
|
||||
|
||||
c.dst=dst;
|
||||
c.dsta=dst_alpha;
|
||||
c.src=src;
|
||||
c.srca=src_alpha;
|
||||
for (y=0;y<y1;y++,c.dst+=dbpl,c.src+=sbpl)
|
||||
{
|
||||
/* don't need to copy alpha since it is either
|
||||
separate and won't be written to or part of the
|
||||
data */
|
||||
/* TODO: this only holds if there's no destination
|
||||
alpha, which is no longer true. ignore for now; why
|
||||
would someone sourceover something on itself? */
|
||||
/* TODO: this looks broken. where is tmpbuf used? */
|
||||
memcpy(tmpbuf,src,x1*DI.bytes_per_pixel);
|
||||
blit_func(&c,x1);
|
||||
c.srca+=asbpl;
|
||||
c.dsta+=adbpl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int y;
|
||||
composite_run_t c;
|
||||
|
||||
c.dst=dst;
|
||||
c.dsta=dst_alpha;
|
||||
c.src=src;
|
||||
c.srca=src_alpha;
|
||||
for (y=0;y<y1;y++,c.dst+=dbpl,c.src+=sbpl)
|
||||
{
|
||||
blit_func(&c,x1);
|
||||
c.srca+=asbpl;
|
||||
c.dsta+=adbpl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) dissolveGState: (GSGState *)source
|
||||
fromRect: (NSRect)aRect
|
||||
toPoint: (NSPoint)aPoint
|
||||
delta: (float)delta
|
||||
{
|
||||
NSLog(@"ignoring dissolveGState: %08x fromRect: (%g %g)+(%g %g) toPoint: (%g %g) delta: %g",
|
||||
source,
|
||||
aRect.origin.x,aRect.origin.y,aRect.size.width,aRect.size.height,
|
||||
aPoint.x,aPoint.y,delta);
|
||||
}
|
||||
|
||||
- (void) compositerect: (NSRect)aRect
|
||||
op: (NSCompositingOperation)op
|
||||
{
|
||||
/* much setup code shared with compositeGState:... */
|
||||
NSRect dr;
|
||||
unsigned char *dst;
|
||||
|
||||
int x0,y0,x1,y1;
|
||||
|
||||
int dbpl;
|
||||
|
||||
void (*blit_func)(composite_run_t *c,int num);
|
||||
|
||||
if (!wi || !wi->data) return;
|
||||
if (all_clipped) return;
|
||||
|
||||
dbpl=wi->bytes_per_line;
|
||||
|
||||
dr=aRect;
|
||||
dr=[ctm rectInMatrixSpace: dr];
|
||||
dr.origin.y=wi->sy-dr.origin.y-dr.size.height;
|
||||
|
||||
x0=dr.origin.x;
|
||||
y0=dr.origin.y;
|
||||
x1=dr.origin.x+dr.size.width;
|
||||
y1=dr.origin.y+dr.size.height;
|
||||
|
||||
if (clip_x0>x0)
|
||||
x0=clip_x0;
|
||||
if (clip_y0>y0)
|
||||
y0=clip_y0;
|
||||
|
||||
if (x1>clip_x1)
|
||||
x1=clip_x1;
|
||||
if (y1>clip_y1)
|
||||
y1=clip_y1;
|
||||
|
||||
if (x0>=x1 || y0>=y1) return;
|
||||
|
||||
dst=wi->data+x0*DI.bytes_per_pixel+y0*dbpl;
|
||||
|
||||
y1-=y0;
|
||||
x1-=x0;
|
||||
|
||||
{
|
||||
BOOL dest_needs_alpha;
|
||||
|
||||
/* TODO: which color? using fill_color for now */
|
||||
op=[self _composite_func: fill_color[3]==255 : fill_color[3]==0
|
||||
: !wi->has_alpha : &dest_needs_alpha
|
||||
: op : &blit_func];
|
||||
|
||||
if (op==-1)
|
||||
return;
|
||||
|
||||
if (dest_needs_alpha)
|
||||
{
|
||||
[wi needsAlpha];
|
||||
if (!wi->has_alpha)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (op==NSCompositeClear)
|
||||
{
|
||||
int y;
|
||||
[wi needsAlpha];
|
||||
if (!wi->has_alpha)
|
||||
return;
|
||||
if (!DI.inline_alpha)
|
||||
{
|
||||
unsigned char *dsta;
|
||||
dsta=wi->alpha+x0+y0*wi->sx;
|
||||
for (y=0;y<y1;y++,dsta+=wi->sx)
|
||||
memset(dsta,0,x1);
|
||||
}
|
||||
x1*=DI.bytes_per_pixel;
|
||||
for (y=0;y<y1;y++,dst+=dbpl)
|
||||
memset(dst,0,x1);
|
||||
return;
|
||||
}
|
||||
else if (op==NSCompositeHighlight)
|
||||
{
|
||||
int y,n;
|
||||
/* This must be reversible, which limits what we can
|
||||
do. */
|
||||
x1*=DI.bytes_per_pixel;
|
||||
for (y=0;y<y1;y++,dst+=dbpl)
|
||||
{
|
||||
unsigned char *d=dst;
|
||||
for (n=x1;n;n--,d++)
|
||||
(*d)^=0xff;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (op==NSCompositeCopy)
|
||||
{
|
||||
render_run_t ri;
|
||||
int y;
|
||||
ri.dst=dst;
|
||||
/* We don't want to blend, so we premultiply and fill the
|
||||
alpha channel manually. */
|
||||
ri.a=fill_color[3];
|
||||
ri.r=(fill_color[0]*ri.a+0xff)>>8;
|
||||
ri.g=(fill_color[1]*ri.a+0xff)>>8;
|
||||
ri.b=(fill_color[2]*ri.a+0xff)>>8;
|
||||
for (y=0;y<y1;y++,ri.dst+=dbpl)
|
||||
DI.render_run_opaque(&ri,x1);
|
||||
|
||||
if (ri.a!=255)
|
||||
[wi needsAlpha];
|
||||
if (wi->has_alpha)
|
||||
{
|
||||
if (DI.inline_alpha)
|
||||
{
|
||||
int n;
|
||||
unsigned char *p;
|
||||
for (y=0;y<y1;y++,dst+=dbpl)
|
||||
{ /* TODO: needs to change to support inline
|
||||
alpha for non-32-bit modes */
|
||||
for (p=dst,n=x1;n;n--,p+=4)
|
||||
dst[DI.inline_alpha_ofs]=ri.a;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char *dsta;
|
||||
dsta=wi->alpha+x0+y0*wi->sx;
|
||||
for (y=0;y<y1;y++,dsta+=wi->sx)
|
||||
memset(dsta,ri.a,x1);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (blit_func)
|
||||
{
|
||||
/* this is slightly ugly, but efficient */
|
||||
unsigned char buf[DI.bytes_per_pixel*x1];
|
||||
unsigned char abuf[fill_color[3]==255?1:x1];
|
||||
int y;
|
||||
composite_run_t c;
|
||||
|
||||
c.src=buf;
|
||||
if (fill_color[3]!=255)
|
||||
c.srca=abuf;
|
||||
else
|
||||
c.srca=NULL;
|
||||
c.dst=dst;
|
||||
if (wi->has_alpha)
|
||||
c.dsta=wi->alpha+x0+y0*wi->sx;
|
||||
else
|
||||
c.dsta=NULL;
|
||||
|
||||
{
|
||||
render_run_t ri;
|
||||
ri.dst=buf;
|
||||
ri.dsta=NULL;
|
||||
/* Note that we premultiply _here_ and set the alpha
|
||||
channel manually (for speed; no reason to do slow
|
||||
blending when we just want a straight blit of all
|
||||
channels). */
|
||||
ri.a=fill_color[3];
|
||||
ri.r=(fill_color[0]*ri.a+0xff)>>8;
|
||||
ri.g=(fill_color[1]*ri.a+0xff)>>8;
|
||||
ri.b=(fill_color[2]*ri.a+0xff)>>8;
|
||||
DI.render_run_opaque(&ri,x1);
|
||||
if (fill_color[3]!=255)
|
||||
memset(abuf,ri.a,x1);
|
||||
}
|
||||
|
||||
for (y=0;y<y1;y++,c.dst+=dbpl,c.dsta+=wi->sx)
|
||||
blit_func(&c,x1);
|
||||
return;
|
||||
}
|
||||
|
||||
NSLog(@"unimplemented compositerect: (%g %g)+(%g %g) op: %i",
|
||||
aRect.origin.x,aRect.origin.y,
|
||||
aRect.size.width,aRect.size.height,
|
||||
op);
|
||||
}
|
||||
|
||||
|
||||
/* TODO:
|
||||
optimize all this. passing device_color_t structures around by value is
|
||||
very expensive
|
||||
|
|
|
@ -41,7 +41,8 @@ SUBPROJECT_NAME=art
|
|||
art_OBJC_FILES = \
|
||||
ARTContext.m blit.m ftfont.m \
|
||||
ARTWindowBuffer.m \
|
||||
image.m
|
||||
image.m \
|
||||
composite.m
|
||||
|
||||
art_HEADER_FILES_DIR = ../../Headers/art
|
||||
art_HEADER_FILES_INSTALL_DIR = gnustep/art
|
||||
|
|
670
Source/art/composite.m
Normal file
670
Source/art/composite.m
Normal file
|
@ -0,0 +1,670 @@
|
|||
/*
|
||||
copyright 2002 Alexander Malmberg <alexander@malmberg.org>
|
||||
|
||||
This file is part of GNUstep.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <AppKit/NSAffineTransform.h>
|
||||
|
||||
#include "ARTGState.h"
|
||||
|
||||
#include "ARTWindowBuffer.h"
|
||||
#include "blit.h"
|
||||
|
||||
|
||||
@implementation ARTGState (composite)
|
||||
|
||||
/* Figure out what blit function we should use. If one or both of the
|
||||
windows are known to be totally opaque, we can optimize in many ways
|
||||
(see big table at the end of blit.m). Will set dst_need_alpha and blit_func
|
||||
if necessary. Returns new operation, or -1 it it's a noop. */
|
||||
-(int) _composite_func: (BOOL)src_opaque : (BOOL)src_transparent
|
||||
: (BOOL)dst_opaque : (BOOL *)dst_needs_alpha
|
||||
: (int)op : (void (**)(composite_run_t *c, int num))blit_func_r
|
||||
{
|
||||
void (*blit_func)(composite_run_t *c, int num);
|
||||
|
||||
*dst_needs_alpha = NO;
|
||||
*blit_func_r = blit_func = NULL;
|
||||
|
||||
if (src_transparent) /* only happens with compositerect */
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case NSCompositeCopy:
|
||||
case NSCompositeSourceIn:
|
||||
case NSCompositeSourceOut:
|
||||
case NSCompositeDestinationIn:
|
||||
case NSCompositeDestinationAtop:
|
||||
case NSCompositePlusDarker:
|
||||
return NSCompositeClear;
|
||||
|
||||
case NSCompositeSourceOver:
|
||||
case NSCompositeSourceAtop:
|
||||
case NSCompositeDestinationOver:
|
||||
case NSCompositeDestinationOut:
|
||||
case NSCompositeXOR:
|
||||
case NSCompositePlusLighter:
|
||||
return -1; /* noop */
|
||||
}
|
||||
}
|
||||
else
|
||||
if (src_opaque && dst_opaque)
|
||||
{ /* both source and destination are totally opaque */
|
||||
switch (op)
|
||||
{
|
||||
case NSCompositeSourceOver:
|
||||
case NSCompositeSourceIn:
|
||||
case NSCompositeSourceAtop:
|
||||
return NSCompositeCopy;
|
||||
|
||||
case NSCompositeSourceOut:
|
||||
case NSCompositeDestinationOut:
|
||||
case NSCompositeXOR:
|
||||
return NSCompositeClear;
|
||||
|
||||
case NSCompositeDestinationOver:
|
||||
case NSCompositeDestinationIn:
|
||||
case NSCompositeDestinationAtop:
|
||||
return -1; /* noop */
|
||||
|
||||
case NSCompositePlusLighter:
|
||||
blit_func = DI.composite_plusl_oo;
|
||||
break;
|
||||
case NSCompositePlusDarker:
|
||||
blit_func = DI.composite_plusd_oo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (src_opaque)
|
||||
{ /* source is opaque, destination has alpha */
|
||||
switch (op)
|
||||
{
|
||||
case NSCompositeSourceOver:
|
||||
return NSCompositeCopy;
|
||||
|
||||
case NSCompositeSourceIn:
|
||||
case NSCompositeSourceAtop:
|
||||
blit_func = DI.composite_sin_oa;
|
||||
break;
|
||||
|
||||
case NSCompositeSourceOut:
|
||||
case NSCompositeXOR:
|
||||
blit_func = DI.composite_sout_oa;
|
||||
break;
|
||||
|
||||
case NSCompositeDestinationOver:
|
||||
case NSCompositeDestinationAtop:
|
||||
blit_func = DI.composite_dover_oa;
|
||||
break;
|
||||
|
||||
case NSCompositeDestinationIn:
|
||||
return -1; /* noop */
|
||||
|
||||
case NSCompositeDestinationOut:
|
||||
return NSCompositeClear;
|
||||
|
||||
case NSCompositePlusLighter:
|
||||
blit_func = DI.composite_plusl_oa;
|
||||
break;
|
||||
case NSCompositePlusDarker:
|
||||
blit_func = DI.composite_plusd_oa;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (dst_opaque)
|
||||
{ /* source has alpha, destination is opaque */
|
||||
switch (op)
|
||||
{
|
||||
case NSCompositeSourceOver:
|
||||
case NSCompositeSourceAtop:
|
||||
blit_func = DI.composite_sover_ao;
|
||||
break;
|
||||
|
||||
case NSCompositeSourceIn:
|
||||
return NSCompositeCopy;
|
||||
|
||||
case NSCompositeSourceOut:
|
||||
return NSCompositeClear;
|
||||
|
||||
case NSCompositeDestinationOver:
|
||||
return -1; /* noop */
|
||||
|
||||
case NSCompositeDestinationIn:
|
||||
case NSCompositeDestinationOut:
|
||||
case NSCompositeDestinationAtop:
|
||||
case NSCompositeXOR:
|
||||
*dst_needs_alpha = YES;
|
||||
goto both_have_alpha;
|
||||
|
||||
case NSCompositePlusLighter:
|
||||
blit_func = DI.composite_plusl_ao;
|
||||
break;
|
||||
case NSCompositePlusDarker:
|
||||
blit_func = DI.composite_plusd_ao;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* both source and destination have alpha */
|
||||
both_have_alpha:
|
||||
switch (op)
|
||||
{
|
||||
case NSCompositeSourceOver:
|
||||
blit_func = DI.composite_sover_aa;
|
||||
break;
|
||||
case NSCompositeSourceIn:
|
||||
blit_func = DI.composite_sin_aa;
|
||||
break;
|
||||
case NSCompositeSourceOut:
|
||||
blit_func = DI.composite_sout_aa;
|
||||
break;
|
||||
case NSCompositeSourceAtop:
|
||||
blit_func = DI.composite_satop_aa;
|
||||
break;
|
||||
case NSCompositeDestinationOver:
|
||||
blit_func = DI.composite_dover_aa;
|
||||
break;
|
||||
case NSCompositeDestinationIn:
|
||||
blit_func = DI.composite_din_aa;
|
||||
break;
|
||||
case NSCompositeDestinationOut:
|
||||
blit_func = DI.composite_dout_aa;
|
||||
break;
|
||||
case NSCompositeDestinationAtop:
|
||||
blit_func = DI.composite_datop_aa;
|
||||
break;
|
||||
case NSCompositeXOR:
|
||||
blit_func = DI.composite_xor_aa;
|
||||
break;
|
||||
case NSCompositePlusLighter:
|
||||
blit_func = DI.composite_plusl_aa;
|
||||
break;
|
||||
case NSCompositePlusDarker:
|
||||
blit_func = DI.composite_plusd_aa;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*blit_func_r = blit_func;
|
||||
return op;
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (void) compositeGState: (GSGState *)source
|
||||
fromRect: (NSRect)aRect
|
||||
toPoint: (NSPoint)aPoint
|
||||
op: (NSCompositingOperation)op
|
||||
{
|
||||
ARTGState *ags = (ARTGState *)source;
|
||||
NSRect sr, dr;
|
||||
unsigned char *dst, *dst_alpha, *src, *src_alpha;
|
||||
|
||||
void (*blit_func)(composite_run_t *c, int num) = NULL;
|
||||
|
||||
int sx, sy;
|
||||
int x0, y0, x1, y1;
|
||||
|
||||
int sbpl, dbpl;
|
||||
int asbpl, adbpl;
|
||||
|
||||
/* 0 = top->down, 1 = bottom->up */
|
||||
/*
|
||||
TODO: this does not handle the horizontal case
|
||||
either 0=top->down, left->right, 2=top->down, right->left
|
||||
or keep 0 and add 2=top->down, make temporary copy of source
|
||||
could allocate a temporary array on the stack large enough to hold
|
||||
one row and do the operations on it
|
||||
*/
|
||||
/* currently 2=top->down, be careful with overlapping rows */
|
||||
/* order=1 is handled generically by flipping sbpl and dbpl and
|
||||
adjusting the pointers. only order=2 needs to be handled for
|
||||
each operator */
|
||||
int order;
|
||||
|
||||
|
||||
if (!wi || !wi->data || !ags->wi || !ags->wi->data) return;
|
||||
if (all_clipped) return;
|
||||
|
||||
|
||||
{
|
||||
BOOL dst_needs_alpha;
|
||||
op = [self _composite_func: !ags->wi->has_alpha : NO
|
||||
: !wi->has_alpha : &dst_needs_alpha
|
||||
: op : &blit_func];
|
||||
if (op == -1)
|
||||
return;
|
||||
|
||||
if (dst_needs_alpha)
|
||||
{
|
||||
[wi needsAlpha];
|
||||
if (!wi->has_alpha)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* these ignore the source window, so we send them off to
|
||||
compositerect: op: */
|
||||
if (op == NSCompositeClear || op == NSCompositeHighlight)
|
||||
{
|
||||
[self compositerect: NSMakeRect(aPoint.x, aPoint.y,
|
||||
aRect.size.width, aRect.size.height)
|
||||
op: op];
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Set up all the pointers and clip things */
|
||||
|
||||
dbpl = wi->bytes_per_line;
|
||||
sbpl = ags->wi->bytes_per_line;
|
||||
|
||||
sr = aRect;
|
||||
sr = [ags->ctm rectInMatrixSpace: sr];
|
||||
sr.origin.y = ags->wi->sy - sr.origin.y - sr.size.height;
|
||||
sx = sr.origin.x;
|
||||
sy = sr.origin.y;
|
||||
|
||||
dr = aRect;
|
||||
dr.origin = aPoint;
|
||||
dr = [ctm rectInMatrixSpace: dr];
|
||||
dr.origin.y = wi->sy - dr.origin.y - dr.size.height;
|
||||
|
||||
x0 = dr.origin.x;
|
||||
y0 = dr.origin.y;
|
||||
x1 = dr.origin.x + dr.size.width;
|
||||
y1 = dr.origin.y + dr.size.height;
|
||||
|
||||
if (clip_x0 > x0) /* TODO: ??? */
|
||||
{
|
||||
sx += clip_x0 - x0;
|
||||
x0 = clip_x0;
|
||||
}
|
||||
if (clip_y0 > y0)
|
||||
{
|
||||
sy += clip_y0 - y0;
|
||||
y0 = clip_y0;
|
||||
}
|
||||
|
||||
if (x1 > clip_x1)
|
||||
x1 = clip_x1;
|
||||
if (y1 > clip_y1)
|
||||
y1 = clip_y1;
|
||||
|
||||
if (x0 >= x1 || y0 >= y1) return;
|
||||
|
||||
/* TODO: clip source? how?
|
||||
we should at least clip the source to the source window to avoid
|
||||
crashes */
|
||||
|
||||
dst = wi->data + x0 * DI.bytes_per_pixel + y0 * dbpl;
|
||||
src = ags->wi->data + sx * DI.bytes_per_pixel + sy * sbpl;
|
||||
|
||||
if (ags->wi->has_alpha && op == NSCompositeCopy)
|
||||
{
|
||||
[wi needsAlpha];
|
||||
if (!wi->has_alpha)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ags->wi->has_alpha)
|
||||
{
|
||||
if (DI.inline_alpha)
|
||||
src_alpha = src;
|
||||
else
|
||||
src_alpha = ags->wi->alpha + sx + sy * ags->wi->sx;
|
||||
asbpl = ags->wi->sx;
|
||||
}
|
||||
else
|
||||
{
|
||||
src_alpha = NULL;
|
||||
asbpl = 0;
|
||||
}
|
||||
|
||||
if (wi->has_alpha)
|
||||
{
|
||||
if (DI.inline_alpha)
|
||||
dst_alpha = dst;
|
||||
else
|
||||
dst_alpha = wi->alpha + x0 + y0 * wi->sx;
|
||||
adbpl = wi->sx;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst_alpha = NULL;
|
||||
adbpl = 0;
|
||||
}
|
||||
|
||||
y1 -= y0;
|
||||
x1 -= x0;
|
||||
|
||||
/* To handle overlapping areas properly, we sometimes need to do
|
||||
things bottom-up instead of top-down. If so, we flip the
|
||||
coordinates here. */
|
||||
order = 0;
|
||||
if (ags == self && sy <= y0)
|
||||
{
|
||||
order = 1;
|
||||
dst += dbpl * (y1 - 1);
|
||||
src += sbpl * (y1 - 1);
|
||||
dst_alpha += adbpl * (y1 - 1);
|
||||
src_alpha += asbpl * (y1 - 1);
|
||||
dbpl = -dbpl;
|
||||
sbpl = -sbpl;
|
||||
adbpl = -adbpl;
|
||||
asbpl = -asbpl;
|
||||
if (sy == y0)
|
||||
{ /* TODO: pure horizontal, not handled properly in all
|
||||
cases */
|
||||
if ((sx >= x0 && sx <= x0 + x1) || (x0 >= sx && x0 <= x0 + x1))
|
||||
order = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (op == NSCompositeCopy)
|
||||
{ /* TODO: for inline alpha, make sure even opaque destinations have
|
||||
alpha properly filled in */
|
||||
int y;
|
||||
|
||||
if (!DI.inline_alpha && wi->has_alpha)
|
||||
{
|
||||
if (ags->wi->has_alpha)
|
||||
for (y = 0; y < y1; y++, dst_alpha += adbpl, src_alpha += asbpl)
|
||||
memmove(dst_alpha, src_alpha, x1);
|
||||
else
|
||||
for (y = 0; y < y1; y++, dst_alpha += adbpl)
|
||||
memset(dst_alpha, 0xff, x1);
|
||||
}
|
||||
|
||||
x1 *= DI.bytes_per_pixel;
|
||||
for (y = 0; y < y1; y++, dst += dbpl, src += sbpl)
|
||||
memmove(dst, src, x1);
|
||||
/* TODO: worth the complexity? */
|
||||
/* {
|
||||
int y;
|
||||
x1 *= DI.bytes_per_pixel;
|
||||
for (y = 0; y < y1; y++, dst += dbpl, src += sbpl)
|
||||
memcpy(dst, src, x1);
|
||||
}*/
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!blit_func)
|
||||
{
|
||||
NSLog(@"unimplemented: compositeGState: %p fromRect: (%g %g)+(%g %g) toPoint: (%g %g) op: %i",
|
||||
source,
|
||||
aRect.origin.x, aRect.origin.y,
|
||||
aRect.size.width, aRect.size.height,
|
||||
aPoint.x, aPoint.y,
|
||||
op);
|
||||
return;
|
||||
}
|
||||
|
||||
/* this breaks the alpha pointer in some, but that's ok since in
|
||||
all those cases, the alpha pointer isn't used (inline alpha or
|
||||
no alpha) */
|
||||
if (order == 2)
|
||||
{
|
||||
unsigned char tmpbuf[x1 * DI.bytes_per_pixel];
|
||||
int y;
|
||||
composite_run_t c;
|
||||
|
||||
c.dst = dst;
|
||||
c.dsta = dst_alpha;
|
||||
c.src = src;
|
||||
c.srca = src_alpha;
|
||||
for (y = 0; y < y1; y++, c.dst += dbpl, c.src += sbpl)
|
||||
{
|
||||
/* don't need to copy alpha since it is either
|
||||
separate and won't be written to or part of the
|
||||
data */
|
||||
/* TODO: this only holds if there's no destination
|
||||
alpha, which is no longer true. ignore for now; why
|
||||
would someone sourceover something on itself? */
|
||||
/* TODO: this looks broken. where is tmpbuf used? */
|
||||
memcpy(tmpbuf, src, x1 * DI.bytes_per_pixel);
|
||||
blit_func(&c, x1);
|
||||
c.srca += asbpl;
|
||||
c.dsta += adbpl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int y;
|
||||
composite_run_t c;
|
||||
|
||||
c.dst = dst;
|
||||
c.dsta = dst_alpha;
|
||||
c.src = src;
|
||||
c.srca = src_alpha;
|
||||
for (y = 0; y < y1; y++, c.dst += dbpl, c.src += sbpl)
|
||||
{
|
||||
blit_func(&c, x1);
|
||||
c.srca += asbpl;
|
||||
c.dsta += adbpl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) dissolveGState: (GSGState *)source
|
||||
fromRect: (NSRect)aRect
|
||||
toPoint: (NSPoint)aPoint
|
||||
delta: (float)delta
|
||||
{
|
||||
NSLog(@"ignoring dissolveGState: %08x fromRect: (%g %g)+(%g %g) toPoint: (%g %g) delta: %g",
|
||||
source,
|
||||
aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height,
|
||||
aPoint.x, aPoint.y, delta);
|
||||
}
|
||||
|
||||
- (void) compositerect: (NSRect)aRect
|
||||
op: (NSCompositingOperation)op
|
||||
{
|
||||
/* much setup code shared with compositeGState:... */
|
||||
NSRect dr;
|
||||
unsigned char *dst;
|
||||
|
||||
int x0, y0, x1, y1;
|
||||
|
||||
int dbpl;
|
||||
|
||||
void (*blit_func)(composite_run_t *c, int num);
|
||||
|
||||
if (!wi || !wi->data) return;
|
||||
if (all_clipped) return;
|
||||
|
||||
dbpl = wi->bytes_per_line;
|
||||
|
||||
dr = aRect;
|
||||
dr = [ctm rectInMatrixSpace: dr];
|
||||
dr.origin.y = wi->sy - dr.origin.y - dr.size.height;
|
||||
|
||||
x0 = dr.origin.x;
|
||||
y0 = dr.origin.y;
|
||||
x1 = dr.origin.x + dr.size.width;
|
||||
y1 = dr.origin.y + dr.size.height;
|
||||
|
||||
if (clip_x0 > x0)
|
||||
x0 = clip_x0;
|
||||
if (clip_y0 > y0)
|
||||
y0 = clip_y0;
|
||||
|
||||
if (x1 > clip_x1)
|
||||
x1 = clip_x1;
|
||||
if (y1 > clip_y1)
|
||||
y1 = clip_y1;
|
||||
|
||||
if (x0 >= x1 || y0 >= y1) return;
|
||||
|
||||
dst = wi->data + x0 * DI.bytes_per_pixel + y0 * dbpl;
|
||||
|
||||
y1 -= y0;
|
||||
x1 -= x0;
|
||||
|
||||
{
|
||||
BOOL dest_needs_alpha;
|
||||
|
||||
/* TODO: which color? using fill_color for now */
|
||||
op = [self _composite_func: fill_color[3] == 255 : fill_color[3] == 0
|
||||
: !wi->has_alpha : &dest_needs_alpha
|
||||
: op : &blit_func];
|
||||
|
||||
if (op == -1)
|
||||
return;
|
||||
|
||||
if (dest_needs_alpha)
|
||||
{
|
||||
[wi needsAlpha];
|
||||
if (!wi->has_alpha)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (op == NSCompositeClear)
|
||||
{
|
||||
int y;
|
||||
[wi needsAlpha];
|
||||
if (!wi->has_alpha)
|
||||
return;
|
||||
if (!DI.inline_alpha)
|
||||
{
|
||||
unsigned char *dsta;
|
||||
dsta = wi->alpha + x0 + y0 * wi->sx;
|
||||
for (y = 0; y < y1; y++, dsta += wi->sx)
|
||||
memset(dsta, 0, x1);
|
||||
}
|
||||
x1 *= DI.bytes_per_pixel;
|
||||
for (y = 0; y < y1; y++, dst += dbpl)
|
||||
memset(dst, 0, x1);
|
||||
return;
|
||||
}
|
||||
else if (op == NSCompositeHighlight)
|
||||
{
|
||||
int y, n;
|
||||
/* This must be reversible, which limits what we can
|
||||
do. */
|
||||
x1 *= DI.bytes_per_pixel;
|
||||
for (y = 0; y < y1; y++, dst += dbpl)
|
||||
{
|
||||
unsigned char *d = dst;
|
||||
for (n = x1; n; n--, d++)
|
||||
(*d) ^= 0xff;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (op == NSCompositeCopy)
|
||||
{
|
||||
render_run_t ri;
|
||||
int y;
|
||||
ri.dst = dst;
|
||||
/* We don't want to blend, so we premultiply and fill the
|
||||
alpha channel manually. */
|
||||
ri.a = fill_color[3];
|
||||
ri.r = (fill_color[0] * ri.a + 0xff) >> 8;
|
||||
ri.g = (fill_color[1] * ri.a + 0xff) >> 8;
|
||||
ri.b = (fill_color[2] * ri.a + 0xff) >> 8;
|
||||
for (y = 0; y < y1; y++, ri.dst += dbpl)
|
||||
DI.render_run_opaque(&ri, x1);
|
||||
|
||||
if (ri.a != 255)
|
||||
[wi needsAlpha];
|
||||
if (wi->has_alpha)
|
||||
{
|
||||
if (DI.inline_alpha)
|
||||
{
|
||||
int n;
|
||||
unsigned char *p;
|
||||
for (y = 0; y < y1; y++, dst += dbpl)
|
||||
{ /* TODO: needs to change to support inline
|
||||
alpha for non-32-bit modes */
|
||||
for (p = dst, n = x1; n; n--, p += 4)
|
||||
dst[DI.inline_alpha_ofs] = ri.a;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char *dsta;
|
||||
dsta = wi->alpha + x0 + y0 * wi->sx;
|
||||
for (y = 0; y < y1; y++, dsta += wi->sx)
|
||||
memset(dsta, ri.a, x1);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (blit_func)
|
||||
{
|
||||
/* this is slightly ugly, but efficient */
|
||||
unsigned char buf[DI.bytes_per_pixel * x1];
|
||||
unsigned char abuf[fill_color[3] == 255? 1 : x1];
|
||||
int y;
|
||||
composite_run_t c;
|
||||
|
||||
c.src = buf;
|
||||
if (fill_color[3] != 255)
|
||||
c.srca = abuf;
|
||||
else
|
||||
c.srca = NULL;
|
||||
c.dst = dst;
|
||||
if (wi->has_alpha)
|
||||
c.dsta = wi->alpha + x0 + y0 * wi->sx;
|
||||
else
|
||||
c.dsta = NULL;
|
||||
|
||||
{
|
||||
render_run_t ri;
|
||||
ri.dst = buf;
|
||||
ri.dsta = NULL;
|
||||
/* Note that we premultiply _here_ and set the alpha
|
||||
channel manually (for speed; no reason to do slow
|
||||
blending when we just want a straight blit of all
|
||||
channels). */
|
||||
ri.a = fill_color[3];
|
||||
ri.r = (fill_color[0] * ri.a + 0xff) >> 8;
|
||||
ri.g = (fill_color[1] * ri.a + 0xff) >> 8;
|
||||
ri.b = (fill_color[2] * ri.a + 0xff) >> 8;
|
||||
DI.render_run_opaque(&ri, x1);
|
||||
if (fill_color[3] != 255)
|
||||
{
|
||||
if (DI.inline_alpha)
|
||||
{
|
||||
int i;
|
||||
unsigned char *s;
|
||||
/* TODO: needs to change to support inline
|
||||
alpha for non-32-bit modes */
|
||||
for (i = 0, s = buf + DI.inline_alpha_ofs; i < x1; i++, s += 4)
|
||||
*s = ri.a;
|
||||
}
|
||||
else
|
||||
memset(abuf, ri.a, x1);
|
||||
}
|
||||
}
|
||||
|
||||
for (y = 0; y < y1; y++, c.dst += dbpl, c.dsta += wi->sx)
|
||||
blit_func(&c, x1);
|
||||
return;
|
||||
}
|
||||
|
||||
NSLog(@"unimplemented compositerect: (%g %g)+(%g %g) op: %i",
|
||||
aRect.origin.x, aRect.origin.y,
|
||||
aRect.size.width, aRect.size.height,
|
||||
op);
|
||||
}
|
||||
|
||||
@end
|
||||
|
Loading…
Reference in a new issue