+void TimelineTracker::start_easing(double new_master_speed, Instant now)
+{
+ if (in_easing) {
+ // Apply whatever we managed to complete of the previous easing.
+ origin.out_pts += easing_out_pts_adjustment(now.out_pts);
+ double reached_speed = master_speed + (master_speed_ease_target - master_speed) * find_ease_t(now.out_pts);
+ change_master_speed(reached_speed, now);
+ }
+ in_easing = true;
+ ease_started_pts = now.out_pts;
+ master_speed_ease_target = new_master_speed;
+}
+
+double TimelineTracker::find_ease_t(double out_pts) const
+{
+ return (out_pts - ease_started_pts) / double(ease_length_out_pts);
+}
+
+double TimelineTracker::easing_out_pts_adjustment(double out_pts) const
+{
+ double t = find_ease_t(out_pts);
+ double area_factor = (master_speed_ease_target - master_speed) * ease_length_out_pts;
+ double val = 0.5 * min(t, 1.0) * min(t, 1.0) * area_factor;
+ if (t > 1.0) {
+ val += area_factor * (t - 1.0);
+ }
+ return val;
+}
+