move around - flatter.
[profile/ivi/evas.git] / src / lib / engines / common / evas_gradient_radial.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_gradient_private.h"
9
10
11 typedef struct _Radial_Data   Radial_Data;
12 struct _Radial_Data
13 {
14    float  r0;
15
16    int    sx, sy, s;
17    float  off;
18    int    len;
19 };
20
21 static void
22 radial_init(void);
23
24 static void
25 radial_shutdown(void);
26
27 static void
28 radial_init_geom(RGBA_Gradient *gr);
29
30 static void
31 radial_setup_geom(RGBA_Gradient *gr);
32
33 static void
34 radial_free_geom(void *gdata);
35
36 static int
37 radial_has_alpha(RGBA_Gradient *gr, int op);
38
39 static int
40 radial_has_mask(RGBA_Gradient *gr, int op);
41
42 static int
43 radial_get_map_len(RGBA_Gradient *gr);
44
45 static Gfx_Func_Gradient_Fill
46 radial_get_fill_func(RGBA_Gradient *gr, int op, unsigned char aa);
47
48 static RGBA_Gradient_Type  radial = {"radial", radial_init, radial_shutdown,
49                                      radial_init_geom, radial_setup_geom, radial_free_geom,
50                                      radial_has_alpha, radial_has_mask,
51                                      radial_get_map_len, radial_get_fill_func};
52
53
54 /** internal functions **/
55
56 static void
57 radial_reflect(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
58                        int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
59
60 static void
61 radial_reflect_aa(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
62                           int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
63
64 static void
65 radial_reflect_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
66                               int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
67
68 static void
69 radial_reflect_aa_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
70                                  int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
71
72 static void
73 radial_repeat(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
74                       int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
75
76 static void
77 radial_repeat_aa(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
78                          int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
79
80 static void
81 radial_repeat_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
82                              int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
83
84 static void
85 radial_repeat_aa_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
86                                 int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
87
88 static void
89 radial_restrict_reflect(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
90                                 int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
91
92 static void
93 radial_restrict_reflect_aa(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
94                                    int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
95
96 static void
97 radial_restrict_reflect_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
98                                        int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
99
100 static void
101 radial_restrict_reflect_aa_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
102                                           int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
103
104 static void
105 radial_restrict_repeat(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
106                                int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
107
108 static void
109 radial_restrict_repeat_aa(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
110                                   int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
111
112 static void
113 radial_restrict_repeat_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
114                                       int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
115
116 static void
117 radial_restrict_repeat_aa_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
118                                          int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
119 static void
120 radial_pad(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
121                    int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
122
123 static void
124 radial_pad_aa(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
125                       int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
126
127 static void
128 radial_pad_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
129                           int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
130
131 static void
132 radial_pad_aa_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
133                              int x, int y, int axx, int axy, int ayx, int ayy, void *params_data);
134
135
136 RGBA_Gradient_Type  *
137 evas_common_gradient_radial_get(void)
138 {
139     return &radial;
140 }
141
142 static void
143 radial_init(void)
144 {
145 }
146
147 static void
148 radial_shutdown(void)
149 {
150 }
151
152 static void
153 radial_free_geom(void *gdata)
154 {
155    Radial_Data *data = (Radial_Data *)gdata;
156    if (data) free(data);
157 }
158
159 static void
160 radial_setup_geom(RGBA_Gradient *gr)
161 {
162    Radial_Data   *radial_data;
163
164    if (!gr || (gr->type.geometer != &radial)) return;
165
166    radial_data = (Radial_Data *)gr->type.gdata;
167    if (!radial_data) return;
168    radial_data->sx = gr->fill.w;
169    radial_data->sy = gr->fill.h;
170    radial_data->s = radial_data->sx;
171    if (radial_data->sy > radial_data->sx)
172         radial_data->s = radial_data->sy;
173    radial_data->off = gr->map.offset;
174    radial_data->len = radial_data->s - (int)(radial_data->s * radial_data->r0);
175 }
176
177 static void
178 radial_init_geom(RGBA_Gradient *gr)
179 {
180    Radial_Data   *radial_data;
181    int    err = 1;
182    char   *s, *p, key[256];
183    float  r0;
184
185    if (!gr || (gr->type.geometer != &radial)) return;
186
187    radial_data = (Radial_Data *)gr->type.gdata;
188    if (!radial_data)
189      {
190         radial_data = calloc(1, sizeof(Radial_Data));
191         if (!radial_data)  return;
192         radial_data->r0 = 0.0;
193         radial_data->sx = 32;
194         radial_data->sy = 32;
195         radial_data->s = 32;
196         radial_data->off = 0.0;
197         radial_data->len = 32;
198      }
199    gr->type.gdata = radial_data;
200
201    if (!gr->type.params || !*(gr->type.params))
202         return;
203
204    s = strdup(gr->type.params);
205    if (!s) return;
206
207    r0 = radial_data->r0;
208    p = s;
209    while ((p = evas_common_gradient_get_key_fval(p, key, &r0)))
210      {
211         if (!strcmp(key, "inner_radius"))
212             err = 0;
213         else
214           {
215             err = 1;
216             break;
217           }
218      }
219    if (!err)
220      {
221         if (r0 < 0.0) r0 = 0.0;
222         if (r0 > 1.0) r0 = 1.0;
223         radial_data->r0 = r0;
224      }
225    free(s);
226 }
227
228
229 static int
230 radial_has_alpha(RGBA_Gradient *gr, int op)
231 {
232    Radial_Data   *radial_data;
233
234    if (!gr || (gr->type.geometer != &radial)) return 0;
235    if (gr->has_alpha | gr->map.has_alpha)
236         return 1;
237    if ( (op == _EVAS_RENDER_COPY) || (op == _EVAS_RENDER_COPY_REL) ||
238          (op == _EVAS_RENDER_MASK) || (op == _EVAS_RENDER_MUL) )
239         return 0;
240    radial_data = (Radial_Data *)gr->type.gdata;
241    if (!radial_data) return 0;
242    if (radial_data->r0 > 0)
243         return 1;
244    if ( (gr->fill.spread == _EVAS_TEXTURE_RESTRICT) ||
245          (gr->fill.spread == _EVAS_TEXTURE_RESTRICT_REFLECT) ||
246          (gr->fill.spread == _EVAS_TEXTURE_RESTRICT_REPEAT) )
247         return 1;
248    return 0;
249 }
250
251 static int
252 radial_has_mask(RGBA_Gradient *gr, int op)
253 {
254    Radial_Data   *radial_data;
255
256    if (!gr || (gr->type.geometer != &radial)) return 0;
257    if ( (op == _EVAS_RENDER_COPY) || (op == _EVAS_RENDER_COPY_REL) ||
258          (op == _EVAS_RENDER_MASK) || (op == _EVAS_RENDER_MUL) )
259      {
260         radial_data = (Radial_Data *)gr->type.gdata;
261         if (!radial_data) return 0;
262         if (radial_data->r0 > 0)
263             return 1;
264         if ( (gr->fill.spread == _EVAS_TEXTURE_RESTRICT) ||
265               (gr->fill.spread == _EVAS_TEXTURE_RESTRICT_REFLECT) ||
266               (gr->fill.spread == _EVAS_TEXTURE_RESTRICT_REPEAT) )
267             return 1;
268      }
269    return 0;
270 }
271
272 static int
273 radial_get_map_len(RGBA_Gradient *gr)
274 {
275    Radial_Data   *radial_data;
276
277    if (!gr || (gr->type.geometer != &radial)) return 0;
278    radial_data = (Radial_Data *)gr->type.gdata;
279    if (!radial_data) return 0;
280    return radial_data->len;
281 }
282
283 static Gfx_Func_Gradient_Fill
284 radial_get_fill_func(RGBA_Gradient *gr, int op, unsigned char aa)
285 {
286    Radial_Data   *radial_data;
287    Gfx_Func_Gradient_Fill  sfunc = NULL;
288    int masked_op = 0;
289
290    if (!gr || (gr->type.geometer != &radial)) return sfunc;
291    radial_data = (Radial_Data *)gr->type.gdata;
292    if (!radial_data) return sfunc;
293
294    radial_data->off = gr->map.offset;
295    if ( (op == _EVAS_RENDER_COPY) || (op == _EVAS_RENDER_COPY_REL) ||
296          (op == _EVAS_RENDER_MASK) || (op == _EVAS_RENDER_MUL) )
297         masked_op = 1;
298
299    switch (gr->fill.spread)
300      {
301       case _EVAS_TEXTURE_REFLECT:
302         {
303          if (aa)
304            {
305              if (radial_data->r0 > 0)
306                {
307                 if (masked_op)
308                    sfunc = radial_reflect_aa_masked;
309                 else
310                    sfunc = radial_reflect_aa;
311                }
312              else
313                 sfunc = radial_reflect_aa;
314            }
315          else
316            {
317              if (radial_data->r0 > 0)
318                {
319                 if (masked_op)
320                    sfunc = radial_reflect_masked;
321                 else
322                    sfunc = radial_reflect;
323                }
324              else
325                 sfunc = radial_reflect;
326            }
327         }
328       break;
329       case _EVAS_TEXTURE_REPEAT:
330         {
331          if (aa)
332            {
333              if (radial_data->r0 > 0)
334                {
335                 if (masked_op)
336                    sfunc = radial_repeat_aa_masked;
337                 else
338                    sfunc = radial_repeat_aa;
339                }
340              else
341                 sfunc = radial_repeat_aa;
342            }
343          else
344            {
345              if (radial_data->r0 > 0)
346                {
347                 if (masked_op)
348                    sfunc = radial_repeat_masked;
349                 else
350                    sfunc = radial_repeat;
351                }
352              else
353                 sfunc = radial_repeat;
354            }
355         }
356       break;
357       case _EVAS_TEXTURE_RESTRICT:
358          radial_data->off = 0;
359       case _EVAS_TEXTURE_RESTRICT_REFLECT:
360         {
361          if (aa)
362            {
363              if (masked_op)
364                 sfunc = radial_restrict_reflect_aa_masked;
365              else
366                 sfunc = radial_restrict_reflect_aa;
367            }
368          else
369            {
370              if (masked_op)
371                 sfunc = radial_restrict_reflect_masked;
372              else
373                 sfunc = radial_restrict_reflect;
374            }
375         }
376       break;
377       case _EVAS_TEXTURE_RESTRICT_REPEAT:
378         {
379          if (aa)
380            {
381              if (masked_op)
382                 sfunc = radial_restrict_repeat_aa_masked;
383              else
384                 sfunc = radial_restrict_repeat_aa;
385            }
386          else
387            {
388              if (masked_op)
389                 sfunc = radial_restrict_repeat_masked;
390              else
391                 sfunc = radial_restrict_repeat;
392            }
393         }
394       break;
395       case _EVAS_TEXTURE_PAD:
396         {
397          if (aa)
398            {
399              if (masked_op)
400                 sfunc = radial_pad_aa_masked;
401              else
402                 sfunc = radial_pad_aa;
403            }
404          else
405            {
406              if (masked_op)
407                 sfunc = radial_pad_masked;
408              else
409                 sfunc = radial_pad;
410            }
411         }
412       break;
413       default:
414         sfunc = radial_reflect_aa;
415       break;
416      }
417    return sfunc;
418 }
419
420 #define SETUP_RADIAL_FILL \
421    if (gdata->sx != gdata->s) \
422      { \
423         axx = (gdata->s * axx) / gdata->sx; \
424         axy = (gdata->s * axy) / gdata->sx; \
425      } \
426    if (gdata->sy != gdata->s) \
427      { \
428         ayy = (gdata->s * ayy) / gdata->sy; \
429         ayx = (gdata->s * ayx) / gdata->sy; \
430      } \
431    xx = (axx * x) + (axy * y); \
432    yy = (ayx * x) + (ayy * y); \
433    rr0 = gdata->r0 * gdata->s; \
434    rr0 <<= 16;
435
436
437 static void
438 radial_reflect(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
439                int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
440 {
441    DATA32  *dst_end = dst + dst_len;
442    Radial_Data  *gdata = (Radial_Data *)params_data;
443    int  xx, yy, rr0;
444    int  off = gdata->off * (src_len - 1);
445
446    SETUP_RADIAL_FILL
447
448    while (dst < dst_end)
449      {
450         int  ll = (hypot(xx, yy) - rr0);
451         int  l = (ll >> 16);
452
453         l += (ll - (l << 16)) >> 15;
454         *dst = 0;
455         if (l >= 0)
456           {
457             l += off;
458             if (l < 0) l = -l;
459             if (l >= src_len)
460               {
461                 int  m = (l % (2 * src_len));
462
463                 l = (l % src_len);
464                 if (m >= src_len)
465                     l = src_len - l - 1;
466               }
467             *dst = src[l];
468           }
469         dst++;  xx += axx;  yy += ayx;
470      }
471 }
472
473 static void
474 radial_reflect_aa(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
475                   int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
476 {
477    DATA32  *dst_end = dst + dst_len;
478    Radial_Data  *gdata = (Radial_Data *)params_data;
479    int  xx, yy, rr0;
480    int  off = gdata->off * (src_len - 1);
481
482    SETUP_RADIAL_FILL
483
484    while (dst < dst_end)
485      {
486         int  ll = (hypot(xx, yy) - rr0);
487         int  l = (ll >> 16), lp;
488
489         *dst = 0;
490         if (l >= 0)
491           {
492             DATA32  a = 1 + ((ll - (l << 16)) >> 8), a0 = a;
493
494             lp = l + off;
495             if (lp < 0) { lp = -lp;  a = 257 - a; }
496             if (lp >= src_len)
497               {
498                 int  m = (lp % (2 * src_len));
499
500                 lp = (lp % src_len);
501                 if (m >= src_len)
502                   { lp = src_len - lp - 1;  a = 257 - a; }
503               }
504             *dst = src[lp];
505             if (lp + 1 < src_len)
506                 *dst = INTERP_256(a, src[lp + 1], *dst);
507             if ((l == 0) && rr0)
508                 *dst = MUL_256(a0, *dst);
509           }
510         dst++;  xx += axx;  yy += ayx;
511      }
512 }
513
514 static void
515 radial_reflect_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
516                       int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
517 {
518    DATA32  *dst_end = dst + dst_len;
519    Radial_Data  *gdata = (Radial_Data *)params_data;
520    int  xx, yy, rr0;
521    int  off = gdata->off * (src_len - 1);
522
523    SETUP_RADIAL_FILL
524
525    while (dst < dst_end)
526      {
527         int  ll = (hypot(xx, yy) - rr0);
528         int  l = (ll >> 16);
529
530         l += (ll - (l << 16)) >> 15;
531         *dst = 0;  *mask = 0;
532         if (l >= 0)
533           {
534             l += off;
535             if (l < 0) l = -l;
536             if (l >= src_len)
537               {
538                 int  m = (l % (2 * src_len));
539
540                 l = (l % src_len);
541                 if (m >= src_len)
542                     l = src_len - l - 1;
543               }
544             *dst = src[l];  *mask = 255;
545           }
546         dst++;  mask++;  xx += axx;  yy += ayx;
547      }
548 }
549
550 static void
551 radial_reflect_aa_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
552                          int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
553 {
554    DATA32  *dst_end = dst + dst_len;
555    Radial_Data  *gdata = (Radial_Data *)params_data;
556    int  xx, yy, rr0;
557    int  off = gdata->off * (src_len - 1);
558
559    SETUP_RADIAL_FILL
560
561    while (dst < dst_end)
562      {
563         int  ll = (hypot(xx, yy) - rr0);
564         int  l = (ll >> 16), lp;
565
566         *dst = 0;  *mask = 0;
567         if (l >= 0)
568           {
569             DATA32 a = 1 + ((ll - (l << 16)) >> 8), a0 = a - 1;
570
571             lp = l + off;
572             if (lp < 0) { lp = -lp;  a = 257 - a; }
573             if (lp >= src_len)
574               {
575                 int  m = (lp % (2 * src_len));
576
577                 lp = (lp % src_len);
578                 if (m >= src_len)
579                   { lp = src_len - lp - 1;  a = 257 - a; }
580               }
581             *dst = src[lp];  *mask = 255;
582             if (lp + 1 < src_len)
583                 *dst = INTERP_256(a, src[lp + 1], *dst);
584             if ((l == 0) && rr0)
585                 *mask = a0;
586           }
587         dst++;  mask++;  xx += axx;  yy += ayx;
588      }
589 }
590
591 static void
592 radial_repeat(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
593               int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
594 {
595    DATA32  *dst_end = dst + dst_len;
596    Radial_Data  *gdata = (Radial_Data *)params_data;
597    int  xx, yy, rr0;
598    int  off = gdata->off * (src_len - 1);
599
600    SETUP_RADIAL_FILL
601
602    while (dst < dst_end)
603      {
604         int  ll = (hypot(xx, yy) - rr0);
605         int  l = (ll >> 16);
606
607         l += (ll - (l << 16)) >> 15;
608         *dst = 0;
609         if (l >= 0)
610           {
611             l += off;
612             l = l % src_len;
613             if (l < 0)
614                 l += src_len;
615             *dst = src[l];
616           }
617         dst++;  xx += axx;  yy += ayx;
618      }
619 }
620
621 static void
622 radial_repeat_aa(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
623                  int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
624 {
625    DATA32  *dst_end = dst + dst_len;
626    Radial_Data  *gdata = (Radial_Data *)params_data;
627    int  xx, yy, rr0;
628    int  off = gdata->off * (src_len - 1);
629
630    SETUP_RADIAL_FILL
631
632    while (dst < dst_end)
633      {
634         int  ll = (hypot(xx, yy) - rr0);
635         int  l = (ll >> 16), lp;
636
637         *dst = 0;
638         if (l >= 0)
639           {
640             DATA32 a = 1 + ((ll - (l << 16)) >> 8);
641
642             lp = l + off;
643             lp = lp % src_len;
644             if (lp < 0)
645                 lp += src_len;
646             *dst = src[lp];
647             if (lp + 1 < src_len)
648                 *dst = INTERP_256(a, src[lp + 1], *dst);
649             if (lp == src_len - 1)
650                 *dst = INTERP_256(a, src[0], *dst);
651             if ((l == 0) && rr0)
652                 *dst = MUL_256(a, *dst);
653           }
654         dst++;  xx += axx;  yy += ayx;
655      }
656 }
657
658 static void
659 radial_repeat_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
660                      int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
661 {
662    DATA32  *dst_end = dst + dst_len;
663    Radial_Data  *gdata = (Radial_Data *)params_data;
664    int  xx, yy, rr0;
665    int  off = gdata->off * (src_len - 1);
666
667    SETUP_RADIAL_FILL
668
669    while (dst < dst_end)
670      {
671         int  ll = (hypot(xx, yy) - rr0);
672         int  l = (ll >> 16);
673
674         l += (ll - (l << 16)) >> 15;
675         *dst = 0;  *mask = 0;
676         if (l >= 0)
677           {
678             l += off;
679             l = l % src_len;
680             if (l < 0)
681                 l += src_len;
682             *dst = src[l];  *mask = 255;
683           }
684         dst++;  mask++;  xx += axx;  yy += ayx;
685      }
686 }
687
688 static void
689 radial_repeat_aa_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
690                         int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
691 {
692    DATA32  *dst_end = dst + dst_len;
693    Radial_Data  *gdata = (Radial_Data *)params_data;
694    int  xx, yy, rr0;
695    int  off = gdata->off * (src_len - 1);
696
697    SETUP_RADIAL_FILL
698
699    while (dst < dst_end)
700      {
701         int  ll = (hypot(xx, yy) - rr0);
702         int  l = (ll >> 16), lp;
703
704         *dst = 0;
705         if (l >= 0)
706           {
707             DATA32 a = 1 + ((ll - (l << 16)) >> 8);
708
709             lp = l + off;
710             lp = lp % src_len;
711             if (lp < 0)
712                 lp += src_len;
713             *dst = src[lp];  *mask = 255;
714             if (lp + 1 < src_len)
715                 *dst = INTERP_256(a, src[lp + 1], *dst);
716             if (lp == src_len - 1)
717                 *dst = INTERP_256(a, src[0], *dst);
718             if ((l == 0) && rr0)
719                 *mask = a - 1;
720           }
721         dst++;  mask++;  xx += axx;  yy += ayx;
722      }
723 }
724
725 static void
726 radial_restrict_reflect(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
727                         int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
728 {
729    DATA32  *dst_end = dst + dst_len;
730    Radial_Data  *gdata = (Radial_Data *)params_data;
731    int  xx, yy, rr0;
732    int  off = gdata->off * (src_len - 1);
733
734    SETUP_RADIAL_FILL
735
736    while (dst < dst_end)
737      {
738         int  ll = (hypot(xx, yy) - rr0);
739         int  l = (ll >> 16);
740
741         l += (ll - (l << 16)) >> 15;
742         *dst = 0;
743         if ((unsigned)l < src_len)
744           {
745             l += off;
746             if (l < 0) l = -l;
747             if (l >= src_len)
748               {
749                 int  m = (l % (2 * src_len));
750
751                 l = (l % src_len);
752                 if (m >= src_len)
753                    l = src_len - l - 1;
754               }
755             *dst = src[l];
756           }
757         dst++;  xx += axx;  yy += ayx;
758      }
759 }
760
761 static void
762 radial_restrict_reflect_aa(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
763                            int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
764 {
765    DATA32  *dst_end = dst + dst_len;
766    Radial_Data  *gdata = (Radial_Data *)params_data;
767    int  xx, yy, rr0;
768    int  off = gdata->off * (src_len - 1);
769
770    SETUP_RADIAL_FILL
771
772    while (dst < dst_end)
773      {
774         int  ll = (hypot(xx, yy) - rr0);
775         int  l = (ll >> 16), lp;
776
777         *dst = 0;
778         if ((unsigned)l < src_len)
779           {
780             DATA32 a = 1 + ((ll - (l << 16)) >> 8), a0 = a;
781
782             lp = l + off;
783             if (lp < 0) { lp = -lp;  a = 257 - a; }
784             if (lp >= src_len)
785               {
786                 int  m = (lp % (2 * src_len));
787
788                 lp = (lp % src_len);
789                 if (m >= src_len)
790                   { lp = src_len - lp - 1;  a = 257 - a; }
791               }
792             *dst = src[lp];
793             if (lp + 1 < src_len)
794                 *dst = INTERP_256(a, src[lp + 1], *dst);
795             if (l == (src_len - 1))
796                 *dst = MUL_256(257 - a0, *dst);
797             if ((l == 0) && rr0)
798                 *dst = MUL_256(a0, *dst);
799           }
800         dst++;  xx += axx;  yy += ayx;
801      }
802 }
803
804 static void
805 radial_restrict_reflect_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
806                                int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
807 {
808    DATA32  *dst_end = dst + dst_len;
809    Radial_Data  *gdata = (Radial_Data *)params_data;
810    int  xx, yy, rr0;
811    int  off = gdata->off * (src_len - 1);
812
813    SETUP_RADIAL_FILL
814
815    while (dst < dst_end)
816      {
817         int  ll = (hypot(xx, yy) - rr0);
818         int  l = (ll >> 16);
819
820         l += (ll - (l << 16)) >> 15;
821         *dst = 0;  *mask = 0;
822         if ((unsigned)l < src_len)
823           {
824             l += off;
825             if (l < 0) l = -l;
826             if (l >= src_len)
827               {
828                 int  m = (l % (2 * src_len));
829
830                 l = (l % src_len);
831                 if (m >= src_len)
832                    l = src_len - l - 1;
833               }
834             *dst = src[l];  *mask = 255;
835           }
836         dst++;  mask++;  xx += axx;  yy += ayx;
837      }
838 }
839
840 static void
841 radial_restrict_reflect_aa_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
842                                   int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
843 {
844    DATA32  *dst_end = dst + dst_len;
845    Radial_Data  *gdata = (Radial_Data *)params_data;
846    int  xx, yy, rr0;
847    int  off = gdata->off * (src_len - 1);
848
849    SETUP_RADIAL_FILL
850
851    while (dst < dst_end)
852      {
853         int  ll = (hypot(xx, yy) - rr0);
854         int  l = (ll >> 16), lp;
855
856         *dst = 0;  *mask = 0;
857         if ((unsigned)l < src_len)
858           {
859             DATA32 a = 1 + ((ll - (l << 16)) >> 8), a0 = a - 1;
860
861             lp = l + off;
862             if (lp < 0) { lp = -lp;  a = 257 - a; }
863             if (lp >= src_len)
864               {
865                 int  m = (lp % (2 * src_len));
866
867                 lp = (lp % src_len);
868                 if (m >= src_len)
869                   { lp = src_len - lp - 1;  a = 257 - a; }
870               }
871             *dst = src[lp];  *mask = 255;
872             if (lp + 1 < src_len)
873                 *dst = INTERP_256(a, src[lp + 1], *dst);
874             if (l == (src_len - 1))
875                 *mask = 255 - a0;
876             if ((l == 0) && rr0)
877                 *mask = a0;
878           }
879         dst++;  mask++;  xx += axx;  yy += ayx;
880      }
881 }
882
883 static void
884 radial_restrict_repeat(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
885                        int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
886 {
887    DATA32  *dst_end = dst + dst_len;
888    Radial_Data  *gdata = (Radial_Data *)params_data;
889    int  xx, yy, rr0;
890    int  off = gdata->off * (src_len - 1);
891
892    SETUP_RADIAL_FILL
893
894    while (dst < dst_end)
895      {
896         int  ll = (hypot(xx, yy) - rr0);
897         int  l = (ll >> 16);
898
899         l += (ll - (l << 16)) >> 15;
900         *dst = 0;
901         if ((unsigned)l < src_len)
902           {
903             l += off;
904             l = (l % src_len);
905             if (l < 0)
906                 l += src_len;
907             *dst = src[l];
908           }
909         dst++;  xx += axx;  yy += ayx;
910      }
911 }
912
913 static void
914 radial_restrict_repeat_aa(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
915                           int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
916 {
917    DATA32  *dst_end = dst + dst_len;
918    Radial_Data  *gdata = (Radial_Data *)params_data;
919    int  xx, yy, rr0;
920    int  off = gdata->off * (src_len - 1);
921
922    SETUP_RADIAL_FILL
923
924    while (dst < dst_end)
925      {
926         int  ll = (hypot(xx, yy) - rr0);
927         int  l = (ll >> 16), lp;
928
929         *dst = 0;
930         if ((unsigned)l < src_len)
931           {
932             DATA32 a = 1 + ((ll - (l << 16)) >> 8);
933
934             lp = l + off;
935             lp = (lp % src_len);
936             if (lp < 0)
937                 lp += src_len;
938             *dst = src[lp];
939             if (lp + 1 < src_len)
940                 *dst = INTERP_256(a, src[lp + 1], *dst);
941             if (lp == (src_len - 1))
942                 *dst = INTERP_256(a, src[0], *dst);
943             if (l == (src_len - 1))
944                 *dst = MUL_256(257 - a, *dst);
945             if ((l == 0) && rr0)
946                 *dst = MUL_256(a, *dst);
947           }
948         dst++;  xx += axx;  yy += ayx;
949      }
950 }
951
952 static void
953 radial_restrict_repeat_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
954                               int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
955 {
956    DATA32  *dst_end = dst + dst_len;
957    Radial_Data  *gdata = (Radial_Data *)params_data;
958    int  xx, yy, rr0;
959    int  off = gdata->off * (src_len - 1);
960
961    SETUP_RADIAL_FILL
962
963    while (dst < dst_end)
964      {
965         int  ll = (hypot(xx, yy) - rr0);
966         int  l = (ll >> 16);
967
968         l += (ll - (l << 16)) >> 15;
969         *dst = 0;  *mask = 0;
970         if ((unsigned)l < src_len)
971           {
972             l += off;
973             l = (l % src_len);
974             if (l < 0)
975                 l += src_len;
976             *dst = src[l];  *mask = 255;
977           }
978         dst++;  mask++;  xx += axx;  yy += ayx;
979      }
980 }
981
982 static void
983 radial_restrict_repeat_aa_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
984                                  int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
985 {
986    DATA32  *dst_end = dst + dst_len;
987    Radial_Data  *gdata = (Radial_Data *)params_data;
988    int  xx, yy, rr0;
989    int  off = gdata->off * (src_len - 1);
990
991    SETUP_RADIAL_FILL
992
993    while (dst < dst_end)
994      {
995         int  ll = (hypot(xx, yy) - rr0);
996         int  l = (ll >> 16), lp;
997
998         *dst = 0;  *mask = 0;
999         if ((unsigned)l < src_len)
1000           {
1001             DATA32 a = 1 + ((ll - (l << 16)) >> 8);
1002
1003             lp = l + off;
1004             lp = (lp % src_len);
1005             if (lp < 0)
1006                 lp += src_len;
1007             *dst = src[lp];  *mask = 255;
1008             if (lp + 1 < src_len)
1009                 *dst = INTERP_256(a, src[lp + 1], *dst);
1010             if (lp == (src_len - 1))
1011                 *dst = INTERP_256(a, src[0], *dst);
1012             if (l == (src_len - 1))
1013                 *mask = 256 - a;
1014             if ((l == 0) && rr0)
1015                 *mask = a - 1;
1016           }
1017         dst++;  mask++;  xx += axx;  yy += ayx;
1018      }
1019 }
1020
1021 static void
1022 radial_pad(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
1023            int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
1024 {
1025    DATA32  *dst_end = dst + dst_len;
1026    Radial_Data  *gdata = (Radial_Data *)params_data;
1027    int  xx, yy, rr0;
1028
1029    SETUP_RADIAL_FILL
1030
1031    while (dst < dst_end)
1032      {
1033         int  ll = (hypot(xx, yy) - rr0);
1034         int  l = (ll >> 16);
1035
1036         l += (ll - (l << 16)) >> 15;
1037         *dst = 0;
1038         if (l >= 0)
1039           {
1040             if (l >= src_len)
1041                 l = src_len - 1;
1042             *dst = src[l];
1043           }
1044         dst++;  xx += axx;  yy += ayx;
1045      }
1046 }
1047
1048 static void
1049 radial_pad_aa(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
1050               int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
1051 {
1052    DATA32  *dst_end = dst + dst_len;
1053    Radial_Data  *gdata = (Radial_Data *)params_data;
1054    int  xx, yy, rr0;
1055
1056    SETUP_RADIAL_FILL
1057
1058    while (dst < dst_end)
1059      {
1060         int  ll = (hypot(xx, yy) - rr0);
1061         int  l = (ll >> 16);
1062         DATA32 a = 1 + ((ll - (l << 16)) >> 8);
1063
1064         *dst = 0;
1065         if ((unsigned)l < src_len)
1066           {
1067             *dst = src[l];
1068             if (l + 1 < src_len)
1069                 *dst = INTERP_256(a, src[l + 1], src[l]);
1070           }
1071          if (l == 0)
1072            {
1073              *dst = src[0];
1074              if (rr0)
1075                 *dst = MUL_256(a, *dst);
1076            }
1077          if (l >= src_len)
1078            {
1079              *dst = src[src_len - 1];
1080            }
1081         dst++;  xx += axx;  yy += ayx;
1082      }
1083 }
1084
1085 static void
1086 radial_pad_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
1087                   int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
1088 {
1089    DATA32  *dst_end = dst + dst_len;
1090    Radial_Data  *gdata = (Radial_Data *)params_data;
1091    int  xx, yy, rr0;
1092
1093    SETUP_RADIAL_FILL
1094
1095    while (dst < dst_end)
1096      {
1097         int  ll = (hypot(xx, yy) - rr0);
1098         int  l = (ll >> 16);
1099
1100         l += (ll - (l << 16)) >> 15;
1101         *dst = 0;  *mask = 0;
1102         if (l >= 0)
1103           {
1104             if (l >= src_len)
1105                 l = src_len - 1;
1106             *dst = src[l];  *mask = 255;
1107           }
1108         dst++;  mask++;  xx += axx;  yy += ayx;
1109      }
1110 }
1111
1112 static void
1113 radial_pad_aa_masked(DATA32 *src, int src_len, DATA32 *dst, DATA8 *mask, int dst_len,
1114                      int x, int y, int axx, int axy, int ayx, int ayy, void *params_data)
1115 {
1116    DATA32  *dst_end = dst + dst_len;
1117    Radial_Data  *gdata = (Radial_Data *)params_data;
1118    int  xx, yy, rr0;
1119
1120    SETUP_RADIAL_FILL
1121
1122    while (dst < dst_end)
1123      {
1124         int  ll = (hypot(xx, yy) - rr0);
1125         int  l = (ll >> 16);
1126         DATA32 a = 1 + ((ll - (l << 16)) >> 8);
1127
1128         *dst = 0;  *mask = 0;
1129         if ((unsigned)l < src_len)
1130           {
1131             *dst = src[l];
1132             if (l + 1 < src_len)
1133                 *dst = INTERP_256(a, src[l + 1], src[l]);
1134           }
1135         if (l == 0)
1136           {
1137             *dst = src[0];  *mask = 255;
1138             if (rr0)
1139                 *mask = a - 1;
1140           }
1141         if (l >= src_len)
1142           {
1143             *dst = src[src_len - 1];  *mask = 255;
1144           }
1145         dst++;  mask++;  xx += axx;  yy += ayx;
1146      }
1147 }