diff options
Diffstat (limited to 'libraries/evas/src/lib/canvas/evas_filter.c')
-rw-r--r-- | libraries/evas/src/lib/canvas/evas_filter.c | 1427 |
1 files changed, 0 insertions, 1427 deletions
diff --git a/libraries/evas/src/lib/canvas/evas_filter.c b/libraries/evas/src/lib/canvas/evas_filter.c deleted file mode 100644 index 6194ec2..0000000 --- a/libraries/evas/src/lib/canvas/evas_filter.c +++ /dev/null | |||
@@ -1,1427 +0,0 @@ | |||
1 | /* | ||
2 | * Filter implementation for evas | ||
3 | */ | ||
4 | |||
5 | #if 0 // filtering disabled | ||
6 | typedef 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; | ||
13 | typedef 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 | |||
197 | typedef struct Evas_Filter_Info_Blur | ||
198 | { | ||
199 | double quality; | ||
200 | int radius; | ||
201 | } Evas_Filter_Info_Blur; | ||
202 | |||
203 | typedef struct Evas_Filter_Info_GreyScale | ||
204 | { | ||
205 | double r,g,b; | ||
206 | } Evas_Filter_Info_GreyScale; | ||
207 | |||
208 | typedef struct Evas_Filter_Info_Brightness | ||
209 | { | ||
210 | double adjust; | ||
211 | } Evas_Filter_Info_Brightness; | ||
212 | |||
213 | typedef struct Evas_Filter_Info_Contrast | ||
214 | { | ||
215 | double adjust; | ||
216 | } Evas_Filter_Info_Contrast; | ||
217 | |||
218 | typedef int (*Filter_Size_FN)(Evas_Filter_Info *,int,int,int*,int*,Eina_Bool); | ||
219 | typedef uint8_t *(*Key_FN)(const Evas_Filter_Info *, uint32_t *); | ||
220 | |||
221 | struct fieldinfo | ||
222 | { | ||
223 | const char *field; | ||
224 | int type; | ||
225 | size_t offset; | ||
226 | }; | ||
227 | |||
228 | struct 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 | |||
237 | enum | ||
238 | { | ||
239 | TYPE_INT, | ||
240 | TYPE_FLOAT | ||
241 | }; | ||
242 | |||
243 | static int blur_size_get(Evas_Filter_Info*, int, int, int *, int *, Eina_Bool); | ||
244 | static uint8_t *gaussian_key_get(const Evas_Filter_Info *, uint32_t *); | ||
245 | |||
246 | static Eina_Bool gaussian_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*); | ||
247 | static Eina_Bool negation_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*); | ||
248 | static Eina_Bool sepia_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*); | ||
249 | static Eina_Bool greyscale_filter(Evas_Filter_Info*, RGBA_Image*, RGBA_Image*); | ||
250 | static Eina_Bool brightness_filter(Evas_Filter_Info*, RGBA_Image*, RGBA_Image*); | ||
251 | static Eina_Bool contrast_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*); | ||
252 | |||
253 | struct 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 | |||
272 | static 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 | |||
279 | static 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 | |||
291 | static struct fieldinfo brightnessfields[] = | ||
292 | { | ||
293 | { "adjust", TYPE_FLOAT, offsetof(Evas_Filter_Info_Brightness, adjust) }, | ||
294 | { NULL, 0, 0 }, | ||
295 | }; | ||
296 | |||
297 | static struct fieldinfo contrastfields[] = | ||
298 | { | ||
299 | { "adjust", TYPE_FLOAT, offsetof(Evas_Filter_Info_Contrast, adjust) }, | ||
300 | { NULL, 0, 0 }, | ||
301 | }; | ||
302 | |||
303 | static struct fieldinfo *filterfields[] = | ||
304 | { | ||
305 | NULL, | ||
306 | blurfields, | ||
307 | NULL, | ||
308 | NULL, | ||
309 | greyfields, | ||
310 | brightnessfields, | ||
311 | contrastfields, | ||
312 | }; | ||
313 | |||
314 | static Evas_Filter_Info *filter_alloc(Evas_Object *o); | ||
315 | |||
316 | EAPI Eina_Bool | ||
317 | evas_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 | |||
341 | EAPI Evas_Filter_Mode | ||
342 | evas_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 | |||
352 | EAPI Eina_Bool | ||
353 | evas_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 | |||
404 | EAPI Evas_Filter | ||
405 | evas_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 | |||
415 | EAPI Eina_Bool | ||
416 | evas_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 | |||
446 | EAPI int | ||
447 | evas_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 | |||
476 | EAPI Eina_Bool | ||
477 | evas_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 | |||
484 | EAPI const char * | ||
485 | evas_object_filter_param_str_get(Evas_Object *o __UNUSED__, | ||
486 | const char *param __UNUSED__) | ||
487 | { | ||
488 | return NULL; | ||
489 | } | ||
490 | |||
491 | EAPI Eina_Bool | ||
492 | evas_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 | |||
499 | EAPI Evas_Object * | ||
500 | evas_object_filter_param_obj_get(Evas_Object *o __UNUSED__, | ||
501 | const char *param __UNUSED__) | ||
502 | { | ||
503 | return NULL; | ||
504 | } | ||
505 | |||
506 | EAPI Eina_Bool | ||
507 | evas_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 | |||
542 | EAPI double | ||
543 | evas_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 | */ | ||
579 | int | ||
580 | evas_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 | |||
594 | Eina_Bool | ||
595 | evas_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 | */ | ||
618 | uint8_t * | ||
619 | evas_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 | |||
639 | Evas_Software_Filter_Fn | ||
640 | evas_filter_software_get(Evas_Filter_Info *info) | ||
641 | { | ||
642 | return filterinfo[info->filter].filter; | ||
643 | } | ||
644 | |||
645 | void | ||
646 | evas_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 | */ | ||
660 | static Evas_Filter_Info * | ||
661 | filter_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 | |||
678 | static int | ||
679 | blur_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 | */ | ||
709 | static uint8_t * | ||
710 | gaussian_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 | |||
760 | typedef int (*FilterH)(int, uint32_t *, int, uint32_t *); | ||
761 | typedef int (*FilterV)(int, uint32_t *, int, int, uint32_t *); | ||
762 | |||
763 | static int gaussian_filter_h(int rad, uint32_t *in, int w, uint32_t *out); | ||
764 | static int gaussian_filter_h64(int rad, uint32_t *in, int w, uint32_t *out); | ||
765 | static int gaussian_filter_hd(int rad, uint32_t *in, int w, uint32_t *out); | ||
766 | static int gaussian_filter_v(int rad, uint32_t *in, int h, int skip, uint32_t *out); | ||
767 | static int gaussian_filter_v64(int rad, uint32_t *in, int h, int skip, uint32_t *out); | ||
768 | static int gaussian_filter_vd(int rad, uint32_t *in, int h, int skip, uint32_t *out); | ||
769 | static const uint32_t *gaussian_row_get(int row, int *npoints, uint32_t *weight); | ||
770 | static const uint64_t *gaussian_row_get64(int row, int *npoints, uint64_t *weight); | ||
771 | static const double *gaussian_row_getd(int row, int *npoints, double *weight); | ||
772 | |||
773 | static Eina_Bool | ||
774 | gaussian_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 */ | ||
824 | static int | ||
825 | gaussian_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 */ | ||
854 | static int | ||
855 | gaussian_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 */ | ||
885 | static int | ||
886 | gaussian_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 | |||
912 | static int | ||
913 | gaussian_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 | |||
944 | static int | ||
945 | gaussian_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 | |||
976 | static int | ||
977 | gaussian_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 | |||
1008 | static const uint32_t * | ||
1009 | gaussian_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 | |||
1047 | static const uint64_t * | ||
1048 | gaussian_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 | |||
1087 | static const double * | ||
1088 | gaussian_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 | ||
1129 | static Eina_Bool | ||
1130 | negation_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 | |||
1186 | static Eina_Bool | ||
1187 | negation_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 | |||
1242 | static Eina_Bool | ||
1243 | sepia_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 | |||
1279 | static Eina_Bool | ||
1280 | greyscale_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 | |||
1329 | static Eina_Bool | ||
1330 | brightness_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 | |||
1400 | static Eina_Bool | ||
1401 | contrast_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 :*/ | ||