ector: refactored software drawing backend to use composition function.

Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
This commit is contained in:
Subhransu Mohanty 2015-08-17 15:18:26 +09:00 committed by Cedric BAIL
parent 48b558a997
commit 2766ce57ce
4 changed files with 452 additions and 195 deletions

View File

@ -95,7 +95,8 @@ lib/ector/software/ector_software_rasterizer.c \
lib/ector/software/ector_software_surface.c \
lib/ector/software/sw_ft_math.c \
lib/ector/software/sw_ft_raster.c \
lib/ector/software/sw_ft_stroker.c
lib/ector/software/sw_ft_stroker.c \
lib/ector/software/ector_drawhelper.c
installed_ectorsoftwareheadersdir = $(includedir)/ector-@VMAJ@/software
nodist_installed_ectorsoftwareheaders_DATA = $(ector_eolian_software_h)
@ -147,7 +148,7 @@ endif
EXTRA_DIST += \
lib/ector/ector_private.h \
lib/ector/cairo/ector_cairo_private.h \
lib/ector/software/ector_blend_private.h \
lib/ector/software/ector_drawhelper_private.h \
lib/ector/software/ector_software_private.h \
lib/ector/software/sw_ft_math.h \
lib/ector/software/sw_ft_raster.h \

View File

@ -0,0 +1,155 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <Ector.h>
#include "ector_drawhelper_private.h"
/*
s = source pixel
d = destination pixel
ca = const_alpha
sia = source inverse alpha
cia = const inverse alpha
*/
/*
result = s + d * sia
dest = (s + d * sia) * ca + d * cia
= s * ca + d * (sia * ca + cia)
= s * ca + d * (1 - sa*ca)
*/
void
comp_func_solid_source_over(uint *dest, int length, uint color, uint const_alpha)
{
int ialpha, i;
if (const_alpha != 255)
color = BYTE_MUL(color, const_alpha);
ialpha = Alpha(~color);
for (i = 0; i < length; ++i)
dest[i] = color + BYTE_MUL(dest[i], ialpha);
}
static void
comp_func_source_over(uint *dest, const uint *src, int length, uint color, uint const_alpha)
{
int i;
uint s, sc, sia;
if (const_alpha != 255)
color = BYTE_MUL(color, const_alpha);
if (color == 0xffffffff) // No color multiplier
{
for (i = 0; i < length; ++i)
{
s = src[i];
if (s >= 0xff000000)
dest[i] = s;
else if (s != 0)
{
sia = Alpha(~s);
dest[i] = s + BYTE_MUL(dest[i], sia);
}
}
}
else
{
for (i = 0; i < length; ++i)
{
s = src[i];
sc = ECTOR_MUL4_SYM(color, s);
sia = Alpha(~sc);
dest[i] = sc + BYTE_MUL(dest[i], sia);
}
}
}
/*
result = s
dest = s * ca + d * cia
*/
static void
comp_func_solid_source(uint *dest, int length, uint color, uint const_alpha)
{
int ialpha, i;
if (const_alpha == 255) _ector_memfill(dest, length, color);
else
{
ialpha = 255 - const_alpha;
color = BYTE_MUL(color, const_alpha);
for (i = 0; i < length; ++i)
dest[i] = color + BYTE_MUL(dest[i], ialpha);
}
}
static void
comp_func_source(uint *dest, const uint *src, int length, uint color, uint const_alpha)
{
int i, ialpha;
uint src_color;
if (color == 0xffffffff) // No color multiplier
{
if (const_alpha == 255)
memcpy(dest, src, length * sizeof(uint));
else
{
ialpha = 255 - const_alpha;
for (i = 0; i < length; ++i)
dest[i] = INTERPOLATE_PIXEL_256(src[i], const_alpha, dest[i], ialpha);
}
}
else
{
if (const_alpha == 255)
{
for (i = 0; i < length; ++i)
dest[i] = ECTOR_MUL4_SYM(src[i], color);
}
else
{
ialpha = 255 - const_alpha;
for (i = 0; i < length; ++i)
{
src_color = ECTOR_MUL4_SYM(src[i], color);
dest[i] = INTERPOLATE_PIXEL_256(src_color, const_alpha, dest[i], ialpha);
}
}
}
}
RGBA_Comp_Func_Solid func_for_mode_solid[ECTOR_ROP_LAST] = {
comp_func_solid_source_over,
comp_func_solid_source
};
RGBA_Comp_Func func_for_mode[ECTOR_ROP_LAST] = {
comp_func_source_over,
comp_func_source
};
RGBA_Comp_Func_Solid
ector_comp_func_solid_span_get(Ector_Rop op, uint color)
{
if ((color & 0xff000000) == 0xff000000)
{
if (op == ECTOR_ROP_BLEND) op = ECTOR_ROP_COPY;
}
return func_for_mode_solid[op];
}
RGBA_Comp_Func ector_comp_func_span_get(Ector_Rop op, uint color, Eina_Bool src_alpha)
{
if (((color & 0xff000000) == 0xff000000) && !src_alpha)
{
if (op == ECTOR_ROP_BLEND) op = ECTOR_ROP_COPY;
}
return func_for_mode[op];
}
void init_draw_helper()
{
}

