Store clipping path as a set of spans instead of as an svp. Update lots of related code.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@14387 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
alexm 2002-08-31 12:42:36 +00:00
parent 3a189c047c
commit ac84d437ff
4 changed files with 334 additions and 97 deletions

View file

@ -1,3 +1,10 @@
2002-08-31 14:40 Alexander Malmberg <alexander@malmberg.org>
* Source/art/ARTContext.m, Source/art/ARTGState.h, Source/art/path.m:
Store clipping path as a set of spans instead of as an svp. Build
spans from DPSclip and DPSeoclip, and use it when clipping (only
implemented for paths, so far).
2002-08-30 15:42 Alexander Malmberg <alexander@malmberg.org> 2002-08-30 15:42 Alexander Malmberg <alexander@malmberg.org>
* Source/art/blit.h, Source/art/blit.m, Source/art/path.m: Move * Source/art/blit.h, Source/art/blit.m, Source/art/path.m: Move

View file

@ -468,42 +468,6 @@ very expensive
@end @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) @interface ARTGState (internal_stuff)
#ifdef RDS #ifdef RDS
-(void) _setup_stuff: (int)window : (RDSClient *)remote; -(void) _setup_stuff: (int)window : (RDSClient *)remote;
@ -521,8 +485,10 @@ static ArtSVP *copy_svp(ArtSVP *svp)
if (dash.dash) if (dash.dash)
free(dash.dash); free(dash.dash);
if (clip_path) if (clip_span)
art_svp_free(clip_path); free(clip_span);
if (clip_index)
free(clip_index);
DESTROY(wi); DESTROY(wi);
@ -550,9 +516,32 @@ static ArtSVP *copy_svp(ArtSVP *svp)
} }
} }
if (clip_path) if (clip_span)
{ {
clip_path=copy_svp(clip_path); unsigned int *n;
n=malloc(sizeof(unsigned int)*clip_num_span);
if (n)
{
memcpy(n,clip_span,sizeof(unsigned int)*clip_num_span);
clip_span=n;
n=malloc(sizeof(unsigned int *)*(clip_sy+1));
if (n)
{
memcpy(n,clip_index,sizeof(unsigned int *)*(clip_sy+1));
clip_index = n;
}
else
{
free(clip_span);
clip_span=clip_index=NULL;
clip_num_span=0;
}
}
else
{
clip_span=clip_index=NULL;
clip_num_span=0;
}
} }
wi=RETAIN(wi); wi=RETAIN(wi);

View file

@ -34,7 +34,7 @@
#endif #endif
#include <libart_lgpl/libart.h> #include <libart_lgpl/art_vpath_dash.h>
@class ARTWindowBuffer; @class ARTWindowBuffer;
@ -59,7 +59,26 @@
#define CLIP_DATA (wi->data+clip_x0*wi->bytes_per_pixel+clip_y0*wi->bytes_per_line) #define CLIP_DATA (wi->data+clip_x0*wi->bytes_per_pixel+clip_y0*wi->bytes_per_line)
int clip_sx,clip_sy; int clip_sx,clip_sy;
ArtSVP *clip_path; /*
Clipping spans are stored this way. clip_index has an index to the
spans (in clip_span) for each line. clip_span has the x-starting
coordinate for each span. A line starts 'off', each coordinate flips
the state. The spans are stored in increasing y order, so
clip_index[y+1]-1 is the index of the last span coordinate. Thus, if
clip_index[y]==clip_index[y+1], the entire line is clipped.
clip_index actually has clip_sy+1 entries, so clip_index[y+1] is
valid for _all_ lines.
All coordinates are in device space and counted inside the clipping
rectangle.
To make things easier, each line also ends in the off state (so the
last entry in clip_span might be a dummy entry at the end of the
line).
*/
unsigned int *clip_span;
unsigned int *clip_index;
int clip_num_span;
} }
@end @end

View file

