--- /dev/null
+#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()
+{
+
+}
#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;
}
}
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;
-
- if(data->type == LinearGradient) fetchfunc = &fetch_linear_gradient;
- if(data->type == RadialGradient) fetchfunc = &fetch_radial_gradient;
-
- unsigned int buffer[BLEND_GRADIENT_BUFFER_SIZE];
-
- // move to the offset location
- unsigned int *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;
- }
+ 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;
+
+ //@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;
+
+ comp_func = ector_comp_func_span_get(data->op, data->mul_col, data->gradient->alpha);
+
+ // move to the offset location
+ destbuffer = data->raster_buffer.buffer + ((data->raster_buffer.width * data->offy) + data->offx);
+
+ 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;
+ }
}
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 )
{
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;
-
- 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;
- }
+ 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;
+
+ 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;
- }
- 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;
+ 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;
+ }
+ }
+
+ *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;
-
- 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;
+ 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++)
+ {
+ 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;
-
- //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, ¤t_clip, spans, end, &clipped, NSPANS);
- if (clipped - cspans)
- fill_data->unclipped_blend(clipped - cspans, cspans, fill_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;
+ SW_FT_Span *clipped;
+
+ //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, ¤t_clip, spans, end, &clipped, NSPANS);
+ if (clipped - cspans)
+ fill_data->unclipped_blend(clipped - cspans, cspans, fill_data);
+ }
}
static void
{
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
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)
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);
}
// 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;
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);
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;
_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);
}