View File

@ -0,0 +1,102 @@
#ifndef ECTOR_DRAWHELPER_PRIVATE_H
#define ECTOR_DRAWHELPER_PRIVATE_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifndef MIN
#define MIN( a, b ) ( (a) < (b) ? (a) : (b) )
#endif
#ifndef MAX
#define MAX( a, b ) ( (a) > (b) ? (a) : (b) )
#endif
#ifndef uint
typedef unsigned int uint;
#endif
inline int Alpha(uint c)
{
return c>>24;
}
#define ECTOR_ARGB_JOIN(a,r,g,b) \
(((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
#define ECTOR_MUL4_SYM(x, y) \
( ((((((x) >> 16) & 0xff00) * (((y) >> 16) & 0xff00)) + 0xff0000) & 0xff000000) + \
((((((x) >> 8) & 0xff00) * (((y) >> 16) & 0xff)) + 0xff00) & 0xff0000) + \
((((((x) & 0xff00) * ((y) & 0xff00)) + 0xff0000) >> 16) & 0xff00) + \
(((((x) & 0xff) * ((y) & 0xff)) + 0xff) >> 8) )
#define BYTE_MUL(c, a) \
( (((((c) >> 8) & 0x00ff00ff) * (a)) & 0xff00ff00) + \
(((((c) & 0x00ff00ff) * (a)) >> 8) & 0x00ff00ff) )
#define LOOP_ALIGNED_U1_A4(DEST, LENGTH, UOP, A4OP) \
{ \
while((uintptr_t)DEST & 0xF && LENGTH) UOP \
\
while(LENGTH) { \
switch(LENGTH) { \
case 3: \
case 2: \
case 1: \
UOP \
break; \
default: \
A4OP \
break; \
} \
} \
}
static inline void
_ector_memfill(uint *dest, int length, uint value)
{
int n;
if (!length)
return;
n = (length + 7) / 8;
switch (length & 0x07)
{
case 0: do { *dest++ = value;
case 7: *dest++ = value;
case 6: *dest++ = value;
case 5: *dest++ = value;
case 4: *dest++ = value;
case 3: *dest++ = value;
case 2: *dest++ = value;
case 1: *dest++ = value;
} while (--n > 0);
}
}
static inline uint
INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b)
{
uint t = (x & 0xff00ff) * a + (y & 0xff00ff) * b;
t >>= 8;
t &= 0xff00ff;
x = ((x >> 8) & 0xff00ff) * a + ((y >> 8) & 0xff00ff) * b;
x &= 0xff00ff00;
x |= t;
return x;
}
typedef void (*RGBA_Comp_Func)(uint *dest, const uint *src, int length, uint mul_col, uint const_alpha);
typedef void (*RGBA_Comp_Func_Solid)(uint *dest, int length, uint color, uint const_alpha);
extern RGBA_Comp_Func_Solid func_for_mode_solid[ECTOR_ROP_LAST];
extern RGBA_Comp_Func func_for_mode[ECTOR_ROP_LAST];
void init_draw_helper();
RGBA_Comp_Func_Solid ector_comp_func_solid_span_get(Ector_Rop op, uint color);
RGBA_Comp_Func ector_comp_func_span_get(Ector_Rop op, uint color, Eina_Bool src_alpha);
#endif

View File

@ -8,49 +8,27 @@
#include "ector_private.h"
#include "ector_software_private.h"
#include "ector_blend_private.h"
#include "ector_drawhelper_private.h"
static void
_blend_color_argb(int count, const SW_FT_Span *spans, void *user_data)
{
RGBA_Comp_Func_Solid comp_func;
Span_Data *data = (Span_Data *)(user_data);
uint color, *buffer, *target;
// multiply the color with mul_col if any
uint color = ECTOR_MUL4_SYM(data->color, data->mul_col);
Eina_Bool solid_source = ((color >> 24) == 255);
color = ECTOR_MUL4_SYM(data->color, data->mul_col);
comp_func = ector_comp_func_solid_span_get(data->op, color);
// move to the offset location
uint *buffer = data->raster_buffer.buffer + (data->raster_buffer.width * data->offy + data->offx);
if (solid_source)
{
while (count--)
{
uint *target = buffer + (data->raster_buffer.width * spans->y + spans->x);
if (spans->coverage == 255)
{
_ector_memfill(target, color, spans->len);
}
else
{
uint c = ECTOR_MUL_256(color, spans->coverage);
int ialpha = 255 - spans->coverage;
for (int i = 0; i < spans->len; ++i)
target[i] = c + ECTOR_MUL_256(target[i], ialpha);
}
++spans;
}
return;
}
buffer = data->raster_buffer.buffer + ((data->raster_buffer.width * data->offy) + data->offx);
while (count--)
{
uint *target = buffer + (data->raster_buffer.width * spans->y + spans->x);
uint c = ECTOR_MUL_256(color, spans->coverage);
int ialpha = (~c) >> 24;
for (int i = 0; i < spans->len; ++i)
target[i] = c + ECTOR_MUL_256(target[i], ialpha);
target = buffer + ((data->raster_buffer.width * spans->y) + spans->x);
comp_func(target, spans->len, color, spans->coverage);
++spans;
}
}
@ -62,37 +40,35 @@ typedef void (*src_fetch) (unsigned int *buffer, Span_Data *data, int y, int x,
static void
_blend_gradient(int count, const SW_FT_Span *spans, void *user_data)
{
Span_Data *data = (Span_Data *)(user_data);
src_fetch fetchfunc = NULL;
RGBA_Comp_Func comp_func;
Span_Data *data = (Span_Data *)(user_data);
src_fetch fetchfunc = NULL;
unsigned int buffer[BLEND_GRADIENT_BUFFER_SIZE], *target, *destbuffer;
int length, l;
if(data->type == LinearGradient) fetchfunc = &fetch_linear_gradient;
if(data->type == RadialGradient) fetchfunc = &fetch_radial_gradient;
//@TODO, Get the proper composition function using ,color, ECTOR_OP etc.
if (data->type == LinearGradient) fetchfunc = &fetch_linear_gradient;
if (data->type == RadialGradient) fetchfunc = &fetch_radial_gradient;
unsigned int buffer[BLEND_GRADIENT_BUFFER_SIZE];
comp_func = ector_comp_func_span_get(data->op, data->mul_col, data->gradient->alpha);
// move to the offset location
unsigned int *destbuffer = data->raster_buffer.buffer + (data->raster_buffer.width * data->offy + data->offx);
// move to the offset location
destbuffer = data->raster_buffer.buffer + ((data->raster_buffer.width * data->offy) + data->offx);
while (count--)
{
unsigned int *target = destbuffer + (data->raster_buffer.width * spans->y + spans->x);
int length = spans->len;
while (length)
{
int l = MIN(length, BLEND_GRADIENT_BUFFER_SIZE);
if (fetchfunc)
fetchfunc(buffer, data, spans->y, spans->x, l);
else
memset(buffer, 0, sizeof(buffer));
if (data->mul_col == 0xffffffff)
_ector_comp_func_source_over(target, buffer, l, spans->coverage); // TODO use proper composition func
else
_ector_comp_func_source_over_mul_c(target, buffer, data->mul_col, l, spans->coverage);
target += l;
length -= l;
}
++spans;
}
while (count--)
{
target = destbuffer + ((data->raster_buffer.width * spans->y) + spans->x);
length = spans->len;
while (length)
{
l = MIN(length, BLEND_GRADIENT_BUFFER_SIZE);
fetchfunc(buffer, data, spans->y, spans->x, l);
comp_func(target, buffer, l, data->mul_col, spans->coverage);
target += l;
length -= l;
}
++spans;
}
}
@ -101,14 +77,18 @@ _blend_gradient(int count, const SW_FT_Span *spans, void *user_data)
spans must be sorted on y
*/
static const
SW_FT_Span *_intersect_spans_rect(const Eina_Rectangle *clip, const SW_FT_Span *spans, const SW_FT_Span *end,
SW_FT_Span **out_spans, int available)
SW_FT_Span *_intersect_spans_rect(const Eina_Rectangle *clip,
const SW_FT_Span *spans,
const SW_FT_Span *end,
SW_FT_Span **out_spans,
int available)
{
SW_FT_Span *out = *out_spans;
const short minx = clip->x;
const short miny = clip->y;
const short maxx = minx + clip->w - 1;
const short maxy = miny + clip->h - 1;
short minx, miny, maxx, maxy;
minx = clip->x;
miny = clip->y;
maxx = minx + clip->w - 1;
maxy = miny + clip->h - 1;
while (available && spans < end )
{
@ -140,129 +120,144 @@ SW_FT_Span *_intersect_spans_rect(const Eina_Rectangle *clip, const SW_FT_Span *
out->coverage = spans->coverage;
++out;
}
++spans;
--available;
}
}
*out_spans = out;
return spans;
*out_spans = out;
return spans;
}
static inline int
_div_255(int x) { return (x + (x>>8) + 0x80) >> 8; }
static const
SW_FT_Span *_intersect_spans_region(const Shape_Rle_Data *clip, int *currentClip,
const SW_FT_Span *spans, const SW_FT_Span *end,
SW_FT_Span **out_spans, int available)
SW_FT_Span *_intersect_spans_region(const Shape_Rle_Data *clip,
int *currentClip,
const SW_FT_Span *spans,
const SW_FT_Span *end,
SW_FT_Span **out_spans,
int available)
{
SW_FT_Span *out = *out_spans;
SW_FT_Span *out = *out_spans;
int sx1, sx2, cx1, cx2, x, len;
const SW_FT_Span *clipSpans = clip->spans + *currentClip;
const SW_FT_Span *clipEnd = clip->spans + clip->size;
const SW_FT_Span *clipSpans = clip->spans + *currentClip;
const SW_FT_Span *clipEnd = clip->spans + clip->size;
while (available && spans < end ) {
if (clipSpans >= clipEnd) {
spans = end;
break;
}
if (clipSpans->y > spans->y) {
++spans;
continue;
}
if (spans->y != clipSpans->y) {
++clipSpans;
continue;
}
while (available && spans < end )
{
if (clipSpans >= clipEnd)
{
spans = end;
break;
}
if (clipSpans->y > spans->y)
{
++spans;
continue;
}
if (spans->y != clipSpans->y)
{
++clipSpans;
continue;
}
//assert(spans->y == clipSpans->y);
sx1 = spans->x;
sx2 = sx1 + spans->len;
cx1 = clipSpans->x;
cx2 = cx1 + clipSpans->len;
int sx1 = spans->x;
int sx2 = sx1 + spans->len;
int cx1 = clipSpans->x;
int cx2 = cx1 + clipSpans->len;
if (cx1 < sx1 && cx2 < sx1)
{
++clipSpans;
continue;
}
else if (sx1 < cx1 && sx2 < cx1)
{
++spans;
continue;
}
x = MAX(sx1, cx1);
len = MIN(sx2, cx2) - x;
if (len)
{
out->x = MAX(sx1, cx1);
out->len = MIN(sx2, cx2) - out->x;
out->y = spans->y;
out->coverage = _div_255(spans->coverage * clipSpans->coverage);
++out;
--available;
}
if (sx2 < cx2)
{
++spans;
}
else
{
++clipSpans;
}
}
if (cx1 < sx1 && cx2 < sx1) {
++clipSpans;
continue;
} else if (sx1 < cx1 && sx2 < cx1) {
++spans;
continue;
}
int x = MAX(sx1, cx1);
int len = MIN(sx2, cx2) - x;
if (len) {
out->x = MAX(sx1, cx1);
out->len = MIN(sx2, cx2) - out->x;
out->y = spans->y;
out->coverage = _div_255(spans->coverage * clipSpans->coverage);
++out;
--available;
}
if (sx2 < cx2) {
++spans;
} else {
++clipSpans;
}
}
*out_spans = out;
*currentClip = clipSpans - clip->spans;
return spans;
*out_spans = out;
*currentClip = clipSpans - clip->spans;
return spans;
}
static void
_span_fill_clipRect(int span_count, const SW_FT_Span *spans, void *user_data)
{
const int NSPANS = 256;
int clip_count, i;
SW_FT_Span cspans[NSPANS];
Span_Data *fill_data = (Span_Data *) user_data;
Clip_Data clip = fill_data->clip;
const int NSPANS = 256;
int clip_count, i;
SW_FT_Span cspans[NSPANS];
Span_Data *fill_data = (Span_Data *) user_data;
Clip_Data clip = fill_data->clip;
SW_FT_Span *clipped;
Eina_Rectangle *rect;
Eina_Rectangle tmp_rect;
clip_count = eina_array_count(clip.clips);
for (i = 0; i < clip_count ; i ++)
{
Eina_Rectangle *rect = (Eina_Rectangle *)eina_array_data_get(clip.clips, i);
Eina_Rectangle tmpRect;
clip_count = eina_array_count(clip.clips);
for (i = 0; i < clip_count; i++)
{
rect = (Eina_Rectangle *)eina_array_data_get(clip.clips, i);
// invert transform the offset
tmpRect.x = rect->x - fill_data->offx;
tmpRect.y = rect->y - fill_data->offy;
tmpRect.w = rect->w;
tmpRect.h = rect->h;
tmp_rect.x = rect->x - fill_data->offx;
tmp_rect.y = rect->y - fill_data->offy;
tmp_rect.w = rect->w;
tmp_rect.h = rect->h;
const SW_FT_Span *end = spans + span_count;
while (spans < end)
{
SW_FT_Span *clipped = cspans;
spans = _intersect_spans_rect(&tmpRect,spans, end, &clipped, NSPANS);
clipped = cspans;
spans = _intersect_spans_rect(&tmp_rect, spans, end, &clipped, NSPANS);
if (clipped - cspans)
fill_data->unclipped_blend(clipped - cspans, cspans, fill_data);
}
}
}
}
static void
_span_fill_clipPath(int span_count, const SW_FT_Span *spans, void *user_data)
{
const int NSPANS = 256;
int current_clip = 0;
SW_FT_Span cspans[NSPANS];
Span_Data *fill_data = (Span_Data *) user_data;
Clip_Data clip = fill_data->clip;
const int NSPANS = 256;
int current_clip = 0;
SW_FT_Span cspans[NSPANS];
Span_Data *fill_data = (Span_Data *) user_data;
Clip_Data clip = fill_data->clip;
SW_FT_Span *clipped;
//TODO take clip path offset into account.
const SW_FT_Span *end = spans + span_count;
while (spans < end)
{
SW_FT_Span *clipped = cspans;
spans = _intersect_spans_region(clip.path, &current_clip, spans, end, &clipped, NSPANS);
if (clipped - cspans)
fill_data->unclipped_blend(clipped - cspans, cspans, fill_data);
}
//TODO take clip path offset into account.
const SW_FT_Span *end = spans + span_count;
while (spans < end)
{
clipped = cspans;
spans = _intersect_spans_region(clip.path, &current_clip, spans, end, &clipped, NSPANS);
if (clipped - cspans)
fill_data->unclipped_blend(clipped - cspans, cspans, fill_data);
}
}
static void
@ -270,19 +265,19 @@ _adjust_span_fill_methods(Span_Data *spdata)
{
switch(spdata->type)
{
case None:
spdata->unclipped_blend = 0;
break;
case Solid:
spdata->unclipped_blend = &_blend_color_argb;
break;
case LinearGradient:
case RadialGradient:
spdata->unclipped_blend = &_blend_gradient;
break;
case Image:
spdata->unclipped_blend = 0;//&_blend_image;
break;
case None:
spdata->unclipped_blend = 0;
break;
case Solid:
spdata->unclipped_blend = &_blend_color_argb;
break;
case LinearGradient:
case RadialGradient:
spdata->unclipped_blend = &_blend_gradient;
break;
case Image:
spdata->unclipped_blend = 0;//&_blend_image;
break;
}
// setup clipping
@ -317,6 +312,7 @@ void ector_software_rasterizer_init(Software_Rasterizer *rasterizer)
rasterizer->fill_data.clip.enabled = EINA_FALSE;
rasterizer->fill_data.unclipped_blend = 0;
rasterizer->fill_data.blend = 0;
init_draw_helper();
}
void ector_software_rasterizer_done(Software_Rasterizer *rasterizer)
@ -325,40 +321,38 @@ void ector_software_rasterizer_done(Software_Rasterizer *rasterizer)
SW_FT_Stroker_Done(rasterizer->stroker);
}
void ector_software_rasterizer_stroke_set(Software_Rasterizer *rasterizer, double width,
Efl_Gfx_Cap cap_style, Efl_Gfx_Join join_style)
{
SW_FT_Stroker_LineCap cap;
SW_FT_Stroker_LineJoin join;
int stroke_width = (int)(width * 64);
switch (cap_style)
{
case EFL_GFX_CAP_SQUARE:
cap = SW_FT_STROKER_LINECAP_SQUARE;
break;
case EFL_GFX_CAP_ROUND:
cap = SW_FT_STROKER_LINECAP_ROUND;
break;
default:
cap = SW_FT_STROKER_LINECAP_BUTT;
break;
case EFL_GFX_CAP_SQUARE:
cap = SW_FT_STROKER_LINECAP_SQUARE;
break;
case EFL_GFX_CAP_ROUND:
cap = SW_FT_STROKER_LINECAP_ROUND;
break;
default:
cap = SW_FT_STROKER_LINECAP_BUTT;
break;
}
switch (join_style)
{
case EFL_GFX_JOIN_BEVEL:
join = SW_FT_STROKER_LINEJOIN_BEVEL;
break;
case EFL_GFX_JOIN_ROUND:
join = SW_FT_STROKER_LINEJOIN_ROUND;
break;
default:
join = SW_FT_STROKER_LINEJOIN_MITER;
break;
case EFL_GFX_JOIN_BEVEL:
join = SW_FT_STROKER_LINEJOIN_BEVEL;
break;
case EFL_GFX_JOIN_ROUND:
join = SW_FT_STROKER_LINEJOIN_ROUND;
break;
default:
join = SW_FT_STROKER_LINEJOIN_MITER;
break;
}
int stroke_width = (int)(width * 64);
SW_FT_Stroker_Set(rasterizer->stroker, stroke_width, cap, join, 0);
}
@ -371,7 +365,7 @@ _rle_generation_cb( int count, const SW_FT_Span* spans,void *user)
// allocate enough memory for new spans
// alloc is required to prevent free and reallocation
// when the rle needs to be regenerated because of attribute change.
if(rle->alloc < newsize)
if (rle->alloc < newsize)
{
rle->spans = (SW_FT_Span *) realloc(rle->spans, newsize * sizeof(SW_FT_Span));
rle->alloc = newsize;
@ -425,18 +419,19 @@ Shape_Rle_Data *
ector_software_rasterizer_generate_stroke_rle_data(Software_Rasterizer *rasterizer, SW_FT_Outline *outline, Eina_Bool closePath)
{
uint points,contors;
Shape_Rle_Data *rle_data;
SW_FT_Outline strokeOutline = { 0, 0, NULL, NULL, NULL, 0 };
SW_FT_Stroker_ParseOutline(rasterizer->stroker, outline, !closePath);
SW_FT_Stroker_GetCounts(rasterizer->stroker,&points, &contors);
SW_FT_Outline strokeOutline = { 0, 0, NULL, NULL, NULL, 0 };
strokeOutline.points = (SW_FT_Vector *) calloc(points, sizeof(SW_FT_Vector));
strokeOutline.tags = (char *) calloc(points, sizeof(char));
strokeOutline.contours = (short *) calloc(contors, sizeof(short));
SW_FT_Stroker_Export(rasterizer->stroker, &strokeOutline);
Shape_Rle_Data *rle_data = ector_software_rasterizer_generate_rle_data(rasterizer, &strokeOutline);
rle_data = ector_software_rasterizer_generate_rle_data(rasterizer, &strokeOutline);
// cleanup the outline data.
free(strokeOutline.points);
@ -503,20 +498,24 @@ void ector_software_rasterizer_color_set(Software_Rasterizer *rasterizer, int r,
rasterizer->fill_data.color = ECTOR_ARGB_JOIN(a, r, g, b);
rasterizer->fill_data.type = Solid;
}
void ector_software_rasterizer_linear_gradient_set(Software_Rasterizer *rasterizer, Ector_Renderer_Software_Gradient_Data *linear)
void ector_software_rasterizer_linear_gradient_set(Software_Rasterizer *rasterizer,
Ector_Renderer_Software_Gradient_Data *linear)
{
rasterizer->fill_data.gradient = linear;
rasterizer->fill_data.type = LinearGradient;
}
void ector_software_rasterizer_radial_gradient_set(Software_Rasterizer *rasterizer, Ector_Renderer_Software_Gradient_Data *radial)
void ector_software_rasterizer_radial_gradient_set(Software_Rasterizer *rasterizer,
Ector_Renderer_Software_Gradient_Data *radial)
{
rasterizer->fill_data.gradient = radial;
rasterizer->fill_data.type = RadialGradient;
}
void ector_software_rasterizer_draw_rle_data(Software_Rasterizer *rasterizer,
int x, int y, uint mul_col, Ector_Rop op, Shape_Rle_Data* rle)
int x, int y, uint mul_col,
Ector_Rop op, Shape_Rle_Data* rle)
{
// check for NULL rle data
if (!rle) return;
@ -529,6 +528,6 @@ void ector_software_rasterizer_draw_rle_data(Software_Rasterizer *rasterizer,
_setup_span_fill_matrix(rasterizer);
_adjust_span_fill_methods(&rasterizer->fill_data);
if(rasterizer->fill_data.blend)
if (rasterizer->fill_data.blend)
rasterizer->fill_data.blend(rle->size, rle->spans, &rasterizer->fill_data);
}