<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[187855] releases/WebKitGTK/webkit-2.8</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/187855">187855</a></dd>
<dt>Author</dt> <dd>carlosgc@webkit.org</dd>
<dt>Date</dt> <dd>2015-08-04 06:01:52 -0700 (Tue, 04 Aug 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Merge <a href="http://trac.webkit.org/projects/webkit/changeset/187121">r187121</a> - Safari mis-applies &quot;animation-fill-mode: forwards&quot; when using fractional iteration count
https://bugs.webkit.org/show_bug.cgi?id=146996

Reviewed by Dean Jackson.
Source/WebCore:

animation-fill-mode: forwards with fractional iteration counts always snapped to
1 or 0, depending on direction. Fix to compute the fill-forward state from the
correct keyframes.

If filling forwards, AnimationBase::progress() sets the elapsed time to the duration,
then uses fractionalTime() to handle animation direction mapping. If the fractionalTime
is integral, we can return early, avoiding the cost of mapping through timing functions.

Tested by existing tests.

* page/animation/AnimationBase.cpp:
(WebCore::AnimationBase::progress):
(WebCore::AnimationBase::getElapsedTime):
* page/animation/KeyframeAnimation.cpp:
(WebCore::KeyframeAnimation::fetchIntervalEndpointsForProperty): It was possible
to end up with prevIndex == nextIndex with reverse animations, which resulted
in divide-by-zero when computing scale. Fix by picking a nextIndex that is different
from prevIndex.

LayoutTests:

Progressions, improved tests.

* animations/animation-direction-reverse-fill-mode-expected.txt: New results; this is a progression.
* animations/animation-direction-reverse-fill-mode.html: Use a shorter animation. Fixed results.
* animations/fill-mode-iteration-count-non-integer-expected.txt:
* animations/fill-mode-iteration-count-non-integer.html: Use iteration counts that are not multiplies
of 0.5, so the test can differentiation between forward and backwards states. Add a non-linear timing
function to check that fill-forwards consults the timing functions. Don't print exact succeeding
results because they may have floating point values.
* animations/fill-mode-reverse-expected.txt: New results; this is a progression.
* animations/fill-mode-reverse.html: Fixed results, use gray.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#releasesWebKitGTKwebkit28LayoutTestsChangeLog">releases/WebKitGTK/webkit-2.8/LayoutTests/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit28LayoutTestsanimationsanimationdirectionreversefillmodeexpectedtxt">releases/WebKitGTK/webkit-2.8/LayoutTests/animations/animation-direction-reverse-fill-mode-expected.txt</a></li>
<li><a href="#releasesWebKitGTKwebkit28LayoutTestsanimationsanimationdirectionreversefillmodehtml">releases/WebKitGTK/webkit-2.8/LayoutTests/animations/animation-direction-reverse-fill-mode.html</a></li>
<li><a href="#releasesWebKitGTKwebkit28LayoutTestsanimationsfillmodeiterationcountnonintegerexpectedtxt">releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-iteration-count-non-integer-expected.txt</a></li>
<li><a href="#releasesWebKitGTKwebkit28LayoutTestsanimationsfillmodeiterationcountnonintegerhtml">releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-iteration-count-non-integer.html</a></li>
<li><a href="#releasesWebKitGTKwebkit28LayoutTestsanimationsfillmodereverseexpectedtxt">releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-reverse-expected.txt</a></li>
<li><a href="#releasesWebKitGTKwebkit28LayoutTestsanimationsfillmodereversehtml">releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-reverse.html</a></li>
<li><a href="#releasesWebKitGTKwebkit28SourceWebCoreChangeLog">releases/WebKitGTK/webkit-2.8/Source/WebCore/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit28SourceWebCorepageanimationAnimationBasecpp">releases/WebKitGTK/webkit-2.8/Source/WebCore/page/animation/AnimationBase.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit28SourceWebCorepageanimationKeyframeAnimationcpp">releases/WebKitGTK/webkit-2.8/Source/WebCore/page/animation/KeyframeAnimation.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="releasesWebKitGTKwebkit28LayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/LayoutTests/ChangeLog (187854 => 187855)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/LayoutTests/ChangeLog        2015-08-04 12:58:10 UTC (rev 187854)
+++ releases/WebKitGTK/webkit-2.8/LayoutTests/ChangeLog        2015-08-04 13:01:52 UTC (rev 187855)
</span><span class="lines">@@ -1,3 +1,22 @@
</span><ins>+2015-07-21  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        Safari mis-applies &quot;animation-fill-mode: forwards&quot; when using fractional iteration count
+        https://bugs.webkit.org/show_bug.cgi?id=146996
+
+        Reviewed by Dean Jackson.
+        
+        Progressions, improved tests.
+
+        * animations/animation-direction-reverse-fill-mode-expected.txt: New results; this is a progression.
+        * animations/animation-direction-reverse-fill-mode.html: Use a shorter animation. Fixed results.
+        * animations/fill-mode-iteration-count-non-integer-expected.txt:
+        * animations/fill-mode-iteration-count-non-integer.html: Use iteration counts that are not multiplies
+        of 0.5, so the test can differentiation between forward and backwards states. Add a non-linear timing
+        function to check that fill-forwards consults the timing functions. Don't print exact succeeding
+        results because they may have floating point values.
+        * animations/fill-mode-reverse-expected.txt: New results; this is a progression.
+        * animations/fill-mode-reverse.html: Fixed results, use gray.
+
</ins><span class="cx"> 2015-07-21  Sungmann Cho  &lt;sungmann.cho@navercorp.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Make PluginProxy::handleMouseEvent() asynchronous.
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit28LayoutTestsanimationsanimationdirectionreversefillmodeexpectedtxt"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/LayoutTests/animations/animation-direction-reverse-fill-mode-expected.txt (187854 => 187855)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/LayoutTests/animations/animation-direction-reverse-fill-mode-expected.txt        2015-08-04 12:58:10 UTC (rev 187854)
+++ releases/WebKitGTK/webkit-2.8/LayoutTests/animations/animation-direction-reverse-fill-mode-expected.txt        2015-08-04 13:01:52 UTC (rev 187855)
</span><span class="lines">@@ -11,7 +11,7 @@
</span><span class="cx"> PASS - start of animation - id: e expected: 300 actual: 300
</span><span class="cx"> PASS - end of animation - id: a expected: 100 actual: 100
</span><span class="cx"> PASS - end of animation - id: b expected: 100 actual: 100
</span><del>-PASS - end of animation - id: c expected: 300 actual: 300
-PASS - end of animation - id: d expected: 300 actual: 300
</del><ins>+PASS - end of animation - id: c expected: 200 actual: 200
+PASS - end of animation - id: d expected: 200 actual: 200
</ins><span class="cx"> PASS - end of animation - id: e expected: 300 actual: 300
</span><span class="cx"> 
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit28LayoutTestsanimationsanimationdirectionreversefillmodehtml"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/LayoutTests/animations/animation-direction-reverse-fill-mode.html (187854 => 187855)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/LayoutTests/animations/animation-direction-reverse-fill-mode.html        2015-08-04 12:58:10 UTC (rev 187854)
+++ releases/WebKitGTK/webkit-2.8/LayoutTests/animations/animation-direction-reverse-fill-mode.html        2015-08-04 13:01:52 UTC (rev 187855)
</span><span class="lines">@@ -10,7 +10,7 @@
</span><span class="cx">       height: 100px;
</span><span class="cx">       width: 100px;
</span><span class="cx">       -webkit-animation-delay: 0.1s;
</span><del>-      -webkit-animation-duration: 2s;
</del><ins>+      -webkit-animation-duration: 0.5s;
</ins><span class="cx">       -webkit-animation-timing-function: linear;
</span><span class="cx">       -webkit-animation-name: anim;
</span><span class="cx">       -webkit-animation-direction: reverse;
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx">       -webkit-animation-fill-mode: both;
</span><span class="cx">     }
</span><span class="cx">     #e {
</span><del>-      background-color: #999;
</del><ins>+      background-color: gray;
</ins><span class="cx">       -webkit-animation-fill-mode: both;
</span><span class="cx">       -webkit-animation-iteration-count: 2;
</span><span class="cx">       -webkit-animation-direction: alternate-reverse;
</span><span class="lines">@@ -50,8 +50,8 @@
</span><span class="cx">     const expectedValues = [
</span><span class="cx">       {id: &quot;a&quot;, start: 100, end: 100},
</span><span class="cx">       {id: &quot;b&quot;, start: 300, end: 100},
</span><del>-      {id: &quot;c&quot;, start: 100, end: 300},
-      {id: &quot;d&quot;, start: 300, end: 300},
</del><ins>+      {id: &quot;c&quot;, start: 100, end: 200},
+      {id: &quot;d&quot;, start: 300, end: 200},
</ins><span class="cx">       {id: &quot;e&quot;, start: 300, end: 300}
</span><span class="cx">     ];
</span><span class="cx">     var result = &quot;&quot;;
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit28LayoutTestsanimationsfillmodeiterationcountnonintegerexpectedtxt"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-iteration-count-non-integer-expected.txt (187854 => 187855)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-iteration-count-non-integer-expected.txt        2015-08-04 12:58:10 UTC (rev 187854)
+++ releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-iteration-count-non-integer-expected.txt        2015-08-04 13:01:52 UTC (rev 187855)
</span><span class="lines">@@ -4,14 +4,20 @@
</span><span class="cx"> Forwards
</span><span class="cx"> Both
</span><span class="cx"> Both iterating
</span><ins>+Both reverse alternate
+Ease function
</ins><span class="cx"> PASS - start of animation - id: a expected: 100 actual: 100
</span><span class="cx"> PASS - start of animation - id: b expected: 200 actual: 200
</span><span class="cx"> PASS - start of animation - id: c expected: 100 actual: 100
</span><span class="cx"> PASS - start of animation - id: d expected: 200 actual: 200
</span><span class="cx"> PASS - start of animation - id: e expected: 200 actual: 200
</span><del>-PASS - end of animation - id: a expected: 100 actual: 100
-PASS - end of animation - id: b expected: 100 actual: 100
-PASS - end of animation - id: c expected: 300 actual: 300
-PASS - end of animation - id: d expected: 300 actual: 300
-PASS - end of animation - id: e expected: 300 actual: 300
</del><ins>+PASS - start of animation - id: f expected: 300 actual: 300
+PASS - start of animation - id: g expected: 300 actual: 300
+PASS - end of animation - id: a close to expected: 100
+PASS - end of animation - id: b close to expected: 100
+PASS - end of animation - id: c close to expected: 225
+PASS - end of animation - id: d close to expected: 225
+PASS - end of animation - id: e close to expected: 225
+PASS - end of animation - id: f close to expected: 275
+PASS - end of animation - id: g close to expected: 291
</ins><span class="cx"> 
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit28LayoutTestsanimationsfillmodeiterationcountnonintegerhtml"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-iteration-count-non-integer.html (187854 => 187855)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-iteration-count-non-integer.html        2015-08-04 12:58:10 UTC (rev 187854)
+++ releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-iteration-count-non-integer.html        2015-08-04 13:01:52 UTC (rev 187855)
</span><span class="lines">@@ -10,10 +10,10 @@
</span><span class="cx">       position: relative;
</span><span class="cx">       left: 100px;
</span><span class="cx">       top: 10px;
</span><del>-      height: 100px;
</del><ins>+      height: 25px;
</ins><span class="cx">       width: 100px;
</span><span class="cx">       -webkit-animation-delay: 0.1s;
</span><del>-      -webkit-animation-duration: 0.2s;
</del><ins>+      -webkit-animation-duration: 2s;
</ins><span class="cx">       -webkit-animation-timing-function: linear;
</span><span class="cx">       -webkit-animation-name: anim;
</span><span class="cx">     }
</span><span class="lines">@@ -34,19 +34,32 @@
</span><span class="cx">     #c {
</span><span class="cx">       background-color: green;
</span><span class="cx">       -webkit-animation-fill-mode: forwards;
</span><del>-      -webkit-animation-iteration-count: 1.5;
</del><ins>+      -webkit-animation-iteration-count: 1.25;
</ins><span class="cx">     }
</span><span class="cx">     #d {
</span><span class="cx">       background-color: yellow;
</span><span class="cx">       -webkit-animation-fill-mode: both;
</span><del>-      -webkit-animation-iteration-count: 1.5;
</del><ins>+      -webkit-animation-iteration-count: 1.25;
</ins><span class="cx">     }
</span><span class="cx">     #e {
</span><del>-      background-color: #999;
</del><ins>+      background-color: gray;
</ins><span class="cx">       -webkit-animation-fill-mode: both;
</span><del>-      -webkit-animation-iteration-count: 2.5;
</del><ins>+      -webkit-animation-iteration-count: 2.25;
</ins><span class="cx">       -webkit-animation-direction: alternate;
</span><span class="cx">     }
</span><ins>+    #f {
+      background-color: silver;
+      -webkit-animation-fill-mode: both;
+      -webkit-animation-iteration-count: 2.25;
+      -webkit-animation-direction: alternate-reverse;
+    }
+    #g {
+      background-color: orange;
+      -webkit-animation-fill-mode: both;
+      -webkit-animation-iteration-count: 2.25;
+      -webkit-animation-timing-function: ease-out;
+      -webkit-animation-direction: alternate-reverse;
+    }
</ins><span class="cx">   &lt;/style&gt;
</span><span class="cx">   &lt;script type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;
</span><span class="cx">     const numAnims = 5;
</span><span class="lines">@@ -55,9 +68,11 @@
</span><span class="cx">     const expectedValues = [
</span><span class="cx">       {id: &quot;a&quot;, start: 100, end: 100},
</span><span class="cx">       {id: &quot;b&quot;, start: 200, end: 100},
</span><del>-      {id: &quot;c&quot;, start: 100, end: 300},
-      {id: &quot;d&quot;, start: 200, end: 300},
-      {id: &quot;e&quot;, start: 200, end: 300}
</del><ins>+      {id: &quot;c&quot;, start: 100, end: 225},
+      {id: &quot;d&quot;, start: 200, end: 225},
+      {id: &quot;e&quot;, start: 200, end: 225},
+      {id: &quot;f&quot;, start: 300, end: 275},
+      {id: &quot;g&quot;, start: 300, end: 291}
</ins><span class="cx">     ];
</span><span class="cx">     var result = &quot;&quot;;
</span><span class="cx"> 
</span><span class="lines">@@ -80,11 +95,10 @@
</span><span class="cx">             var expectedValue = expectedValues[i].end;
</span><span class="cx">             var realValue = window.getComputedStyle(el).getPropertyCSSValue(&quot;left&quot;).getFloatValue(CSSPrimitiveValue.CSS_NUMBER);
</span><span class="cx">             if (Math.abs(expectedValue - realValue) &lt; allowance) {
</span><del>-              result += &quot;PASS&quot;;
</del><ins>+              result += &quot;PASS - end of animation - id: &quot; + expectedValues[i].id + &quot; close to expected: &quot; + expectedValue + &quot;&lt;br&gt;&quot;;
</ins><span class="cx">             } else {
</span><del>-              result += &quot;FAIL&quot;;
</del><ins>+              result += &quot;FAIL - end of animation - id: &quot; + expectedValues[i].id + &quot; expected: &quot; + expectedValue + &quot; actual: &quot; + realValue + &quot;&lt;br&gt;&quot;;
</ins><span class="cx">             }
</span><del>-            result += &quot; - end of animation - id: &quot; + expectedValues[i].id + &quot; expected: &quot; + expectedValue + &quot; actual: &quot; + realValue + &quot;&lt;br&gt;&quot;;
</del><span class="cx">         }
</span><span class="cx">         document.getElementById('result').innerHTML = result;
</span><span class="cx"> 
</span><span class="lines">@@ -128,6 +142,12 @@
</span><span class="cx"> &lt;div id=&quot;e&quot; class=&quot;box&quot;&gt;
</span><span class="cx">   Both iterating
</span><span class="cx"> &lt;/div&gt;
</span><ins>+&lt;div id=&quot;f&quot; class=&quot;box&quot;&gt;
+  Both reverse alternate
+&lt;/div&gt;
+&lt;div id=&quot;g&quot; class=&quot;box&quot;&gt;
+  Ease function
+&lt;/div&gt;
</ins><span class="cx"> &lt;div id=&quot;result&quot;&gt;
</span><span class="cx"> &lt;/div&gt;
</span><span class="cx"> &lt;/body&gt;
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit28LayoutTestsanimationsfillmodereverseexpectedtxt"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-reverse-expected.txt (187854 => 187855)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-reverse-expected.txt        2015-08-04 12:58:10 UTC (rev 187854)
+++ releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-reverse-expected.txt        2015-08-04 13:01:52 UTC (rev 187855)
</span><span class="lines">@@ -11,7 +11,7 @@
</span><span class="cx"> PASS - start of animation - id: e expected: 200 actual: 200
</span><span class="cx"> PASS - end of animation - id: a expected: 100 actual: 100
</span><span class="cx"> PASS - end of animation - id: b expected: 100 actual: 100
</span><del>-PASS - end of animation - id: c expected: 300 actual: 300
-PASS - end of animation - id: d expected: 300 actual: 300
</del><ins>+PASS - end of animation - id: c expected: 200 actual: 200
+PASS - end of animation - id: d expected: 200 actual: 200
</ins><span class="cx"> PASS - end of animation - id: e expected: 200 actual: 200
</span><span class="cx"> 
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit28LayoutTestsanimationsfillmodereversehtml"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-reverse.html (187854 => 187855)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-reverse.html        2015-08-04 12:58:10 UTC (rev 187854)
+++ releases/WebKitGTK/webkit-2.8/LayoutTests/animations/fill-mode-reverse.html        2015-08-04 13:01:52 UTC (rev 187855)
</span><span class="lines">@@ -39,7 +39,7 @@
</span><span class="cx">       -webkit-animation-fill-mode: both;
</span><span class="cx">     }
</span><span class="cx">     #e {
</span><del>-      background-color: #999;
</del><ins>+      background-color: gray;
</ins><span class="cx">       -webkit-animation-fill-mode: both;
</span><span class="cx">       -webkit-animation-iteration-count: 2;
</span><span class="cx">       -webkit-animation-direction: alternate;
</span><span class="lines">@@ -52,8 +52,8 @@
</span><span class="cx">     const expectedValues = [
</span><span class="cx">       {id: &quot;a&quot;, start: 100, end: 100},
</span><span class="cx">       {id: &quot;b&quot;, start: 300, end: 100},
</span><del>-      {id: &quot;c&quot;, start: 100, end: 300},
-      {id: &quot;d&quot;, start: 300, end: 300},
</del><ins>+      {id: &quot;c&quot;, start: 100, end: 200},
+      {id: &quot;d&quot;, start: 300, end: 200},
</ins><span class="cx">       {id: &quot;e&quot;, start: 200, end: 200}
</span><span class="cx">     ];
</span><span class="cx">     var result = &quot;&quot;;
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit28SourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/Source/WebCore/ChangeLog (187854 => 187855)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/Source/WebCore/ChangeLog        2015-08-04 12:58:10 UTC (rev 187854)
+++ releases/WebKitGTK/webkit-2.8/Source/WebCore/ChangeLog        2015-08-04 13:01:52 UTC (rev 187855)
</span><span class="lines">@@ -1,3 +1,29 @@
</span><ins>+2015-07-21  Simon Fraser  &lt;simon.fraser@apple.com&gt;
+
+        Safari mis-applies &quot;animation-fill-mode: forwards&quot; when using fractional iteration count
+        https://bugs.webkit.org/show_bug.cgi?id=146996
+
+        Reviewed by Dean Jackson.
+
+        animation-fill-mode: forwards with fractional iteration counts always snapped to
+        1 or 0, depending on direction. Fix to compute the fill-forward state from the
+        correct keyframes.
+        
+        If filling forwards, AnimationBase::progress() sets the elapsed time to the duration,
+        then uses fractionalTime() to handle animation direction mapping. If the fractionalTime
+        is integral, we can return early, avoiding the cost of mapping through timing functions.
+
+        Tested by existing tests.
+
+        * page/animation/AnimationBase.cpp:
+        (WebCore::AnimationBase::progress):
+        (WebCore::AnimationBase::getElapsedTime):
+        * page/animation/KeyframeAnimation.cpp:
+        (WebCore::KeyframeAnimation::fetchIntervalEndpointsForProperty): It was possible
+        to end up with prevIndex == nextIndex with reverse animations, which resulted
+        in divide-by-zero when computing scale. Fix by picking a nextIndex that is different
+        from prevIndex.
+
</ins><span class="cx"> 2015-07-20  Ada Chan  &lt;adachan@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Follow-up to my earlier fix for r147085
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit28SourceWebCorepageanimationAnimationBasecpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/Source/WebCore/page/animation/AnimationBase.cpp (187854 => 187855)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/Source/WebCore/page/animation/AnimationBase.cpp        2015-08-04 12:58:10 UTC (rev 187854)
+++ releases/WebKitGTK/webkit-2.8/Source/WebCore/page/animation/AnimationBase.cpp        2015-08-04 13:01:52 UTC (rev 187855)
</span><span class="lines">@@ -569,23 +569,25 @@
</span><span class="cx">     if (preActive())
</span><span class="cx">         return 0;
</span><span class="cx"> 
</span><ins>+    if (postActive() || !m_animation-&gt;duration())
+        return 1.0;
+
</ins><span class="cx">     double elapsedTime = getElapsedTime();
</span><span class="cx"> 
</span><span class="cx">     double dur = m_animation-&gt;duration();
</span><span class="cx">     if (m_animation-&gt;iterationCount() &gt; 0)
</span><span class="cx">         dur *= m_animation-&gt;iterationCount();
</span><span class="cx"> 
</span><del>-    if (postActive() || !m_animation-&gt;duration())
-        return 1.0;
</del><ins>+    if (fillingForwards())
+        elapsedTime = dur;
</ins><span class="cx"> 
</span><ins>+    double fractionalTime = this-&gt;fractionalTime(scale, elapsedTime, offset);
+
</ins><span class="cx">     if (m_animation-&gt;iterationCount() &gt; 0 &amp;&amp; elapsedTime &gt;= dur) {
</span><del>-        const int integralIterationCount = static_cast&lt;int&gt;(m_animation-&gt;iterationCount());
-        const bool iterationCountHasFractional = m_animation-&gt;iterationCount() - integralIterationCount;
-        return (integralIterationCount % 2 || iterationCountHasFractional) ? 1.0 : 0.0;
</del><ins>+        if (WTF::isIntegral(fractionalTime))
+            return fractionalTime;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    const double fractionalTime = this-&gt;fractionalTime(scale, elapsedTime, offset);
-
</del><span class="cx">     if (!tf)
</span><span class="cx">         tf = m_animation-&gt;timingFunction().get();
</span><span class="cx"> 
</span><span class="lines">@@ -675,7 +677,7 @@
</span><span class="cx">         return m_pauseTime - m_startTime;
</span><span class="cx">     if (m_startTime &lt;= 0)
</span><span class="cx">         return 0;
</span><del>-    if (postActive())
</del><ins>+    if (postActive() || fillingForwards())
</ins><span class="cx">         return 1;
</span><span class="cx"> 
</span><span class="cx">     return beginAnimationUpdateTime() - m_startTime;
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit28SourceWebCorepageanimationKeyframeAnimationcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.8/Source/WebCore/page/animation/KeyframeAnimation.cpp (187854 => 187855)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.8/Source/WebCore/page/animation/KeyframeAnimation.cpp        2015-08-04 12:58:10 UTC (rev 187854)
+++ releases/WebKitGTK/webkit-2.8/Source/WebCore/page/animation/KeyframeAnimation.cpp        2015-08-04 13:01:52 UTC (rev 187855)
</span><span class="lines">@@ -103,9 +103,16 @@
</span><span class="cx">     if (prevIndex == -1)
</span><span class="cx">         prevIndex = 0;
</span><span class="cx"> 
</span><del>-    if (nextIndex == -1)
-        nextIndex = m_keyframes.size() - 1;
</del><ins>+    if (nextIndex == -1) {
+        int lastIndex = m_keyframes.size() - 1;
+        if (prevIndex == lastIndex)
+            nextIndex = 0;
+        else
+            nextIndex = lastIndex;
+    }
</ins><span class="cx"> 
</span><ins>+    ASSERT(prevIndex != nextIndex);
+
</ins><span class="cx">     const KeyframeValue&amp; prevKeyframe = m_keyframes[prevIndex];
</span><span class="cx">     const KeyframeValue&amp; nextKeyframe = m_keyframes[nextIndex];
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>