mirror of
https://github.com/gnustep/libs-back.git
synced 2025-02-23 11:51:27 +00:00
Implement proper handling of clipping paths.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@14318 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
ec1da56cfb
commit
deb3553fde
2 changed files with 293 additions and 110 deletions
|
@ -1,3 +1,9 @@
|
|||
2002-08-23 01:44 Alexander Malmberg <alexander@malmberg.org>
|
||||
|
||||
* Source/art/ARTContext.m: Implement handling of non-rectangle
|
||||
clipping paths. Use it when rendering paths (but not for other
|
||||
operators yet).
|
||||
|
||||
2002-08-22 02:34 Alexander Malmberg <alexander@malmberg.org>
|
||||
|
||||
* Source/art/ARTContext.m: (-DPSrectclip::::): Fix rounding when
|
||||
|
|
|
@ -68,9 +68,6 @@ of crashing, they just print a warning.
|
|||
- (void) DPSwidthshow: (float)x : (float)y : (int)c : (const char*)s
|
||||
DPSxshow, DPSyshow, DPSxyshow
|
||||
|
||||
- (void) DPSclip
|
||||
- (void) DPSeoclip
|
||||
|
||||
|
||||
** Other unimplemented stuff **
|
||||
|
||||
|
@ -132,6 +129,8 @@ static draw_info_t DI;
|
|||
BOOL all_clipped;
|
||||
#define CLIP_DATA (wi->data+clip_x0*wi->bytes_per_pixel+clip_y0*wi->bytes_per_line)
|
||||
int clip_sx,clip_sy;
|
||||
|
||||
ArtSVP *clip_path;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -538,7 +537,7 @@ if necessary. Returns new operation, op==-1 means noop. */
|
|||
// 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)
|
||||
if (clip_x0>x0) /* TODO: ??? */
|
||||
{
|
||||
sx+=clip_x0-x0;
|
||||
x0=clip_x0;
|
||||
|
@ -689,6 +688,7 @@ if necessary. Returns new operation, op==-1 means noop. */
|
|||
/* 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;
|
||||
|
@ -737,7 +737,6 @@ if necessary. Returns new operation, op==-1 means noop. */
|
|||
|
||||
void (*blit_func)(composite_run_t *c,int num);
|
||||
|
||||
|
||||
if (!wi || !wi->data) return;
|
||||
if (all_clipped) return;
|
||||
|
||||
|
@ -914,6 +913,7 @@ very expensive
|
|||
-(void) setColor: (device_color_t)color state: (color_state_t)cState
|
||||
{
|
||||
device_color_t c;
|
||||
|
||||
[super setColor: color state: cState];
|
||||
if (cState&(COLOR_FILL|COLOR_STROKE))
|
||||
{
|
||||
|
@ -1319,17 +1319,6 @@ very expensive
|
|||
}
|
||||
|
||||
|
||||
- (void) DPSclip
|
||||
{
|
||||
NSLog(@"ignoring DPSclip");
|
||||
}
|
||||
|
||||
- (void) DPSeoclip
|
||||
{
|
||||
NSLog(@"ignoring DPSeoclip");
|
||||
}
|
||||
|
||||
|
||||
-(ArtVpath *) _vpath_from_current_path: (BOOL)fill
|
||||
{
|
||||
ArtBpath *bpath,*bp2;
|
||||
|
@ -1453,6 +1442,86 @@ very expensive
|
|||
}
|
||||
|
||||
|
||||
/* will free the passed in svp */
|
||||
-(void) _clip_add_svp: (ArtSVP *)svp
|
||||
{
|
||||
if (clip_path)
|
||||
{
|
||||
ArtSVP *svp2;
|
||||
/* ArtSvpWriter *svpw;
|
||||
|
||||
svpw=art_svp_writer_rewind_new(ART_WIND_RULE_INTERSECT);
|
||||
art_svp_intersector(svp,svpw);
|
||||
art_svp_intersector(clip_path,svpw);
|
||||
svp2=art_svp_writer_rewind_reap(svpw);*/
|
||||
svp2=art_svp_intersect(svp,clip_path);
|
||||
art_svp_free(svp);
|
||||
art_svp_free(clip_path);
|
||||
clip_path=svp2;
|
||||
}
|
||||
else
|
||||
{
|
||||
clip_path=svp;
|
||||
}
|
||||
}
|
||||
|
||||
-(void) _clip: (int)rule
|
||||
{
|
||||
ArtVpath *vp;
|
||||
ArtSVP *svp;
|
||||
|
||||
vp=[self _vpath_from_current_path: NO];
|
||||
if (!vp)
|
||||
return;
|
||||
svp=art_svp_from_vpath(vp);
|
||||
art_free(vp);
|
||||
|
||||
{
|
||||
ArtSVP *svp2;
|
||||
ArtSvpWriter *svpw;
|
||||
|
||||
svpw=art_svp_writer_rewind_new(rule);
|
||||
art_svp_intersector(svp,svpw);
|
||||
svp2=art_svp_writer_rewind_reap(svpw);
|
||||
art_svp_free(svp);
|
||||
svp=svp2;
|
||||
}
|
||||
|
||||
[self _clip_add_svp: svp];
|
||||
}
|
||||
|
||||
-(ArtSVP *) _clip_svp: (ArtSVP *)svp
|
||||
{
|
||||
ArtSVP *svp2;
|
||||
// ArtSvpWriter *svpw;
|
||||
|
||||
if (!clip_path)
|
||||
return svp;
|
||||
/* TODO */
|
||||
/* svpw=art_svp_writer_rewind_new(ART_WIND_RULE_INTERSECT);
|
||||
art_svp_intersector(svp,svpw);
|
||||
art_svp_intersector(clip_path,svpw);
|
||||
svp2=art_svp_writer_rewind_reap(svpw);
|
||||
art_svp_free(svp);*/
|
||||
|
||||
svp2=art_svp_intersect(svp,clip_path);
|
||||
art_svp_free(svp);
|
||||
|
||||
return svp2;
|
||||
}
|
||||
|
||||
|
||||
- (void) DPSclip
|
||||
{
|
||||
[self _clip: ART_WIND_RULE_NONZERO];
|
||||
}
|
||||
|
||||
- (void) DPSeoclip
|
||||
{
|
||||
[self _clip: ART_WIND_RULE_ODDEVEN];
|
||||
}
|
||||
|
||||
|
||||
-(void) _fill: (int)rule
|
||||
{
|
||||
ArtVpath *vp;
|
||||
|
@ -1479,6 +1548,9 @@ very expensive
|
|||
svp=svp2;
|
||||
}
|
||||
|
||||
if (clip_path)
|
||||
svp=[self _clip_svp: svp];
|
||||
|
||||
|
||||
artcontext_render_svp(svp,clip_x0,clip_y0,clip_x1,clip_y1,
|
||||
fill_color[0],fill_color[1],fill_color[2],fill_color[3],
|
||||
|
@ -1503,94 +1575,19 @@ very expensive
|
|||
}
|
||||
|
||||
|
||||
- (void) DPSinitclip;
|
||||
{ /* TODO: try all this again with reversed paths */
|
||||
if (!wi)
|
||||
{
|
||||
all_clipped=YES;
|
||||
return;
|
||||
}
|
||||
|
||||
clip_x0=clip_y0=0;
|
||||
clip_x1=wi->sx;
|
||||
clip_y1=wi->sy;
|
||||
all_clipped=NO;
|
||||
clip_sx=clip_x1-clip_x0;
|
||||
clip_sy=clip_y1-clip_y0;
|
||||
}
|
||||
|
||||
- (void) DPSrectclip: (float)x : (float)y : (float)w : (float)h
|
||||
/* Fills in vp. If the rectangle is axis- (and optionally pixel)-aligned,
|
||||
also fills in the axis coordinates (x0/y0 is min) and returns 1. Otherwise
|
||||
returns 0. (Actually, if pixel is NO, it's enough that the edges remain
|
||||
within one pixel.) */
|
||||
-(int) _axis_rectangle: (float)x : (float)y : (float)w : (float)h
|
||||
vpath: (ArtVpath *)vp
|
||||
axis: (int *)px0 : (int *)py0 : (int *)px1 : (int *)py1
|
||||
pixel: (BOOL)pixel;
|
||||
{
|
||||
NSPoint p;
|
||||
NSSize s;
|
||||
NSRect r;
|
||||
|
||||
if (all_clipped)
|
||||
return;
|
||||
|
||||
if (!wi)
|
||||
{
|
||||
all_clipped=YES;
|
||||
return;
|
||||
}
|
||||
|
||||
r=[ctm rectInMatrixSpace: NSMakeRect(x,y,w,h)];
|
||||
|
||||
p=r.origin;
|
||||
s=r.size;
|
||||
|
||||
p.y=wi->sy-p.y;
|
||||
p.y-=s.height;
|
||||
|
||||
/* PS says that any pixel covered by the clipping path is not to
|
||||
be clipped, so we need to round 'outwards' here. */
|
||||
s.width=ceil(s.width+p.x);
|
||||
s.height=ceil(s.height+p.y);
|
||||
p.x=floor(p.x);
|
||||
p.y=floor(p.y);
|
||||
|
||||
/* printf("%p clip was (%i %i)-(%i %i) (%g %g)+(%g %g) -> (%g %g)+(%g %g)\n",
|
||||
self,
|
||||
clip_x0,clip_y0,clip_x1,clip_y1,
|
||||
x,y,w,h,p.x,p.y,s.width,s.height);*/
|
||||
|
||||
if (p.x>clip_x0)
|
||||
clip_x0=p.x;
|
||||
if (p.y>clip_y0)
|
||||
clip_y0=p.y;
|
||||
|
||||
p.x=s.width;
|
||||
p.y=s.height;
|
||||
|
||||
if (p.x<clip_x1)
|
||||
clip_x1=p.x;
|
||||
if (p.y<clip_y1)
|
||||
clip_y1=p.y;
|
||||
|
||||
if (clip_x0>=clip_x1 || clip_y0>=clip_y1)
|
||||
{
|
||||
// printf("%p all_clipped by (%g %g)+(%g %g)\n",self,x,y,w,h);
|
||||
all_clipped=YES;
|
||||
}
|
||||
|
||||
clip_sx=clip_x1-clip_x0;
|
||||
clip_sy=clip_y1-clip_y0;
|
||||
|
||||
// printf("now %i (%i %i)-(%i %i)\n",all_clipped,clip_x0,clip_y0,clip_x1,clip_y1);
|
||||
}
|
||||
|
||||
- (void) DPSrectfill: (float)x : (float)y : (float)w : (float)h
|
||||
{
|
||||
ArtVpath vp[6];
|
||||
ArtSVP *svp;
|
||||
float matrix[6];
|
||||
float det;
|
||||
int i;
|
||||
int x0,y0,x1,y1,t;
|
||||
|
||||
if (!wi || !wi->data) return;
|
||||
if (all_clipped) return;
|
||||
if (!fill_color[3]) return;
|
||||
int x0,y0,x1,y1;
|
||||
|
||||
if (w<0) x+=w,w=-w;
|
||||
if (h<0) y+=h,h=-h;
|
||||
|
@ -1638,21 +1635,153 @@ very expensive
|
|||
x1=vp[2].x+0.5;
|
||||
y0=vp[0].y+0.5;
|
||||
y1=vp[2].y+0.5;
|
||||
if (fabs(vp[0].x-vp[1].x)<0.01 && fabs(vp[1].y-vp[2].y)<0.01 &&
|
||||
fabs(vp[0].x-x0)<0.01 && fabs(vp[0].y-y0)<0.01 &&
|
||||
fabs(vp[2].x-x1)<0.01 && fabs(vp[2].y-y1)<0.01)
|
||||
{
|
||||
}
|
||||
else if (fabs(vp[0].y-vp[1].y)<0.01 && fabs(vp[1].x-vp[2].x)<0.01 &&
|
||||
fabs(vp[0].x-x0)<0.01 && fabs(vp[0].y-y0)<0.01 &&
|
||||
fabs(vp[2].x-x1)<0.01 && fabs(vp[2].y-y1)<0.01)
|
||||
|
||||
if (pixel)
|
||||
{
|
||||
if (x0>x1)
|
||||
*px0=x1,*px1=x0;
|
||||
else
|
||||
*px0=x0,*px1=x1;
|
||||
if (y0>y1)
|
||||
*py0=y1,*py1=y0;
|
||||
else
|
||||
*py0=y0,*py1=y1;
|
||||
|
||||
if (fabs(vp[0].x-vp[1].x)<0.01 && fabs(vp[1].y-vp[2].y)<0.01 &&
|
||||
fabs(vp[0].x-x0)<0.01 && fabs(vp[0].y-y0)<0.01 &&
|
||||
fabs(vp[2].x-x1)<0.01 && fabs(vp[2].y-y1)<0.01)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fabs(vp[0].y-vp[1].y)<0.01 && fabs(vp[1].x-vp[2].x)<0.01 &&
|
||||
fabs(vp[0].x-x0)<0.01 && fabs(vp[0].y-y0)<0.01 &&
|
||||
fabs(vp[2].x-x1)<0.01 && fabs(vp[2].y-y1)<0.01)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is used when clipping, so we need to make sure we
|
||||
contain all pixels. */
|
||||
if (vp[0].x<vp[2].x)
|
||||
*px0=floor(vp[0].x),*px1=ceil(vp[2].x);
|
||||
else
|
||||
*px0=floor(vp[2].x),*px1=ceil(vp[0].x);
|
||||
if (vp[0].y<vp[2].y)
|
||||
*py0=floor(vp[0].y),*py1=ceil(vp[2].y);
|
||||
else
|
||||
*py0=floor(vp[2].y),*py1=ceil(vp[0].y);
|
||||
|
||||
if (floor(vp[0].x)==floor(vp[1].x) && floor(vp[0].y)==floor(vp[3].y) &&
|
||||
floor(vp[1].y)==floor(vp[2].y) && floor(vp[2].x)==floor(vp[3].x))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (floor(vp[0].y)==floor(vp[1].y) && floor(vp[0].x)==floor(vp[3].x) &&
|
||||
floor(vp[1].x)==floor(vp[2].x) && floor(vp[2].y)==floor(vp[3].y))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
- (void) DPSinitclip;
|
||||
{
|
||||
if (!wi)
|
||||
{
|
||||
all_clipped=YES;
|
||||
return;
|
||||
}
|
||||
|
||||
clip_x0=clip_y0=0;
|
||||
clip_x1=wi->sx;
|
||||
clip_y1=wi->sy;
|
||||
all_clipped=NO;
|
||||
clip_sx=clip_x1-clip_x0;
|
||||
clip_sy=clip_y1-clip_y0;
|
||||
|
||||
if (clip_path)
|
||||
{
|
||||
art_svp_free(clip_path);
|
||||
clip_path=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
- (void) DPSrectclip: (float)x : (float)y : (float)w : (float)h
|
||||
{
|
||||
ArtVpath vp[6];
|
||||
ArtSVP *svp;
|
||||
int x0,y0,x1,y1;
|
||||
int axis_aligned;
|
||||
|
||||
if (all_clipped)
|
||||
return;
|
||||
|
||||
if (!wi)
|
||||
{
|
||||
all_clipped=YES;
|
||||
return;
|
||||
}
|
||||
|
||||
axis_aligned=[self _axis_rectangle: x : y : w : h vpath: vp
|
||||
axis: &x0 : &y0 : &x1 : &y1
|
||||
pixel: NO];
|
||||
|
||||
if (!axis_aligned)
|
||||
{
|
||||
svp=art_svp_from_vpath(vp);
|
||||
[self _clip_add_svp: svp];
|
||||
return;
|
||||
}
|
||||
|
||||
if (x0>clip_x0)
|
||||
clip_x0=x0;
|
||||
if (y0>clip_y0)
|
||||
clip_y0=y0;
|
||||
|
||||
if (x1<clip_x1)
|
||||
clip_x1=x1;
|
||||
if (y1<clip_y1)
|
||||
clip_y1=y1;
|
||||
|
||||
if (clip_x0>=clip_x1 || clip_y0>=clip_y1)
|
||||
{
|
||||
all_clipped=YES;
|
||||
}
|
||||
|
||||
clip_sx=clip_x1-clip_x0;
|
||||
clip_sy=clip_y1-clip_y0;
|
||||
}
|
||||
|
||||
- (void) DPSrectfill: (float)x : (float)y : (float)w : (float)h
|
||||
{
|
||||
ArtVpath vp[6];
|
||||
ArtSVP *svp;
|
||||
int x0,y0,x1,y1;
|
||||
int axis_aligned;
|
||||
|
||||
if (!wi || !wi->data) return;
|
||||
if (all_clipped) return;
|
||||
if (!fill_color[3]) return;
|
||||
|
||||
axis_aligned=[self _axis_rectangle: x : y : w : h vpath: vp
|
||||
axis: &x0 : &y0 : &x1 : &y1
|
||||
pixel: YES];
|
||||
|
||||
if (!axis_aligned || clip_path)
|
||||
{
|
||||
/* Not properly aligned. Handle the general case. */
|
||||
svp=art_svp_from_vpath(vp);
|
||||
|
||||
if (clip_path)
|
||||
svp=[self _clip_svp: svp];
|
||||
|
||||
artcontext_render_svp(svp,clip_x0,clip_y0,clip_x1,clip_y1,
|
||||
fill_color[0],fill_color[1],fill_color[2],fill_color[3],
|
||||
CLIP_DATA,wi->bytes_per_line,
|
||||
|
@ -1669,7 +1798,6 @@ very expensive
|
|||
unsigned char *dst=CLIP_DATA;
|
||||
render_run_t ri;
|
||||
|
||||
if (x0>x1) t=x1,x1=x0,x0=t;
|
||||
x0-=clip_x0;
|
||||
x1-=clip_x0;
|
||||
if (x0<=0)
|
||||
|
@ -1682,7 +1810,6 @@ very expensive
|
|||
if (x1<=0)
|
||||
return;
|
||||
|
||||
if (y0>y1) t=y1,y1=y0,y0=t;
|
||||
y0-=clip_y0;
|
||||
y1-=clip_y0;
|
||||
if (y0<=0)
|
||||
|
@ -1809,6 +1936,9 @@ very expensive
|
|||
svp=art_svp_vpath_stroke(vp,linejoinstyle,linecapstyle,temp_scale*line_width,miter_limit,0.5);
|
||||
art_free(vp);
|
||||
|
||||
if (clip_path)
|
||||
svp=[self _clip_svp: svp];
|
||||
|
||||
artcontext_render_svp(svp,clip_x0,clip_y0,clip_x1,clip_y1,
|
||||
stroke_color[0],stroke_color[1],stroke_color[2],stroke_color[3],
|
||||
CLIP_DATA,wi->bytes_per_line,
|
||||
|
@ -1884,6 +2014,9 @@ will give correct results as long as both axises are scaled the same.
|
|||
svp=art_svp_vpath_stroke(vp,linejoinstyle,linecapstyle,temp_scale*line_width,miter_limit,0.5);
|
||||
art_free(vp);
|
||||
|
||||
if (clip_path)
|
||||
svp=[self _clip_svp: svp];
|
||||
|
||||
artcontext_render_svp(svp,clip_x0,clip_y0,clip_x1,clip_y1,
|
||||
stroke_color[0],stroke_color[1],stroke_color[2],stroke_color[3],
|
||||
CLIP_DATA,wi->bytes_per_line,
|
||||
|
@ -2005,6 +2138,42 @@ and that covers most (all?) actual uses of it */
|
|||
@end
|
||||
|
||||
|
||||
static ArtSVP *copy_svp(ArtSVP *svp)
|
||||
{
|
||||
int i;
|
||||
ArtSVP *svp2;
|
||||
ArtSVPSeg *dst,*src;
|
||||
|
||||
if (!svp->n_segs)
|
||||
return NULL;
|
||||
|
||||
svp2=malloc(sizeof(ArtSVP)+sizeof(ArtSVPSeg)*(svp->n_segs-1));
|
||||
if (!svp2)
|
||||
{
|
||||
NSLog(@"out of memory copying svp");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
svp2->n_segs=svp->n_segs;
|
||||
|
||||
for (i=0,src=svp->segs,dst=svp2->segs;i<svp->n_segs;i++,src++,dst++)
|
||||
{
|
||||
dst->n_points=src->n_points;
|
||||
dst->dir=src->dir;
|
||||
dst->bbox=src->bbox;
|
||||
if (src->n_points)
|
||||
{
|
||||
dst->points=malloc(sizeof(ArtPoint)*src->n_points);
|
||||
memcpy(dst->points,src->points,sizeof(ArtPoint)*src->n_points);
|
||||
}
|
||||
else
|
||||
dst->points=NULL;
|
||||
}
|
||||
|
||||
return svp2;
|
||||
}
|
||||
|
||||
|
||||
@interface ARTGState (internal_stuff)
|
||||
#ifdef RDS
|
||||
-(void) _setup_stuff: (int)window : (RDSClient *)remote;
|
||||
|
@ -2021,6 +2190,9 @@ and that covers most (all?) actual uses of it */
|
|||
if (dash.dash)
|
||||
free(dash.dash);
|
||||
|
||||
if (clip_path)
|
||||
art_svp_free(clip_path);
|
||||
|
||||
DESTROY(wi);
|
||||
|
||||
[super dealloc];
|
||||
|
@ -2047,6 +2219,11 @@ and that covers most (all?) actual uses of it */
|
|||
}
|
||||
}
|
||||
|
||||
if (clip_path)
|
||||
{
|
||||
clip_path=copy_svp(clip_path);
|
||||
}
|
||||
|
||||
wi=RETAIN(wi);
|
||||
|
||||
return self;
|
||||
|
|
Loading…
Reference in a new issue