Commit e519fcb2 authored by dino@apple.com's avatar dino@apple.com

2010-06-25 Dean Jackson <dino@apple.com>

        Reviewed by Simon Fraser.

        https://bugs.webkit.org/show_bug.cgi?id=41188
        Animations should not require 0% and 100% keyframes

        When we are generating the animation lists in CSSStyleSelector,
        rather than bail if we notice that "from" or "to" are missing, we
        now generate synthetic keyframes for those cases.

        Tests: animations/missing-from-to-transforms.html
               animations/missing-from-to.html
               WebCore/manual-tests/animation-with-transition.html

        * css/CSSStyleSelector.cpp:
        (WebCore::CSSStyleSelector::styleForKeyframe):
                Moved individual keyframe generation into a new function.
        (WebCore::CSSStyleSelector::keyframeStylesForAnimation):
                Call the new function above for regular keyframes, and
                also check for missing keyframes and generate them if
                necessary.
        * css/CSSStyleSelector.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@61933 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 20f5edfd
2010-06-25 Dean Jackson <dino@apple.com>
Reviewed by Simon Fraser.
https://bugs.webkit.org/show_bug.cgi?id=41188
Animations should not require 0% and 100% keyframes
* animations/keyframes-from-missing-expected.txt: Removed.
* animations/keyframes-from-missing.html: Removed.
* animations/keyframes-to-missing-expected.txt: Removed.
* animations/keyframes-to-missing.html: Removed.
* animations/missing-from-to-transforms-expected.txt: Added.
* animations/missing-from-to-transforms.html: Added.
* animations/missing-from-to-expected.txt: Added.
* animations/missing-from-to.html: Added.
2010-06-25 Csaba Osztrogonác <ossy@webkit.org>
Unreviewed.
This test performs an animation of the left property. The 'from' keyframe is missing so it should not animate
PASS
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Keyframes test with 'from' keyframe missing</title>
<style type="text/css" media="screen">
#box {
position: absolute;
left: 0;
top: 100px;
height: 100px;
width: 100px;
background-color: blue;
-webkit-animation-duration: 1s;
-webkit-animation-timing-function: linear;
-webkit-animation-name: "anim";
}
@-webkit-keyframes "anim" {
20% { left: 100px; }
40% { left: 100px; }
60% { left: 200px; }
80% { left: 200px; }
to { left: 300px; }
}
</style>
<script type="text/javascript" charset="utf-8">
function start()
{
layoutTestController.dumpAsText();
if (layoutTestController.pauseAnimationAtTimeOnElementWithId("anim", 0.5, "box"))
document.getElementById('result').innerHTML = "FAIL: animation is running";
else
document.getElementById('result').innerHTML = "PASS";
}
if (window.layoutTestController)
window.addEventListener('load', start, false);
</script>
</head>
<body>
This test performs an animation of the left property. The 'from' keyframe is missing so it should not animate
<div id="box">
</div>
<div id="result">
</div>
</body>
</html>
This test performs an animation of the left property. The 'to' keyframe is missing so it should not animate
PASS
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Keyframes test with 'to' keyframe missing</title>
<style type="text/css" media="screen">
#box {
position: absolute;
left: 0;
top: 100px;
height: 100px;
width: 100px;
background-color: blue;
-webkit-animation-duration: 1s;
-webkit-animation-timing-function: linear;
-webkit-animation-name: "anim";
}
@-webkit-keyframes "anim" {
from { left: 50px; }
20% { left: 100px; }
40% { left: 100px; }
60% { left: 200px; }
80% { left: 200px; }
}
</style>
<script type="text/javascript" charset="utf-8">
function start()
{
layoutTestController.dumpAsText();
if (layoutTestController.pauseAnimationAtTimeOnElementWithId("anim", 0.5, "box"))
document.getElementById('result').innerHTML = "FAIL: animation is running";
else
document.getElementById('result').innerHTML = "PASS";
}
if (window.layoutTestController)
window.addEventListener('load', start, false);
</script>
</head>
<body>
This test performs an animation of the left property. The 'to' keyframe is missing so it should not animate
<div id="box">
</div>
<div id="result">
</div>
</body>
</html>
This test performs animations of the left property on five boxes over 2 seconds. Box 1 has all keyframes. Box 2 has a missing "from" keyframe. Box 3 has a missing "to" keyframe. Box 4 has both "from" and "to" keyframes missing, but other keyframes which should trigger the generation of "from" and "to". Box 5 has no keyframes, and should not animate. The test takes 3 snapshots each and expects each result to be within a specified range.
PASS - box5 animation was not running
PASS - "left" property for "box1" element at 0.4s saw something close to: 20
PASS - "left" property for "box1" element at 1s saw something close to: 20
PASS - "left" property for "box1" element at 1.6s saw something close to: 15
PASS - "left" property for "box2" element at 0.4s saw something close to: 20
PASS - "left" property for "box2" element at 1s saw something close to: 20
PASS - "left" property for "box2" element at 1.6s saw something close to: 15
PASS - "left" property for "box3" element at 0.4s saw something close to: 20
PASS - "left" property for "box3" element at 1s saw something close to: 20
PASS - "left" property for "box3" element at 1.6s saw something close to: 15
PASS - "left" property for "box4" element at 0.4s saw something close to: 20
PASS - "left" property for "box4" element at 1s saw something close to: 25
PASS - "left" property for "box4" element at 1.6s saw something close to: 15
This test performs animations of the transform property on five boxes over 2 seconds. Box 1 has all keyframes. Box 2 has a missing "from" keyframe. Box 3 has a missing "to" keyframe. Box 4 has both "from" and "to" keyframes missing, but other keyframes which should trigger the generation of "from" and "to". Box 5 has no keyframes, and should not animate. The test takes 3 snapshots each and expects each result to be within a specified range.
PASS - box5 animation was not running
PASS - "webkitTransform.4" property for "box1" element at 0.4s saw something close to: 20
PASS - "webkitTransform.4" property for "box1" element at 1s saw something close to: 20
PASS - "webkitTransform.4" property for "box1" element at 1.6s saw something close to: 15
PASS - "webkitTransform.4" property for "box2" element at 0.4s saw something close to: 20
PASS - "webkitTransform.4" property for "box2" element at 1s saw something close to: 20
PASS - "webkitTransform.4" property for "box2" element at 1.6s saw something close to: 15
PASS - "webkitTransform.4" property for "box3" element at 0.4s saw something close to: 20
PASS - "webkitTransform.4" property for "box3" element at 1s saw something close to: 20
PASS - "webkitTransform.4" property for "box3" element at 1.6s saw something close to: 15
PASS - "webkitTransform.4" property for "box4" element at 0.4s saw something close to: 20
PASS - "webkitTransform.4" property for "box4" element at 1s saw something close to: 25
PASS - "webkitTransform.4" property for "box4" element at 1.6s saw something close to: 15
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Test animation with missing from and to keyframes</title>
<style type="text/css" media="screen">
.box {
position: relative;
left: 10px;
top: 10px;
height: 20px;
width: 20px;
-webkit-transform: translateX(10px);
background-color: blue;
-webkit-animation-duration: 2s;
-webkit-animation-timing-function: linear;
}
#box1 {
-webkit-animation-name: anim1;
}
@-webkit-keyframes anim1 {
from { -webkit-transform: translateX(10px); }
40% { -webkit-transform: translateX(30px); }
60% { -webkit-transform: translateX(10px); }
to { -webkit-transform: translateX(20px); }
}
#box2 {
-webkit-animation-name: anim2;
background-color: red;
}
@-webkit-keyframes anim2 {
40% { -webkit-transform: translateX(30px); }
60% { -webkit-transform: translateX(10px); }
to { -webkit-transform: translateX(20px); }
}
#box3 {
-webkit-transform: translateX(20px);
-webkit-animation-name: anim3;
background-color: green;
}
@-webkit-keyframes anim3 {
from { -webkit-transform: translateX(10px); }
40% { -webkit-transform: translateX(30px); }
60% { -webkit-transform: translateX(10px); }
}
#box4 {
-webkit-animation-name: anim4;
background-color: yellow;
}
@-webkit-keyframes anim4 {
40% { -webkit-transform: translateX(30px); }
60% { -webkit-transform: translateX(20px); }
}
#box5 {
-webkit-animation-name: anim5;
background-color: orange;
}
@-webkit-keyframes anim5 {
}
#result {
margin-top: 20px;
}
</style>
<script src="animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
const expectedValues = [
// [animation-name, time, element-id, property, expected-value, tolerance]
["anim1", 0.4, "box1", "webkitTransform.4", 20, 2],
["anim1", 1.0, "box1", "webkitTransform.4", 20, 2],
["anim1", 1.6, "box1", "webkitTransform.4", 15, 2],
["anim2", 0.4, "box2", "webkitTransform.4", 20, 2],
["anim2", 1.0, "box2", "webkitTransform.4", 20, 2],
["anim2", 1.6, "box2", "webkitTransform.4", 15, 2],
["anim3", 0.4, "box3", "webkitTransform.4", 20, 2],
["anim3", 1.0, "box3", "webkitTransform.4", 20, 2],
["anim3", 1.6, "box3", "webkitTransform.4", 15, 2],
["anim4", 0.4, "box4", "webkitTransform.4", 20, 2],
["anim4", 1.0, "box4", "webkitTransform.4", 25, 2],
["anim4", 1.6, "box4", "webkitTransform.4", 15, 2]
];
runAnimationTest(expectedValues, function() {
if (layoutTestController) {
if (layoutTestController.pauseAnimationAtTimeOnElementWithId("anim5", 0.1, "box5"))
result += "FAIL - box5 animation was running<br>";
else
result += "PASS - box5 animation was not running<br>";
}
});
</script>
</head>
<body>
This test performs animations of the transform property on five boxes over 2 seconds.
Box 1 has all keyframes. Box 2 has a missing "from" keyframe.
Box 3 has a missing "to" keyframe.
Box 4 has both "from" and "to" keyframes missing, but other keyframes which
should trigger the generation of "from" and "to". Box 5 has no keyframes, and
should not animate.
The test takes 3 snapshots each and expects each result to be within a specified range.
<div class="box" id="box1">
</div>
<div class="box" id="box2">
</div>
<div class="box" id="box3">
</div>
<div class="box" id="box4">
</div>
<div class="box" id="box5">
</div>
<div id="result">
</div>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Test animation with missing from and to keyframes</title>
<style type="text/css" media="screen">
.box {
position: relative;
left: 10px;
top: 10px;
height: 20px;
width: 20px;
background-color: blue;
-webkit-animation-duration: 2s;
-webkit-animation-timing-function: linear;
}
#box1 {
-webkit-animation-name: anim1;
}
@-webkit-keyframes anim1 {
from { left: 10px; }
40% { left: 30px; }
60% { left: 10px; }
to { left: 20px; }
}
#box2 {
-webkit-animation-name: anim2;
background-color: red;
}
@-webkit-keyframes anim2 {
40% { left: 30px; }
60% { left: 10px; }
to { left: 20px; }
}
#box3 {
left: 20px;
-webkit-animation-name: anim3;
background-color: green;
}
@-webkit-keyframes anim3 {
from { left: 10px; }
40% { left: 30px; }
60% { left: 10px; }
}
#box4 {
-webkit-animation-name: anim4;
background-color: yellow;
}
@-webkit-keyframes anim4 {
40% { left: 30px; }
60% { left: 20px; }
}
#box5 {
-webkit-animation-name: anim5;
background-color: orange;
}
@-webkit-keyframes anim5 {
}
#result {
margin-top: 20px;
}
</style>
<script src="animation-test-helpers.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
const expectedValues = [
// [animation-name, time, element-id, property, expected-value, tolerance]
["anim1", 0.4, "box1", "left", 20, 2],
["anim1", 1.0, "box1", "left", 20, 2],
["anim1", 1.6, "box1", "left", 15, 2],
["anim2", 0.4, "box2", "left", 20, 2],
["anim2", 1.0, "box2", "left", 20, 2],
["anim2", 1.6, "box2", "left", 15, 2],
["anim3", 0.4, "box3", "left", 20, 2],
["anim3", 1.0, "box3", "left", 20, 2],
["anim3", 1.6, "box3", "left", 15, 2],
["anim4", 0.4, "box4", "left", 20, 2],
["anim4", 1.0, "box4", "left", 25, 2],
["anim4", 1.6, "box4", "left", 15, 2]
];
runAnimationTest(expectedValues, function() {
if (layoutTestController) {
if (layoutTestController.pauseAnimationAtTimeOnElementWithId("anim5", 0.1, "box5"))
result += "FAIL - box5 animation was running<br>";
else
result += "PASS - box5 animation was not running<br>";
}
});
</script>
</head>
<body>
This test performs animations of the left property on five boxes over 2 seconds.
Box 1 has all keyframes. Box 2 has a missing "from" keyframe.
Box 3 has a missing "to" keyframe.
Box 4 has both "from" and "to" keyframes missing, but other keyframes which
should trigger the generation of "from" and "to". Box 5 has no keyframes, and
should not animate.
The test takes 3 snapshots each and expects each result to be within a specified range.
<div class="box" id="box1">
</div>
<div class="box" id="box2">
</div>
<div class="box" id="box3">
</div>
<div class="box" id="box4">
</div>
<div class="box" id="box5">
</div>
<div id="result">
</div>
</body>
</html>
2010-06-25 Dean Jackson <dino@apple.com>
Reviewed by Simon Fraser.
https://bugs.webkit.org/show_bug.cgi?id=41188
Animations should not require 0% and 100% keyframes
When we are generating the animation lists in CSSStyleSelector,
rather than bail if we notice that "from" or "to" are missing, we
now generate synthetic keyframes for those cases.
Tests: animations/missing-from-to-transforms.html
animations/missing-from-to.html
WebCore/manual-tests/animation-with-transition.html
* css/CSSStyleSelector.cpp:
(WebCore::CSSStyleSelector::styleForKeyframe):
Moved individual keyframe generation into a new function.
(WebCore::CSSStyleSelector::keyframeStylesForAnimation):
Call the new function above for regular keyframes, and
also check for missing keyframes and generate them if
necessary.
* css/CSSStyleSelector.h:
2010-06-25 Adam Barth <abarth@webkit.org>
Reviewed by Eric Seidel.
......
......@@ -1373,6 +1373,55 @@ PassRefPtr<RenderStyle> CSSStyleSelector::styleForElement(Element* e, RenderStyl
return m_style.release();
}
PassRefPtr<RenderStyle> CSSStyleSelector::styleForKeyframe(const RenderStyle* elementStyle, const WebKitCSSKeyframeRule* keyframeRule, KeyframeList& list)
{
if (keyframeRule->style())
addMatchedDeclaration(keyframeRule->style());
ASSERT(!m_style);
// Create the style
m_style = RenderStyle::clone(elementStyle);
m_lineHeightValue = 0;
// We don't need to bother with !important. Since there is only ever one
// decl, there's nothing to override. So just add the first properties.
if (keyframeRule->style())
applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1);
// If our font got dirtied, go ahead and update it now.
if (m_fontDirty)
updateFont();
// Line-height is set when we are sure we decided on the font-size
if (m_lineHeightValue)
applyProperty(CSSPropertyLineHeight, m_lineHeightValue);
// Now do rest of the properties.
if (keyframeRule->style())
applyDeclarations<false>(false, 0, m_matchedDecls.size() - 1);
// If our font got dirtied by one of the non-essential font props,
// go ahead and update it a second time.
if (m_fontDirty)
updateFont();
// Add all the animating properties to the list
if (keyframeRule->style()) {
CSSMutableStyleDeclaration::const_iterator end = keyframeRule->style()->end();
for (CSSMutableStyleDeclaration::const_iterator it = keyframeRule->style()->begin(); it != end; ++it) {
int property = (*it).id();
// Timing-function within keyframes is special, because it is not animated; it just
// describes the timing function between this keyframe and the next.
if (property != CSSPropertyWebkitAnimationTimingFunction)
list.addProperty(property);
}
}
return m_style.release();
}
void CSSStyleSelector::keyframeStylesForAnimation(Element* e, const RenderStyle* elementStyle, KeyframeList& list)
{
list.clear();
......@@ -1387,6 +1436,7 @@ void CSSStyleSelector::keyframeStylesForAnimation(Element* e, const RenderStyle*
return;
const WebKitCSSKeyframesRule* rule = m_keyframesRuleMap.find(list.animationName().impl()).get()->second.get();
RefPtr<RenderStyle> keyframeStyle;
// Construct and populate the style for each keyframe
for (unsigned i = 0; i < rule->length(); ++i) {
......@@ -1394,65 +1444,36 @@ void CSSStyleSelector::keyframeStylesForAnimation(Element* e, const RenderStyle*
initElement(e);
initForStyleResolve(e);
const WebKitCSSKeyframeRule* kf = rule->item(i);
addMatchedDeclaration(kf->style());
ASSERT(!m_style);
// Create the style
m_style = RenderStyle::clone(elementStyle);
m_lineHeightValue = 0;
// We don't need to bother with !important. Since there is only ever one
// decl, there's nothing to override. So just add the first properties.
applyDeclarations<true>(false, 0, m_matchedDecls.size() - 1);
const WebKitCSSKeyframeRule* keyframeRule = rule->item(i);
// If our font got dirtied, go ahead and update it now.
if (m_fontDirty)
updateFont();
keyframeStyle = styleForKeyframe(elementStyle, keyframeRule, list);
// Line-height is set when we are sure we decided on the font-size
if (m_lineHeightValue)
applyProperty(CSSPropertyLineHeight, m_lineHeightValue);
// Now do rest of the properties.
applyDeclarations<false>(false, 0, m_matchedDecls.size() - 1);
// If our font got dirtied by one of the non-essential font props,
// go ahead and update it a second time.
if (m_fontDirty)
updateFont();
// Add all the animating properties to the list
CSSMutableStyleDeclaration::const_iterator end = kf->style()->end();
for (CSSMutableStyleDeclaration::const_iterator it = kf->style()->begin(); it != end; ++it) {
int property = (*it).id();
// Timing-function within keyframes is special, because it is not animated; it just
// describes the timing function between this keyframe and the next.
if (property != CSSPropertyWebkitAnimationTimingFunction)
list.addProperty(property);
}
// Add this keyframe style to all the indicated key times
Vector<float> keys;
kf->getKeys(keys);
keyframeRule->getKeys(keys);
for (size_t keyIndex = 0; keyIndex < keys.size(); ++keyIndex) {
float key = keys[keyIndex];
list.insert(key, m_style);
list.insert(key, keyframeStyle.get());
}
m_style = 0;
keyframeStyle.release();
}
// Make sure there is a 0% and a 100% keyframe
float first = -1;
float last = -1;
if (list.size() >= 2) {
first = list.beginKeyframes()->key();
last = (list.endKeyframes()-1)->key();
}
if (first != 0 || last != 1)
list.clear();
// If the 0% keyframe is missing, create it (but only if there is at least one other keyframe)
int initialListSize = list.size();
if (initialListSize > 0 && list.beginKeyframes()->key() != 0) {
RefPtr<WebKitCSSKeyframeRule> keyframe = WebKitCSSKeyframeRule::create();
keyframe->setKeyText("0%");
keyframeStyle = styleForKeyframe(elementStyle, keyframe.get(), list);
list.insert(0, keyframeStyle.release());
}
// If the 100% keyframe is missing, create it (but only if there is at least one other keyframe)
if (initialListSize > 0 && (list.endKeyframes() - 1)->key() != 1) {
RefPtr<WebKitCSSKeyframeRule> keyframe = WebKitCSSKeyframeRule::create();
keyframe->setKeyText("100%");
keyframeStyle = styleForKeyframe(elementStyle, keyframe.get(), list);
list.insert(1, keyframeStyle.release());
}
}
PassRefPtr<RenderStyle> CSSStyleSelector::pseudoStyleForElement(PseudoId pseudo, Element* e, RenderStyle* parentStyle, bool matchVisitedPseudoClass)
......
......@@ -64,6 +64,7 @@ class StyleImage;
class StyleSheet;
class StyleSheetList;
class StyledElement;
class WebKitCSSKeyframeRule;
class WebKitCSSKeyframesRule;
class MediaQueryResult : public Noncopyable {
......@@ -111,6 +112,8 @@ public:
RenderStyle* style() const { return m_style.get(); }
PassRefPtr<RenderStyle> styleForKeyframe(const RenderStyle*, const WebKitCSSKeyframeRule*, KeyframeList&);
public:
// These methods will give back the set of rules that matched for a given element (or a pseudo-element).
PassRefPtr<CSSRuleList> styleRulesForElement(Element*, bool authorOnly);
......
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>simple-animation</title>
<style type="text/css" media="screen">
div {
position: relative;
left: 10px;
top: 10px;
width: 200px;
height: 200px;
background-color: #696;
-webkit-transition: left 5s, top 5s;
}
.animate {
-webkit-animation-name: simple;
-webkit-animation-duration: 2s;
-webkit-animation-timing-function: linear;
-webkit-animation-fill-mode: backwards;
}
@-webkit-keyframes simple {
50% {
left: 300px;
}
100% {
left: 80px;
}
}
</style>
<script type="text/javascript" charset="utf-8">
function doTransition() {
var div = document.querySelector("div");
div.style.left = "200px";
}
function doAnimation() {
var div = document.querySelector("div");
div.className = "animate";
}
</script>
</head>
<body>
<p>Testing setting an animation while a transition is running, in the
case where the animation synthesizes the initial keyframe</p>
<p>
Start the transition, then start the animation.</p>
<p>
<a href="https://bugs.webkit.org/show_bug.cgi?id=41188">https://bugs.webkit.org/show_bug.cgi?id=41188</a>
</p>
<button onclick="doTransition();">Transition</button>
<button onclick="doAnimation();">Set Animation</button>
<div></div>
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment