libs-back/Source/art/composite.m
Richard Frith-Macdonald 08c5a3d3d0 Coding style fixups
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@22020 72102866-910b-0410-8b05-ffd578937521
2005-11-16 11:40:31 +00:00

1489 lines
33 KiB
Objective-C

/*
Copyright (C) 2002 Free Software Foundation, Inc.
Author: 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 <math.h>
#include <AppKit/NSAffineTransform.h>
#include "ARTGState.h"
#ifndef RDS
#include "x11/XWindowBuffer.h"
#endif
#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 NSCompositeCopy:
*dst_needs_alpha = YES;
break;
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;
}
static void copy_oo(composite_run_t *c, int num)
{
memcpy(c->dst,c->src,num*DI.bytes_per_pixel);
}
static void copy_oa(composite_run_t *c, int num)
{
memcpy(c->dst,c->src,num*DI.bytes_per_pixel);
if (DI.inline_alpha)
{
unsigned char *dsta=c->dst+DI.inline_alpha_ofs;
for (;num;num--,dsta+=4)
*dsta=0xff;
}
else
memset(c->dsta,0xff,num);
}
static void copy_aa(composite_run_t *c, int num)
{
memcpy(c->dst,c->src,num*DI.bytes_per_pixel);
if (!DI.inline_alpha)
memcpy(c->dsta,c->srca,num);
}
/*
Handle compositing in transformed coordinate spaces. _rect_setup sets up
the a rect_trace_t structure, and each call to _rect_advance returns YES
and the left and right points on the next row, or NO if all rows are done.
*/
typedef struct
{
int x[4], y[4];
int cy, ey;
int left_delta;
int lx, lx_frac, ldx, ldx_frac, l_de, le;
int rx, rx_frac, rdx, rdx_frac, r_de, re;
int cx0, cx1;
} rect_trace_t;
static void _rect_setup(rect_trace_t *t, NSRect r, int cx0, int cx1,
NSAffineTransform *ctm, int up, int *y0, int wi_sy)
{
float fx[4], fy[4];
NSPoint p;
t->cx0 = cx0;
t->cx1 = cx1;
p = r.origin;
p = [ctm pointInMatrixSpace: p];
fx[0] = p.x; fy[0] = p.y;
p = r.origin; p.x += r.size.width;
p = [ctm pointInMatrixSpace: p];
fx[1] = p.x; fy[1] = p.y;
p = r.origin; p.x += r.size.width; p.y += r.size.height;
p = [ctm pointInMatrixSpace: p];
fx[2] = p.x; fy[2] = p.y;
p = r.origin; p.y += r.size.height;
p = [ctm pointInMatrixSpace: p];
fx[3] = p.x; fy[3] = p.y;
if (fabs(fx[0] - floor(fx[0] + .5)) < 0.001) fx[0] = floor(fx[0] + .5);
if (fabs(fx[1] - floor(fx[1] + .5)) < 0.001) fx[1] = floor(fx[1] + .5);
if (fabs(fx[2] - floor(fx[2] + .5)) < 0.001) fx[2] = floor(fx[2] + .5);
if (fabs(fx[3] - floor(fx[3] + .5)) < 0.001) fx[3] = floor(fx[3] + .5);
if (fabs(fy[0] - floor(fy[0] + .5)) < 0.001) fy[0] = floor(fy[0] + .5);
if (fabs(fy[1] - floor(fy[1] + .5)) < 0.001) fy[1] = floor(fy[1] + .5);
if (fabs(fy[2] - floor(fy[2] + .5)) < 0.001) fy[2] = floor(fy[2] + .5);
if (fabs(fy[3] - floor(fy[3] + .5)) < 0.001) fy[3] = floor(fy[3] + .5);
t->x[0] = floor(fx[0]); t->y[0] = wi_sy - floor(fy[0]);
t->x[1] = floor(fx[1]); t->y[1] = wi_sy - floor(fy[1]);
t->x[2] = floor(fx[2]); t->y[2] = wi_sy - floor(fy[2]);
t->x[3] = floor(fx[3]); t->y[3] = wi_sy - floor(fy[3]);
/* If we're tracing the 'other way', we just flip the y-coordinates
and unflip when returning them */
if (up)
{
t->y[0] = -t->y[0];
t->y[1] = -t->y[1];
t->y[2] = -t->y[2];
t->y[3] = -t->y[3];
}
t->cy = t->y[t->le = 0];
if (t->y[1] < t->cy) t->cy = t->y[t->le = 1];
if (t->y[2] < t->cy) t->cy = t->y[t->le = 2];
if (t->y[3] < t->cy) t->cy = t->y[t->le = 3];
t->re = t->le;
t->ey = t->y[0];
if (t->y[1] > t->ey) t->ey = t->y[1];
if (t->y[2] > t->ey) t->ey = t->y[2];
if (t->y[3] > t->ey) t->ey = t->y[3];
if (t->x[(t->le + 1) & 3] < t->x[(t->le - 1) & 3])
t->left_delta = 1;
else
t->left_delta = -1;
/* silence the compiler */
t->lx = t->lx_frac = t->ldx = t->ldx_frac = t->l_de = 0;
t->rx = t->rx_frac = t->rdx = t->rdx_frac = t->r_de = 0;
if (up)
*y0 = -t->cy;
else
*y0 = t->cy;
}
static BOOL _rect_advance(rect_trace_t *t, int *x0, int *x1)
{
int next;
if (t->cy > t->ey)
return NO;
if (t->cy == t->y[t->le])
{
next = (t->le + t->left_delta) & 3;
if (t->y[t->le] == t->y[next])
{
t->le = next;
next = (t->le + t->left_delta) & 3;
}
t->l_de = t->y[next] - t->y[t->le];
if (!t->l_de)
return NO;
t->lx = t->x[t->le];
t->lx_frac = 0;
t->ldx = (t->x[next] - t->x[t->le]) / t->l_de;
t->ldx_frac = (t->x[next] - t->x[t->le]) % t->l_de;
t->le = next;
}
else
{
t->lx += t->ldx;
t->lx_frac += t->ldx_frac;
if (t->lx_frac < 0)
t->lx--, t->lx_frac += t->l_de;
if (t->lx_frac > t->l_de)
t->lx++, t->lx_frac -= t->l_de;
}
if (t->cy == t->y[t->re])
{
next = (t->re - t->left_delta) & 3;
if (t->y[t->re] == t->y[next])
{
t->re = next;
next = (t->re - t->left_delta) & 3;
}
t->r_de = t->y[next] - t->y[t->re];
if (!t->r_de)
return NO;
t->rx = t->x[t->re];
t->rx_frac = t->r_de - 1; /* TODO? */
t->rdx = (t->x[next] - t->x[t->re]) / t->r_de;
t->rdx_frac = (t->x[next] - t->x[t->re]) % t->r_de;
t->re = next;
}
else
{
t->rx += t->rdx;
t->rx_frac += t->rdx_frac;
if (t->rx_frac < 0)
t->rx--, t->rx_frac += t->r_de;
if (t->rx_frac > t->r_de)
t->rx++, t->rx_frac -= t->r_de;
}
if (t->rx > t->lx && t->rx >= t->cx0 && t->lx < t->cx1)
{
*x0 = t->lx - t->cx0;
if (*x0 < 0)
*x0 = 0;
*x1 = t->rx - t->cx0;
if (*x1 > t->cx1 - t->cx0)
*x1 = t->cx1 - t->cx0;
}
else
{
*x0 = *x1 = 0;
}
t->cy++;
return YES;
}
- (void) compositeGState: (GSGState *)source
fromRect: (NSRect)aRect
toPoint: (NSPoint)aPoint
op: (NSCompositingOperation)composite_op
{
ARTGState *ags = (ARTGState *)source;
unsigned char *dst, *dst_alpha, *src, *src_alpha;
int op;
void (*blit_func)(composite_run_t *c, int num) = NULL;
NSPoint sp, dp;
int cx0,cy0,cx1,cy1;
int sx0,sy0;
int sbpl, dbpl;
int asbpl, adbpl;
rect_trace_t state;
/* 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. order=2 is handled specially */
int order;
int delta;
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
: composite_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;
cx0 = clip_x0;
cy0 = clip_y0;
cx1 = clip_x1;
cy1 = clip_y1;
sp = [ags->ctm pointInMatrixSpace: aRect.origin];
sp.x = floor(sp.x);
sp.y = floor(ags->wi->sy - sp.y);
dp = [ctm pointInMatrixSpace: aPoint];
dp.x = floor(dp.x);
dp.y = floor(wi->sy - dp.y);
if (dp.x - cx0 > sp.x)
cx0 = dp.x - sp.x;
if (dp.y - cy0 > sp.y)
cy0 = dp.y - sp.y;
if (cx1 - dp.x > ags->wi->sx - sp.x)
cx1 = dp.x + ags->wi->sx - sp.x;
if (cy1 - dp.y > ags->wi->sy - sp.y)
cy1 = dp.y + ags->wi->sy - sp.y;
sx0 = sp.x - dp.x + cx0;
sy0 = sp.y - dp.y + cy0;
dst = wi->data + cx0 * DI.bytes_per_pixel + cy0 * dbpl;
src = ags->wi->data + sx0 * DI.bytes_per_pixel + sy0 * 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 + sx0 + sy0 * 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 + cx0 + cy0 * wi->sx;
adbpl = wi->sx;
}
else
{
dst_alpha = NULL;
adbpl = 0;
}
cy1 -= cy0;
cx1 -= cx0;
if (cx0<0 || cy0<0 || cx0+cx1>wi->sx || cy0+cy1>wi->sy ||
sx0<0 || sy0<0 || sx0+cx1>ags->wi->sx || sy0+cy1>ags->wi->sy)
{
NSLog(@"Warning: invalid coordinates in composite: (%g %g)+(%g %g) -> (%g %g) got (%i %i) (%i %i) +(%i %i)",
aRect.origin.x,aRect.origin.x,aRect.size.width,aRect.size.height,aPoint.x,aPoint.y,
cx0,cy0,sx0,sy0,cx1,cy1);
return;
}
if (cx1<=0 || cy1<=0)
return;
/* 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->wi == self->wi && sy0 <= cy0)
{
order = 1;
dst += dbpl * (cy1 - 1);
src += sbpl * (cy1 - 1);
dst_alpha += adbpl * (cy1 - 1);
src_alpha += asbpl * (cy1 - 1);
dbpl = -dbpl;
sbpl = -sbpl;
adbpl = -adbpl;
asbpl = -asbpl;
if (sy0 == cy0)
{
if ((sx0 >= cx0 && sx0 <= cx0 + cx1) || (cx0 >= sx0 && cx0 <= sx0 + cx1))
{
order = 2;
}
}
}
if (op == NSCompositeCopy)
{
if (ags->wi->has_alpha)
blit_func = copy_aa;
else if (wi->has_alpha)
blit_func = copy_oa;
else
blit_func = copy_oo;
}
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;
}
{
int ry;
int x0, x1;
_rect_setup(&state, aRect, sx0, sx0 + cx1, ags->ctm, order, &ry, ags->wi->sy);
if (order)
{
if (ry < sy0)
return;
delta = sy0 + cy1 - ry;
}
else
{
if (ry >= sy0 + cy1)
return;
delta = ry - sy0;
}
if (delta > 0)
{
src += sbpl * delta;
src_alpha += asbpl * delta;
dst += dbpl * delta;
dst_alpha += adbpl * delta;
}
else if (delta < 0)
{
delta = -delta;
while (delta)
{
if (!_rect_advance(&state,&x0,&x1))
{
break;
}
delta--;
}
if (delta)
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[cx1 * DI.bytes_per_pixel];
unsigned char tmpbufa[cx1];
int y;
composite_run_t c;
int x0, x1;
c.dst = dst;
c.dsta = dst_alpha;
c.src = tmpbuf;
c.srca = tmpbufa;
for (y = cy1 - delta - 1; y >= 0; y--)
{
if (!_rect_advance(&state,&x0,&x1))
break;
x1 -= x0;
c.dst += x0 * DI.bytes_per_pixel;
c.dsta += x0;
/* TODO: update c.dst and c.dsta properly when x1==0 */
if (x1)
{
memcpy(tmpbuf, src + x0 * DI.bytes_per_pixel, x1 * DI.bytes_per_pixel);
if (ags->wi->has_alpha && !DI.inline_alpha)
memcpy(tmpbufa, src_alpha + x0, x1);
if (!clip_span)
{
blit_func(&c, x1);
c.dst += dbpl - x0 * DI.bytes_per_pixel;
c.dsta += adbpl - x0;
}
else
{
unsigned int *span, *end;
BOOL state = NO;
span = &clip_span[clip_index[y + cy0 - clip_y0]];
end = &clip_span[clip_index[y + cy0 - clip_y0 + 1]];
x0 = x0 + cx0 - clip_x0;
x1 += x0;
while (span != end && *span < x0)
{
state = !state;
span++;
if (span == end)
break;
}
if (span != end)
{
while (span != end && *span < x1)
{
if (state)
blit_func(&c, *span - x0);
c.dst += (*span - x0) * DI.bytes_per_pixel;
c.dsta += (*span - x0);
c.src += (*span - x0) * DI.bytes_per_pixel;
c.srca += (*span - x0);
x0 = *span;
state = !state;
span++;
if (span == end)
break;
}
if (state)
blit_func(&c, x1 - x0);
}
x0 = x0 - cx0 + clip_x0;
c.dst += dbpl - x0 * DI.bytes_per_pixel;
c.dsta += adbpl - x0;
c.src = tmpbuf;
c.srca = tmpbufa;
}
}
src += sbpl;
src_alpha += asbpl;
}
}
else
{
int y;
composite_run_t c;
int x0, x1;
c.dst = dst;
c.dsta = dst_alpha;
c.src = src;
c.srca = src_alpha;
if (order)
y = cy1 - delta - 1;
else
y = delta;
for (; y < cy1 && y >= 0; order? y-- : y++)
{
if (!_rect_advance(&state,&x0,&x1))
break;
x1 -= x0;
if (x1 <= 0)
{
c.dst += dbpl;
c.dsta += adbpl;
c.src += sbpl;
c.srca += asbpl;
continue;
}
c.dst += x0 * DI.bytes_per_pixel;
c.dsta += x0;
c.src += x0 * DI.bytes_per_pixel;
c.srca += x0;
if (!clip_span)
{
blit_func(&c, x1);
c.dst += dbpl - x0 * DI.bytes_per_pixel;
c.dsta += adbpl - x0;
c.src += sbpl - x0 * DI.bytes_per_pixel;
c.srca += asbpl - x0;
}
else
{
unsigned int *span, *end;
BOOL state = NO;
span = &clip_span[clip_index[y + cy0 - clip_y0]];
end = &clip_span[clip_index[y + cy0 - clip_y0 + 1]];
x0 = x0 + cx0 - clip_x0;
x1 += x0;
while (span != end && *span < x0)
{
state = !state;
span++;
if (span == end)
break;
}
if (span != end)
{
while (span != end && *span < x1)
{
if (state)
blit_func(&c, *span - x0);
c.dst += (*span - x0) * DI.bytes_per_pixel;
c.dsta += (*span - x0);
c.src += (*span - x0) * DI.bytes_per_pixel;
c.srca += (*span - x0);
x0 = *span;
state = !state;
span++;
if (span == end)
break;
}
if (state)
blit_func(&c, x1 - x0);
}
x0 = x0 - cx0 + clip_x0;
c.dst += dbpl - x0 * DI.bytes_per_pixel;
c.dsta += adbpl - x0;
c.src += sbpl - x0 * DI.bytes_per_pixel;
c.srca += asbpl - x0;
}
}
}
UPDATE_UNBUFFERED
}
- (void) dissolveGState: (GSGState *)source
fromRect: (NSRect)aRect
toPoint: (NSPoint)aPoint
delta: (float)fraction
{
/* much setup code shared with compositeGState:... */
ARTGState *ags = (ARTGState *)source;
unsigned char *dst, *dst_alpha, *src, *src_alpha;
void (*blit_func)(composite_run_t *c, int num) = NULL;
NSPoint sp, dp;
int cx0,cy0,cx1,cy1;
int sx0,sy0;
int sbpl, dbpl;
int asbpl, adbpl;
rect_trace_t state;
/* 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. order=2 is handled specially */
int order;
int delta;
if (!wi || !wi->data || !ags->wi || !ags->wi->data) return;
if (all_clipped) return;
/* Set up all the pointers and clip things */
dbpl = wi->bytes_per_line;
sbpl = ags->wi->bytes_per_line;
cx0 = clip_x0;
cy0 = clip_y0;
cx1 = clip_x1;
cy1 = clip_y1;
sp = [ags->ctm pointInMatrixSpace: aRect.origin];
sp.x = floor(sp.x);
sp.y = floor(ags->wi->sy - sp.y);
dp = [ctm pointInMatrixSpace: aPoint];
dp.x = floor(dp.x);
dp.y = floor(wi->sy - dp.y);
if (dp.x - cx0 > sp.x)
cx0 = dp.x - sp.x;
if (dp.y - cy0 > sp.y)
cy0 = dp.y - sp.y;
if (cx1 - dp.x > ags->wi->sx - sp.x)
cx1 = dp.x + ags->wi->sx - sp.x;
if (cy1 - dp.y > ags->wi->sy - sp.y)
cy1 = dp.y + ags->wi->sy - sp.y;
sx0 = sp.x - dp.x + cx0;
sy0 = sp.y - dp.y + cy0;
dst = wi->data + cx0 * DI.bytes_per_pixel + cy0 * dbpl;
src = ags->wi->data + sx0 * DI.bytes_per_pixel + sy0 * sbpl;
if (ags->wi->has_alpha)
{
if (DI.inline_alpha)
src_alpha = src;
else
src_alpha = ags->wi->alpha + sx0 + sy0 * 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 + cx0 + cy0 * wi->sx;
adbpl = wi->sx;
}
else
{
dst_alpha = NULL;
adbpl = 0;
}
cy1 -= cy0;
cx1 -= cx0;
if (cx0<0 || cy0<0 || cx0+cx1>wi->sx || cy0+cy1>wi->sy ||
sx0<0 || sy0<0 || sx0+cx1>ags->wi->sx || sy0+cy1>ags->wi->sy)
{
NSLog(@"Warning: invalid coordinates in dissolve: (%g %g)+(%g %g) -> (%g %g) got (%i %i) (%i %i) +(%i %i)",
aRect.origin.x,aRect.origin.x,aRect.size.width,aRect.size.height,aPoint.x,aPoint.y,
cx0,cy0,sx0,sy0,cx1,cy1);
return;
}
if (cx1<=0 || cy1<=0)
return;
/* 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->wi == self->wi && sy0 <= cy0)
{
order = 1;
dst += dbpl * (cy1 - 1);
src += sbpl * (cy1 - 1);
dst_alpha += adbpl * (cy1 - 1);
src_alpha += asbpl * (cy1 - 1);
dbpl = -dbpl;
sbpl = -sbpl;
adbpl = -adbpl;
asbpl = -asbpl;
if (sy0 == cy0)
{
if ((sx0 >= cx0 && sx0 <= cx0 + cx1) || (cx0 >= sx0 && cx0 <= sx0 + cx1))
{
order = 2;
}
}
}
if (ags->wi->has_alpha && wi->has_alpha)
blit_func = DI.dissolve_aa;
else if (wi->has_alpha)
blit_func = DI.dissolve_oa;
else if (ags->wi->has_alpha)
blit_func = DI.dissolve_ao;
else
blit_func = DI.dissolve_oo;
if (!blit_func)
{
NSLog(@"unimplemented: dissolveGState: %p 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,
fraction);
return;
}
{
int ry;
int x0, x1;
_rect_setup(&state, aRect, sx0, sx0 + cx1, ags->ctm, order, &ry, ags->wi->sy);
if (order)
{
if (ry < sy0)
return;
delta = sy0 + cy1 - ry;
}
else
{
if (ry >= sy0 + cy1)
return;
delta = ry - sy0;
}
if (delta > 0)
{
src += sbpl * delta;
src_alpha += asbpl * delta;
dst += dbpl * delta;
dst_alpha += adbpl * delta;
}
else if (delta < 0)
{
delta = -delta;
while (delta)
{
if (!_rect_advance(&state,&x0,&x1))
{
break;
}
delta--;
}
if (delta)
return;
}
}
/* this breaks the alpha pointer in some cases, 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[cx1 * DI.bytes_per_pixel];
unsigned char tmpbufa[cx1];
int y;
composite_run_t c;
int x0, x1;
c.dst = dst;
c.dsta = dst_alpha;
c.src = tmpbuf;
c.srca = tmpbufa;
c.fraction = fraction * 255;
for (y = cy1 - delta - 1; y >= 0; y--)
{
if (!_rect_advance(&state,&x0,&x1))
break;
x1 -= x0;
c.dst += x0 * DI.bytes_per_pixel;
c.dsta += x0;
if (x1)
{
memcpy(tmpbuf, src + x0 * DI.bytes_per_pixel, x1 * DI.bytes_per_pixel);
if (ags->wi->has_alpha && !DI.inline_alpha)
memcpy(tmpbufa, src_alpha + x0, x1);
if (!clip_span)
{
blit_func(&c, x1);
c.dst += dbpl - x0 * DI.bytes_per_pixel;
c.dsta += adbpl - x0;
}
else
{
unsigned int *span, *end;
BOOL state = NO;
span = &clip_span[clip_index[y + cy0 - clip_y0]];
end = &clip_span[clip_index[y + cy0 - clip_y0 + 1]];
x0 = x0 + cx0 - clip_x0;
x1 += x0;
while (span != end && *span < x0)
{
state = !state;
span++;
if (span == end)
break;
}
if (span != end)
{
while (span != end && *span < x1)
{
if (state)
blit_func(&c, *span - x0);
c.dst += (*span - x0) * DI.bytes_per_pixel;
c.dsta += (*span - x0);
c.src += (*span - x0) * DI.bytes_per_pixel;
c.srca += (*span - x0);
x0 = *span;
state = !state;
span++;
if (span == end)
break;
}
if (state)
blit_func(&c, x1 - x0);
}
x0 = x0 - cx0 + clip_x0;
c.dst += dbpl - x0 * DI.bytes_per_pixel;
c.dsta += adbpl - x0;
c.src = tmpbuf;
c.srca = tmpbufa;
}
}
src += sbpl;
src_alpha += asbpl;
}
}
else
{
int y;
composite_run_t c;
int x0, x1;
c.dst = dst;
c.dsta = dst_alpha;
c.src = src;
c.srca = src_alpha;
c.fraction = fraction * 255;
if (order)
y = cy1 - delta - 1;
else
y = delta;
for (; y < cy1 && y >= 0; order? y-- : y++)
{
if (!_rect_advance(&state,&x0,&x1))
break;
x1 -= x0;
if (x1 <= 0)
{
c.dst += dbpl;
c.dsta += adbpl;
c.src += sbpl;
c.srca += asbpl;
continue;
}
c.dst += x0 * DI.bytes_per_pixel;
c.dsta += x0;
c.src += x0 * DI.bytes_per_pixel;
c.srca += x0;
if (!clip_span)
{
blit_func(&c, x1);
c.dst += dbpl - x0 * DI.bytes_per_pixel;
c.dsta += adbpl - x0;
c.src += sbpl - x0 * DI.bytes_per_pixel;
c.srca += asbpl - x0;
}
else
{
unsigned int *span, *end;
BOOL state = NO;
span = &clip_span[clip_index[y + cy0 - clip_y0]];
end = &clip_span[clip_index[y + cy0 - clip_y0 + 1]];
x0 = x0 + cx0 - clip_x0;
x1 += x0;
while (span != end && *span < x0)
{
state = !state;
span++;
if (span == end)
break;
}
if (span != end)
{
while (span != end && *span < x1)
{
if (state)
blit_func(&c, *span - x0);
c.dst += (*span - x0) * DI.bytes_per_pixel;
c.dsta += (*span - x0);
c.src += (*span - x0) * DI.bytes_per_pixel;
c.srca += (*span - x0);
x0 = *span;
state = !state;
span++;
if (span == end)
break;
}
if (state)
blit_func(&c, x1 - x0);
}
x0 = x0 - cx0 + clip_x0;
c.dst += dbpl - x0 * DI.bytes_per_pixel;
c.dsta += adbpl - x0;
c.src += sbpl - x0 * DI.bytes_per_pixel;
c.srca += asbpl - x0;
}
}
}
UPDATE_UNBUFFERED
}
- (void) compositerect: (NSRect)aRect
op: (NSCompositingOperation)op
{
/* much setup code shared with compositeGState:... */
unsigned char *dst, *dst_alpha;
int dbpl, adbpl;
int cx0, cy0, cx1, cy1;
void (*blit_func)(composite_run_t *c, int num);
rect_trace_t state;
int delta;
if (!wi || !wi->data) return;
if (all_clipped) return;
{
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 || op == NSCompositeClear)
{
[wi needsAlpha];
if (!wi->has_alpha)
return;
}
}
dbpl = wi->bytes_per_line;
adbpl = wi->sx;
cx0 = clip_x0; cy0 = clip_y0;
cx1 = clip_x1; cy1 = clip_y1;
dst = wi->data + cx0 * DI.bytes_per_pixel + cy0 * dbpl;
dst_alpha = wi->alpha + cx0 + cy0 * wi->sx;
cx1 -= cx0;
cy1 -= cy0;
{
int ry;
int x0, x1;
_rect_setup(&state, aRect, cx0, cx0 + cx1, ctm, 0, &ry, wi->sy);
if (ry >= cy0 + cy1)
return;
delta = ry - cy0;
if (delta > 0)
{
dst += dbpl * delta;
dst_alpha += adbpl * delta;
}
else if (delta < 0)
{
delta = -delta;
while (delta)
{
if (!_rect_advance(&state,&x0,&x1))
break;
delta--;
}
if (delta)
return;
}
}
#define DO_STUFF(HANDLE_SPAN) \
{ \
int y; \
int x0, x1; \
int n; \
\
if (clip_span) \
{ \
for (y = delta; y < cy1; y++) \
{ \
unsigned int *span, *end; \
BOOL clip_state = NO; \
\
if (!_rect_advance(&state,&x0,&x1)) \
break; \
\
x1 -= x0; \
if (!x1) \
{ \
dst += dbpl; \
dst_alpha += adbpl; \
continue; \
} \
\
dst += x0 * DI.bytes_per_pixel; \
dst_alpha += x0; \
\
span = &clip_span[clip_index[y + cy0 - clip_y0]]; \
end = &clip_span[clip_index[y + cy0 - clip_y0 + 1]]; \
\
x0 = x0 + cx0 - clip_x0; \
x1 += x0; \
while (span != end && *span < x0) \
{ \
clip_state = !clip_state; \
span++; \
if (span == end) \
break; \
} \
if (span != end) \
{ \
while (span != end && *span < x1) \
{ \
if (clip_state) \
{ \
n = (*span - x0); \
HANDLE_SPAN \
} \
dst += (*span - x0) * DI.bytes_per_pixel; \
dst_alpha += (*span - x0); \
x0 = *span; \
\
clip_state = !clip_state; \
span++; \
if (span == end) \
break; \
} \
if (clip_state) \
{ \
n = x1 - x0; \
HANDLE_SPAN \
} \
} \
x0 = x0 - cx0 + clip_x0; \
\
dst += dbpl - x0 * DI.bytes_per_pixel; \
dst_alpha += adbpl - x0; \
} \
} \
else \
{ \
for (y = delta; y < cy1; y++) \
{ \
if (!_rect_advance(&state,&x0,&x1)) \
break; \
\
x1 -= x0; \
if (!x1) \
{ \
dst += dbpl; \
dst_alpha += adbpl; \
continue; \
} \
\
dst += x0 * DI.bytes_per_pixel; \
dst_alpha += x0; \
\
n = x1; \
HANDLE_SPAN \
\
dst += dbpl - x0 * DI.bytes_per_pixel; \
dst_alpha += adbpl - x0; \
} \
} \
}
if (op == NSCompositeClear)
{
DO_STUFF(
memset(dst, 0, n * DI.bytes_per_pixel);
if (!DI.inline_alpha)
memset(dst_alpha, 0, n);
)
}
else if (op == NSCompositeHighlight)
{
DO_STUFF(
{
unsigned char *d = dst;
n *= DI.bytes_per_pixel;
for (; n; n--, d++)
(*d) ^= 0xff;
}
)
}
else if (op == NSCompositeCopy)
{
render_run_t ri;
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;
if (ri.a != 255 && !wi->has_alpha)
return;
DO_STUFF(
ri.dst = dst;
DI.render_run_opaque(&ri, n);
if (ri.a != 255)
{
if (DI.inline_alpha)
{
/* TODO: needs to change to support inline
alpha for non-32-bit modes */
unsigned char *p;
for (p = dst; n; n--, p += 4)
p[DI.inline_alpha_ofs] = ri.a;
}
else
{
memset(dst_alpha, ri.a, n);
}
}
)
}
else if (blit_func)
{
/* this is slightly ugly, but efficient */
unsigned char buf[DI.bytes_per_pixel * cx1];
unsigned char abuf[fill_color[3] == 255? 1 : cx1];
composite_run_t c;
c.src = buf;
if (fill_color[3] != 255)
c.srca = abuf;
else
c.srca = 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, cx1);
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 < cx1; i++, s += 4)
*s = ri.a;
}
else
memset(abuf, ri.a, cx1);
}
}
DO_STUFF(
c.dst = dst;
c.dsta = dst_alpha;
blit_func(&c, n);
)
}
else
{
NSLog(@"unimplemented compositerect: (%g %g)+(%g %g) op: %i",
aRect.origin.x, aRect.origin.y,
aRect.size.width, aRect.size.height,
op);
}
UPDATE_UNBUFFERED
}
@end