scroller: apply "Improved scroller performance" patch. 92/94492/2
authorHosang Kim <hosang12.kim@samsung.com>
Mon, 31 Oct 2016 07:23:42 +0000 (16:23 +0900)
committerGerrit Code Review <gerrit@review.vlan103.tizen.org>
Thu, 3 Nov 2016 11:14:38 +0000 (04:14 -0700)
Signed-off-by: Hosang Kim <hosang12.kim@samsung.com>
Change-Id: I30329241b0030dd368e6c5f25ab083fe33114d61

src/lib/elm_interface_scrollable.c
src/lib/elm_interface_scrollable.h

index cdc275a..ea481d3 100644 (file)
@@ -1390,7 +1390,6 @@ _elm_scroll_bounce_eval(Elm_Scrollable_Smart_Interface_Data *sid)
         if (sid->content_info.resized)
           _elm_scroll_wanted_region_set(sid->obj);
      }
-   ELM_SAFE_FREE(sid->down.hold_enterer, ecore_idle_enterer_del);
 
    eo_do(sid->pan_obj, elm_obj_pan_pos_max_get(&mx, &my));
    eo_do(sid->pan_obj, elm_obj_pan_pos_min_get(&minx, &miny));
@@ -1747,7 +1746,6 @@ _elm_scroll_content_region_show_internal(Evas_Object *obj,
         if (sid->content_info.resized)
           _elm_scroll_wanted_region_set(sid->obj);
      }