@ -34,6 +34,8 @@ Path handling.
#include "ARTWindowBuffer.h" #include "ARTWindowBuffer.h"
#include "blit.h" #include "blit.h"
#include <libart_lgpl/libart.h>
#include <libart_lgpl/art_svp_intersect.h> #include <libart_lgpl/art_svp_intersect.h>
@ -90,6 +92,20 @@ static void dump_bpath(ArtBpath *vp)
} }
} }
{
int i,j;
printf("size=%i num=%i\n",ci.span_size,ci.num_span);
for (i=0;i<clip_sy;i++)
{
printf("y=%3i:",i);
for (j=clip_index[i];j<clip_index[i+1];j++)
{
printf(" %i",clip_span[j]);
}
printf("\n");
}
}
#endif #endif
@ -100,10 +116,12 @@ typedef struct
render_run_t ri; render_run_t ri;
unsigned char real_a; unsigned char real_a;
int x0, x1; int x0, x1, y0;
int rowstride, arowstride, bpp; int rowstride, arowstride, bpp;
void (*run_alpha)(struct render_run_s *ri, int num); void (*run_alpha)(struct render_run_s *ri, int num);
void (*run_opaque)(struct render_run_s *ri, int num); void (*run_opaque)(struct render_run_s *ri, int num);
unsigned int *clip_span, *clip_index;
} svp_render_info_t; } svp_render_info_t;
static void render_svp_callback(void *data, int y, int start, static void render_svp_callback(void *data, int y, int start,
@ -163,16 +181,158 @@ static void render_svp_callback(void *data, int y, int start,
ri->ri.dsta = dsta; ri->ri.dsta = dsta;
} }
static void render_svp_clipped_callback(void *data, int y, int start,
ArtSVPRenderAAStep *steps, int n_steps)
{
svp_render_info_t *ri = data;
int x0, x1;
int num;
int alpha;
unsigned char *dst, *dsta;
unsigned int *span, *end;
BOOL state;
alpha = start;
/* empty line; very common case */
if (alpha < 0x10000 && !n_steps)
{
ri->ri.dst += ri->rowstride;
ri->ri.dsta += ri->arowstride;
return;
}
/* completely clipped line? */
if (ri->clip_index[y - ri->y0] == ri->clip_index[y - ri->y0 + 1])
{
ri->ri.dst += ri->rowstride;
ri->ri.dsta += ri->arowstride;
return;
}
span = &ri->clip_span[ri->clip_index[y - ri->y0]];
end = &ri->clip_span[ri->clip_index[y - ri->y0 + 1]];
state = NO;
dst = ri->ri.dst + ri->rowstride;
dsta = ri->ri.dsta + ri->arowstride;
x0 = 0;
for (; n_steps; n_steps--, steps++)
{
x1 = steps->x - ri->x0;
ri->ri.a = (alpha * ri->real_a + 0x800000) >> 24;
if (ri->ri.a)
{
while (*span < x1)
{
num = *span - x0;
if (state)
{
if (ri->ri.a == 255)
ri->run_opaque(&ri->ri, num);
else
ri->run_alpha(&ri->ri, num);
}
x0 = *span;
ri->ri.dst += ri->bpp * num;
ri->ri.dsta += num;
state = !state;
span++;
if (span == end)
{
ri->ri.dst = dst;
ri->ri.dsta = dsta;
return;
}
}
num = x1 - x0;
if (num && state)
{
if (ri->ri.a == 255)
ri->run_opaque(&ri->ri, num);
else
ri->run_alpha(&ri->ri, num);
}
ri->ri.dst += ri->bpp * num;
ri->ri.dsta += num;
}
else
{
num = x1 - x0;
while (*span <= x1)
{
state = !state;
span++;
if (span == end)
{
ri->ri.dst = dst;
ri->ri.dsta = dsta;
return;
}
}
ri->ri.dst += ri->bpp * num;
ri->ri.dsta += num;
}
alpha += steps->delta;
x0 = x1;
}
x1 = ri->x1 - ri->x0;
num = x1 - x0;
ri->ri.a = (alpha * ri->real_a + 0x800000) >> 24;
if (ri->ri.a && num)
{
while (*span < x1)
{
num = *span - x0;
if (state)
{
if (ri->ri.a == 255)
ri->run_opaque(&ri->ri, num);
else
ri->run_alpha(&ri->ri, num);
}
x0 = *span;
ri->ri.dst += ri->bpp * num;
ri->ri.dsta += num;
state = !state;
span++;
if (span == end)
{
ri->ri.dst = dst;
ri->ri.dsta = dsta;
return;
}
}
num = x1 - x0;
if (num && state)
{
if (ri->ri.a == 255)
ri->run_opaque(&ri->ri, num);
else
ri->run_alpha(&ri->ri, num);
}
}
ri->ri.dst = dst;
ri->ri.dsta = dsta;
}
static void artcontext_render_svp(const ArtSVP *svp, int x0, int y0, int x1, int y1, static void artcontext_render_svp(const ArtSVP *svp, int x0, int y0, int x1, int y1,
unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned char r, unsigned char g, unsigned char b, unsigned char a,
unsigned char *dst, int rowstride, unsigned char *dst, int rowstride,
unsigned char *dsta, int arowstride, int has_alpha, unsigned char *dsta, int arowstride, int has_alpha,
draw_info_t *di) draw_info_t *di,
unsigned int *clip_span, unsigned int *clip_index)
{ {
svp_render_info_t ri; svp_render_info_t ri;
ri.x0 = x0; ri.x0 = x0;
ri.x1 = x1; ri.x1 = x1;
ri.y0 = y0;
ri.ri.r = r; ri.ri.r = r;
ri.ri.g = g; ri.ri.g = g;
@ -184,6 +344,9 @@ static void artcontext_render_svp(const ArtSVP *svp, int x0, int y0, int x1, int
ri.ri.dst = dst; ri.ri.dst = dst;
ri.rowstride = rowstride; ri.rowstride = rowstride;
ri.clip_span = clip_span;
ri.clip_index = clip_index;
if (has_alpha) if (has_alpha)
{ {
ri.ri.dsta = dsta; ri.ri.dsta = dsta;
@ -197,7 +360,8 @@ static void artcontext_render_svp(const ArtSVP *svp, int x0, int y0, int x1, int
ri.run_opaque = di->render_run_opaque; ri.run_opaque = di->render_run_opaque;
} }
art_svp_render_aa(svp, x0, y0, x1, y1, render_svp_callback, &ri); art_svp_render_aa(svp, x0, y0, x1, y1,
clip_span? render_svp_clipped_callback : render_svp_callback, &ri);
} }
@ -448,27 +612,112 @@ within one pixel.) */
/** Clipping **/ /** Clipping **/
typedef struct
{
int x0, x1, y0, sy;
unsigned int *span;
unsigned int *index;
int span_size, num_span;
unsigned int *cur_span;
unsigned int *cur_index;
} clip_info_t;
static void clip_svp_callback(void *data, int y, int start,
ArtSVPRenderAAStep *steps, int n_steps)
{
clip_info_t *ci = data;
int x;
int alpha;
BOOL state, nstate;
alpha = start;
ci->index[y - ci->y0] = ci->num_span;
if (y-ci->y0<0 || y-ci->y0>=ci->sy)
{
printf("weird y=%i (%i)\n",y,y-ci->y0);
}
/* empty line; very common case */
if (!alpha && !n_steps)
{
return;
}
x = 0;
state = alpha >= 0x10000;
if (state)
{
if (ci->num_span == ci->span_size)
{
ci->span_size += 16;
ci->span = realloc(ci->span, sizeof(unsigned int) * ci->span_size);
}
ci->span[ci->num_span++] = x;
}
for (; n_steps; n_steps--, steps++)
{
alpha += steps->delta;
x = steps->x - ci->x0;
nstate = alpha >= 0x10000;
if (state != nstate)
{
if (ci->num_span == ci->span_size)
{
ci->span_size += 16;
ci->span = realloc(ci->span, sizeof(unsigned int) * ci->span_size);
}
ci->span[ci->num_span++] = x;
state = nstate;
}
}
if (state)
{
if (ci->num_span == ci->span_size)
{
ci->span_size += 16;
ci->span = realloc(ci->span, sizeof(unsigned int) * ci->span_size);
}
ci->span[ci->num_span++] = ci->x1;
}
}
/* will free the passed in svp */ /* will free the passed in svp */
-(void) _clip_add_svp: (ArtSVP *)svp -(void) _clip_add_svp: (ArtSVP *)svp
{ {
if (clip_path) clip_info_t ci;
ci.span = NULL;
ci.index = malloc(sizeof(unsigned int) * (clip_sy + 1));
if (!ci.index)
{ {
ArtSVP *svp2; NSLog(@"Warning: out of memory calculating clipping spans (%i bytes)",
/* ArtSvpWriter *svpw; sizeof(unsigned int) * (clip_sy + 1));
return;
svpw = art_svp_writer_rewind_new(ART_WIND_RULE_INTERSECT); }
art_svp_intersector(svp, svpw); ci.span_size = ci.num_span = 0;
art_svp_intersector(clip_path, svpw); ci.x0 = clip_x0;
svp2 = art_svp_writer_rewind_reap(svpw); */ ci.x1 = clip_x1;
svp2 = art_svp_intersect(svp, clip_path); ci.y0 = clip_y0;
art_svp_free(svp); ci.sy = clip_sy;
art_svp_free(clip_path); if (clip_span)
clip_path = svp2; {
NSLog(@"TODO: _clip_add_svp: with existing clip_span not implemented");
free(ci.index);
return;
} }
else else
{ {
clip_path = svp; art_svp_render_aa(svp, clip_x0, clip_y0, clip_x1, clip_y1, clip_svp_callback, &ci);
clip_span = ci.span;
clip_index = ci.index;
clip_index[clip_sy] = clip_num_span = ci.num_span;
} }
art_svp_free(svp);
} }
-(void) _clip: (int)rule -(void) _clip: (int)rule
@ -496,26 +745,6 @@ within one pixel.) */
[self _clip_add_svp: svp]; [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 - (void) DPSclip
{ {
@ -588,10 +817,12 @@ within one pixel.) */
clip_sx = clip_x1 - clip_x0; clip_sx = clip_x1 - clip_x0;
clip_sy = clip_y1 - clip_y0; clip_sy = clip_y1 - clip_y0;
if (clip_path) if (clip_span)
{ {
art_svp_free(clip_path); free(clip_span);
clip_path = NULL; free(clip_index);
clip_span = clip_index = NULL;
clip_num_span = 0;
} }
} }
@ -624,16 +855,13 @@ within one pixel.) */
svp = svp2; svp = svp2;
} }
if (clip_path)
svp = [self _clip_svp: svp];
artcontext_render_svp(svp, clip_x0, clip_y0, clip_x1, clip_y1, artcontext_render_svp(svp, clip_x0, clip_y0, clip_x1, clip_y1,
fill_color[0], fill_color[1], fill_color[2], fill_color[3], fill_color[0], fill_color[1], fill_color[2], fill_color[3],
CLIP_DATA, wi->bytes_per_line, CLIP_DATA, wi->bytes_per_line,
wi->has_alpha? wi->alpha + clip_x0 + clip_y0 * wi->sx : NULL, wi->sx, wi->has_alpha? wi->alpha + clip_x0 + clip_y0 * wi->sx : NULL, wi->sx,
wi->has_alpha, wi->has_alpha,
&DI); &DI, clip_span, clip_index);
art_svp_free(svp); art_svp_free(svp);
@ -665,20 +893,17 @@ within one pixel.) */
axis: &x0 : &y0 : &x1 : &y1 axis: &x0 : &y0 : &x1 : &y1
pixel: YES]; pixel: YES];
if (!axis_aligned || clip_path) if (!axis_aligned || clip_span)
{ {
/* Not properly aligned. Handle the general case. */ /* Not properly aligned. Handle the general case. */
svp = art_svp_from_vpath(vp); 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, artcontext_render_svp(svp, clip_x0, clip_y0, clip_x1, clip_y1,
fill_color[0], fill_color[1], fill_color[2], fill_color[3], fill_color[0], fill_color[1], fill_color[2], fill_color[3],
CLIP_DATA, wi->bytes_per_line, CLIP_DATA, wi->bytes_per_line,
wi->has_alpha? wi->alpha + clip_x0 + clip_y0 * wi->sx : NULL, wi->sx, wi->has_alpha? wi->alpha + clip_x0 + clip_y0 * wi->sx : NULL, wi->sx,
wi->has_alpha, wi->has_alpha,
&DI); &DI, clip_span, clip_index);
art_svp_free(svp); art_svp_free(svp);
return; return;
@ -792,15 +1017,12 @@ within one pixel.) */
temp_scale * line_width, miter_limit, 0.5); temp_scale * line_width, miter_limit, 0.5);
art_free(vp); art_free(vp);
if (clip_path)
svp = [self _clip_svp: svp];
artcontext_render_svp(svp, clip_x0, clip_y0, clip_x1, clip_y1, artcontext_render_svp(svp, clip_x0, clip_y0, clip_x1, clip_y1,
stroke_color[0], stroke_color[1], stroke_color[2], stroke_color[3], stroke_color[0], stroke_color[1], stroke_color[2], stroke_color[3],
CLIP_DATA, wi->bytes_per_line, CLIP_DATA, wi->bytes_per_line,
wi->has_alpha? wi->alpha + clip_x0 + clip_y0 * wi->sx : NULL, wi->sx, wi->has_alpha? wi->alpha + clip_x0 + clip_y0 * wi->sx : NULL, wi->sx,
wi->has_alpha, wi->has_alpha,
&DI); &DI, clip_span, clip_index);
art_svp_free(svp); art_svp_free(svp);
} }