aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/lib/canvas/evas_filter.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/evas/src/lib/canvas/evas_filter.c1427
1 files changed, 1427 insertions, 0 deletions
diff --git a/libraries/evas/src/lib/canvas/evas_filter.c b/libraries/evas/src/lib/canvas/evas_filter.c
new file mode 100644
index 0000000..6194ec2
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_filter.c
@@ -0,0 +1,1427 @@
1/*
2 * Filter implementation for evas
3 */
4
5#if 0 // filtering disabled
6typedef enum
7{
8 /** Apply any filter effects to this object (Default) */
9 EVAS_FILTER_MODE_OBJECT,
10 /** Filter all objects beneath this object on the canvas */
11 EVAS_FILTER_MODE_BELOW,
12} Evas_Filter_Mode;
13typedef enum
14{
15 /** No filter: Default */
16 EVAS_FILTER_NONE,
17 /** A blur filter. Params are quality (float), and radius (int). */
18 EVAS_FILTER_BLUR,
19 /** Negates the colors of an image. Also called solarize */
20 EVAS_FILTER_INVERT,
21 EVAS_FILTER_SOLARIZE = EVAS_FILTER_INVERT,
22 /** Makes a sepia version of the image. */
23 EVAS_FILTER_SEPIA,
24 /** Makes a greyscale version of the image. Params are 'red',
25 * 'green', 'blue' (all floats) which must add to 1. The defaults are
26 * 0.3, 0.59 and 0.11 which approximates human vision. Setting 'all'
27 * sets rgb to the same value. */
28 EVAS_FILTER_GREYSCALE,
29 EVAS_FILTER_GRAYSCALE = EVAS_FILTER_GREYSCALE,
30 /** Brighten (or darken) image. Param 'adjust' float (-1.0 to 1.0)
31 * amount to adjust. */
32 EVAS_FILTER_BRIGHTNESS,
33 /** Enhance contrast on image. Param 'adjust' float (-1.0 to 1.0)
34 * amount to adjust. */
35 EVAS_FILTER_CONTRAST,
36
37 EVAS_FILTER_LAST = EVAS_FILTER_CONTRAST
38} Evas_Filter;
39
40/**
41 * Set the filter mode for an object.
42 *
43 * There are two valid filtering modes currently:
44 * - EVAS_FILTER_MODE_OBJECT: which applies the filter to the object itself
45 * - EVAS_FILTER_MODE_BELOW: which makes the object invisible and filters
46 * what is below the object.
47 *
48 * The default filter mode is EVAS_FILTER_MODE_OBJECT.
49 *
50 * @param o Object to set filter mode on.
51 * @param mode Mode to set.
52 * @return EINA_TRUE on success, EINA_FALSE otherwise.
53 */
54 EAPI Eina_Bool evas_object_filter_mode_set (Evas_Object *o, Evas_Filter_Mode mode);
55
56/**
57 * Get the current filtering mode for an object.
58 *
59 * By default all objects are in object filtering mode, even if no filter is
60 * set.
61 *
62 * @param o Object to get filter mode of.
63 * @return Filter mode (default EVAS_FILTER_MODE_OBJECT)
64 */
65 EAPI Evas_Filter_Mode evas_object_filter_mode_get (Evas_Object *o);
66
67/**
68 * Set the current filter type.
69 *
70 * This sets the filter type, whether a blur, color filter or some other type
71 * of filter. This is normally the only filter call necessary, although some
72 * filters require additional parameters.
73 *
74 * If the object has a filter already, and existing parameters will be
75 * cleared.
76 *
77 * Setting the blur to EVAS_FILTER_NONE removes any filter.
78 *
79 * @param o Object to set the filter on.
80 * @param filter Filter to set.
81 * @return EINA_TRUE On success
82 */
83 EAPI Eina_Bool evas_object_filter_set (Evas_Object *o, Evas_Filter filter);
84
85/**
86 * Get the current filter.
87 *
88 * @param o Object to get filter of.
89 * @return The filter if set, or EVAS_FILTER_NONE.
90 */
91 EAPI Evas_Filter evas_object_filter_get (Evas_Object *o);
92
93/**
94 * Set an integer parameter of a filter.
95 *
96 * This sets an integer parameter of a filter, if such parameter is known to
97 * the filter. Note that some parameters may actually set multiple fields.
98 * The individual filters define the specific parameters available.
99 *
100 * It should be noted that filter parameters are lost after the filter type
101 * changes, so set the filter type, then the parameters.
102 *
103 * @param o Object to set parameter on.
104 * @param param Name of parameter to set.
105 * @param val Value to set.
106 * @return EINA_TRUE if at least one parameter was set, EINA_FALSE
107 * otherwise.
108 */
109 EAPI Eina_Bool evas_object_filter_param_int_set (Evas_Object *o, const char *param, int val);
110
111/**
112 * Get an integer value parameter from a filter.
113 *
114 * Gets the first matching parameter for a filter. Note there is no way to
115 * later fields if they do not have their own accessor name.
116 *
117 * Also note that there is no way to tell the difference between a -1 as a
118 * value, and the error code. Ask your filter writer to use a different
119 * range.
120 *
121 * @param o The object.
122 * @Param param Name of the parameter to get.
123 * @return The value, or -1 on error.
124 */
125 EAPI int evas_object_filter_param_int_get (Evas_Object *o, const char *param);
126
127/**
128 * Set a string parameter on a filter
129 *
130 * Currently unimplemented as no filters use this yet
131 */
132 EAPI Eina_Bool evas_object_filter_param_str_set (Evas_Object *o, const char *param, const char *val);
133
134/**
135 * Get a string parameter from a filter
136 *
137 * Currently unimplemented as no filters use this yet
138 */
139 EAPI const char *evas_object_filter_param_str_get (Evas_Object *o, const char *param);
140
141/**
142 * Set an object parameter on a filter
143 *
144 * Currently unimplemented as no filters use this yet
145 */
146 EAPI Eina_Bool evas_object_filter_param_obj_set (Evas_Object *o, const char *param, Evas_Object *val);
147
148/**
149 * get an object parameter from a filter
150 *
151 * Currently unimplemented as no filters use this yet
152 */
153 EAPI Evas_Object *evas_object_filter_param_obj_get (Evas_Object *o, const char *param);
154
155/**
156 * Set a float parameter of a filter.
157 *
158 * This is the same as evas_object_filter_param_int_set(), but for floating
159 * point values.
160 *
161 * @param o Object to set value on.
162 * @param param Name of the parameter to set.
163 * @param EINA_TRUE if at least one parameter was set, EINA_FALSE otherwise.
164 */
165 EAPI Eina_Bool evas_object_filter_param_float_set(Evas_Object *o, const char *param, double val);
166
167/**
168 * Get a float parameter of a filter.
169 *
170 * This is the same as evas_object_filter_param_int_get(), but for floating
171 * point values.
172 *
173 * @param o Object to set value on.
174 * @param param Name of the parameter to set.
175 * @return The value, or -1 on error.
176 */
177 EAPI double evas_object_filter_param_float_get(Evas_Object *o, const char *param);
178
179#include <stddef.h> // offsetof
180
181#include "evas_common.h"
182#include "evas_private.h"
183
184#include <assert.h>
185/* disable neon - even after fixes:
186 * Error: ARM register expected -- vdup.u32 q14,$0xff000000'
187 * not going to fix now
188#ifdef BUILD_NEON
189# define BUILD_NEON0 1
190#else
191# define BUILD_NEON0 0
192#endif
193*/
194
195#define BUILD_NEON0 0
196
197typedef struct Evas_Filter_Info_Blur
198{
199 double quality;
200 int radius;
201} Evas_Filter_Info_Blur;
202
203typedef struct Evas_Filter_Info_GreyScale
204{
205 double r,g,b;
206} Evas_Filter_Info_GreyScale;
207
208typedef struct Evas_Filter_Info_Brightness
209{
210 double adjust;
211} Evas_Filter_Info_Brightness;
212
213typedef struct Evas_Filter_Info_Contrast
214{
215 double adjust;
216} Evas_Filter_Info_Contrast;
217
218typedef int (*Filter_Size_FN)(Evas_Filter_Info *,int,int,int*,int*,Eina_Bool);
219typedef uint8_t *(*Key_FN)(const Evas_Filter_Info *, uint32_t *);
220
221struct fieldinfo
222{
223 const char *field;
224 int type;
225 size_t offset;
226};
227
228struct filterinfo
229{
230 Evas_Software_Filter_Fn filter;
231 const size_t datasize;
232 Filter_Size_FN sizefn;
233 Key_FN keyfn;
234 Eina_Bool alwaysalpha;
235};
236
237enum
238{
239 TYPE_INT,
240 TYPE_FLOAT
241};
242
243static int blur_size_get(Evas_Filter_Info*, int, int, int *, int *, Eina_Bool);
244static uint8_t *gaussian_key_get(const Evas_Filter_Info *, uint32_t *);
245
246static Eina_Bool gaussian_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
247static Eina_Bool negation_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
248static Eina_Bool sepia_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
249static Eina_Bool greyscale_filter(Evas_Filter_Info*, RGBA_Image*, RGBA_Image*);
250static Eina_Bool brightness_filter(Evas_Filter_Info*, RGBA_Image*, RGBA_Image*);
251static Eina_Bool contrast_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*);
252
253struct filterinfo filterinfo[] =
254{
255 /* None */
256 { NULL, 0, NULL, NULL, EINA_FALSE},
257 /* Blur */
258 { gaussian_filter, sizeof(Evas_Filter_Info_Blur), blur_size_get, gaussian_key_get, EINA_TRUE },
259 /* Negation */
260 { negation_filter, 0, NULL, NULL, EINA_FALSE },
261 /* Sepia */
262 { sepia_filter, 0, NULL, NULL, EINA_FALSE },
263 /* Greyscale */
264 { greyscale_filter, sizeof(Evas_Filter_Info_GreyScale), NULL, NULL, EINA_FALSE },
265 /* Brightness */
266 { brightness_filter, sizeof(Evas_Filter_Info_Brightness), NULL, NULL, EINA_FALSE },
267 /* Contrast */
268 { contrast_filter, sizeof(Evas_Filter_Info_Contrast), NULL, NULL, EINA_FALSE},
269};
270
271
272static struct fieldinfo blurfields[] =
273{
274 { "quality", TYPE_FLOAT, offsetof(Evas_Filter_Info_Blur, quality) },
275 { "radius", TYPE_INT, offsetof(Evas_Filter_Info_Blur, radius) },
276 { NULL, 0, 0 },
277};
278
279static struct fieldinfo greyfields[] =
280{
281 { "red", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, r) },
282 { "green", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, g) },
283 { "blue", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, b) },
284
285 { "all", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, r) },
286 { "all", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, g) },
287 { "all", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, b) },
288 { NULL, 0, 0 },
289};
290
291static struct fieldinfo brightnessfields[] =
292{
293 { "adjust", TYPE_FLOAT, offsetof(Evas_Filter_Info_Brightness, adjust) },
294 { NULL, 0, 0 },
295};
296
297static struct fieldinfo contrastfields[] =
298{
299 { "adjust", TYPE_FLOAT, offsetof(Evas_Filter_Info_Contrast, adjust) },
300 { NULL, 0, 0 },
301};
302
303static struct fieldinfo *filterfields[] =
304{
305 NULL,
306 blurfields,
307 NULL,
308 NULL,
309 greyfields,
310 brightnessfields,
311 contrastfields,
312};
313
314static Evas_Filter_Info *filter_alloc(Evas_Object *o);
315
316EAPI Eina_Bool
317evas_object_filter_mode_set(Evas_Object *o, Evas_Filter_Mode mode)
318{
319 Evas_Filter_Info *info;
320
321 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
322 return EINA_FALSE;
323 MAGIC_CHECK_END();
324
325 if ((mode != EVAS_FILTER_MODE_OBJECT) && (mode != EVAS_FILTER_MODE_BELOW))
326 return EINA_FALSE;
327
328 if (!o->filter)
329 {
330 filter_alloc(o);
331 }
332 if (!o->filter) return EINA_FALSE;
333 info = o->filter;
334
335 if (info->mode == mode) return EINA_TRUE; /* easy case */
336 info->mode = mode;
337 info->dirty = 1;
338 return EINA_TRUE;
339}
340
341EAPI Evas_Filter_Mode
342evas_object_filter_mode_get(Evas_Object *o)
343{
344 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
345 return EVAS_FILTER_MODE_OBJECT;
346 MAGIC_CHECK_END();
347
348 if (!o->filter) return EVAS_FILTER_MODE_OBJECT;
349 return o->filter->mode;
350}
351
352EAPI Eina_Bool
353evas_object_filter_set(Evas_Object *o, Evas_Filter filter)
354{
355 Evas_Filter_Info *info;
356 struct filterinfo *finfo;
357
358 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
359 return EINA_FALSE;
360 MAGIC_CHECK_END();
361
362 /* force filter to be signed: else gcc complains, but enums may always be
363 * signed */
364 if (((int)filter < (int)EVAS_FILTER_NONE) || (filter > EVAS_FILTER_LAST))
365 return EINA_FALSE;
366
367 /* Don't alloc on no-op */
368 if (!o-filter && filter == EVAS_FILTER_NONE) return EINA_TRUE;
369
370 if (!o->filter) filter_alloc(o);
371 if (!o->filter) return EINA_FALSE;
372
373 info = o->filter;
374
375 if (info->filter == filter) return EINA_TRUE;
376
377 finfo = filterinfo + filter;
378 info->filter = filter;
379 info->dirty = 1;
380 if (info->data)
381 {
382 if (info->data_free)
383 info->data_free(info->data);
384 else
385 free(info->data);
386 }
387 info->datalen = finfo->datasize;
388 if (finfo->datasize)
389 {
390 info->data = calloc(1, finfo->datasize);
391 if (!info->data)
392 {
393 o->filter = EVAS_FILTER_NONE;
394 return EINA_FALSE;
395 }
396 }
397 else
398 info->data = NULL;
399 info->data_free = NULL;
400
401 return EINA_TRUE;
402}
403
404EAPI Evas_Filter
405evas_object_filter_get(Evas_Object *o)
406{
407 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
408 return EVAS_FILTER_NONE;
409 MAGIC_CHECK_END();
410
411 if (!o->filter) return EVAS_FILTER_NONE;
412 return o->filter->filter;
413}
414
415EAPI Eina_Bool
416evas_object_filter_param_int_set(Evas_Object *o, const char *param, int val)
417{
418 char *data;
419 const struct fieldinfo *fields;
420 Eina_Bool found;
421 int i;
422
423 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
424 return EINA_FALSE;
425 MAGIC_CHECK_END();
426
427 if ((!o->filter) || (!o->filter->data)) return EINA_FALSE;
428
429 fields = filterfields[o->filter->filter];
430 data = o->filter->data;
431 found = EINA_FALSE;
432 for (i = 0; fields[i].field; i++)
433 {
434 if (!strcmp(fields[i].field, param))
435 {
436 if (fields[i].type != TYPE_INT) continue;
437 *(int *)(data + fields[i].offset) = val;
438 o->filter->dirty = 1;
439 evas_object_change(o);
440 found = EINA_TRUE;
441 }
442 }
443 return found;
444}
445
446EAPI int
447evas_object_filter_param_int_get(Evas_Object *o, const char *param)
448{
449 char *data;
450 const struct fieldinfo *fields;
451 int val;
452 int i;
453
454 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
455 return -1;
456 MAGIC_CHECK_END();
457
458 if ((!o->filter) || (!o->filter->data)) return -1;
459
460 fields = filterfields[o->filter->filter];
461 if (!fields) return -1;
462 data = o->filter->data;
463
464 for (i = 0; fields[i].field; i++)
465 {
466 if (!strcmp(fields[i].field, param))
467 {
468 if (fields[i].type != TYPE_INT) continue;
469 val = *(int *)(data + fields[i].offset);
470 return val;
471 }
472 }
473 return -1;
474}
475
476EAPI Eina_Bool
477evas_object_filter_param_str_set(Evas_Object *o __UNUSED__,
478 const char *param __UNUSED__,
479 const char *val __UNUSED__)
480{
481 return EINA_FALSE;
482}
483
484EAPI const char *
485evas_object_filter_param_str_get(Evas_Object *o __UNUSED__,
486 const char *param __UNUSED__)
487{
488 return NULL;
489}
490
491EAPI Eina_Bool
492evas_object_filter_param_obj_set(Evas_Object *o __UNUSED__,
493 const char *param __UNUSED__,
494 Evas_Object *val __UNUSED__)
495{
496 return EINA_FALSE;
497}
498
499EAPI Evas_Object *
500evas_object_filter_param_obj_get(Evas_Object *o __UNUSED__,
501 const char *param __UNUSED__)
502{
503 return NULL;
504}
505
506EAPI Eina_Bool
507evas_object_filter_param_float_set(Evas_Object *o, const char *param,
508 double val)
509{
510 char *data;
511 const struct fieldinfo *fields;
512 int i;
513 Eina_Bool rv;
514
515 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
516 return EINA_FALSE;
517 MAGIC_CHECK_END();
518
519 if ((!o->filter) || (!o->filter->data)) return EINA_FALSE;
520
521 rv = EINA_FALSE;
522 fields = filterfields[o->filter->filter];
523 if (!fields) return EINA_FALSE;
524
525 data = o->filter->data;
526
527 for (i = 0; fields[i].field; i++)
528 {
529 if (!strcmp(fields[i].field, param))
530 {
531 if (fields[i].type != TYPE_FLOAT) continue;
532 *(double *)(data + fields[i].offset) = val;
533 o->filter->dirty = 1;
534 o->changed = 1;
535 evas_object_change(o);
536 rv = EINA_TRUE;
537 }
538 }
539 return rv;
540}
541
542EAPI double
543evas_object_filter_param_float_get(Evas_Object *o, const char *param)
544{
545 char *data;
546 const struct fieldinfo *fields;
547 double val;
548 int i;
549
550 MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ);
551 return -1;
552 MAGIC_CHECK_END();
553
554 if ((!o->filter) || (!o->filter->data)) return -1;
555
556 fields = filterfields[o->filter->filter];
557 if (!fields) return -1;
558 data = o->filter->data;
559
560 for (i = 0; fields[i].field; i++)
561 {
562 if (!strcmp(fields[i].field, param))
563 {
564 if (fields[i].type != TYPE_FLOAT) continue;
565 val = *(double *)(data + fields[i].offset);
566 return val;
567 }
568 }
569 return -1;
570}
571
572
573
574
575
576/*
577 * Internal call
578 */
579int
580evas_filter_get_size(Evas_Filter_Info *info, int inw, int inh,
581 int *outw, int *outh, Eina_Bool inv)
582{
583 if (!info) return -1;
584 if ((!outw) && (!outh)) return 0;
585
586 if (filterinfo[info->filter].sizefn)
587 return filterinfo[info->filter].sizefn(info, inw, inh, outw, outh, inv);
588
589 if (outw) *outw = inw;
590 if (outh) *outh = inh;
591 return 0;
592}
593
594Eina_Bool
595evas_filter_always_alpha(Evas_Filter_Info *info)
596{
597 if (!info) return EINA_FALSE;
598 return filterinfo[info->filter].alwaysalpha;
599}
600
601/*
602 * Another internal call:
603 * Given a filterinfo, generate a unique key for it
604 *
605 * For simple filters, it's just the filter type.
606 * for more complex filters, it's the type, with it's params.
607 *
608 * Note management of the key data is up to the caller, that is it should
609 * probably be freed after use.
610 *
611 * Note the automatic fallback generation places the single byte at the end so
612 * the memcpy will be aligned. Micro-optimisations FTW!
613 *
614 * @param info Filter info to generate from
615 * @param len Length of the buffer returned.
616 * @return key Key buffer
617 */
618uint8_t *
619evas_filter_key_get(const Evas_Filter_Info *info, uint32_t *lenp)
620{
621 struct filterinfo *finfo;
622 uint8_t *key;
623 int len;
624
625 if (!info) return NULL;
626
627 finfo = filterinfo + info->filter;
628 if (finfo->keyfn) return finfo->keyfn(info, lenp);
629
630 len = 1 + finfo->datasize;
631 key = malloc(len);
632 if (!key) return NULL;
633 if (finfo->datasize) memcpy(key, info->data, finfo->datasize);
634 key[finfo->datasize] = info->filter;
635 if (lenp) *lenp = len;
636 return key;
637}
638
639Evas_Software_Filter_Fn
640evas_filter_software_get(Evas_Filter_Info *info)
641{
642 return filterinfo[info->filter].filter;
643}
644
645void
646evas_filter_free(Evas_Object *o)
647{
648 if (!o->filter) return;
649 if (o->filter->key) free(o->filter->key);
650 free(o->filter);
651 o->filter = NULL;
652}
653
654
655
656
657/*
658 * Private calls
659 */
660static Evas_Filter_Info *
661filter_alloc(Evas_Object *o)
662{
663 Evas_Filter_Info *info;
664
665 if (!o) return NULL;
666 info = calloc(1,sizeof(struct Evas_Filter_Info));
667 if (!info) return NULL;
668 info->dirty = 1;
669 info->filter = EVAS_FILTER_NONE;
670 info->mode = EVAS_FILTER_MODE_OBJECT;
671 info->datalen = 0;
672
673 o->filter = info;
674
675 return info;
676}
677
678static int
679blur_size_get(Evas_Filter_Info *info, int inw, int inh, int *outw, int *outh,
680 Eina_Bool inv)
681{
682 Evas_Filter_Info_Blur *blur = info->data;
683
684 if (inv)
685 {
686 if (outw) *outw = MAX(inw - (blur->radius * 2), 0);
687 if (outh) *outh = MAX(inh - (blur->radius * 2), 0);
688 }
689 else
690 {
691 if (outw) *outw = inw + (blur->radius * 2);
692 if (outh) *outh = inh + (blur->radius * 2);
693 }
694 return 0;
695}
696
697/*
698 * Generate a key for the Gaussian generator.
699 *
700 * The size is:
701 * - 1 byte for the type (blur)
702 * - 1 byte for the quality (0-1 -> 0-255)
703 * - 2 bytes for radius (max is 508 anyway)
704 *
705 * @param info Filter info
706 * @param len Length of the returned buffer
707 * @return new buffer
708 */
709static uint8_t *
710gaussian_key_get(const Evas_Filter_Info *info, uint32_t *lenp)
711{
712 struct Evas_Filter_Info_Blur *blur;
713 uint8_t *key;
714
715 if ((!info) || (!info->data)) return NULL;
716 blur = info->data;
717
718 if (lenp) *lenp = 4;
719 key = malloc(4);
720 if (!key) return NULL;
721 key[0] = EVAS_FILTER_BLUR;
722 key[1] = blur->quality * 255;
723 key[2] = blur->radius >> 8;
724 key[3] = blur->radius;
725
726 return key;
727}
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747/**
748 * Software implementations
749 */
750#define all(OP, A, R, G, B, W, I) \
751 do { \
752 A OP A_VAL(I) * W; \
753 R OP R_VAL(I) * W; \
754 G OP G_VAL(I) * W; \
755 B OP B_VAL(I) * W; \
756 } while (0)
757#define wavg(x,n) (((x) / (n)) & 0xff)
758#define wavgd(x,n) ((uint32_t)((x) / (n)) & 0xff)
759
760typedef int (*FilterH)(int, uint32_t *, int, uint32_t *);
761typedef int (*FilterV)(int, uint32_t *, int, int, uint32_t *);
762
763static int gaussian_filter_h(int rad, uint32_t *in, int w, uint32_t *out);
764static int gaussian_filter_h64(int rad, uint32_t *in, int w, uint32_t *out);
765static int gaussian_filter_hd(int rad, uint32_t *in, int w, uint32_t *out);
766static int gaussian_filter_v(int rad, uint32_t *in, int h, int skip, uint32_t *out);
767static int gaussian_filter_v64(int rad, uint32_t *in, int h, int skip, uint32_t *out);
768static int gaussian_filter_vd(int rad, uint32_t *in, int h, int skip, uint32_t *out);
769static const uint32_t *gaussian_row_get(int row, int *npoints, uint32_t *weight);
770static const uint64_t *gaussian_row_get64(int row, int *npoints, uint64_t *weight);
771static const double *gaussian_row_getd(int row, int *npoints, double *weight);
772
773static Eina_Bool
774gaussian_filter(Evas_Filter_Info *filter, RGBA_Image *src, RGBA_Image *dst)
775{
776 int i;
777 uint32_t nw, nh;
778 uint32_t *in, *tmp, *out;
779 FilterV filter_v = gaussian_filter_v;
780 FilterH filter_h = gaussian_filter_h;
781 Evas_Filter_Info_Blur *blur;
782 int w, h;
783
784 blur = filter->data;
785
786 /* Use 64 bit version if we are going to overflow */
787 if (blur->radius > 508) /** too big for doubles: Bail out */
788 return EINA_FALSE;
789 else if (blur->radius > 28)
790 {
791 filter_v = gaussian_filter_vd;
792 filter_h = gaussian_filter_hd;
793 }
794 else if (blur->radius > 12)
795 {
796 filter_v = gaussian_filter_v64;
797 filter_h = gaussian_filter_h64;
798 }
799
800 w = src->cache_entry.w;
801 h = src->cache_entry.h;
802 in = src->image.data;
803
804 if (!in) return EINA_FALSE;
805
806 nw = w + (2 * blur->radius);
807 nh = h + (2 * blur->radius);
808
809 out = dst->image.data;
810 if (!out) return EINA_FALSE;
811 tmp = malloc(nw * h * sizeof(uint32_t));
812
813 for (i = 0; i < h; i++)
814 filter_h(blur->radius,in + (i * w), w, tmp + (i * nw));
815
816 for (i = 0; i < (int)nw; i++)
817 filter_v(blur->radius,tmp + i, h, nw, out + i);
818
819 free(tmp);
820 return EINA_TRUE;
821}
822
823/* Blur only horizontally */
824static int
825gaussian_filter_h(int rad, uint32_t *in, int w, uint32_t *out)
826{
827 const uint32_t *points;
828 int npoints = 0;
829 uint32_t weight = 0;
830 int i = 0, k = 0;
831 uint32_t r, g, b, a;
832
833 /* Get twice the radius: even rows have 1 element */
834 points = gaussian_row_get(rad * 2, &npoints, &weight);
835 for (i = -rad; i < (w + rad); i++)
836 {
837 r = g = b = a = 0;
838 for (k = -rad; k <= rad; k++)
839 {
840 if ((k + i) < 0) continue;
841 if ((k + i) >= w) continue;
842 all(+=, a, r, g, b, points[k + rad], in + k + i);
843 }
844 *(out) = ARGB_JOIN(wavg(a, weight),
845 wavg(r, weight),
846 wavg(g, weight),
847 wavg(b, weight));
848 out++;
849 }
850 return 0;
851}
852
853/* Blur only horizontally */
854static int
855gaussian_filter_hd(int rad, uint32_t *in, int w, uint32_t *out)
856{
857 const double *points;
858 int npoints = 0;
859 double weight = 0.0;
860 int i = 0, k = 0;
861 double r, g, b, a;
862
863 /* Get twice the radius: even rows have 1 element */
864 points = gaussian_row_getd(rad * 2, &npoints, &weight);
865 for (i = -rad; i < (w + rad); i++)
866 {
867 r = g = b = a = 0;
868 for (k = -rad; k <= rad; k++)
869 {
870 if ((k + i) < 0) continue;
871 if ((k + i) >= w) continue;
872 all(+=, a, r, g, b, points[k + rad], in + k + i);
873 }
874 *(out) = ARGB_JOIN(wavgd(a, weight),
875 wavgd(r, weight),
876 wavgd(g, weight),
877 wavgd(b, weight));
878 out++;
879 }
880 return 0;
881}
882
883
884/* Blur only horizontally */
885static int
886gaussian_filter_h64(int rad, uint32_t *in, int w, uint32_t *out)
887{
888 const uint64_t *points;
889 int npoints = 0;
890 uint64_t weight = 0;
891 int i = 0, k = 0;
892 uint64_t r, g, b, a;
893
894 /* Get twice the radius: even rows have 1 element */
895 points = gaussian_row_get64(rad * 2, &npoints, &weight);
896 for (i = -rad ; i < w + rad; i ++){
897 r = g = b = a = 0;
898 for (k = -rad ; k <= rad ; k ++){
899 if ((k + i) < 0) continue;
900 if ((k + i) >= w) continue;
901 all(+=, a, r, g, b, points[k + rad], in + k + i);
902 }
903 *(out) = ARGB_JOIN(wavg(a, weight),
904 wavg(r, weight),
905 wavg(g, weight),
906 wavg(b, weight));
907 out++;
908 }
909 return 0;
910}
911
912static int
913gaussian_filter_v(int rad, uint32_t *in, int h, int skip, uint32_t *out)
914{
915 const uint32_t *points;
916 int npoints = 0;
917 uint32_t weight = 0;
918 int i = 0, k = 0;
919 uint32_t r, g, b, a;
920
921 /* Get twice the radius: even rows have 1 element */
922 points = gaussian_row_get(rad * 2, &npoints, &weight);
923 weight = 0;
924 for (i = 0; i < npoints; i++) weight += points[i];
925
926 for (i = -rad; i < (h + rad); i++)
927 {
928 r = g = b = a = 0;
929 for (k = -rad; k <= rad; k++)
930 {
931 if ((k + i) < 0) continue;
932 if ((k + i) >= h) continue;
933 all(+=, a, r, g, b, points[k + rad], in + (skip * (k + i)));
934 }
935 *(out) = ARGB_JOIN(wavg(a, weight),
936 wavg(r, weight),
937 wavg(g, weight),
938 wavg(b, weight));
939 out += skip;
940 }
941 return 0;
942}
943
944static int
945gaussian_filter_v64(int rad, uint32_t *in, int h, int skip, uint32_t *out)
946{
947 const uint64_t *points;
948 int npoints = 0;
949 uint64_t weight;
950 int i = 0, k = 0;
951 uint64_t r, g, b, a;
952
953 /* Get twice the radius: even rows have 1 element */
954 points = gaussian_row_get64(rad * 2, &npoints, &weight);
955 weight = 0;
956 for (i = 0; i < npoints; i++) weight += points[i];
957
958 for (i = -rad; i < (h + rad); i++)
959 {
960 r = g = b = a = 0;
961 for (k = -rad ; k <= rad ; k++)
962 {
963 if ((k + i) < 0) continue;
964 if ((k + i) >= h) continue;
965 all(+=, a, r, g, b, points[k + rad], in + (skip * (k + i)));
966 }
967 *(out) = ARGB_JOIN(wavg(a, weight),
968 wavg(r, weight),
969 wavg(g, weight),
970 wavg(b, weight));
971 out += skip;
972 }
973 return 0;
974}
975
976static int
977gaussian_filter_vd(int rad, uint32_t *in, int h, int skip, uint32_t *out)
978{
979 const double *points;
980 int npoints = 0;
981 double weight = 0.0;
982 int i = 0, k = 0;
983 double r, g, b, a;
984
985 /* Get twice the radius: even rows have 1 element */
986 points = gaussian_row_getd(rad * 2, &npoints, &weight);
987 weight = 0;
988 for (i = 0 ; i < npoints ; i ++) weight += points[i];
989
990 for (i = -rad ; i < h + rad; i ++)
991 {
992 r = g = b = a = 0;
993 for (k = -rad ; k <= rad ; k ++)
994 {
995 if ((k + i) < 0) continue;
996 if ((k + i) >= h) continue;
997 all(+=, a, r, g, b, points[k + rad], in + (skip * (k + i)));
998 }
999 *(out) = ARGB_JOIN(wavgd(a, weight),
1000 wavgd(r, weight),
1001 wavgd(g, weight),
1002 wavgd(b, weight));
1003 out += skip;
1004 }
1005 return 0;
1006}
1007
1008static const uint32_t *
1009gaussian_row_get(int row, int *npoints, uint32_t *weight)
1010{
1011 static uint32_t *points = NULL;
1012 static int last = -1;
1013 static uint32_t lastweight = -1;
1014 int c, k;
1015
1016 if (row < 0) return NULL;
1017
1018 if (npoints) *npoints = row + 1;
1019
1020 if (last == row)
1021 {
1022 if (weight) *weight = lastweight;
1023 return points;
1024 }
1025 if (points) free(points);
1026
1027 points = malloc((row + 1) * sizeof(uint32_t));
1028 if (!points)
1029 {
1030 last = -1;
1031 return NULL;
1032 }
1033 last = row;
1034
1035 c = 1;
1036 for (k = 0; k <= row; k++)
1037 {
1038 points[k] = c;
1039 c = c * (row - k) / (k + 1);
1040 }
1041
1042 for (k = 0, lastweight = 0; k <= row; k++) lastweight += points[k];
1043 if (weight) *weight = lastweight;
1044 return points;
1045}
1046
1047static const uint64_t *
1048gaussian_row_get64(int row, int *npoints, uint64_t *weight)
1049{
1050 static uint64_t *points = NULL;
1051 static int last = -1;
1052 static uint64_t lastweight = -1;
1053 uint64_t c;
1054 int k;
1055
1056 if (row < 0) return NULL;
1057
1058 if (npoints) *npoints = row + 1;
1059 if (last == row)
1060 {
1061 if (weight) *weight = lastweight;
1062 return points;
1063 }
1064 if (points) free(points);
1065
1066 points = malloc((row + 1) * sizeof(uint64_t));
1067 if (!points)
1068 {
1069 last = -1;
1070 return NULL;
1071 }
1072 last = row;
1073
1074 c = 1;
1075 for (k = 0; k <= row; k++)
1076 {
1077 points[k] = c;
1078 c = c * (row - k) / (k + 1);
1079 }
1080
1081 for (k = 0, lastweight = 0; k <= row; k ++) lastweight += points[k];
1082 if (weight) *weight = lastweight;
1083
1084 return points;
1085}
1086
1087static const double *
1088gaussian_row_getd(int row, int *npoints, double *weight)
1089{
1090 static double *points = NULL;
1091 static int last = -1;
1092 static double lastweight = -1;
1093 double c;
1094 int k;
1095
1096 if (row < 0) return NULL;
1097
1098 if (last == row)
1099 {
1100 if (weight) *weight = lastweight;
1101 return points;
1102 }
1103
1104 if (points) free(points);
1105 points = malloc((row + 1) * sizeof(double));
1106 if (!points)
1107 {
1108 last = -1;
1109 return NULL;
1110 }
1111 last = row;
1112
1113 if (npoints) *npoints = row + 1;
1114
1115 c = 1;
1116 for (k = 0; k <= row; k++)
1117 {
1118 points[k] = c;
1119 c = c * (row - k) / (k + 1);
1120 }
1121
1122 for (k = 0, lastweight = 0; k <= row; k++) lastweight += points[k];
1123 if (weight) *weight = lastweight;
1124
1125 return points;
1126}
1127
1128#if BUILD_NEON0
1129static Eina_Bool
1130negation_filter_neon(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
1131{
1132 uint32_t tmp;
1133
1134 if (src->cache_entry.flags.alpha)
1135 {
1136 // FIXME: not implemented
1137 }
1138 else
1139 {
1140 /* No alpha */
1141#define AP "NEG_FILTER_NA"
1142 asm volatile (
1143
1144 ".fpu neon \n\t"
1145 "vdup.u32 q14, $0xff000000 \n\t"
1146 "vmvn.u32 q15, q1 \n\t"
1147
1148 // fixme: do check for small loops
1149 AP"loopinit: \n\t"
1150 "sub %[tmp], %[e], #31 \n\t"
1151
1152 AP"loop: \n\t"
1153 "vldm %[s]!, {d0,d1,d2,d3} \n\t"
1154 "vand q2, q0, q15 \n\t"
1155 "vand q3, q1, q15 \n\t"
1156 "vand q4, q0, q14 \n\t"
1157 "vand q5, q1, q14 \n\t"
1158 // fixme: can i do this with xor
1159 "cmp %[tmp], %[s] \n\t"
1160
1161 "vmvn q6, q2 \n\t"
1162 "vmvn q7, q3 \n\t"
1163
1164 "vorr q0, q6,q4 \n\t"
1165 "vorr q1, q7,q5 \n\t"
1166
1167 "vstm %[d]!, {d0,d1,d2,d3} \n\t"
1168
1169 "bhi "AP"loop \n\t"
1170
1171 : // no out
1172 : // input
1173 [e] "r" (src->image.data+ src->cache_entry.w*src->cache_entry.h),
1174 [s] "r" (src->image.data),
1175 [tmp] "r" (tmp),
1176 [d] "r" (dst->image.data)
1177 : "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q14", "q15",
1178 "memory"
1179 );
1180#undef AP
1181 }
1182 return EINA_TRUE;
1183}
1184#endif
1185
1186static Eina_Bool
1187negation_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
1188{
1189 uint32_t *in, *out;
1190 int i,j;
1191 int w,h;
1192 uint32_t a;
1193 uint8_t r,g,b;
1194
1195#if BUILD_NEON0
1196 if (evas_common_cpu_has_feature(CPU_FEATURE_NEON) &&
1197 (!src->cache_entry.flags.alpha))
1198 return negation_filter_neon(info, src, dst);
1199#endif
1200
1201 in = src->image.data;
1202 out = dst->image.data;
1203 w = src->cache_entry.w;
1204 h = src->cache_entry.h;
1205
1206 if (src->cache_entry.flags.alpha)
1207 {
1208 for (i = 0; i < h; i++)
1209 {
1210 for (j = 0; j < w; j++)
1211 {
1212 a = A_VAL(in);
1213 r = R_VAL(in);
1214 g = G_VAL(in);
1215 b = B_VAL(in);
1216 *out = ARGB_JOIN(a, a - r, a - g, a - b);
1217 out++;
1218 in++;
1219 }
1220 }
1221 }
1222 else
1223 {
1224 for (i = 0; i < h; i++)
1225 {
1226 for (j = 0; j < w; j++)
1227 {
1228 a = A_VAL(in);
1229 r = R_VAL(in);
1230 g = G_VAL(in);
1231 b = B_VAL(in);
1232 *out = ARGB_JOIN(a, ~r, ~g, ~b);
1233 out++;
1234 in++;
1235 }
1236 }
1237 }
1238 return EINA_TRUE;
1239 info = NULL;
1240}
1241
1242static Eina_Bool
1243sepia_filter(Evas_Filter_Info *info __UNUSED__, RGBA_Image *src, RGBA_Image *dst)
1244{
1245 uint32_t *in, *out;
1246 int i, j;
1247 int w, h;
1248 uint32_t a, r, g, b, nr, ng, nb;
1249
1250 in = src->image.data;
1251 out = dst->image.data;
1252 w = src->cache_entry.w;
1253 h = src->cache_entry.h;
1254
1255 for (i = 0; i < h; i++)
1256 {
1257 for (j = 0; j < w; j++)
1258 {
1259 a = A_VAL(in);
1260 r = R_VAL(in);
1261 g = G_VAL(in);
1262 b = B_VAL(in);
1263 nr = ((uint32_t)((r * 0.393) + (g * 0.769) + (b * 0.189)));
1264 ng = ((uint32_t)((r * 0.349) + (g * 0.686) + (b * 0.168)));
1265 nb = ((uint32_t)((r * 0.272) + (g * 0.534) + (b * 0.131)));
1266 if (nr > 255) nr = 255;
1267 if (ng > 255) ng = 255;
1268 if (nb > 255) nb = 255;
1269 *out = ARGB_JOIN(a, nr, ng, nb);
1270 out++;
1271 in++;
1272 }
1273 }
1274
1275 return EINA_TRUE;
1276
1277}
1278
1279static Eina_Bool
1280greyscale_filter(Evas_Filter_Info *info __UNUSED__, RGBA_Image *src, RGBA_Image *dst)
1281{
1282 uint32_t *in, *out;
1283 int i, j;
1284 int w, h;
1285 uint32_t cur;
1286 uint32_t a, r, g, b;
1287
1288 in = src->image.data;
1289 out = dst->image.data;
1290 w = src->cache_entry.w;
1291 h = src->cache_entry.h;
1292
1293 if (src->cache_entry.flags.alpha)
1294 {
1295 for (i = 0; i < h; i++)
1296 {
1297 for (j = 0; j < w; j++)
1298 {
1299 a = A_VAL(in);
1300 r = R_VAL(in);
1301 g = G_VAL(in);
1302 b = B_VAL(in);
1303 cur = (r * 0.3) + (g * 0.59) + (b * 0.11);
1304 *out = ARGB_JOIN(a, r, g, b);
1305 out++;
1306 in++;
1307 }
1308 }
1309 }
1310 else
1311 {
1312 for (i = 0 ; i < h ; i ++)
1313 {
1314 for (j = 0; j < w ; j ++)
1315 {
1316 r = R_VAL(in);
1317 g = G_VAL(in);
1318 b = B_VAL(in);
1319 cur = r * 0.3 + g * 0.59 + b * 0.11;
1320 *out = ARGB_JOIN(255, r, g, b);
1321 out++;
1322 in++;
1323 }
1324 }
1325 }
1326 return EINA_TRUE;
1327}
1328
1329static Eina_Bool
1330brightness_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst)
1331{
1332 uint32_t *in, *out;
1333 int i, j;
1334 int w, h;
1335 int a,r,g,b;
1336 int delta;
1337 int adjdelta;
1338 Evas_Filter_Info_Brightness *bness;
1339
1340 in = src->image.data;
1341 out = dst->image.data;
1342 w = src->cache_entry.w;
1343 h = src->cache_entry.h;
1344 bness = info->data;
1345
1346 delta = bness->adjust * 255;
1347 if (delta > 255)
1348 delta = 255;
1349 else if (delta < -255)
1350 delta = -255;
1351
1352 /* Note we could optimise the -255, 0 and 255 cases, but why would people
1353 * be doing that */
1354 if (delta >= 0)
1355 {
1356 for (i = 0; i < h; i++)
1357 {
1358 for (j = 0; j < w; j++)
1359 {
1360 a = A_VAL(in);
1361 r = R_VAL(in);
1362 g = G_VAL(in);
1363 b = B_VAL(in);
1364 adjdelta = (a * delta) >> 8;
1365 r = MIN(r + adjdelta, a);
1366 g = MIN(g + adjdelta, a);
1367 b = MIN(b + adjdelta, a);
1368 *out = ARGB_JOIN(a, r ,g, b);
1369 out++;
1370 in++;
1371 }
1372 }
1373 }
1374 else
1375 {
1376 /* Delta negative */
1377 for (i = 0; i < h; i++)
1378 {
1379 for (j = 0; j < w; j++)
1380 {
1381 a = A_VAL(in);
1382 r = R_VAL(in);
1383 g = G_VAL(in);
1384 b = B_VAL(in);
1385 adjdelta = (a * delta) >> 8;
1386 r = MAX(r + adjdelta, 0);
1387 g = MAX(g + adjdelta, 0);
1388 b = MAX(b + adjdelta, 0);
1389 *out = ARGB_JOIN(a, r ,g, b);
1390 out++;
1391 in++;
1392 }
1393 }
1394 }
1395
1396 return EINA_TRUE;
1397
1398}
1399
1400static Eina_Bool
1401contrast_filter(Evas_Filter_Info *info __UNUSED__, RGBA_Image *src, RGBA_Image *dst)
1402{
1403 uint32_t *in, *out;
1404 int i, j;
1405 int w, h;
1406
1407 in = src->image.data;
1408 out = dst->image.data;
1409 w = src->cache_entry.w;
1410 h = src->cache_entry.h;
1411
1412 for (i = 0; i < h; i++)
1413 {
1414 for (j = 0; j < w; j++)
1415 {
1416 // FIXME: not even implemented
1417 out++;
1418 in++;
1419 }
1420 }
1421
1422 return EINA_TRUE;
1423
1424}
1425#endif
1426
1427/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/