1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #include <math.h>
6 
7 #include "evas_common_private.h"
8 #include "evas_blend_private.h"
9 
10 typedef struct _RGBA_Span RGBA_Span;
11 typedef struct _RGBA_Edge RGBA_Edge;
12 typedef struct _RGBA_Vertex RGBA_Vertex;
13 
14 struct _RGBA_Span
15 {
16    EINA_INLIST;
17    int x, y, w;
18 };
19 
20 struct _RGBA_Edge
21 {
22    double x, dx;
23    int i;
24 };
25 
26 struct _RGBA_Vertex
27 {
28    double x, y;
29    int i;
30 };
31 
32 #define POLY_EDGE_DEL(_i)                                               \
33 {                                                                       \
34    int _j;                                                              \
35                                                                         \
36    for (_j = 0; (_j < num_active_edges) && (edges[_j].i != _i); _j++);  \
37    if (_j < num_active_edges)                                           \
38      {                                                                  \
39 	num_active_edges--;                                             \
40 	memmove(&(edges[_j]), &(edges[_j + 1]),                         \
41 	        (num_active_edges - _j) * sizeof(RGBA_Edge));           \
42      }                                                                  \
43 }
44 
45 #define POLY_EDGE_ADD(_i, _y)                                           \
46 {                                                                       \
47    int _j;                                                              \
48    float _dx;                                                           \
49    RGBA_Vertex *_p, *_q;                                                \
50    if (_i < (n - 1)) _j = _i + 1;                                       \
51    else _j = 0;                                                         \
52    if (point[_i].y < point[_j].y)                                       \
53      {                                                                  \
54 	_p = &(point[_i]);                                              \
55 	_q = &(point[_j]);                                              \
56      }                                                                  \
57    else                                                                 \
58      {                                                                  \
59 	_p = &(point[_j]);                                              \
60 	_q = &(point[_i]);                                              \
61      }                                                                  \
62    edges[num_active_edges].dx = _dx = (_q->x - _p->x) / (_q->y - _p->y); \
63    edges[num_active_edges].x = (_dx * ((float)_y + 0.5 - _p->y)) + _p->x; \
64    edges[num_active_edges].i = _i;                                      \
65    num_active_edges++;                                                  \
66 }
67 
68 EAPI void
evas_common_polygon_init(void)69 evas_common_polygon_init(void)
70 {
71 }
72 
73 EAPI RGBA_Polygon_Point *
evas_common_polygon_point_add(RGBA_Polygon_Point * points,int x,int y)74 evas_common_polygon_point_add(RGBA_Polygon_Point *points, int x, int y)
75 {
76    RGBA_Polygon_Point *pt;
77 
78    pt = malloc(sizeof(RGBA_Polygon_Point));
79    if (!pt) return points;
80    pt->x = x;
81    pt->y = y;
82    points = (RGBA_Polygon_Point *)eina_inlist_append(EINA_INLIST_GET(points), EINA_INLIST_GET(pt));
83    return points;
84 }
85 
86 EAPI RGBA_Polygon_Point *
evas_common_polygon_points_clear(RGBA_Polygon_Point * points)87 evas_common_polygon_points_clear(RGBA_Polygon_Point *points)
88 {
89    if (points)
90      {
91 	while (points)
92 	  {
93 	     RGBA_Polygon_Point *old_p;
94 
95 	     old_p = points;
96 	     points = (RGBA_Polygon_Point *)eina_inlist_remove(EINA_INLIST_GET(points), EINA_INLIST_GET(points));
97 	     free(old_p);
98 	  }
99      }
100    return NULL;
101 }
102 
103 static int
polygon_point_sorter(const void * a,const void * b)104 polygon_point_sorter(const void *a, const void *b)
105 {
106    RGBA_Vertex *p, *q;
107 
108    p = (RGBA_Vertex *)a;
109    q = (RGBA_Vertex *)b;
110    if (p->y <= q->y) return -1;
111    return 1;
112 }
113 
114 static int
polygon_edge_sorter(const void * a,const void * b)115 polygon_edge_sorter(const void *a, const void *b)
116 {
117    RGBA_Edge *p, *q;
118 
119    p = (RGBA_Edge *)a;
120    q = (RGBA_Edge *)b;
121    if (p->x <= q->x) return -1;
122    return 1;
123 }
124 
125 EAPI void
evas_common_polygon_draw(RGBA_Image * dst,RGBA_Draw_Context * dc,RGBA_Polygon_Point * points,int x,int y)126 evas_common_polygon_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Polygon_Point *points, int x, int y)
127 {
128    RGBA_Gfx_Func      func;
129    RGBA_Polygon_Point *pt;
130    RGBA_Vertex       *point;
131    RGBA_Edge         *edges;
132    Eina_Inlist  *spans;
133    int                num_active_edges;
134    int                n;
135    int                i, j, k;
136    int                yy0, yy1, yi;
137    int                ext_x, ext_y, ext_w, ext_h;
138    int               *sorted_index;
139 
140    if (!dst->image.data) return;
141 #ifdef HAVE_PIXMAN
142 # ifdef PIXMAN_POLY
143    pixman_op_t op = PIXMAN_OP_SRC; // _EVAS_RENDER_COPY
144    if (dc->render_op == _EVAS_RENDER_BLEND)
145      op = PIXMAN_OP_OVER;
146 # endif
147 #endif
148 
149    ext_x = 0;
150    ext_y = 0;
151    ext_w = dst->cache_entry.w;
152    ext_h = dst->cache_entry.h;
153    if (dc->clip.use)
154      {
155 	if (dc->clip.x > ext_x)
156 	  {
157 	     ext_w += ext_x - dc->clip.x;
158 	     ext_x = dc->clip.x;
159 	  }
160 	if ((ext_x + ext_w) > (dc->clip.x + dc->clip.w))
161 	  {
162 	     ext_w = (dc->clip.x + dc->clip.w) - ext_x;
163 	  }
164 	if (dc->clip.y > ext_y)
165 	  {
166 	     ext_h += ext_y - dc->clip.y;
167 	     ext_y = dc->clip.y;
168 	  }
169 	if ((ext_y + ext_h) > (dc->clip.y + dc->clip.h))
170 	  {
171 	     ext_h = (dc->clip.y + dc->clip.h) - ext_y;
172 	  }
173      }
174    if ((ext_w <= 0) || (ext_h <= 0)) return;
175 
176    evas_common_cpu_end_opt();
177 
178    n = 0; EINA_INLIST_FOREACH(points, pt) n++;
179    if (n < 3) return;
180    edges = malloc(sizeof(RGBA_Edge) * n);
181    if (!edges) return;
182    point = malloc(sizeof(RGBA_Vertex) * n);
183    if (!point)
184      {
185 	free(edges);
186 	return;
187      }
188    sorted_index = malloc(sizeof(int) * n);
189    if (!sorted_index)
190      {
191 	free(edges);
192 	free(point);
193 	return;
194      }
195 
196    k = 0;
197    EINA_INLIST_FOREACH(points, pt)
198      {
199 	point[k].x = pt->x + x;
200 	point[k].y = pt->y + y;
201 	point[k].i = k;
202 	k++;
203      }
204    qsort(point, n, sizeof(RGBA_Vertex), polygon_point_sorter);
205    for (k = 0; k < n; k++) sorted_index[k] = point[k].i;
206    k = 0;
207    EINA_INLIST_FOREACH(points, pt)
208      {
209 	point[k].x = pt->x + x;
210 	point[k].y = pt->y + y;
211 	point[k].i = k;
212 	k++;
213      }
214 
215    yy0 = MAX(ext_y, ceil(point[sorted_index[0]].y - 0.5));
216    yy1 = MIN(ext_y + ext_h - 1, floor(point[sorted_index[n - 1]].y - 0.5));
217 
218    k = 0;
219    num_active_edges = 0;
220    spans = NULL;
221 
222    for (yi = yy0; yi <= yy1; yi++)
223      {
224 	for (; (k < n) && (point[sorted_index[k]].y <= ((double)yi + 0.5)); k++)
225 	  {
226 	     i = sorted_index[k];
227 
228 	     if (i > 0) j = i - 1;
229 	     else j = n - 1;
230 	     if (point[j].y <= ((double)yi - 0.5))
231 	       {
232 		  POLY_EDGE_DEL(j)
233 	       }
234 	     else if (point[j].y > ((double)yi + 0.5))
235 	       {
236 		  POLY_EDGE_ADD(j, yi)
237 	       }
238 	     if (i < (n - 1)) j = i + 1;
239 	     else j = 0;
240 	     if (point[j].y <= ((double)yi - 0.5))
241 	       {
242 		  POLY_EDGE_DEL(i)
243 	       }
244 	     else if (point[j].y > ((double)yi + 0.5))
245 	       {
246 		  POLY_EDGE_ADD(i, yi)
247 	       }
248 	  }
249 
250 	qsort(edges, num_active_edges, sizeof(RGBA_Edge), polygon_edge_sorter);
251 
252 	for (j = 0; j < num_active_edges; j += 2)
253 	  {
254 	     int x0, x1;
255 
256 	     x0 = ceil(edges[j].x - 0.5);
257 	     if (j < (num_active_edges - 1))
258 	       x1 = floor(edges[j + 1].x - 0.5);
259 	     else
260 	       x1 = x0;
261 	     if ((x1 >= ext_x) && (x0 < (ext_x + ext_w)) && (x0 <= x1))
262 	       {
263 		  RGBA_Span *span;
264 
265 		  if (x0 < ext_x) x0 = ext_x;
266 		  if (x1 >= (ext_x + ext_w)) x1 = ext_x + ext_w - 1;
267 		  span = malloc(sizeof(RGBA_Span));
268 		  spans = eina_inlist_append(spans, EINA_INLIST_GET(span));
269 		  span->y = yi;
270 		  span->x = x0;
271 		  span->w = (x1 - x0) + 1;
272 	       }
273 	     edges[j].x += edges[j].dx;
274 	     edges[j + 1].x += edges[j + 1].dx;
275 	  }
276      }
277 
278    free(edges);
279    free(point);
280    free(sorted_index);
281 
282    if(dc->clip.mask)
283      func = evas_common_gfx_func_composite_mask_color_span_get(dc->col.col, dst->cache_entry.flags.alpha, 1, dc->render_op);
284    else
285      func = evas_common_gfx_func_composite_color_span_get(dc->col.col, dst->cache_entry.flags.alpha, 1, dc->render_op);
286    if (spans)
287      {
288 	RGBA_Span *span;
289 
290 	EINA_INLIST_FOREACH(spans, span)
291 	  {
292 	     DATA32 *ptr;
293              DATA8 *mask;
294              RGBA_Image *mask_ie;
295 
296 #ifdef HAVE_PIXMAN
297 # ifdef PIXMAN_POLY
298 	     if ((dst->pixman.im) && (dc->col.pixman_color_image))
299 	       pixman_image_composite(op, dc->col.pixman_color_image,
300 				      NULL, dst->pixman.im,
301 				      span->x, span->y, 0, 0,
302 				      span->x, span->y, span->w, 1);
303 	     else
304 # endif
305 #endif
306 	       {
307 		 ptr = dst->image.data + (span->y * (dst->cache_entry.w)) + span->x;
308                   if (dc->clip.mask)
309                     {
310                        mask_ie = dc->clip.mask;
311                        mask = mask_ie->image.data8
312                           + ((span->y - dc->clip.mask_y) * mask_ie->cache_entry.w)
313                           + (span->x - dc->clip.mask_x);
314                        func(NULL, mask, dc->col.col, ptr, span->w);
315                     }
316                   else
317                     func(NULL, NULL, dc->col.col, ptr, span->w);
318 	       }
319           }
320 	while (spans)
321 	  {
322 	     span = (RGBA_Span *)spans;
323 	     spans = eina_inlist_remove(spans, spans);
324 	     free(span);
325 	  }
326      }
327 }
328 
329 EAPI void
evas_common_polygon_rgba_draw(RGBA_Image * dst,int ext_x,int ext_y,int ext_w,int ext_h,DATA32 col,int render_op,RGBA_Polygon_Point * points,int x,int y,RGBA_Image * mask_ie,int mask_x,int mask_y)330 evas_common_polygon_rgba_draw(RGBA_Image *dst, int ext_x, int ext_y, int ext_w, int ext_h, DATA32 col, int render_op, RGBA_Polygon_Point *points, int x, int y, RGBA_Image *mask_ie, int mask_x, int mask_y)
331 {
332    RGBA_Gfx_Func      func;
333    RGBA_Polygon_Point *pt;
334    RGBA_Vertex       *point;
335    RGBA_Edge         *edges;
336    Eina_Inlist  *spans;
337    int                num_active_edges;
338    int                n;
339    int                i, j, k;
340    int                yy0, yy1, yi;
341    int               *sorted_index;
342 
343    if (!dst->image.data) return;
344    if ((ext_w <= 0) || (ext_h <= 0)) return;
345 
346    evas_common_cpu_end_opt();
347 
348    n = 0; EINA_INLIST_FOREACH(points, pt) n++;
349    if (n < 3) return;
350    edges = malloc(sizeof(RGBA_Edge) * n);
351    if (!edges) return;
352    point = malloc(sizeof(RGBA_Vertex) * n);
353    if (!point)
354      {
355 	free(edges);
356 	return;
357      }
358    sorted_index = malloc(sizeof(int) * n);
359    if (!sorted_index)
360      {
361 	free(edges);
362 	free(point);
363 	return;
364      }
365 
366    k = 0;
367    EINA_INLIST_FOREACH(points, pt)
368      {
369 	point[k].x = pt->x + x;
370 	point[k].y = pt->y + y;
371 	point[k].i = k;
372 	k++;
373      }
374    qsort(point, n, sizeof(RGBA_Vertex), polygon_point_sorter);
375    for (k = 0; k < n; k++) sorted_index[k] = point[k].i;
376    k = 0;
377    EINA_INLIST_FOREACH(points, pt)
378      {
379 	point[k].x = pt->x + x;
380 	point[k].y = pt->y + y;
381 	point[k].i = k;
382 	k++;
383      }
384 
385    yy0 = MAX(ext_y, ceil(point[sorted_index[0]].y - 0.5));
386    yy1 = MIN(ext_y + ext_h - 1, floor(point[sorted_index[n - 1]].y - 0.5));
387 
388    k = 0;
389    num_active_edges = 0;
390    spans = NULL;
391 
392    for (yi = yy0; yi <= yy1; yi++)
393      {
394 	for (; (k < n) && (point[sorted_index[k]].y <= ((double)yi + 0.5)); k++)
395 	  {
396 	     i = sorted_index[k];
397 
398 	     if (i > 0) j = i - 1;
399 	     else j = n - 1;
400 	     if (point[j].y <= ((double)yi - 0.5))
401 	       {
402 		  POLY_EDGE_DEL(j)
403 	       }
404 	     else if (point[j].y > ((double)yi + 0.5))
405 	       {
406 		  POLY_EDGE_ADD(j, yi)
407 	       }
408 	     if (i < (n - 1)) j = i + 1;
409 	     else j = 0;
410 	     if (point[j].y <= ((double)yi - 0.5))
411 	       {
412 		  POLY_EDGE_DEL(i)
413 	       }
414 	     else if (point[j].y > ((double)yi + 0.5))
415 	       {
416 		  POLY_EDGE_ADD(i, yi)
417 	       }
418 	  }
419 
420 	qsort(edges, num_active_edges, sizeof(RGBA_Edge), polygon_edge_sorter);
421 
422 	for (j = 0; j < num_active_edges; j += 2)
423 	  {
424 	     int x0, x1;
425 
426 	     x0 = ceil(edges[j].x - 0.5);
427 	     if (j < (num_active_edges - 1))
428 	       x1 = floor(edges[j + 1].x - 0.5);
429 	     else
430 	       x1 = x0;
431 	     if ((x1 >= ext_x) && (x0 < (ext_x + ext_w)) && (x0 <= x1))
432 	       {
433 		  RGBA_Span *span;
434 
435 		  if (x0 < ext_x) x0 = ext_x;
436 		  if (x1 >= (ext_x + ext_w)) x1 = ext_x + ext_w - 1;
437 		  span = malloc(sizeof(RGBA_Span));
438 		  spans = eina_inlist_append(spans, EINA_INLIST_GET(span));
439 		  span->y = yi;
440 		  span->x = x0;
441 		  span->w = (x1 - x0) + 1;
442 	       }
443 	     edges[j].x += edges[j].dx;
444 	     edges[j + 1].x += edges[j + 1].dx;
445 	  }
446      }
447 
448    free(edges);
449    free(point);
450    free(sorted_index);
451 
452    if (mask_ie)
453      func = evas_common_gfx_func_composite_mask_color_span_get(col, dst->cache_entry.flags.alpha, 1, render_op);
454    else
455      func = evas_common_gfx_func_composite_color_span_get(col, dst->cache_entry.flags.alpha, 1, render_op);
456    if (spans)
457      {
458 	RGBA_Span *span;
459         DATA8 *mask;
460 
461 	EINA_INLIST_FOREACH(spans, span)
462 	  {
463 	     DATA32 *ptr;
464 
465              ptr = dst->image.data + (span->y * (dst->cache_entry.w)) + span->x;
466              if (mask_ie)
467                {
468                   mask = mask_ie->image.data8
469                      + ((span->y - mask_y) * mask_ie->cache_entry.w)
470                      + (span->x - mask_x);
471                   func(NULL, mask, col, ptr, span->w);
472                }
473              else
474                func(NULL, NULL, col, ptr, span->w);
475           }
476 	while (spans)
477 	  {
478 	     span = (RGBA_Span *)spans;
479 	     spans = eina_inlist_remove(spans, spans);
480 	     free(span);
481 	  }
482      }
483 }
484