-   ELM_SAFE_FREE(sid->down.hold_enterer, ecore_idle_enterer_del);
    if (sid->down.momentum_animator)
      {
         ELM_SAFE_FREE(sid->down.momentum_animator, ecore_animator_del);
@@ -2748,7 +2746,6 @@ _elm_scroll_mouse_up_event_cb(void *data,
              if (sid->content_info.resized)
                _elm_scroll_wanted_region_set(sid->obj);
           }
-        ELM_SAFE_FREE(sid->down.hold_enterer, ecore_idle_enterer_del);
         if (sid->down.scroll)
           {
              ev->event_flags |= EVAS_EVENT_FLAG_ON_SCROLL;
@@ -2836,7 +2833,6 @@ _elm_scroll_mouse_down_event_cb(void *data,
         if (sid->content_info.resized)
           _elm_scroll_wanted_region_set(sid->obj);
      }
-   ELM_SAFE_FREE(sid->down.hold_enterer, ecore_idle_enterer_del);
    if (sid->down.momentum_animator)
      {
         ELM_SAFE_FREE(sid->down.momentum_animator, ecore_animator_del);
@@ -3044,116 +3040,379 @@ _elm_scroll_down_coord_eval(Elm_Scrollable_Smart_Interface_Data *sid,
        _elm_config->thumbscroll_border_friction;
 }
 
+
+
+//TIZEN ONLY : for scroll smooth algorithm
+#define iround(x) ((x)>=0?(int)((x)+0.5):(int)((x)-0.5))
+
+//> Frequency of move events
+#define ELM_MOVE_PER_SECOND (90.75f)
+//>Time between two subsequent events
+static const float ELM_MOVE_TIMEOUT = (1.0f/ELM_MOVE_PER_SECOND);
+
+//>Quantity of move events in time interval
+#define ELM_MOVE_COUNT(t) iround((t)*ELM_MOVE_PER_SECOND)
+
+//>Getting coordinate (x is 0, y is 1) from struct Elm_Scroll_Pos or Elm_Scroll_History_Item.
+#define ELM_GET_COORD(p, coord) (*((int *)p + coord))
+
+//>Difference of coordinates of points with indexes ind and ind+inc.
+#define ELM_DIFF(p, coord, ind, inc)  (ELM_GET_COORD((p + ind), coord) - ELM_GET_COORD((p + ind + inc), coord))
+
+//>Index in array for calculation of smoothed velocity.
+#define ELM_SMOOTH_SPEED_INDEX 9
+
+//>in seconds, includes driver to X time gap
+#define EXTRA_PREDIOCTION_TIME (-0.005)
+
+//>Calculating current velocity. In normal situation it is (pos[0].x - pos[ELM_SMOOTH_SPEED_INDEX].x) / (pos[0].t - pos[ELM_SMOOTH_SPEED_INDEX].t).
+//>But in situations when: 1. Sign of velocity was changes or 2. The acceleration is of constant sign or 3. There was stop of movement
+//>The index ELM_SMOOTH_SPEED_INDEX is replaced by 1.
+double _elm_scroll_get_v(Elm_Scroll_Pos *pos, int num, int coord,
+                         double *dt, int *pdiff, double *padt, Elm_Scroll_Predict *predict)
+{
+   double v = 0;
+   int nmeasure_idx = (num > ELM_SMOOTH_SPEED_INDEX) ? ELM_SMOOTH_SPEED_INDEX : (num -1);
+   // a recent input takes higher priority
+#if USE_HISTORY_WEIGHT
+   if (nmeasure_idx >= 2)
+     *pdiff = (ELM_DIFF(pos, coord, 0, 1) * 2 + ELM_DIFF(pos, coord, 1, 1))/3;
+   else
+#else
+     *pdiff = ELM_DIFF(pos, coord, 0, 1);
+#endif
+
+#if ADJUST_EVENT_TIME
+   *dt = -ELM_MOVE_TIMEOUT;
+#else
+   if (nmeasure_idx >= 2)
+       *dt = -(pos[2].t - pos[0].t)/2.;
+   else
+       *dt = -(pos[1].t - pos[0].t);
+#endif
+   if (*dt == 0)
+     *dt = -ELM_MOVE_TIMEOUT;
+   v = *pdiff / *dt;
+   predict->k[coord] = 0;
+   *padt = EXTRA_PREDIOCTION_TIME;
+
+   return v;
+}
+
 static Eina_Bool
-_elm_scroll_hold_enterer(void *data)
+_elm_scroll_get_pos(Elm_Scrollable_Smart_Interface_Data *sid,
+                                     Elm_Scroll_Pos *pos, int num, int *fx, int *fy)
 {
-   Elm_Scrollable_Smart_Interface_Data *sid = data;
-   Evas_Coord ox = 0, oy = 0, fx = 0, fy = 0;
-//   Evas_Coord fy2;
+   double vx = 0, vy = 0, dt = 0, dtx = 0, dty = 0;
+
+   if (num < 1)
+     {
+        return EINA_FALSE;
+     }
+   else if (num == 1)
+     {
+        *fx = iround((double)pos[0].x);
+        *fy = iround((double)pos[0].y);
+     }
+   else if (num >= 2)
+     {
+        int diffx, diffy;
+        if (sid->down.dir_y)
+          vy = _elm_scroll_get_v(pos, num, 1, &dt, &diffy, &dty, &sid->down.predict);
+        if (sid->down.dir_x)
+          vx = _elm_scroll_get_v(pos, num, 0, &dt, &diffx, &dtx, &sid->down.predict);
+     }
+
+   if (sid->down.dir_x)
+     {
+        *fx = iround((double)pos[0].x - (pos[0].t + dtx) * vx);
+        // don't go back even though over-run is detected.
+        if (sid->down.anim_vx_prev && sid->down.anim_vx_prev * vx >= 0)
+          if (vx == 0 || (vx > 0 && *fx  > sid->down.anim_x_prev) ||
+              (vx < 0 && *fx  < sid->down.anim_x_prev))
+            *fx = sid->down.anim_x_prev;
+     }
+
+   if (sid->down.dir_y)
+     {
+        *fy = iround((double)pos[0].y - (pos[0].t + dty) * vy);
+        // don't go back even though over-run is detected.
+        if (sid->down.anim_vy_prev && sid->down.anim_vy_prev * vy >= 0)
+          if (vy == 0 || (vy > 0 && *fy  > sid->down.anim_y_prev) ||
+              (vy < 0 && *fy  < sid->down.anim_y_prev))
+            *fy = sid->down.anim_y_prev;
+     }
+
+   sid->down.anim_x_prev = *fx;
+   sid->down.anim_y_prev = *fy;
+   sid->down.anim_vx_prev = vx;
+   sid->down.anim_vy_prev = vy;
+
+   return EINA_TRUE;
+}
 
-   sid->down.hold_enterer = NULL;
+#define COMPENSATE_FOR_INITIAL_RENDER_DELAY 0
+#define ADJUST_ANIMATOR_TIMING              0
+#define SMART_SMOOTH_START                  1
+#define HOLD_ANIMATOR_DEBUG_LEVEL1          0
+#define HOLD_ANIMATOR_DEBUG_LEVEL2          0
+#define HOLD_ANIMATOR_DEBUG_X_AXIS          1
+#define ADJUST_EVENT_TIME                   0
+#define USE_HISTORY_WEIGHT                  0
+#define USE_LOOP_TIME                       1
+#define PREDICT_WHEN_PAUSED                 0
 
+static Eina_Bool
+_elm_scroll_hold_animator(void *data)
+{
+   Elm_Scrollable_Smart_Interface_Data *sid = data;
+   Evas_Coord ox = 0, oy = 0, fx = 0, fy = 0, x = 0, y = 0, num = 0;
+   Evas_Coord fx_coord = 0, fy_coord = 0;
    fx = sid->down.hold_x;
    fy = sid->down.hold_y;
-//   fy2 = fy;
-   if ((_elm_config->scroll_smooth_amount > 0.0) &&
-       (_elm_config->scroll_smooth_time_window > 0.0))
-     {
-        int i, count = 0;
-        Evas_Coord basex = 0, basey = 0, x, y;
-        double dt, tdiff, tnow, twin, ttot;
-        double xx, yy, tot;
-        struct
+   fx_coord = sid->down.anim_x_coord_prev;
+   fy_coord = sid->down.anim_y_coord_prev;
+#define QUEUE_SIZE 3 /* for event queue size */
+   Elm_Scroll_Pos pos[QUEUE_SIZE];
+
+   double now, now_diff, prev;
+   double animators_frametime=0, d = 0;
+
+   sid->down.anim_count++;
+
+#if COMPENSATE_FOR_INITIAL_RENDER_DELAY
+   Ecore_Animator_Source source = ecore_animator_source_get();
+#endif
+
+   // FIXME: assume server and client have the same "timezone"
+   // (0 timepoint) for now. this needs to be figured out in advance
+   // though.
+#if USE_LOOP_TIME
+   now = ecore_loop_time_get();
+#else
+   now = ecore_time_get();
+#endif
+
+   // init variables for the first animator run
+   if (sid->down.anim_count == 1)
+     {
+        sid->down.anim_t_prev = now;
+        sid->down.anim_x_coord_prev = fx;
+        sid->down.anim_y_coord_prev = fy;
+        fx_coord = fx;
+        fy_coord = fy;
+     }
+   prev = sid->down.anim_t_prev;
+   now_diff = now - prev;
+   animators_frametime = ecore_animator_frametime_get();
+#if COMPENSATE_FOR_INITIAL_RENDER_DELAY
+   if (sid->down.anim_count == 1)
+     {
+        if (source != ECORE_ANIMATOR_SOURCE_CUSTOM)
+          sid->down.anim_t_delay = fmod(now, animators_frametime);
+     }
+   else
+#endif
+     {
+        sid->down.anim_t_delay += now_diff - animators_frametime;
+     }
+
+   // skip this turn if specified.
+   if (sid->down.anim_skip > 0)
+     {
+        sid->down.anim_skip--;
+#if HOLD_ANIMATOR_DEBUG_LEVEL1
+        DBG("[%03d/%s] %.4f %.3f/%.3f dt:%.3f = %.3f%+.3f ev: %.4f skip(%d)\n",
+            sid->down.anim_count, (source == ECORE_ANIMATOR_SOURCE_CUSTOM) ? "V" : "T",
+            now, sid->down.anim_t_delay * 1000, sid->down.anim_t_adjusted * 1000,
+            now_diff*1000,
+            (now_diff - d)*1000,
+            d*1000,
+            sid->down.history[0].timestamp,
+            sid->down.anim_skip);
+#endif
+            if ((now_diff * 1000) > 18)
+              {
+#if ADJUST_ANIMATOR_TIMING
+                 sid->down.anim_t_dont_adjust = 1;
+#endif
+                 goto update_time_and_quit;
+              }
+     }
+
+   // We don't need to process old events again.
+   if (sid->down.anim_count != 1 &&
+           sid->down.anim_pos_t_prev == sid->down.history[0].timestamp)
+     {
+#if HOLD_ANIMATOR_DEBUG_LEVEL1
+        DBG("[%03d/%s] %.4f %.3f/%.3f dt:%.3f = %.3f%+.3f ev:%.4f skip(%d) no events.\n",
+            sid->down.anim_count, (source == ECORE_ANIMATOR_SOURCE_CUSTOM) ? "V" : "T",
+            now, sid->down.anim_t_delay * 1000, sid->down.anim_t_adjusted * 1000,
+            now_diff*1000,
+            (now_diff - d)*1000,
+            d*1000,
+            sid->down.history[0].timestamp,
+            sid->down.anim_skip);
+#endif
+
+        goto update_time_and_quit;
+   }
+
+#if ADJUST_ANIMATOR_TIMING
+   if (sid->down.anim_count != 1 && !sid->down.anim_t_dont_adjust)
+     {
+        if (now_diff < animators_frametime*3/4)
           {
-             Evas_Coord x, y;
-             double t;
-          } pos[100];
-
-        tdiff = sid->down.hist.est_timestamp_diff;
-        tnow = ecore_loop_time_get();
-        twin = _elm_config->scroll_smooth_time_window;
-        for (i = 0; i < 60; i++)
+             d += animators_frametime/4;
+          }
+        else if (now_diff < animators_frametime)
           {
-             if ((sid->down.history[i].timestamp - tdiff) > tnow)
-               continue;
-             if ((sid->down.history[i].timestamp >
-                 sid->down.dragged_began_timestamp) || (count == 0))
+             d = animators_frametime - now_diff;
+          }
+        else if (now_diff < animators_frametime*5/4)
+          {
+             d = -(now_diff - animators_frametime);
+          }
+        else
+          {
+             d = -animators_frametime/4;
+          }
+
+        now += d;
+        now_diff +=d;
+        sid->down.anim_t_adjusted += d;
+     }
+
+   sid->down.anim_t_dont_adjust = 0;
+
+#endif
+
+#if COMPENSATE_FOR_INITIAL_RENDER_DELAY
+   // in case the first animator is called manually to make up for gpu's wake-up time,
+   // then the second animator should be skipped.
+   if ((sid->down.anim_count == 1) && (sid->down.anim_skip <= 0))
+     sid->down.anim_skip++;
+#endif
+
+   if ((!sid->hold) && (!sid->freeze))
+     {
+        int i = 0;
+        int ncur_diff_x=0, ncur_diff_y=0;
+        int nprev_diff_x=0, nprev_diff_y=0;
+
+        for (i = 0; i < QUEUE_SIZE; i++)
+          {
+             if (sid->down.history[i].timestamp >=
+                 sid->down.dragged_began_timestamp)
                {
                   x = sid->down.history[i].x;
                   y = sid->down.history[i].y;
-                  _elm_scroll_down_coord_eval(sid, &x, &y);
-                  if (count == 0)
+
+                  //if there is no history value, we don't deal with it if
+                  //there is better wat to know existance of history value
+                  //, I will modify this code to it
+                  if ((x == 0) && (y == 0))
                     {
-                       basex = x;
-                       basey = y;
+                       break;
                     }
-                  dt = (tnow + tdiff) - sid->down.history[i].timestamp;
-                  if ((dt > twin) && (count > 0)) break;
-                  if ((dt > 0.0) && (count == 0))
+
+                  pos[i].x = x;
+                  pos[i].y = y;
+                  pos[i].t = now - sid->down.history[i].timestamp;
+                  num++;
+
+                  if (num <= 1)
+                      continue;
+
+                  // get rid of histories with different move direction.
+                  if (sid->down.dir_x)
+                    ncur_diff_x = pos[i].x - pos[i-1].x;
+                  if (sid->down.dir_y)
+                    ncur_diff_y = pos[i].y - pos[i-1].y;
+
+                  if (ncur_diff_x * nprev_diff_x < 0 || ncur_diff_y * nprev_diff_y < 0)
                     {
-                       pos[count].x = x - basex;
-                       pos[count].y = y - basey;
-                       pos[count].t = 0.0;
-                       count++;
+                       num--;
+#if HOLD_ANIMATOR_DEBUG_LEVEL2
+                       DBG("[%03d] i=%d a dir change detected. stopped.\n",
+                           sid->down.anim_count, i);
+#endif
+                       break;
                     }
-                  pos[count].x = x - basex;
-                  pos[count].y = y - basey;
-                  pos[count].t = dt;
-                  count++;
-               }
-          }
-        if (count > 0)
-          {
-             xx = 0.0;
-             yy = 0.0;
-             tot = 0.0;
-             ttot = pos[count - 1].t;
-             for (i = 0; i < count; i++)
-               {
-                  double wt;
 
-                  if (ttot > 0.0)
+                  nprev_diff_x = ncur_diff_x;
+                  nprev_diff_y = ncur_diff_y;
+
+#if ADJUST_EVENT_TIME
+                  //> a event is delayed??
+                  if (ELM_MOVE_COUNT(pos[i].t - pos[i-1].t) <= 0)
                     {
-                       if (i < (count - 1))
-                         wt = (ttot - pos[i].t) * (pos[i + 1].t - pos[i].t);
-                       else
-                         wt = 0.0;
+                       DBG("[%03d] i=%d a event is delayed (%f) ??????????????????\n",
+                           sid->down.anim_count,
+                           i, pos[i].t - pos[i-1].t);
                     }
-                  else wt = 1.0;
 
-                  xx += ((double)(pos[i].x)) * wt;
-                  yy += ((double)(pos[i].y)) * wt;
-                  tot += wt;
+                  //> a pause in movement detected
+                  if (ELM_MOVE_COUNT(pos[i].t - pos[i-1].t) >= 2)
+                    {
+#if HOLD_ANIMATOR_DEBUG_LEVEL2
+                       DBG("[%03d] i=%d a pause(%f) in movement detected. stopped.\n",
+                           sid->down.anim_count, i, pos[i].t - pos[i-1].t);
+#endif
+#if PREDICT_WHEN_PAUSED
+                       pos[i].t = pos[i-1].t + ELM_MOVE_TIMEOUT;
+#else
+                       num--;
+#endif
+                       break;
+                    }
+#endif
                }
-             if (tot > 0.0)
+          }
+
+#if ADJUST_EVENT_TIME
+        // X server fills in time in milisecond order and it rounds off.
+        // let's makt it more precise and this is proven by machine moving at constant speed.
+        //double pos_diff = 0;
+        if (num >= 2)
+          {
+             double tmp = sid->down.history[0].timestamp;
+             for (i = num - 1; i >= 1; i--)
                {
-                  xx = basex + (xx / tot);
-                  yy = basey + (yy / tot);
-                  fx =
-                    (_elm_config->scroll_smooth_amount * xx) +
-                    ((1.0 - _elm_config->scroll_smooth_amount) * fx);
-                  fy =
-                    (_elm_config->scroll_smooth_amount * yy) +
-                    ((1.0 - _elm_config->scroll_smooth_amount) * fy);
+                  pos[i-1].t = pos[i].t - ELM_MOVE_TIMEOUT;
+                  sid->down.history[i-1].timestamp = now - pos[i-1].t;
                }
+             //pos_diff = sid->down.history[0].timestamp - tmp;
           }
+
+#endif
+        sid->down.anim_pos_t_prev = sid->down.history[0].timestamp;
+
+        //TIZEN ONLY : for scroll smooth algorithm
+        _elm_scroll_get_pos(sid, pos, num, &fx, &fy);
+
+        fx_coord = fx;
+        fy_coord = fy;
+        _elm_scroll_down_coord_eval(sid, &fx_coord, &fy_coord);
+
      }
-//   printf("%1.5f %i %i\n",
-//          ecore_loop_time_get() - sid->down.dragged_began_timestamp,
-//          fy, fy2);
 
    eo_do(sid->obj, elm_interface_scrollable_content_pos_get(&ox, &oy));
    if (sid->down.dir_x)
      {
         if ((!sid->obj) ||
             (!elm_widget_drag_child_locked_x_get(sid->obj)))
-          ox = fx;
+            {
+          ox = fx_coord;
+     }
      }
    if (sid->down.dir_y)
      {
         if ((!sid->obj) ||
             (!elm_widget_drag_child_locked_y_get(sid->obj)))
-          oy = fy;
+            {
+          oy = fy_coord;
+     }
      }
 
 #ifdef SMOOTHDBG
@@ -3162,18 +3421,42 @@ _elm_scroll_hold_enterer(void *data)
 #endif
 
    eo_do(sid->obj, elm_interface_scrollable_content_pos_set(ox, oy, EINA_TRUE));
+   ERR("[DDO] ox(%d), oy(%d)", ox, oy);
+
+#if HOLD_ANIMATOR_DEBUG_LEVEL1
+#if HOLD_ANIMATOR_DEBUG_X_AXIS
+   DBG("[%03d/%s] %.4f %.3f/%.3f dt:%.3f = %.3f%+.3f ev:%02d %3.4f/%+.3f p:%d(%d) = %d%+d %d %d\n",
+       sid->down.anim_count, (source == ECORE_ANIMATOR_SOURCE_CUSTOM) ? "V" : "T",
+       now, sid->down.anim_t_delay * 1000, sid->down.anim_t_adjusted * 1000,
+       now_diff*1000,
+       (now_diff - d)*1000,
+       d*1000,
+       num, sid->down.history[0].timestamp, pos_diff*1000,
+       ox, fx,
+       sid->down.hold_x, ox - sid->down.hold_x,
+       ox - sid->down.anim_x_coord_prev,
+       (int)sid->down.anim_vx_prev);
+#else
+   DBG("[%03d/%s] %.4f %.3f/%.3f dt:%.3f = %.3f%+.3f ev:%02d %3.4f/%+.3f p:%d(%d) = %d%+d %d %d\n",
+       sid->down.anim_count, (source == ECORE_ANIMATOR_SOURCE_CUSTOM) ? "V" : "T",
+       now, sid->down.anim_t_delay * 1000, sid->down.anim_t_adjusted * 1000,
+       now_diff*1000,
+       (now_diff - d)*1000,
+       d*1000,
+       num, sid->down.history[0].timestamp, pos_diff*1000,
+       oy, fy,
+       sid->down.hold_y, oy - sid->down.hold_y,
+       oy - sid->down.anim_y_coord_prev,
+       (int)sid->down.anim_vy_prev);
+#endif
+#endif
 
-   return EINA_FALSE;
-}
+   sid->down.anim_x_coord_prev = ox;
+   sid->down.anim_y_coord_prev = oy;
 
-static Eina_Bool
-_elm_scroll_hold_animator(void *data)
-{
-   Elm_Scrollable_Smart_Interface_Data *sid = data;
+update_time_and_quit:
+   sid->down.anim_t_prev = now;
 
-   ecore_idle_enterer_del(sid->down.hold_enterer);
-   sid->down.hold_enterer =
-     ecore_idle_enterer_before_add(_elm_scroll_hold_enterer, sid);
    return ECORE_CALLBACK_RENEW;
 }
 
@@ -3401,12 +3684,36 @@ _elm_scroll_mouse_move_event_cb(void *data,
              if (!sid->down.dragged_began &&
                  _elm_config->scroll_smooth_start_enable)
                {
-                  sid->down.x = ev->cur.canvas.x;
-                  sid->down.y = ev->cur.canvas.y;
+#if SMART_SMOOTH_START
+                  int i = 0;
+                  for (i = 0 ; i < 5 ; i++)
+                     if (!sid->down.history[i].timestamp)
+                        break;
+                  if (i > 0)
+                    {
+                       i--;
+                       DBG("smooth-start(-%d): %d->%d->%d->%d->%d->%d\n",
+                       i,
+                       sid->down.history[0].x,
+                       sid->down.history[1].x,
+                       sid->down.history[2].x,
+                       sid->down.history[3].x,
+                       sid->down.history[4].x,
+                       sid->down.x);
+                       sid->down.x = sid->down.history[i].x;
+                       sid->down.y = sid->down.history[i].y;
+                       sid->down.dragged_began_timestamp = sid->down.history[i].timestamp;
+                    }
+#else
+                 sid->down.x = ev->cur.canvas.x;
+                 sid->down.y = ev->cur.canvas.y;
 #ifdef EVTIME
-                  sid->down.dragged_began_timestamp = ev->timestamp / 1000.0;
+                 sid->down.dragged_began_timestamp =
+                 ev->timestamp / 1000.0;
 #else
-                  sid->down.dragged_began_timestamp = ecore_loop_time_get();
+                 sid->down.dragged_began_timestamp =
+                 ecore_loop_time_get();
+#endif
 #endif
                }
 
@@ -3481,8 +3788,24 @@ _elm_scroll_mouse_move_event_cb(void *data,
              sid->down.hold_x = x;
              sid->down.hold_y = y;
              if (!sid->down.hold_animator)
-               sid->down.hold_animator =
-                 ecore_animator_add(_elm_scroll_hold_animator, sid);
+                {
+                       sid->down.hold_animator =
+                          ecore_animator_add(_elm_scroll_hold_animator, sid);
+                        sid->down.anim_x_prev = 0;
+                        sid->down.anim_y_prev = 0;
+                        sid->down.anim_vx_prev = 0;
+                        sid->down.anim_vy_prev = 0;
+                        sid->down.anim_t_prev = 0;
+                        sid->down.anim_x_coord_prev = 0;
+                        sid->down.anim_y_coord_prev = 0;
+                        sid->down.anim_count = 0;
+                        sid->down.anim_skip = 0;
+                        sid->down.anim_t_dont_adjust = 0;
+                        sid->down.anim_t_delay = 0;
+                        sid->down.anim_t_adjusted = 0;
+                        sid->down.anim_pos_t_prev = 0;
+                        memset(&sid->down.predict, 0 , sizeof(sid->down.predict));
+                }
           }
         else
           {
@@ -4610,7 +4933,6 @@ _elm_interface_scrollable_evas_object_smart_del(Eo *obj, Elm_Scrollable_Smart_In
    eo_do(obj, elm_interface_scrollable_content_set(NULL));
    if (!sid->extern_pan) evas_object_del(sid->pan_obj);
 
-   ecore_idle_enterer_del(sid->down.hold_enterer);
    ecore_animator_del(sid->down.hold_animator);
    ecore_animator_del(sid->down.onhold_animator);
    ecore_animator_del(sid->down.momentum_animator);
index a3ec419..c99a644 100644 (file)
@@ -46,6 +46,25 @@ struct _Elm_Pan_Smart_Data
    Evas_Coord                     content_w, content_h, px, py;
 };
 
+//TIZEN ONLY :  for scroller smooth algorithm
+typedef struct _Elm_Scroll_Pos
+{
+   Evas_Coord x, y;
+   double     t;
+} Elm_Scroll_Pos;
+
+typedef struct _Elm_Scroll_History_Item
+{
+   Evas_Coord x, y;
+   double     timestamp, localtimestamp;
+} Elm_Scroll_History_Item;
+
+typedef struct _Elm_Scroll_Predict
+{
+    double k[2];
+} Elm_Scroll_Predict;
+#define ELM_SCROLL_HISTORY_SIZE 60
+
 /**
  * Elementary scrollable interface base data.
  */
@@ -110,7 +129,6 @@ struct _Elm_Scrollable_Smart_Interface_Data
       Evas_Coord      locked_x, locked_y;
       int             hdir, vdir;
 
-      Ecore_Idle_Enterer *hold_enterer;
       Ecore_Animator *hold_animator;
       Ecore_Animator *onhold_animator;
       Ecore_Animator *momentum_animator; /**< an animator which is called whenever a scroller is moving due to a flick action(mouse down, move, up) */
@@ -133,6 +151,22 @@ struct _Elm_Scrollable_Smart_Interface_Data
       Eina_Bool       dir_y : 1;
       Eina_Bool       hold : 1;
       Eina_Bool       now : 1;
+      double          anim_t_prev;
+      int             anim_x_prev;
+      int             anim_y_prev;
+      double          anim_vx_prev;
+      double          anim_vy_prev;
+      int             anim_x_coord_prev;
+      int             anim_y_coord_prev;
+      int             anim_count;
+      int             anim_skip;
+      int             anim_t_dont_adjust;
+      double          anim_t_delay;
+      double          anim_t_adjusted;
+      double          anim_pos_t_prev;
+      Evas_Coord    pageflick_h;
+      Evas_Coord    pageflick_v;
+      Elm_Scroll_Predict predict;
    } down;
 
    struct