elm image: Fix async open to avoid multiple mmap
[platform/upstream/elementary.git] / src / lib / elm_image.c
1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #define ELM_INTERFACE_ATSPI_IMAGE_PROTECTED
6 #define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED
7 #define ELM_INTERFACE_ATSPI_WIDGET_ACTION_PROTECTED
8
9 #include <Elementary.h>
10
11 #include "elm_priv.h"
12 #include "elm_widget_image.h"
13
14 #define FMT_SIZE_T "%zu"
15
16 #define MY_CLASS ELM_IMAGE_CLASS
17 #define MY_CLASS_NAME "Elm_Image"
18 #define MY_CLASS_NAME_LEGACY "elm_image"
19
20 static const char SIG_DND[] = "drop";
21 static const char SIG_CLICKED[] = "clicked";
22 static const char SIG_DOWNLOAD_START[] = "download,start";
23 static const char SIG_DOWNLOAD_PROGRESS[] = "download,progress";
24 static const char SIG_DOWNLOAD_DONE[] = "download,done";
25 static const char SIG_DOWNLOAD_ERROR[] = "download,error";
26 static const char SIG_LOAD_OPEN[] = "load,open";
27 static const char SIG_LOAD_READY[] = "load,ready";
28 static const char SIG_LOAD_ERROR[] = "load,error";
29 static const char SIG_LOAD_CANCEL[] = "load,cancel";
30 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
31    {SIG_DND, ""},
32    {SIG_CLICKED, ""},
33    {SIG_DOWNLOAD_START, ""},
34    {SIG_DOWNLOAD_PROGRESS, ""},
35    {SIG_DOWNLOAD_DONE, ""},
36    {SIG_DOWNLOAD_ERROR, ""},
37    {SIG_LOAD_OPEN, "Triggered when the file has been opened (image size is known)"},
38    {SIG_LOAD_READY, "Triggered when the image file is ready for display"},
39    {SIG_LOAD_ERROR, "Triggered whenener an I/O or decoding error occured"},
40    {SIG_LOAD_CANCEL, "Triggered whenener async I/O was cancelled"},
41    {NULL, NULL}
42 };
43
44 static Eina_Bool _key_action_activate(Evas_Object *obj, const char *params);
45 static Eina_Bool _elm_image_smart_internal_file_set(Eo *obj, Elm_Image_Data *sd, const char *file, const Eina_File *f, const char *key);
46
47 static const Elm_Action key_actions[] = {
48    {"activate", _key_action_activate},
49    {NULL, NULL}
50 };
51
52 typedef struct _Async_Open_Data Async_Open_Data;
53
54 struct _Async_Open_Data {
55    Eo               *obj;
56    Eina_Stringshare *file, *key;
57    Eina_File        *f_set, *f_open;
58    void             *map;
59 };
60
61 static void
62 _prev_img_del(Elm_Image_Data *sd)
63 {
64    elm_widget_sub_object_del(sd->self, sd->prev_img);
65    evas_object_smart_member_del(sd->prev_img);
66    evas_object_del(sd->prev_img);
67    sd->prev_img = NULL;
68 }
69
70 static void
71 _on_image_preloaded(void *data,
72                     Evas *e EINA_UNUSED,
73                     Evas_Object *obj,
74                     void *event EINA_UNUSED)
75 {
76    Elm_Image_Data *sd = data;
77    Evas_Load_Error err;
78
79    sd->preload_status = ELM_IMAGE_PRELOADED;
80    if (sd->show) evas_object_show(obj);
81    _prev_img_del(sd);
82    err = evas_object_image_load_error_get(obj);
83    if (!err) evas_object_smart_callback_call(sd->self, SIG_LOAD_READY, NULL);
84    else evas_object_smart_callback_call(sd->self, SIG_LOAD_ERROR, NULL);
85 }
86
87 static void
88 _on_mouse_up(void *data,
89              Evas *e EINA_UNUSED,
90              Evas_Object *obj EINA_UNUSED,
91              void *event_info)
92 {
93    ELM_WIDGET_DATA_GET_OR_RETURN(data, wd);
94
95    Evas_Event_Mouse_Up *ev = event_info;
96
97    if (ev->button != 1) return;
98    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
99    if (!wd->still_in) return;
100
101    eo_do(data, eo_event_callback_call(EVAS_CLICKABLE_INTERFACE_EVENT_CLICKED, NULL));
102 }
103
104 static Eina_Bool
105 _elm_image_animate_cb(void *data)
106 {
107    ELM_IMAGE_DATA_GET(data, sd);
108
109    if (!sd->anim) return ECORE_CALLBACK_CANCEL;
110
111    sd->cur_frame++;
112    if ((sd->frame_count > 0) && (sd->cur_frame > sd->frame_count))
113      sd->cur_frame = sd->cur_frame % sd->frame_count;
114
115    evas_object_image_animated_frame_set(sd->img, sd->cur_frame);
116
117    sd->frame_duration = evas_object_image_animated_frame_duration_get
118        (sd->img, sd->cur_frame, 0);
119
120    if (sd->frame_duration > 0)
121      ecore_timer_interval_set(sd->anim_timer, sd->frame_duration);
122
123    return ECORE_CALLBACK_RENEW;
124 }
125
126 static Evas_Object *
127 _img_new(Evas_Object *obj)
128 {
129    Evas_Object *img;
130
131    ELM_IMAGE_DATA_GET(obj, sd);
132
133    img = evas_object_image_add(evas_object_evas_get(obj));
134    evas_object_image_scale_hint_set(img, EVAS_IMAGE_SCALE_HINT_STATIC);
135    // TIZEN_ONLY(20161111): Preserve backward compatibility with Tizen 2.4.
136    evas_object_repeat_events_set(img, EINA_TRUE);
137    //
138    evas_object_event_callback_add
139      (img, EVAS_CALLBACK_IMAGE_PRELOADED, _on_image_preloaded, sd);
140
141    evas_object_smart_member_add(img, obj);
142    elm_widget_sub_object_add(obj, img);
143
144    return img;
145 }
146
147 static void
148 _elm_image_internal_sizing_eval(Evas_Object *obj, Elm_Image_Data *sd)
149 {
150    Evas_Coord x, y, w, h;
151
152    if (!sd->img) return;
153
154    w = sd->img_w;
155    h = sd->img_h;
156
157    if (eo_isa(sd->img, EDJE_OBJECT_CLASS))
158      {
159         x = sd->img_x;
160         y = sd->img_y;
161         evas_object_move(sd->img, x, y);
162         evas_object_resize(sd->img, w, h);
163      }
164    else
165      {
166         double alignh = 0.5, alignv = 0.5;
167         int iw = 0, ih = 0, offset_w = 0, offset_h = 0;
168         evas_object_image_size_get(sd->img, &iw, &ih);
169
170         iw = ((double)iw) * sd->scale;
171         ih = ((double)ih) * sd->scale;
172
173         if (iw < 1) iw = 1;
174         if (ih < 1) ih = 1;
175
176         if (sd->aspect_fixed)
177           {
178              h = ((double)ih * w) / (double)iw;
179              if (sd->fill_inside)
180                {
181                   if (h > sd->img_h)
182                     {
183                        h = sd->img_h;
184                        w = ((double)iw * h) / (double)ih;
185                     }
186                }
187              else
188                {
189                   if (h < sd->img_h)
190                     {
191                        h = sd->img_h;
192                        w = ((double)iw * h) / (double)ih;
193                     }
194                }
195           }
196         if (!sd->resize_up)
197           {
198              if (w > iw) w = iw;
199              if (h > ih) h = ih;
200           }
201         if (!sd->resize_down)
202           {
203              if (w < iw) w = iw;
204              if (h < ih) h = ih;
205           }
206
207         evas_object_size_hint_align_get
208            (obj, &alignh, &alignv);
209
210         if (alignh == EVAS_HINT_FILL) alignh = 0.5;
211         if (alignv == EVAS_HINT_FILL) alignv = 0.5;
212
213         offset_w = ((sd->img_w - w) * alignh);
214         offset_h = ((sd->img_h - h) * alignv);
215
216         if (sd->aspect_fixed && !sd->fill_inside)
217           {
218              evas_object_image_fill_set(sd->img, offset_w, offset_h, w, h);
219
220              w = sd->img_w;
221              h = sd->img_h;
222              x = sd->img_x;
223              y = sd->img_y;
224           }
225         else
226           {
227              evas_object_image_fill_set(sd->img, 0, 0, w, h);
228
229              x = sd->img_x + offset_w;
230              y = sd->img_y + offset_h;
231           }
232
233         evas_object_move(sd->img, x, y);
234         evas_object_resize(sd->img, w, h);
235      }
236    evas_object_move(sd->hit_rect, x, y);
237    evas_object_resize(sd->hit_rect, w, h);
238 }
239
240 static inline void
241 _async_open_data_free(Async_Open_Data *data)
242 {
243    if (!data) return;
244    eina_stringshare_del(data->file);
245    eina_stringshare_del(data->key);
246    if (data->map) eina_file_map_free(data->f_open, data->map);
247    if (data->f_open) eina_file_close(data->f_open);
248    if (data->f_set) eina_file_close(data->f_set);
249    free(data);
250 }
251
252 static void
253 _elm_image_async_open_do(void *data, Ecore_Thread *thread)
254 {
255    Async_Open_Data *todo = data;
256    Eina_File *f;
257    void *map = NULL;
258    size_t size;
259
260    if (ecore_thread_check(thread)) return;
261
262    if (todo->f_set) f = eina_file_dup(todo->f_set);
263    else if (todo->file)
264      {
265         // blocking
266         f = eina_file_open(todo->file, EINA_FALSE);
267         if (!f) return;
268      }
269    else
270      {
271         CRI("Async open has no input file!");
272         return;
273      }
274    if (ecore_thread_check(thread))
275      {
276         if (!todo->f_set) eina_file_close(f);
277         return;
278      }
279
280    // Read just enough data for map to actually do something.
281    size = eina_file_size_get(f);
282    // Read and ensure all pages are in memory for sure first just
283    // 1 byte per page will do. also keep a limit on how much we will
284    // blindly load in here to let's say 32KB (Should be enough to get
285    // image headers without getting to much data from the hard drive).
286    size = size > 32 * 1024 ? 32 * 1024 : size;
287    map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
288    eina_file_map_populate(f, EINA_FILE_POPULATE, map, 0, size);
289
290    if (ecore_thread_check(thread))
291      {
292         if (map) eina_file_map_free(f, map);
293         if (!todo->f_set) eina_file_close(f);
294         return;
295      }
296    todo->f_open = f;
297    todo->map = map;
298 }
299
300 static void
301 _async_clear(Elm_Image_Data *sd)
302 {
303    sd->async.th = NULL;
304    sd->async.todo = NULL;
305    eina_stringshare_del(sd->async.file);
306    eina_stringshare_del(sd->async.key);
307    sd->async.file = NULL;
308    sd->async.key = NULL;
309 }
310
311 static void
312 _async_cancel(Elm_Image_Data *sd)
313 {
314    if (sd->async.th)
315      {
316         ecore_thread_cancel(sd->async.th);
317         ((Async_Open_Data *)(sd->async.todo))->obj = NULL;
318         _async_clear(sd);
319      }
320 }
321
322 static void
323 _elm_image_async_open_cancel(void *data, Ecore_Thread *thread)
324 {
325    Async_Open_Data *todo = data;
326
327    DBG("Async open thread was canceled");
328    if (todo->obj)
329      {
330         ELM_IMAGE_DATA_GET(todo->obj, sd);
331         if (sd)
332           {
333              evas_object_smart_callback_call(todo->obj, SIG_LOAD_CANCEL, NULL);
334              if (thread == sd->async.th) _async_clear(sd);
335           }
336      }
337    _async_open_data_free(todo);
338 }
339
340 static void
341 _elm_image_async_open_done(void *data, Ecore_Thread *thread)
342 {
343    Async_Open_Data *todo = data;
344    Eina_Stringshare *file, *key;
345    Eina_Bool ok;
346    Eina_File *f;
347    void *map;
348
349    if (todo->obj)
350      {
351         ELM_IMAGE_DATA_GET(todo->obj, sd);
352         if (sd)
353           {
354              if (thread == sd->async.th)
355                {
356                   DBG("Async open succeeded");
357                   _async_clear(sd);
358                   key = todo->key;
359                   map = todo->map;
360                   f = todo->f_open;
361                   ok = f && map;
362                   if (todo->file) file = todo->file;
363                   else file = f ? eina_file_filename_get(f) : NULL;
364
365                   if (ok)
366                     {
367                        if (sd->edje)
368                          {
369                             _prev_img_del(sd);
370                             ok = edje_object_mmap_set(sd->img, f, key);
371                          }
372                        else
373                          ok = _elm_image_smart_internal_file_set
374                            (sd->self, sd, file, f, key);
375                     }
376                   if (ok) evas_object_smart_callback_call(sd->self, SIG_LOAD_OPEN, NULL);
377                   else evas_object_smart_callback_call(sd->self, SIG_LOAD_ERROR, NULL);
378                }
379           }
380      }
381    // close f, map and free strings
382    _async_open_data_free(todo);
383 }
384
385 static Eina_Bool
386 _elm_image_async_file_set(Eo *obj, Elm_Image_Data *sd, const char *file,
387                           const Eina_File *f, const char *key)
388 {
389    Async_Open_Data *todo;
390
391    if (sd->async.th &&
392        ((file == sd->async.file) ||
393         (file && sd->async.file && !strcmp(file, sd->async.file))) &&
394        ((key == sd->async.key) ||
395         (key && sd->async.key && !strcmp(key, sd->async.key))))
396      return EINA_TRUE;
397
398    todo = calloc(1, sizeof(Async_Open_Data));
399    if (!todo) return EINA_FALSE;
400
401    _async_cancel(sd);
402
403    todo->obj = obj;
404    todo->file = eina_stringshare_add(file);
405    todo->key = eina_stringshare_add(key);
406    todo->f_set = f ? eina_file_dup(f) : NULL;
407
408    eina_stringshare_replace(&sd->async.file, file);
409    eina_stringshare_replace(&sd->async.key, key);
410
411    sd->async.todo = todo;
412    sd->async.th = ecore_thread_run(_elm_image_async_open_do,
413                                    _elm_image_async_open_done,
414                                    _elm_image_async_open_cancel, todo);
415    if (sd->async.th) return EINA_TRUE;
416
417    _async_open_data_free(todo);
418    _async_clear(sd);
419    DBG("Could not spawn an async thread!");
420    return EINA_FALSE;
421 }
422
423 static Eina_Bool
424 _elm_image_edje_file_set(Evas_Object *obj,
425                          const char *file,
426                          const Eina_File *f,
427                          const char *group)
428 {
429    Evas_Object *pclip;
430
431    ELM_IMAGE_DATA_GET(obj, sd);
432
433    _prev_img_del(sd);
434
435    if (!sd->edje)
436      {
437         pclip = evas_object_clip_get(sd->img);
438         evas_object_del(sd->img);
439
440         /* Edje object instead */
441         sd->img = edje_object_add(evas_object_evas_get(obj));
442         evas_object_smart_member_add(sd->img, obj);
443         if (sd->show) evas_object_show(sd->img);
444         evas_object_clip_set(sd->img, pclip);
445      }
446
447    _async_cancel(sd);
448
449    sd->edje = EINA_TRUE;
450    if (!sd->async_enable)
451      {
452         if (f)
453           {
454              if (!edje_object_mmap_set(sd->img, f, group))
455                {
456                   ERR("failed to set edje file '%s', group '%s': %s", file, group,
457                       edje_load_error_str(edje_object_load_error_get(sd->img)));
458                   return EINA_FALSE;
459                }
460           }
461         else
462           {
463              if (!edje_object_file_set(sd->img, file, group))
464                {
465                   ERR("failed to set edje file '%s', group '%s': %s", file, group,
466                       edje_load_error_str(edje_object_load_error_get(sd->img)));
467                   return EINA_FALSE;
468                }
469           }
470      }
471    else
472      return _elm_image_async_file_set(obj, sd, file, f, group);
473
474    /* FIXME: do i want to update icon on file change ? */
475    _elm_image_internal_sizing_eval(obj, sd);
476
477    return EINA_TRUE;
478 }
479
480 EOLIAN static void
481 _elm_image_efl_image_smooth_scale_set(Eo *obj EINA_UNUSED, Elm_Image_Data *sd, Eina_Bool smooth)
482 {
483    if (sd->edje) return;
484
485    evas_object_image_smooth_scale_set(sd->img, smooth);
486 }
487
488 EOLIAN static Eina_Bool
489 _elm_image_efl_image_smooth_scale_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
490 {
491    if (sd->edje) return EINA_FALSE;
492
493    return evas_object_image_smooth_scale_get(sd->img);
494 }
495
496 EOLIAN static void
497 _elm_image_fill_inside_set(Eo *obj, Elm_Image_Data *sd, Eina_Bool fill_inside)
498 {
499    fill_inside = !!fill_inside;
500
501    if (sd->fill_inside == fill_inside) return;
502
503    sd->fill_inside = fill_inside;
504
505    _elm_image_internal_sizing_eval(obj, sd);
506 }
507
508 EOLIAN static Eina_Bool
509 _elm_image_fill_inside_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
510 {
511    return sd->fill_inside;
512 }
513
514 EOLIAN static void
515 _elm_image_resize_up_set(Eo *obj, Elm_Image_Data *sd, Eina_Bool resize_up)
516 {
517    resize_up = !!resize_up;
518
519    if (sd->resize_up == resize_up) return;
520
521    sd->resize_up = resize_up;
522
523    _elm_image_internal_sizing_eval(obj, sd);
524 }
525
526 EOLIAN static Eina_Bool
527 _elm_image_resize_up_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
528 {
529    return sd->resize_up;
530 }
531
532 EOLIAN static void
533 _elm_image_resize_down_set(Eo *obj, Elm_Image_Data *sd, Eina_Bool resize_down)
534 {
535    resize_down = !!resize_down;
536
537    if (sd->resize_down == resize_down) return;
538
539    sd->resize_down = resize_down;
540
541    _elm_image_internal_sizing_eval(obj, sd);
542 }
543
544 EOLIAN static Eina_Bool
545 _elm_image_resize_down_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
546 {
547    return sd->resize_up;
548 }
549
550 static Eina_Bool
551 _elm_image_drag_n_drop_cb(void *elm_obj,
552       Evas_Object *obj,
553       Elm_Selection_Data *drop)
554 {
555    Eina_Bool ret = EINA_FALSE;
556    eo_do(obj, ret = efl_file_set(drop->data, NULL));
557    if (ret)
558      {
559         DBG("dnd: %s, %s, %s", elm_widget_type_get(elm_obj),
560               SIG_DND, (char *)drop->data);
561
562         eo_do(elm_obj, eo_event_callback_call(ELM_IMAGE_EVENT_DROP, drop->data));
563         return EINA_TRUE;
564      }
565
566    return EINA_FALSE;
567 }
568
569 EOLIAN static void
570 _elm_image_evas_object_smart_add(Eo *obj, Elm_Image_Data *priv)
571 {
572    eo_do_super(obj, MY_CLASS, evas_obj_smart_add());
573    elm_widget_sub_object_parent_add(obj);
574
575    priv->hit_rect = evas_object_rectangle_add(evas_object_evas_get(obj));
576    evas_object_smart_member_add(priv->hit_rect, obj);
577    elm_widget_sub_object_add(obj, priv->hit_rect);
578
579    evas_object_color_set(priv->hit_rect, 0, 0, 0, 0);
580    evas_object_show(priv->hit_rect);
581    evas_object_repeat_events_set(priv->hit_rect, EINA_TRUE);
582
583    evas_object_event_callback_add
584       (priv->hit_rect, EVAS_CALLBACK_MOUSE_UP, _on_mouse_up, obj);
585
586    /* starts as an Evas image. may switch to an Edje object */
587    priv->img = _img_new(obj);
588
589    priv->smooth = EINA_TRUE;
590    priv->fill_inside = EINA_TRUE;
591    priv->resize_up = EINA_TRUE;
592    priv->resize_down = EINA_TRUE;
593    priv->aspect_fixed = EINA_TRUE;
594    priv->load_size = 0;
595    priv->scale = 1.0;
596
597    elm_widget_can_focus_set(obj, EINA_FALSE);
598
599    eo_do(obj, elm_obj_image_sizing_eval());
600 }
601
602 EOLIAN static void
603 _elm_image_evas_object_smart_del(Eo *obj, Elm_Image_Data *sd)
604 {
605    ecore_timer_del(sd->anim_timer);
606    evas_object_del(sd->img);
607    evas_object_del(sd->prev_img);
608    if (sd->remote) _elm_url_cancel(sd->remote);
609    free(sd->remote_data);
610    eina_stringshare_del(sd->key);
611    _async_cancel(sd);
612    eo_do_super(obj, MY_CLASS, evas_obj_smart_del());
613 }
614
615 EOLIAN static void
616 _elm_image_evas_object_smart_move(Eo *obj, Elm_Image_Data *sd, Evas_Coord x, Evas_Coord y)
617 {
618    eo_do_super(obj, MY_CLASS, evas_obj_smart_move(x, y));
619
620    if ((sd->img_x == x) && (sd->img_y == y)) return;
621    sd->img_x = x;
622    sd->img_y = y;
623
624    /* takes care of moving */
625    _elm_image_internal_sizing_eval(obj, sd);
626 }
627
628 EOLIAN static void
629 _elm_image_evas_object_smart_resize(Eo *obj, Elm_Image_Data *sd, Evas_Coord w, Evas_Coord h)
630 {
631    eo_do_super(obj, MY_CLASS, evas_obj_smart_resize(w, h));
632
633    if ((sd->img_w == w) && (sd->img_h == h)) return;
634
635    sd->img_w = w;
636    sd->img_h = h;
637
638    /* takes care of resizing */
639    _elm_image_internal_sizing_eval(obj, sd);
640 }
641
642 EOLIAN static void
643 _elm_image_evas_object_smart_show(Eo *obj, Elm_Image_Data *sd)
644 {
645    sd->show = EINA_TRUE;
646    eo_do_super(obj, MY_CLASS, evas_obj_smart_show());
647
648    if (sd->preload_status == ELM_IMAGE_PRELOADING)
649      {
650         //TIZEN_ONLY(20170106): This code will be added in upstream
651         //                      after a related patch is applied in evas
652         evas_object_hide(sd->img);
653         //
654         return;
655      }
656
657    evas_object_show(sd->img);
658
659    _prev_img_del(sd);
660 }
661
662 EOLIAN static void
663 _elm_image_evas_object_smart_hide(Eo *obj, Elm_Image_Data *sd)
664 {
665    eo_do_super(obj, MY_CLASS, evas_obj_smart_hide());
666
667    sd->show = EINA_FALSE;
668    evas_object_hide(sd->img);
669
670    _prev_img_del(sd);
671 }
672
673 EOLIAN static void
674 _elm_image_evas_object_smart_member_add(Eo *obj, Elm_Image_Data *sd, Evas_Object *member)
675 {
676    eo_do_super(obj, MY_CLASS, evas_obj_smart_member_add(member));
677
678    if (sd->hit_rect)
679      evas_object_raise(sd->hit_rect);
680 }
681
682 EOLIAN static void
683 _elm_image_evas_object_smart_color_set(Eo *obj, Elm_Image_Data *sd, int r, int g, int b, int a)
684 {
685    eo_do_super(obj, MY_CLASS, evas_obj_smart_color_set(r, g, b, a));
686
687    evas_object_color_set(sd->hit_rect, 0, 0, 0, 0);
688    evas_object_color_set(sd->img, r, g, b, a);
689    if (sd->prev_img) evas_object_color_set(sd->prev_img, r, g, b, a);
690 }
691
692 EOLIAN static void
693 _elm_image_evas_object_smart_clip_set(Eo *obj, Elm_Image_Data *sd, Evas_Object *clip)
694 {
695    eo_do_super(obj, MY_CLASS, evas_obj_smart_clip_set(clip));
696
697    evas_object_clip_set(sd->img, clip);
698    if (sd->prev_img) evas_object_clip_set(sd->prev_img, clip);
699 }
700
701 EOLIAN static void
702 _elm_image_evas_object_smart_clip_unset(Eo *obj, Elm_Image_Data *sd)
703 {
704    eo_do_super(obj, MY_CLASS, evas_obj_smart_clip_unset());
705
706    evas_object_clip_unset(sd->img);
707    if (sd->prev_img) evas_object_clip_unset(sd->prev_img);
708 }
709
710 EOLIAN static Elm_Theme_Apply
711 _elm_image_elm_widget_theme_apply(Eo *obj, Elm_Image_Data *sd EINA_UNUSED)
712 {
713    Elm_Theme_Apply int_ret = ELM_THEME_APPLY_FAILED;
714    eo_do_super(obj, MY_CLASS, int_ret = elm_obj_widget_theme_apply());
715    if (!int_ret) return ELM_THEME_APPLY_FAILED;
716
717    eo_do(obj, elm_obj_image_sizing_eval());
718
719    return int_ret;
720 }
721
722 static Eina_Bool
723 _key_action_activate(Evas_Object *obj, const char *params EINA_UNUSED)
724 {
725    eo_do(obj, eo_event_callback_call(EVAS_CLICKABLE_INTERFACE_EVENT_CLICKED, NULL));
726    return EINA_TRUE;
727 }
728
729 EOLIAN static Eina_Bool
730 _elm_image_elm_widget_event(Eo *obj, Elm_Image_Data *_pd EINA_UNUSED, Evas_Object *src, Evas_Callback_Type type, void *event_info)
731 {
732    (void) src;
733    Evas_Event_Key_Down *ev = event_info;
734
735    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
736    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
737
738    if (!_elm_config_key_binding_call(obj, ev, key_actions))
739      return EINA_FALSE;
740
741    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
742    return EINA_TRUE;
743 }
744
745 EOLIAN static void
746 _elm_image_sizing_eval(Eo *obj, Elm_Image_Data *sd)
747 {
748    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
749    int w = 0, h = 0;
750    double ts;
751
752    _elm_image_internal_sizing_eval(obj, sd);
753
754    eo_do(obj, efl_image_smooth_scale_set(sd->smooth));
755
756    if (sd->no_scale)
757      eo_do(obj, elm_obj_image_scale_set(1.0));
758    else
759      eo_do(obj, efl_image_smooth_scale_set(elm_widget_scale_get(obj) * elm_config_scale_get()));
760
761    ts = sd->scale;
762    sd->scale = 1.0;
763    eo_do(obj, elm_obj_image_object_size_get(&w, &h));
764
765    sd->scale = ts;
766    evas_object_size_hint_min_get(obj, &minw, &minh);
767
768    if (sd->no_scale)
769      {
770         maxw = minw = w;
771         maxh = minh = h;
772         if ((sd->scale > 1.0) && (sd->resize_up))
773           {
774              maxw = minw = w * sd->scale;
775              maxh = minh = h * sd->scale;
776           }
777         else if ((sd->scale < 1.0) && (sd->resize_down))
778           {
779              maxw = minw = w * sd->scale;
780              maxh = minh = h * sd->scale;
781           }
782      }
783    else
784      {
785         if (!sd->resize_down)
786           {
787              minw = w * sd->scale;
788              minh = h * sd->scale;
789           }
790         if (!sd->resize_up)
791           {
792              maxw = w * sd->scale;
793              maxh = h * sd->scale;
794           }
795      }
796
797    evas_object_size_hint_min_set(obj, minw, minh);
798    evas_object_size_hint_max_set(obj, maxw, maxh);
799 }
800
801 static void
802 _elm_image_file_set_do(Evas_Object *obj)
803 {
804    Evas_Object *pclip = NULL;
805    int w = 0, h = 0;
806
807    ELM_IMAGE_DATA_GET(obj, sd);
808
809    _prev_img_del(sd);
810    if (sd->img)
811      {
812         pclip = evas_object_clip_get(sd->img);
813         sd->prev_img = sd->img;
814      }
815
816    sd->img = _img_new(obj);
817
818    evas_object_image_load_orientation_set(sd->img, EINA_TRUE);
819
820    evas_object_clip_set(sd->img, pclip);
821
822    sd->edje = EINA_FALSE;
823
824    if (sd->load_size > 0)
825      evas_object_image_load_size_set(sd->img, sd->load_size, sd->load_size);
826    else
827      {
828         eo_do((Eo *) obj, elm_obj_image_object_size_get(&w, &h));
829         evas_object_image_load_size_set(sd->img, w, h);
830      }
831 }
832
833 EOLIAN static Eina_Bool
834 _elm_image_memfile_set(Eo *obj, Elm_Image_Data *sd, const void *img, size_t size, const char *format, const char *key)
835 {
836    EINA_SAFETY_ON_NULL_RETURN_VAL(img, EINA_FALSE);
837
838    _elm_image_file_set_do(obj);
839
840    evas_object_image_memfile_set
841      (sd->img, (void *)img, size, (char *)format, (char *)key);
842
843    if (sd->preload_status == ELM_IMAGE_PRELOAD_DISABLED)
844      _prev_img_del(sd);
845    else
846      {
847         sd->preload_status = ELM_IMAGE_PRELOADING;
848         evas_object_image_preload(sd->img, EINA_FALSE);
849      }
850
851    if (evas_object_image_load_error_get(sd->img) != EVAS_LOAD_ERROR_NONE)
852      {
853         ERR("Things are going bad for some random " FMT_SIZE_T
854             " byte chunk of memory (%p)", size, sd->img);
855
856         _prev_img_del(sd);
857         return EINA_FALSE;
858      }
859
860    _elm_image_internal_sizing_eval(obj, sd);
861
862    return EINA_TRUE;
863 }
864
865 EOLIAN static void
866 _elm_image_scale_set(Eo *obj, Elm_Image_Data *sd, double scale)
867 {
868    sd->scale = scale;
869
870    _elm_image_internal_sizing_eval(obj, sd);
871 }
872
873 EOLIAN static double
874 _elm_image_scale_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
875 {
876    return sd->scale;
877 }
878
879 EAPI Evas_Object *
880 elm_image_add(Evas_Object *parent)
881 {
882    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
883    Evas_Object *obj = eo_add(MY_CLASS, parent);
884    return obj;
885 }
886
887 EOLIAN static Eo *
888 _elm_image_eo_base_constructor(Eo *obj, Elm_Image_Data *pd)
889 {
890    obj = eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
891    eo_do(obj,
892          evas_obj_type_set(MY_CLASS_NAME_LEGACY),
893          evas_obj_smart_callbacks_descriptions_set(_smart_callbacks),
894          elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_IMAGE));
895
896    pd->self = obj;
897
898    return obj;
899 }
900
901 EAPI Eina_Bool
902 elm_image_file_set(Evas_Object *obj,
903                    const char *file,
904                    const char *group)
905 {
906    Eina_Bool ret = EINA_FALSE;
907
908    ELM_IMAGE_CHECK(obj) EINA_FALSE;
909    EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE);
910    eo_do(obj,
911          ret = efl_file_set(file, group);
912          elm_obj_image_sizing_eval());
913    return ret;
914 }
915
916 EAPI void
917 elm_image_file_get(const Eo *obj, const char **file, const char **group)
918 {
919    eo_do((Eo *) obj, efl_file_get(file, group));
920 }
921
922 EAPI Eina_Bool
923 elm_image_mmap_set(Evas_Object *obj,
924                    const Eina_File *file,
925                    const char *group)
926 {
927    Eina_Bool ret = EINA_FALSE;
928
929    ELM_IMAGE_CHECK(obj) EINA_FALSE;
930    EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE);
931    eo_do(obj, ret = efl_file_mmap_set(file, group));
932    return ret;
933 }
934
935 EOLIAN Eina_Bool
936 _elm_image_efl_file_mmap_set(Eo *obj, Elm_Image_Data *pd EINA_UNUSED,
937                              const Eina_File *file, const char *key)
938 {
939    Eina_Bool ret = EINA_FALSE;
940
941    EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE);
942    eo_do(obj,
943          ret = elm_obj_image_mmap_set(file, key),
944          elm_obj_image_sizing_eval());
945
946    return ret;
947 }
948
949 static Eina_Bool
950 _elm_image_smart_internal_file_set(Eo *obj, Elm_Image_Data *sd,
951                                    const char *file, const Eina_File *f, const char *key)
952 {
953    Evas_Load_Error err;
954
955    if (eina_str_has_extension(file, ".edj"))
956      return _elm_image_edje_file_set(obj, file, f, key);
957
958    _elm_image_file_set_do(obj);
959
960    if (f)
961      evas_object_image_mmap_set(sd->img, f, key);
962    else
963      evas_object_image_file_set(sd->img, file, key);
964
965    err = evas_object_image_load_error_get(sd->img);
966    if (err != EVAS_LOAD_ERROR_NONE)
967      {
968         if (file || f)
969           {
970              if (key)
971                ERR("Failed to load image '%s' '%s': %s. (%p)",
972                    file ? file : eina_file_filename_get(f), key,
973                    evas_load_error_str(err), obj);
974              else
975                 ERR("Failed to load image '%s': %s. (%p)",
976                     file ? file : eina_file_filename_get(f),
977                     evas_load_error_str(err), obj);
978           }
979         else
980           {
981              ERR("NULL image file passed! (%p)", obj);
982           }
983         _prev_img_del(sd);
984         return EINA_FALSE;
985      }
986
987    if (sd->preload_status == ELM_IMAGE_PRELOAD_DISABLED)
988      _prev_img_del(sd);
989    else
990      {
991         evas_object_hide(sd->img);
992         sd->preload_status = ELM_IMAGE_PRELOADING;
993         evas_object_image_preload(sd->img, EINA_FALSE);
994      }
995
996    _elm_image_internal_sizing_eval(obj, sd);
997
998    return EINA_TRUE;
999 }
1000
1001 static void
1002 _elm_image_smart_download_done(void *data, Elm_Url *url, Eina_Binbuf *download)
1003 {
1004    Eo *obj = data;
1005    Elm_Image_Data *sd = eo_data_scope_get(obj, MY_CLASS);
1006    Eina_File *f;
1007    size_t length;
1008    Eina_Bool ret = EINA_FALSE;
1009
1010    free(sd->remote_data);
1011    length = eina_binbuf_length_get(download);
1012    sd->remote_data = eina_binbuf_string_steal(download);
1013    f = eina_file_virtualize(_elm_url_get(url),
1014                             sd->remote_data, length,
1015                             EINA_FALSE);
1016    ret = _elm_image_smart_internal_file_set(obj, sd, _elm_url_get(url), f, sd->key);
1017    eina_file_close(f);
1018
1019    sd->remote = NULL;
1020    if (!ret)
1021      {
1022         Elm_Image_Error err = { 0, EINA_TRUE };
1023
1024         free(sd->remote_data);
1025         sd->remote_data = NULL;
1026         evas_object_smart_callback_call(obj, SIG_DOWNLOAD_ERROR, &err);
1027      }
1028    else
1029      {
1030         if (sd->preload_status != ELM_IMAGE_PRELOAD_DISABLED)
1031           {
1032              sd->preload_status = ELM_IMAGE_PRELOADING;
1033              evas_object_image_preload(sd->img, EINA_FALSE);
1034           }
1035
1036         evas_object_smart_callback_call(obj, SIG_DOWNLOAD_DONE, NULL);
1037      }
1038
1039    ELM_SAFE_FREE(sd->key, eina_stringshare_del);
1040 }
1041
1042 static void
1043 _elm_image_smart_download_cancel(void *data, Elm_Url *url EINA_UNUSED, int error)
1044 {
1045    Eo *obj = data;
1046    Elm_Image_Data *sd = eo_data_scope_get(obj, MY_CLASS);
1047    Elm_Image_Error err = { error, EINA_FALSE };
1048
1049    evas_object_smart_callback_call(obj, SIG_DOWNLOAD_ERROR, &err);
1050
1051    sd->remote = NULL;
1052    ELM_SAFE_FREE(sd->key, eina_stringshare_del);
1053 }
1054
1055 static void
1056 _elm_image_smart_download_progress(void *data, Elm_Url *url EINA_UNUSED, double now, double total)
1057 {
1058    Eo *obj = data;
1059    Elm_Image_Progress progress;
1060
1061    progress.now = now;
1062    progress.total = total;
1063    evas_object_smart_callback_call(obj, SIG_DOWNLOAD_PROGRESS, &progress);
1064 }
1065
1066 static const char *remote_uri[] = {
1067   "http://", "https://", "ftp://"
1068 };
1069
1070 EOLIAN static Eina_Bool
1071 _elm_image_efl_file_file_set(Eo *obj, Elm_Image_Data *sd, const char *file, const char *key)
1072 {
1073    Eina_Bool ret = EINA_FALSE;
1074    unsigned int i;
1075
1076    if (sd->remote) _elm_url_cancel(sd->remote);
1077    sd->remote = NULL;
1078
1079    for (i = 0; i < sizeof (remote_uri) / sizeof (remote_uri[0]); ++i)
1080      if (file && !strncmp(remote_uri[i], file, strlen(remote_uri[i])))
1081        {
1082           // Found a remote target !
1083           evas_object_hide(sd->img);
1084           sd->remote = _elm_url_download(file,
1085                                         _elm_image_smart_download_done,
1086                                         _elm_image_smart_download_cancel,
1087                                         _elm_image_smart_download_progress,
1088                                         obj);
1089           if (sd->remote)
1090             {
1091                evas_object_smart_callback_call(obj, SIG_DOWNLOAD_START, NULL);
1092                eina_stringshare_replace(&sd->key, key);
1093                return EINA_TRUE;
1094             }
1095           break;
1096        }
1097
1098    _async_cancel(sd);
1099
1100    if (!sd->async_enable)
1101      ret = _elm_image_smart_internal_file_set(obj, sd, file, NULL, key);
1102    else
1103      ret = _elm_image_async_file_set(obj, sd, file, NULL, key);
1104
1105    return ret;
1106 }
1107
1108 EOLIAN static void
1109 _elm_image_edje_object_signal_emit(Eo *obj EINA_UNUSED, Elm_Image_Data *sd, const char *emission, const char *source)
1110 {
1111    if (sd->edje)
1112      edje_object_signal_emit(sd->img, emission, source);
1113 }
1114
1115 EOLIAN static void
1116 _elm_image_edje_object_size_min_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd, int *w, int *h)
1117 {
1118    if (sd->edje)
1119      edje_object_size_min_get(sd->img, w, h);
1120    else
1121      evas_object_size_hint_min_get(sd->img, w, h);
1122 }
1123
1124 EOLIAN static void
1125 _elm_image_edje_object_size_max_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd, int *w, int *h)
1126 {
1127    if (sd->edje)
1128      edje_object_size_max_get(sd->img, w, h);
1129    else
1130      evas_object_size_hint_max_get(sd->img, w, h);
1131 }
1132
1133 EOLIAN static void
1134 _elm_image_edje_object_calc_force(Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
1135 {
1136    if (sd->edje)
1137      edje_object_calc_force(sd->img);
1138 }
1139
1140 EOLIAN static void
1141 _elm_image_edje_object_size_min_calc(Eo *obj EINA_UNUSED, Elm_Image_Data *sd, int *w, int *h)
1142 {
1143    if (sd->edje)
1144      edje_object_size_min_calc(sd->img, w, h);
1145    else
1146      evas_object_size_hint_min_get(sd->img, w, h);
1147 }
1148
1149 EOLIAN static Eina_Bool
1150 _elm_image_mmap_set(Eo *obj, Elm_Image_Data *sd, const Eina_File *f, const char *key)
1151 {
1152    Eina_Bool ret;
1153
1154    if (sd->remote) _elm_url_cancel(sd->remote);
1155    sd->remote = NULL;
1156
1157    _async_cancel(sd);
1158
1159    if (!sd->async_enable)
1160      ret = _elm_image_smart_internal_file_set(obj, sd, eina_file_filename_get(f), f, key);
1161    else
1162      ret = _elm_image_async_file_set(obj, sd, eina_file_filename_get(f), f, key);
1163
1164     return ret;
1165 }
1166
1167 EOLIAN static void
1168 _elm_image_efl_file_file_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd, const char **file, const char **key)
1169 {
1170    if (sd->async.th)
1171      {
1172         if (file) *file = sd->async.file;
1173         if (key) *key = sd->async.key;
1174         return;
1175      }
1176    evas_object_image_file_get(sd->img, file, key);
1177 }
1178
1179 EOLIAN static void
1180 _elm_image_smooth_set(Eo *obj, Elm_Image_Data *sd, Eina_Bool smooth)
1181 {
1182    sd->smooth = smooth;
1183
1184    eo_do(obj, elm_obj_image_sizing_eval());
1185 }
1186
1187 EOLIAN static Eina_Bool
1188 _elm_image_smooth_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
1189 {
1190    return sd->smooth;
1191 }
1192
1193 #if 0
1194 // Kept for reference: wait for async open to complete - probably unused.
1195 static Eina_Bool
1196 _elm_image_efl_file_async_wait(const Eo *obj EINA_UNUSED, Elm_Image_Data *pd)
1197 {
1198    Eina_Bool ok = EINA_TRUE;
1199    if (!pd->async_enable) return ok;
1200    if (!pd->async.th) return ok;
1201    if (!ecore_thread_wait(pd->async.th, 1.0))
1202      {
1203         ERR("Failed to wait on async file open!");
1204         ok = EINA_FALSE;
1205      }
1206    return ok;
1207 }
1208 #endif
1209
1210 /* Legacy style async API. While legacy only, this is new from 1.19.
1211  * Tizen has used elm_image_async_open_set() internally for a while, despite
1212  * EFL upstream not exposing a proper async API. */
1213
1214 EAPI void
1215 elm_image_async_open_set(Eo *obj, Eina_Bool async)
1216 {
1217    Elm_Image_Data *pd = eo_data_scope_get(obj, MY_CLASS);
1218    if (pd->async_enable == async) return;
1219    pd->async_enable = async;
1220    if (!async) _async_cancel(pd);
1221 }
1222
1223 EOLIAN static void
1224 _elm_image_object_size_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd, int *w, int *h)
1225 {
1226    int tw, th;
1227    int cw = 0, ch = 0;
1228
1229    if (w) *w = 0;
1230    if (h) *h = 0;
1231
1232    if (eo_isa(sd->img, EDJE_OBJECT_CLASS))
1233      edje_object_size_min_get(sd->img, &tw, &th);
1234    else
1235      evas_object_image_size_get(sd->img, &tw, &th);
1236
1237    if ((sd->resize_up) || (sd->resize_down))
1238      evas_object_geometry_get(sd->img, NULL, NULL, &cw, &ch);
1239
1240    tw = tw > cw ? tw : cw;
1241    th = th > ch ? th : ch;
1242    tw = ((double)tw) * sd->scale;
1243    th = ((double)th) * sd->scale;
1244    if (w) *w = tw;
1245    if (h) *h = th;
1246 }
1247
1248 EOLIAN static void
1249 _elm_image_no_scale_set(Eo *obj, Elm_Image_Data *sd, Eina_Bool no_scale)
1250 {
1251    sd->no_scale = no_scale;
1252
1253    eo_do(obj, elm_obj_image_sizing_eval());
1254 }
1255
1256 EOLIAN static Eina_Bool
1257 _elm_image_no_scale_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
1258 {
1259    return sd->no_scale;
1260 }
1261
1262 EOLIAN static void
1263 _elm_image_resizable_set(Eo *obj EINA_UNUSED, Elm_Image_Data *sd, Eina_Bool up, Eina_Bool down)
1264 {
1265    sd->resize_up = !!up;
1266    sd->resize_down = !!down;
1267
1268    eo_do(obj, elm_obj_image_sizing_eval());
1269 }
1270
1271 EOLIAN static void
1272 _elm_image_resizable_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd, Eina_Bool *size_up, Eina_Bool *size_down)
1273 {
1274    if (size_up) *size_up = sd->resize_up;
1275    if (size_down) *size_down = sd->resize_down;
1276 }
1277
1278 EOLIAN static void
1279 _elm_image_fill_outside_set(Eo *obj, Elm_Image_Data *sd, Eina_Bool fill_outside)
1280 {
1281    sd->fill_inside = !fill_outside;
1282
1283    eo_do(obj, elm_obj_image_sizing_eval());
1284 }
1285
1286 EOLIAN static Eina_Bool
1287 _elm_image_fill_outside_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
1288 {
1289    return !sd->fill_inside;
1290 }
1291
1292 // TODO: merge preload and async code
1293 EOLIAN static void
1294 _elm_image_preload_disabled_set(Eo *obj EINA_UNUSED, Elm_Image_Data *sd, Eina_Bool disable)
1295 {
1296    if (sd->edje || !sd->img) return;
1297
1298    if (disable)
1299      {
1300         if (sd->preload_status == ELM_IMAGE_PRELOADING)
1301           {
1302              evas_object_image_preload(sd->img, disable);
1303              if (sd->show) evas_object_show(sd->img);
1304              _prev_img_del(sd);
1305           }
1306         sd->preload_status = ELM_IMAGE_PRELOAD_DISABLED;
1307      }
1308    else if (sd->preload_status == ELM_IMAGE_PRELOAD_DISABLED)
1309     {
1310        sd->preload_status = ELM_IMAGE_PRELOADING;
1311        evas_object_image_preload(sd->img, disable);
1312     }
1313 }
1314
1315 EAPI void
1316 elm_image_prescale_set(Evas_Object *obj,
1317                        int size)
1318 {
1319    ELM_IMAGE_CHECK(obj);
1320    eo_do(obj, efl_image_load_size_set(size, size));
1321 }
1322
1323 EOLIAN static void
1324 _elm_image_efl_image_load_size_set(Eo *obj EINA_UNUSED, Elm_Image_Data *sd, int w, int h)
1325 {
1326    if (w > h)
1327       sd->load_size = w;
1328    else
1329       sd->load_size = h;
1330 }
1331
1332 EAPI int
1333 elm_image_prescale_get(const Evas_Object *obj)
1334 {
1335    ELM_IMAGE_CHECK(obj) 0;
1336
1337    int w = 0;
1338    eo_do((Eo *)obj, efl_image_load_size_get(&w, NULL));
1339    return w;
1340 }
1341
1342 EOLIAN static void
1343 _elm_image_efl_image_load_size_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd, int *w, int *h)
1344 {
1345    if (w) *w = sd->load_size;
1346    if (h) *h = sd->load_size;
1347 }
1348
1349 EOLIAN static void
1350 _elm_image_orient_set(Eo *obj, Elm_Image_Data *sd, Elm_Image_Orient orient)
1351 {
1352    if (sd->edje) return;
1353    if (sd->orient == orient) return;
1354
1355    evas_object_image_orient_set(sd->img, orient);
1356    sd->orient = orient;
1357    _elm_image_internal_sizing_eval(obj, sd);
1358 }
1359
1360 EOLIAN static Elm_Image_Orient
1361 _elm_image_orient_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
1362 {
1363    return sd->orient;
1364 }
1365
1366 /**
1367  * Turns on editing through drag and drop and copy and paste.
1368  */
1369 EOLIAN static void
1370 _elm_image_editable_set(Eo *obj, Elm_Image_Data *sd, Eina_Bool edit)
1371 {
1372    if (sd->edje)
1373      {
1374         WRN("No editing edje objects yet (ever)\n");
1375         return;
1376      }
1377
1378    edit = !!edit;
1379
1380    if (edit == sd->edit) return;
1381
1382    sd->edit = edit;
1383
1384    if (sd->edit)
1385      elm_drop_target_add
1386        (obj, ELM_SEL_FORMAT_IMAGE,
1387            NULL, NULL,
1388            NULL, NULL,
1389            NULL, NULL,
1390            _elm_image_drag_n_drop_cb, obj);
1391    else
1392      elm_drop_target_del
1393        (obj, ELM_SEL_FORMAT_IMAGE,
1394            NULL, NULL,
1395            NULL, NULL,
1396            NULL, NULL,
1397            _elm_image_drag_n_drop_cb, obj);
1398 }
1399
1400 EOLIAN static Eina_Bool
1401 _elm_image_editable_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
1402 {
1403    return sd->edit;
1404 }
1405
1406 EOLIAN static Evas_Object*
1407 _elm_image_object_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
1408 {
1409    return sd->img;
1410 }
1411
1412 EOLIAN static void
1413 _elm_image_aspect_fixed_set(Eo *obj, Elm_Image_Data *sd, Eina_Bool fixed)
1414 {
1415    fixed = !!fixed;
1416    if (sd->aspect_fixed == fixed) return;
1417
1418    sd->aspect_fixed = fixed;
1419
1420    _elm_image_internal_sizing_eval(obj, sd);
1421 }
1422
1423 EOLIAN static Eina_Bool
1424 _elm_image_aspect_fixed_get(Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
1425 {
1426    return sd->aspect_fixed;
1427 }
1428
1429 EAPI Eina_Bool
1430 elm_image_animated_available_get(const Evas_Object *obj)
1431 {
1432    Eina_Bool ret;
1433    eo_do(obj, ret = efl_player_playable_get());
1434    return ret;
1435 }
1436
1437 EOLIAN static Eina_Bool
1438 _elm_image_efl_player_playable_get(Eo *obj, Elm_Image_Data *sd)
1439 {
1440    if (sd->edje) return EINA_FALSE;
1441
1442    return evas_object_image_animated_get(elm_image_object_get(obj));
1443 }
1444
1445 static void
1446 _elm_image_animated_set_internal(Eo *obj, Elm_Image_Data *sd, Eina_Bool anim)
1447 {
1448    anim = !!anim;
1449    if (sd->anim == anim) return;
1450
1451    sd->anim = anim;
1452
1453    if (sd->edje)
1454      {
1455         edje_object_animation_set(sd->img, anim);
1456         return;
1457      }
1458    sd->img = elm_image_object_get(obj);
1459    if (!evas_object_image_animated_get(sd->img)) return;
1460
1461    if (anim)
1462      {
1463         sd->frame_count = evas_object_image_animated_frame_count_get(sd->img);
1464         sd->cur_frame = 1;
1465         sd->frame_duration =
1466           evas_object_image_animated_frame_duration_get
1467             (sd->img, sd->cur_frame, 0);
1468         evas_object_image_animated_frame_set(sd->img, sd->cur_frame);
1469      }
1470    else
1471      {
1472         sd->frame_count = -1;
1473         sd->cur_frame = -1;
1474         sd->frame_duration = -1;
1475      }
1476
1477    return;
1478 }
1479
1480 static Eina_Bool
1481 _elm_image_animated_get_internal(const Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
1482 {
1483    if (sd->edje)
1484      return edje_object_animation_get(sd->img);
1485    return sd->anim;
1486 }
1487
1488 EAPI void
1489 elm_image_animated_set(Evas_Object *obj, Eina_Bool anim)
1490 {
1491    Elm_Image_Data *sd = eo_data_scope_get(obj, MY_CLASS);
1492    if (!sd) return;
1493    _elm_image_animated_set_internal(obj, sd, anim);
1494 }
1495
1496 EAPI Eina_Bool
1497 elm_image_animated_get(const Evas_Object *obj)
1498 {
1499    Elm_Image_Data *sd = eo_data_scope_get(obj, MY_CLASS);
1500    if (!sd) return EINA_FALSE;
1501    return _elm_image_animated_get_internal(obj, sd);
1502 }
1503
1504 static void
1505 _elm_image_animated_play_set_internal(Eo *obj, Elm_Image_Data *sd, Eina_Bool play)
1506 {
1507    if (!sd->anim) return;
1508    if (sd->play == play) return;
1509    sd->play = play;
1510    if (sd->edje)
1511      {
1512         edje_object_play_set(sd->img, play);
1513         return;
1514      }
1515    if (play)
1516      {
1517         sd->anim_timer = ecore_timer_add
1518             (sd->frame_duration, _elm_image_animate_cb, obj);
1519      }
1520    else
1521      {
1522         ELM_SAFE_FREE(sd->anim_timer, ecore_timer_del);
1523      }
1524 }
1525
1526 static Eina_Bool
1527 _elm_image_animated_play_get_internal(const Eo *obj EINA_UNUSED, Elm_Image_Data *sd)
1528 {
1529    if (sd->edje)
1530      return edje_object_play_get(sd->img);
1531    return sd->play;
1532 }
1533
1534 EAPI void
1535 elm_image_animated_play_set(Elm_Image *obj, Eina_Bool play)
1536 {
1537    Elm_Image_Data *sd = eo_data_scope_get(obj, MY_CLASS);
1538    if (!sd) return;
1539    _elm_image_animated_play_set_internal(obj, sd, play);
1540 }
1541
1542 EAPI Eina_Bool
1543 elm_image_animated_play_get(const Elm_Image *obj)
1544 {
1545    Elm_Image_Data *sd = eo_data_scope_get(obj, MY_CLASS);
1546    if (!sd) return EINA_FALSE;
1547    return _elm_image_animated_play_get_internal(obj, sd);
1548 }
1549
1550 EOLIAN static void
1551 _elm_image_efl_player_play_set(Eo *obj, Elm_Image_Data *sd, Eina_Bool play)
1552 {
1553    if (play && !_elm_image_animated_get_internal(obj, sd))
1554      _elm_image_animated_set_internal(obj, sd, play);
1555    _elm_image_animated_play_set_internal(obj, sd, play);
1556 }
1557
1558 EOLIAN static Eina_Bool
1559 _elm_image_efl_player_play_get(Eo *obj, Elm_Image_Data *sd)
1560 {
1561    return _elm_image_animated_play_get_internal(obj, sd);
1562 }
1563
1564 static void
1565 _elm_image_class_constructor(Eo_Class *klass)
1566 {
1567    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
1568 }
1569
1570 // A11Y
1571
1572 EOLIAN static void
1573 _elm_image_elm_interface_atspi_image_extents_get(Eo *obj, Elm_Image_Data *sd EINA_UNUSED, Eina_Bool screen_coords, int *x, int *y, int *w, int *h)
1574 {
1575    int ee_x, ee_y;
1576    Evas_Object *image = elm_image_object_get(obj);
1577    if (!image) return;
1578
1579    evas_object_geometry_get(image, x, y, NULL, NULL);
1580    if (screen_coords)
1581      {
1582         Ecore_Evas *ee = ecore_evas_ecore_evas_get(evas_object_evas_get(image));
1583         if (!ee) return;
1584         ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
1585         if (x) *x += ee_x;
1586         if (y) *y += ee_y;
1587      }
1588    elm_image_object_size_get(obj, w, h);
1589 }
1590
1591 EOLIAN const Elm_Atspi_Action *
1592 _elm_image_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUSED, Elm_Image_Data *pd EINA_UNUSED)
1593 {
1594    static Elm_Atspi_Action atspi_actions[] = {
1595         { "activate", "activate", NULL, _key_action_activate },
1596         { NULL, NULL, NULL, NULL },
1597    };
1598    return &atspi_actions[0];
1599 }
1600
1601
1602 // A11Y - END
1603
1604 #include "elm_image.eo.c"