move around - flatter.
[profile/ivi/evas.git] / src / lib / engines / common / evas_gradient_main.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #include <math.h>
6
7 #include "evas_common.h"
8 #include "evas_blend_private.h"
9 #include "evas_gradient_private.h"
10
11
12 static void _get_word(char *in, char *key);
13 static void evas_common_gradient_map_argb(RGBA_Draw_Context *dc, RGBA_Gradient *gr, int len);
14 static void evas_common_gradient_map_ahsv(RGBA_Draw_Context *dc, RGBA_Gradient *gr, int len);
15
16 static  int grad_initialised = 0;
17
18 static void
19 _get_word(char *in, char *key)
20 {
21    char  *p, *pp;
22    int    l;
23
24    if (!key) return;
25    *key = 0;
26    if (!in || !*in) return;
27
28    p = in;
29    while (*p && isspace(*p))
30         p++;
31    if (!*p) return;
32    pp = p;
33    while (*pp && !isspace(*pp))
34         pp++;
35    l = pp - p;
36    if (l >= 255) return;
37    *(p + l) = 0;
38    strncpy(key, p, l + 1);
39 }
40
41 static void
42 _evas_common_gradient_stops_free(RGBA_Gradient *gr)
43 {
44    if (!gr) return;
45    if (gr->color.stops)
46      {
47         Evas_Object_List *l;
48
49         while (gr->color.stops)
50           {
51            l = gr->color.stops;
52            gr->color.stops = evas_object_list_remove(gr->color.stops, gr->color.stops);
53            free(l);
54           }
55         gr->color.stops = NULL;
56         gr->color.nstops = 0;
57      }
58    if (gr->alpha.stops)
59      {
60         Evas_Object_List *l;
61
62         while (gr->alpha.stops)
63           {
64            l = gr->alpha.stops;
65            gr->alpha.stops = evas_object_list_remove(gr->alpha.stops, gr->alpha.stops);
66            free(l);
67           }
68         gr->alpha.stops = NULL;
69         gr->alpha.nstops = 0;
70      }
71 }
72
73
74 char *
75 evas_common_gradient_get_key_fval(char *in, char *key, float *val)
76 {
77    char   *p, *pp, sval[256];
78
79    if (!key || !val) return NULL;
80    *key = 0;
81    if (!in || !*in) return NULL;
82    p = strchr(in, '=');
83    if (!p || !*p)  return NULL;
84    *p = 0;  p++;
85    if (!*p)  return NULL;
86    pp = strchr(p, ';');
87    if (!pp || !*pp)  return NULL;
88    _get_word(in, key);
89    if (!*key)  return NULL;
90    *pp = 0;
91    _get_word(p, sval);
92    if (!sval[0])  return NULL;
93    *val = atof(sval);
94    return (pp + 1);
95 }
96
97 EAPI void
98 evas_common_gradient_init(void)
99 {
100    RGBA_Gradient_Type  *geom;
101
102    if (grad_initialised)
103         return;
104    geom = evas_common_gradient_geometer_get("linear");
105    if (geom)
106         geom->init();
107    geom = evas_common_gradient_geometer_get("radial");
108    if (geom)
109         geom->init();
110    geom = evas_common_gradient_geometer_get("rectangular");
111    if (geom)
112         geom->init();
113    geom = evas_common_gradient_geometer_get("angular");
114    if (geom)
115         geom->init();
116    geom = evas_common_gradient_geometer_get("sinusoidal");
117    if (geom)
118         geom->init();
119    grad_initialised = 1;
120 }
121
122 void
123 evas_common_gradient_shutdown(void)
124 {
125    RGBA_Gradient_Type  *geom;
126
127    if (!grad_initialised)
128         return;
129    geom = evas_common_gradient_geometer_get("linear");
130    if (geom)
131         geom->shutdown();
132    geom = evas_common_gradient_geometer_get("radial");
133    if (geom)
134         geom->shutdown();
135    geom = evas_common_gradient_geometer_get("rectangular");
136    if (geom)
137         geom->shutdown();
138    geom = evas_common_gradient_geometer_get("angular");
139    if (geom)
140         geom->shutdown();
141    geom = evas_common_gradient_geometer_get("sinusoidal");
142    if (geom)
143         geom->shutdown();
144    grad_initialised = 0;
145 }
146
147 EAPI RGBA_Gradient *
148 evas_common_gradient_new(void)
149 {
150    RGBA_Gradient *gr;
151
152    gr = calloc(1, sizeof(RGBA_Gradient));
153    gr->references = 1;
154    return gr;
155 }
156
157 EAPI void
158 evas_common_gradient_free(RGBA_Gradient *gr)
159 {
160    if (!gr) return;
161    gr->references--;
162    if (gr->references > 0) return;
163    evas_common_gradient_clear(gr);
164    if (gr->type.name) free(gr->type.name);
165    if (gr->type.params) free(gr->type.params);
166    if (gr->type.geometer && gr->type.gdata)
167         gr->type.geometer->geom_free(gr->type.gdata);
168    if (gr->map.data) free(gr->map.data);
169    free(gr);
170 }
171
172 EAPI void
173 evas_common_gradient_clear(RGBA_Gradient *gr)
174 {
175    if (!gr) return;
176
177    _evas_common_gradient_stops_free(gr);
178
179    if (gr->color.data && !gr->imported_data)
180         free(gr->color.data);
181    gr->color.data = NULL;
182    gr->color.len = 0;
183    if (gr->alpha.data && !gr->imported_data)
184         free(gr->alpha.data);
185    gr->alpha.data = NULL;
186    gr->alpha.len = 0;
187
188    gr->imported_data = 0;
189    gr->has_alpha = 0;
190 }
191
192 EAPI void
193 evas_common_gradient_color_stop_add(RGBA_Gradient *gr, int r, int g, int b, int a, int dist)
194 {
195    RGBA_Gradient_Color_Stop *gc, *gcm, *gc_last;
196
197    if (!gr) return;
198    if (gr->imported_data)
199      {
200         gr->color.data = NULL;
201         gr->color.len = 0;
202         gr->alpha.data = NULL;
203         gr->alpha.len = 0;
204         gr->imported_data = 0;
205         gr->has_alpha = 0;
206      }
207    gc = malloc(sizeof(RGBA_Gradient_Color_Stop));
208    if (!gc) return;
209    if (dist < 1) dist = 1;
210    if (dist > 32768) dist = 32768;
211    if (r < 0) r = 0;  if (r > 255) r = 255;
212    if (g < 0) g = 0;  if (g > 255) g = 255;
213    if (b < 0) b = 0;  if (b > 255) b = 255;
214    if (a < 0) a = 0;  if (a > 255) a = 255;
215    gc->r = r;
216    gc->g = g;
217    gc->b = b;
218    gc->a = a;
219    gc->dist = dist;
220
221    if (!gr->color.stops)
222      {
223         gr->color.stops = evas_object_list_append(gr->color.stops, gc);
224         gr->color.nstops = 1;
225         gr->color.len = 1;
226         if (a < 255)
227            gr->has_alpha = 1;
228         return;
229      }
230    gcm = malloc(sizeof(RGBA_Gradient_Color_Stop));
231    if (!gcm) { free(gc); return; }
232    gc_last = (RGBA_Gradient_Color_Stop *)(gr->color.stops->last);
233    if ((dist + gc_last->dist + gr->color.len) > 65535)
234         { free(gc); free(gcm); return; }
235    gcm->r = (gc_last->r + r) / 2;
236    gcm->g = (gc_last->g + g) / 2;
237    gcm->b = (gc_last->b + b) / 2;
238    gcm->a = (gc_last->a + a) / 2;
239    gcm->dist = dist;
240    gr->color.stops = evas_object_list_append(gr->color.stops, gcm);
241    gr->color.len += gc_last->dist;
242    gr->color.stops = evas_object_list_append(gr->color.stops, gc);
243    gr->color.len += dist;
244    gr->color.nstops += 2;
245    if (a < 255)
246         gr->has_alpha = 1;
247 }
248
249 EAPI void
250 evas_common_gradient_alpha_stop_add(RGBA_Gradient *gr, int a, int dist)
251 {
252    RGBA_Gradient_Alpha_Stop *ga, *gam, *ga_last;
253
254    if (!gr) return;
255    if (gr->imported_data)
256      {
257         gr->color.data = NULL;
258         gr->color.len = 0;
259         gr->alpha.data = NULL;
260         gr->alpha.len = 0;
261         gr->imported_data = 0;
262         gr->has_alpha = 0;
263      }
264    ga = malloc(sizeof(RGBA_Gradient_Alpha_Stop));
265    if (!ga) return;
266    if (dist < 1) dist = 1;
267    if (dist > 32768) dist = 32768;
268    if (a < 0) a = 0;  if (a > 255) a = 255;
269    ga->a = a;
270    ga->dist = dist;
271
272    if (!gr->alpha.stops)
273      {
274         gr->alpha.stops = evas_object_list_append(gr->alpha.stops, ga);
275         gr->alpha.nstops = 1;
276         gr->alpha.len = 1;
277         if (a < 255)
278            gr->has_alpha = 1;
279         return;
280      }
281    gam = malloc(sizeof(RGBA_Gradient_Alpha_Stop));
282    if (!gam) { free(ga); return; }
283    ga_last = (RGBA_Gradient_Alpha_Stop *)(gr->alpha.stops->last);
284    if ((dist + ga_last->dist + gr->alpha.len) > 65535)
285         { free(ga); free(gam); return; }
286    gam->a = (ga_last->a + a) / 2;
287    gam->dist = dist;
288    gr->alpha.stops = evas_object_list_append(gr->alpha.stops, gam);
289    gr->alpha.len += ga_last->dist;
290    gr->alpha.stops = evas_object_list_append(gr->alpha.stops, ga);
291    gr->alpha.len += dist;
292    gr->alpha.nstops += 2;
293    if (a < 255)
294         gr->has_alpha = 1;
295 }
296
297 EAPI void
298 evas_common_gradient_color_data_set(RGBA_Gradient *gr, DATA32 *data, int len, int alpha_flags)
299 {
300    if (!gr) return;
301    if (!gr->imported_data)
302         evas_common_gradient_clear(gr);
303    if (len < 1) data = NULL;
304    if (!data) len = 0;
305    gr->color.data = data;
306    gr->color.len = len;
307    gr->has_alpha = !!alpha_flags;
308    gr->imported_data = 1;
309 }
310
311 EAPI void
312 evas_common_gradient_alpha_data_set(RGBA_Gradient *gr, DATA8 *data, int len)
313 {
314    if (!gr) return;
315    if (!gr->imported_data)
316         evas_common_gradient_clear(gr);
317    if (len < 1) data = NULL;
318    if (!data) len = 0;
319    gr->alpha.data = data;
320    gr->alpha.len = len;
321    gr->has_alpha = 1;
322    gr->imported_data = 1;
323 }
324
325 EAPI void
326 evas_common_gradient_type_set(RGBA_Gradient *gr, const char *name, char *params)
327 {
328    RGBA_Gradient_Type   *geometer;
329
330    if (!gr) return;
331    if (!name || !*name)
332         name = "linear";
333
334    geometer = evas_common_gradient_geometer_get(name);
335    if (!geometer) return;
336    if (gr->type.gdata && (geometer != gr->type.geometer))
337      {
338         if (gr->type.geometer)
339            gr->type.geometer->geom_free(gr->type.gdata);
340         gr->type.gdata = NULL;
341      }
342    gr->type.geometer = geometer;
343
344    if (gr->type.name) free(gr->type.name);
345    gr->type.name = strdup(name);
346
347    if (params && !*params) 
348         params = NULL;
349    if (gr->type.params) free(gr->type.params);
350    gr->type.params = NULL;
351    if (params) gr->type.params = strdup(params);
352
353    gr->type.geometer->geom_init(gr);
354 }
355
356 EAPI void
357 evas_common_gradient_fill_set(RGBA_Gradient *gr, int x, int y, int w, int h)
358 {
359    if (!gr) return;
360    gr->fill.x = x;
361    gr->fill.y = y;
362    if ((w < 1) && (h < 1))
363      { w = h = 1; }
364    gr->fill.w = w;
365    gr->fill.h = h;
366 }
367
368 EAPI void
369 evas_common_gradient_fill_angle_set(RGBA_Gradient *gr, float angle)
370 {
371    if (!gr) return;
372    gr->fill.angle = angle;
373 }
374
375 EAPI void
376 evas_common_gradient_fill_spread_set(RGBA_Gradient *gr, int spread)
377 {
378    if (!gr) return;
379    gr->fill.spread = spread;
380 }
381
382 EAPI void
383 evas_common_gradient_map_offset_set(RGBA_Gradient *gr, float offset)
384 {
385    if (!gr) return;
386    gr->map.offset = offset;
387 }
388
389 EAPI void
390 evas_common_gradient_map_direction_set(RGBA_Gradient *gr, int direction)
391 {
392    if (!gr) return;
393    gr->map.direction = (direction >= 0 ? 1 : -1);
394 }
395
396 EAPI void
397 evas_common_gradient_map_angle_set(RGBA_Gradient *gr, float angle)
398 {
399    if (!gr) return;
400    gr->map.angle = angle;
401 }
402
403 EAPI RGBA_Gradient_Type  *
404 evas_common_gradient_geometer_get(const char *name)
405 {
406    RGBA_Gradient_Type  *geom = NULL;
407
408    if (!name || !*name)
409         name = "linear";
410    if (!strcmp(name,"linear") || !strcmp(name,"linear.diag") || !strcmp(name,"linear.codiag"))
411         geom = evas_common_gradient_linear_get();
412    else if (!strcmp(name,"radial"))
413         geom = evas_common_gradient_radial_get();
414    else if (!strcmp(name,"angular"))
415         geom = evas_common_gradient_angular_get();
416    else if (!strcmp(name,"sinusoidal"))
417         geom = evas_common_gradient_sinusoidal_get();
418    else if (!strcmp(name,"rectangular"))
419         geom = evas_common_gradient_rectangular_get();
420    if (!geom)
421         geom = evas_common_gradient_linear_get();
422    return geom;
423 }
424
425 EAPI void
426 evas_common_gradient_draw(RGBA_Image *dst, RGBA_Draw_Context *dc,
427                           int x, int y, int w, int h, RGBA_Gradient *gr)
428 {
429    Gfx_Func_Gradient_Fill   gfunc;
430    RGBA_Gfx_Func            bfunc;
431    int             len;
432    int             xin, yin, xoff, yoff;
433    int             clx, cly, clw, clh;
434    int             axx, axy, ayx, ayy;
435    DATA32          *pdst, *dst_end, *buf, *map;
436    RGBA_Image      *argb_buf = NULL, *alpha_buf = NULL;
437    DATA8           *mask = NULL;
438    void            *gdata;
439    float           angle;
440    int             direct_copy = 0, buf_step = 0;
441
442    if (!dst || !dc || !gr || !dst || !dst->image.data)
443      return;
444    if (!gr->map.data || !gr->type.geometer)
445      return;
446    if ((gr->fill.w < 1) || (gr->fill.h < 1))
447      return;
448    if ((w < 1) || (h < 1))
449      return;
450    clx = 0;  cly = 0;  clw = dst->cache_entry.w;  clh = dst->cache_entry.h;
451    if ((clw < 1) || (clh < 1))  return;
452
453    if (dc->clip.use)
454      RECTS_CLIP_TO_RECT(clx,cly,clw,clh, dc->clip.x,dc->clip.y,dc->clip.w,dc->clip.h);
455    if ((clw < 1) || (clh < 1))  return;
456
457    xin = x;  yin = y;
458    RECTS_CLIP_TO_RECT(x,y,w,h, clx,cly,clw,clh);
459    if ((w < 1) || (h < 1))  return;
460
461    xoff = (x - xin) - gr->fill.x;
462    yoff = (y - yin) - gr->fill.y;
463
464    if (!gr->type.geometer->has_mask(gr, dc->render_op))
465      {
466         if ((dc->render_op == _EVAS_RENDER_FILL) ||
467             (dc->render_op == _EVAS_RENDER_COPY))
468           {
469              direct_copy = 1;  buf_step = dst->cache_entry.w;
470              if (gr->type.geometer->has_alpha(gr, dc->render_op))
471                 dst->cache_entry.flags.alpha = 1;
472           }
473         else if ((dc->render_op == _EVAS_RENDER_BLEND) &&
474                  !gr->type.geometer->has_alpha(gr, dc->render_op))
475           {
476              direct_copy = 1;  buf_step = dst->cache_entry.w;
477           }
478      }
479
480    if (!direct_copy)
481      {
482         argb_buf = evas_common_image_line_buffer_obtain(w);
483         if (!argb_buf)
484            return;
485         argb_buf->cache_entry.flags.alpha = gr->type.geometer->has_alpha(gr, dc->render_op) ? 1 : 0;
486
487         if (gr->type.geometer->has_mask(gr, dc->render_op))
488           {
489              alpha_buf = evas_common_image_alpha_line_buffer_obtain(w);
490              if (!alpha_buf)
491                {
492                   evas_common_image_line_buffer_release(argb_buf);
493                   return;
494                }
495              bfunc = evas_common_gfx_func_composite_pixel_mask_span_get(argb_buf, dst, w, dc->render_op);
496           }
497         else
498           bfunc = evas_common_gfx_func_composite_pixel_span_get(argb_buf, dst, w, dc->render_op);
499      }
500
501    gfunc = gr->type.geometer->get_fill_func(gr, dc->render_op, dc->anti_alias);
502    gdata = gr->type.gdata;
503    if (!gdata)
504      {
505         if (!direct_copy)
506           {
507             evas_common_image_line_buffer_release(argb_buf);
508             if (alpha_buf)
509                 evas_common_image_alpha_line_buffer_release(alpha_buf);
510           }
511         return;
512      }
513
514    /* I TOLD YOU! this here STOPS the gradeint bugs. it's a missing
515     * emms() before doing floating point operations! the thread pipe code
516     * just brought it out reliably. i swear i had seen this long before i
517     * ever added the thread/pipe code.
518     * 
519     * now here is why it happens. NO drawing function... EXCEPT
520     * evas_common_polygon_draw() and evas_common_gradient_draw() use floating
521     * point for drawing (the poly stuff should really lose it actually), but
522     * nicely nestled in the poly draw code is a evas_common_cpu_end_opt()
523     * before it does any operations that would use floating point. the fact
524     * is the gradient code was LUCKY before without the thread pipes to almost
525     * all the time have another func do a evas_common_cpu_end_opt() before it
526     * was called. that was no longer the case with the thread renderer and
527     * it suffered. that is why on amd systems it seemed to work as i beileve
528     * on amd cpu's the amms done by evas_common_cpu_end_opt() is not needed
529     * to do floatingpoint ops again.
530     * 
531     * after a lot of futzing about - this was the culprit (well axx and axy
532     * were garbage values eventually i found after much debugging and i traced
533     * their garbageness back to here).
534     */
535    evas_common_cpu_end_opt();
536    
537    angle = (gr->fill.angle * M_PI) / 180.0;
538    axx = (cos(angle) * 65536.0);
539    ayy = axx;
540    axy = (sin(angle) * 65536.0);
541    ayx = -axy;
542
543    map = gr->map.data;
544    len = gr->map.len;
545    pdst = dst->image.data + (y * dst->cache_entry.w) + x;
546    dst_end = pdst + (h * dst->cache_entry.w);
547    if (!direct_copy)
548      {
549         buf = argb_buf->image.data;
550         if (alpha_buf)
551           mask = (DATA8 *)alpha_buf->image.data;
552      }
553    else
554      buf = pdst;
555    while (pdst < dst_end)
556      {
557 #ifdef EVAS_SLI
558         if (((yoff + y) % dc->sli.h) == dc->sli.y)
559 #endif
560           {
561              gfunc(map, len, buf, mask, w, xoff, yoff, axx, axy, ayx, ayy, gdata);
562              evas_common_cpu_end_opt();
563              if (!direct_copy)
564                bfunc(buf, mask, 0, pdst, w);
565              evas_common_cpu_end_opt();
566           }
567         buf += buf_step;
568         pdst += dst->cache_entry.w;
569         yoff++;
570      }
571    
572    if (!direct_copy)
573      {
574         evas_common_image_line_buffer_release(argb_buf);
575         if (alpha_buf)
576            evas_common_image_alpha_line_buffer_release(alpha_buf);
577      }
578 }
579
580 static void
581 evas_common_gradient_map_argb(RGBA_Draw_Context *dc, RGBA_Gradient *gr, int len)
582 {
583    DATA32   color;
584    int      mul_use;
585
586    if (!gr || !dc)
587         return;
588    if (len < 1)
589      {
590         if (gr->map.data)
591            free(gr->map.data);
592         gr->map.data = NULL;
593         gr->map.len = 0;
594         return;
595      }
596    if ((len != gr->map.len) || (!gr->map.data))
597         gr->map.data = realloc(gr->map.data, len * sizeof(DATA32));
598    if (!gr->map.data)
599      { gr->map.len = 0; return; }
600    gr->map.len = len;
601    gr->map.has_alpha = gr->has_alpha;
602
603    color = dc->mul.col;
604    mul_use = dc->mul.use;
605    if (dc->mul.col == 0xffffffff)
606         mul_use = 0;
607
608    if ((!gr->imported_data) && (!gr->color.stops) && (!gr->alpha.stops))
609      {
610         static DATA32  p = 0xffffffff;
611
612         gr->color.data = &p;
613         gr->color.len = 1;
614         gr->imported_data = 1;
615         gr->has_alpha = 0;
616      }
617
618    if (gr->color.stops)
619      {
620         Evas_Object_List  *lc;
621         RGBA_Gradient_Color_Stop  *gc, *gc_next;
622         DATA32  *pmap, *map_end;
623         int   i, dii;
624         int   r, g, b, a;
625         int   next_r, next_g, next_b, next_a;
626         int   rr, drr, gg, dgg, bb, dbb, aa, daa;
627         int   mr = 256, mg = 256, mb = 256, ma = 256;
628
629         gr->color.data = realloc(gr->color.data, gr->color.len * sizeof(DATA32));
630         if (!gr->color.data)  return;
631
632         gc = (RGBA_Gradient_Color_Stop *)gr->color.stops;
633         r = gc->r;  g = gc->g;  b = gc->b;  a = gc->a;
634         if (mul_use)
635           {
636             mr = 1 + ((color >> 16) & 0xff);  mg = 1 + ((color >> 8) & 0xff);
637             mb = 1 + ((color) & 0xff);  ma = 1 + (color >> 24);
638             if (ma < 256)
639                gr->map.has_alpha = 1;
640             r = (r * mr) >> 8;  g = (g * mg) >> 8;
641             b = (b * mb) >> 8;  a = (a * ma) >> 8;
642           }
643         lc = gr->color.stops->next;
644         pmap = gr->color.data;  map_end = pmap + gr->color.len;
645
646         while (pmap < map_end)
647           {
648             if (lc)
649               {
650                 i = gc->dist;
651                 dii = 65536 / i;
652                 gc_next = (RGBA_Gradient_Color_Stop *)lc;
653                 next_r = gc_next->r;  next_g = gc_next->g;
654                 next_b = gc_next->b;  next_a = gc_next->a;
655                 if (mul_use)
656                   {
657                     next_r = (next_r * mr) >> 8;  next_g = (next_g * mg) >> 8;
658                     next_b = (next_b * mb) >> 8;  next_a = (next_a * ma) >> 8;
659                   }
660                 rr = r << 16;  drr = ((next_r - r) * dii);
661                 gg = g << 16;  dgg = ((next_g - g) * dii);
662                 bb = b << 16;  dbb = ((next_b - b) * dii);
663                 aa = a << 16;  daa = ((next_a - a) * dii);
664                 while (i--)
665                   {
666                     r = rr >> 16;  r += (rr - (r << 16)) >> 15;
667                     g = gg >> 16;  g += (gg - (g << 16)) >> 15;
668                     b = bb >> 16;  b += (bb - (b << 16)) >> 15;
669                     a = aa >> 16;  a += (aa - (a << 16)) >> 15;
670                     *pmap++ = ARGB_JOIN(a,r,g,b);
671                     rr += drr;  gg += dgg;  bb += dbb;  aa += daa;
672                   }
673                 gc = gc_next;
674                 r = next_r; g = next_g; b = next_b; a = next_a;
675                 lc = lc->next;
676               }
677             else
678                 *pmap++ = ARGB_JOIN(a,r,g,b);
679           }
680      }
681
682    if (gr->alpha.stops)
683      {
684         Evas_Object_List  *lc;
685         RGBA_Gradient_Alpha_Stop  *ga, *ga_next;
686         DATA8  *pamap, *amap_end;
687         int   i, dii;
688         int   a, next_a;
689         int   aa, daa;
690
691         gr->alpha.data = realloc(gr->alpha.data, gr->alpha.len * sizeof(DATA8));
692         if (!gr->alpha.data)  return;
693
694         ga = (RGBA_Gradient_Alpha_Stop *)gr->alpha.stops;
695         a = ga->a;
696         lc = gr->alpha.stops->next;
697         pamap = gr->alpha.data;  amap_end = pamap + gr->alpha.len;
698
699         while (pamap < amap_end)
700           {
701             if (lc)
702               {
703                 i = ga->dist;
704                 dii = 65536 / i;
705                 ga_next = (RGBA_Gradient_Alpha_Stop *)lc;
706                 next_a = ga_next->a;
707                 aa = a << 16;  daa = ((next_a - a) * dii);
708                 while (i--)
709                   {
710                     a = aa >> 16;  a += (aa - (a << 16)) >> 15;
711                     *pamap++ = a;
712                     aa += daa;
713                   }
714                 ga = ga_next;
715                 a = next_a;
716                 lc = lc->next;
717               }
718             else
719                 *pamap++ = a;
720           }
721      }
722
723    if (gr->color.data && gr->alpha.data)
724      {
725         if (!gr->imported_data)
726            color = 0xffffffff;
727         if (gr->color.len == gr->alpha.len)
728           {
729             evas_common_scale_rgba_a8_span(gr->color.data, gr->alpha.data, gr->color.len,
730                                            color, gr->map.data, gr->map.len, gr->map.direction);
731             return;
732           }
733         evas_common_scale_rgba_span(gr->color.data, NULL, gr->color.len,
734                                     color, gr->map.data, gr->map.len, gr->map.direction);
735         evas_common_scale_clip_a8_span(NULL, gr->alpha.data, gr->alpha.len,
736                                         0xffffffff, gr->map.data, gr->map.len, gr->map.direction);
737         return;
738      }
739
740    if (gr->color.data)
741      {
742         if (!gr->imported_data)
743            color = 0xffffffff;
744         evas_common_scale_rgba_span(gr->color.data, NULL, gr->color.len,
745                                     color, gr->map.data, gr->map.len, gr->map.direction);
746         gr->map.has_alpha |= (!!(255 - (color >> 24)));
747         return;
748      }
749         
750    evas_common_scale_a8_span(NULL, gr->alpha.data, gr->alpha.len,
751                              color, gr->map.data, gr->map.len, gr->map.direction);
752 }
753
754 static void
755 evas_common_gradient_map_ahsv(RGBA_Draw_Context *dc, RGBA_Gradient *gr, int len)
756 {
757    DATA32   color;
758
759    if (!gr || !dc)
760         return;
761    if (len < 1)
762      {
763         if (gr->map.data)
764            free(gr->map.data);
765         gr->map.data = NULL;
766         gr->map.len = 0;
767         return;
768      }
769    if ((len != gr->map.len) || (!gr->map.data))
770         gr->map.data = realloc(gr->map.data, len * sizeof(DATA32));
771    if (!gr->map.data)
772      { gr->map.len = 0; return; }
773    gr->map.len = len;
774    gr->map.has_alpha = gr->has_alpha;
775
776    color = dc->mul.col;
777    if (!dc->mul.use)
778         color = 0xffffffff;
779
780    if ((!gr->imported_data) && (!gr->color.stops) && (!gr->alpha.stops))
781      {
782         static DATA32  p = 0xffffffff;
783
784         gr->color.data = &p;
785         gr->color.len = 1;
786         gr->imported_data = 1;
787         gr->has_alpha = 0;
788      }
789
790    if (gr->color.stops)
791      {
792         Evas_Object_List  *lc;
793         RGBA_Gradient_Color_Stop  *gc, *gc_next;
794         DATA32  *pmap, *map_end;
795         int   i, dii;
796         int   h, s, v;
797         int   next_h, next_s, next_v;
798         int   hh, dhh, ss, dss, vv, dvv, aa, daa;
799         int   r, g, b, a;
800         int   next_r, next_g, next_b, next_a;
801
802         gr->color.data = realloc(gr->color.data, gr->color.len * sizeof(DATA32));
803         if (!gr->color.data)  return;
804
805         gc = (RGBA_Gradient_Color_Stop *)gr->color.stops;
806         r = gc->r;  g = gc->g;  b = gc->b;  a = gc->a;
807         evas_common_convert_color_rgb_to_hsv_int(r, g, b, &h, &s, &v);
808
809         lc = gr->color.stops->next;
810         pmap = gr->color.data;  map_end = pmap + gr->color.len;
811
812         while (pmap < map_end)
813           {
814             if (lc)
815               {
816                 i = gc->dist;
817                 dii = 65536 / i;
818                 gc_next = (RGBA_Gradient_Color_Stop *)lc;
819
820                 next_r = gc_next->r;  next_g = gc_next->g;
821                 next_b = gc_next->b;  next_a = gc_next->a;
822                 evas_common_convert_color_rgb_to_hsv_int(next_r, next_g, next_b,
823                                                          &next_h, &next_s, &next_v);
824                 hh = h << 16;  dhh = ((next_h - h) * dii);
825                 ss = s << 16;  dss = ((next_s - s) * dii);
826                 vv = v << 16;  dvv = ((next_v - v) * dii);
827                 aa = a << 16;  daa = ((next_a - a) * dii);
828                 while (i--)
829                   {
830                     h = hh >> 16;  h += (hh - (h << 16)) >> 15;
831                     s = ss >> 16;  s += (ss - (s << 16)) >> 15;
832                     v = vv >> 16;  v += (vv - (v << 16)) >> 15;
833                     a = aa >> 16;  a += (aa - (a << 16)) >> 15;
834                     evas_common_convert_color_hsv_to_rgb_int(h, s, v, &r, &g, &b);
835                     *pmap++ = ARGB_JOIN(a,r,g,b);
836                     hh += dhh;  ss += dss;  vv += dvv;  aa += daa;
837                   }
838                 gc = gc_next;
839                 h = next_h; s = next_s; v = next_v; a = next_a;
840                 lc = lc->next;
841               }
842             else
843                 *pmap++ = ARGB_JOIN(gc->a,gc->r,gc->g,gc->b);
844           }
845      }
846
847    if (gr->alpha.stops)
848      {
849         Evas_Object_List  *lc;
850         RGBA_Gradient_Alpha_Stop  *ga, *ga_next;
851         DATA8  *pamap, *amap_end;
852         int   i, dii;
853         int   a, next_a;
854         int   aa, daa;
855
856         gr->alpha.data = realloc(gr->alpha.data, gr->alpha.len * sizeof(DATA8));
857         if (!gr->alpha.data)  return;
858
859         ga = (RGBA_Gradient_Alpha_Stop *)gr->alpha.stops;
860         a = ga->a;
861         lc = gr->alpha.stops->next;
862         pamap = gr->alpha.data;  amap_end = pamap + gr->alpha.len;
863
864         while (pamap < amap_end)
865           {
866             if (lc)
867               {
868                 i = ga->dist;
869                 dii = 65536 / i;
870                 ga_next = (RGBA_Gradient_Alpha_Stop *)lc;
871                 next_a = ga_next->a;
872                 aa = a << 16;  daa = ((next_a - a) * dii);
873                 while (i--)
874                   {
875                     a = aa >> 16;  a += (aa - (a << 16)) >> 15;
876                     *pamap++ = a;
877                     aa += daa;
878                   }
879                 ga = ga_next;
880                 a = next_a;
881                 lc = lc->next;
882               }
883             else
884                 *pamap++ = a;
885           }
886      }
887
888    if (gr->color.data && gr->alpha.data)
889      {
890         if (gr->color.len == gr->alpha.len)
891           {
892             evas_common_scale_hsva_a8_span(gr->color.data, gr->alpha.data, gr->color.len,
893                                            color, gr->map.data, gr->map.len, gr->map.direction);
894             return;
895           }
896         evas_common_scale_hsva_span(gr->color.data, NULL, gr->color.len,
897                                     color, gr->map.data, gr->map.len, gr->map.direction);
898         evas_common_scale_clip_a8_span(NULL, gr->alpha.data, gr->alpha.len,
899                                         0xffffffff, gr->map.data, gr->map.len, gr->map.direction);
900         return;
901      }
902    if (gr->color.data)
903      {
904         evas_common_scale_hsva_span(gr->color.data, NULL, gr->color.len,
905                                     color, gr->map.data, gr->map.len, gr->map.direction);
906         gr->map.has_alpha |= (!!(255 - (color >> 24)));
907         return;
908      }
909         
910    evas_common_scale_a8_span(NULL, gr->alpha.data, gr->alpha.len,
911                              color, gr->map.data, gr->map.len, gr->map.direction);
912 }
913
914 EAPI void
915 evas_common_gradient_map(RGBA_Draw_Context *dc, RGBA_Gradient *gr, int len)
916 {
917    if (!gr || !dc) return;
918    if (dc->interpolation.color_space == _EVAS_COLOR_SPACE_AHSV)
919      {
920         evas_common_gradient_map_ahsv(dc, gr, len);
921         return;
922      }
923    evas_common_gradient_map_argb(dc, gr, len);
924 }