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