Diff
Added: trunk/LayoutTests/animations/keyframes-dynamic-expected.txt (0 => 156912)
--- trunk/LayoutTests/animations/keyframes-dynamic-expected.txt (rev 0)
+++ trunk/LayoutTests/animations/keyframes-dynamic-expected.txt 2013-10-04 20:46:57 UTC (rev 156912)
@@ -0,0 +1,7 @@
+This test performs an animation of the left property. It should stop for 100ms at 100px and 200px We test for those values 50ms after it has stopped at each position. The animations for the three boxes are inserted by _javascript_. The first box's keyframes remain in the stylesheet. The second box's keyframes are removed after its animation starts (but it should animate). The third box's keyframes are removed before its animation starts, and it should not animate.
+PASS - box3 animation was not running
+PASS - "left" property for "box1" element at 0.3s saw something close to: 100
+PASS - "left" property for "box1" element at 0.7s saw something close to: 200
+PASS - "left" property for "box2" element at 0.3s saw something close to: 100
+PASS - "left" property for "box2" element at 0.7s saw something close to: 200
+
Added: trunk/LayoutTests/animations/keyframes-dynamic.html (0 => 156912)
--- trunk/LayoutTests/animations/keyframes-dynamic.html (rev 0)
+++ trunk/LayoutTests/animations/keyframes-dynamic.html 2013-10-04 20:46:57 UTC (rev 156912)
@@ -0,0 +1,95 @@
+<!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>Dynamic Keyframes test</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;
+ }
+ #box2 { top: 210px; }
+ #box3 { top: 320px; }
+ </style>
+ <script src="" 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.3, "box1", "left", 100, 1],
+ ["anim1", 0.7, "box1", "left", 200, 1],
+ ["anim2", 0.3, "box2", "left", 100, 1],
+ ["anim2", 0.7, "box2", "left", 200, 1],
+ ];
+
+ function addKeyframes() {
+ var style = document.createElement('style');
+ document.head.appendChild(style);
+ var keyframes =
+ "{\n" +
+ " from { left: 50px; }\n" +
+ " 20% { left: 100px; }\n" +
+ " 40% { left: 100px; }\n" +
+ " 60% { left: 200px; }\n" +
+ " 80% { left: 200px; }\n" +
+ " to { left: 300px; }\n" +
+ "}";
+ var box1Keyframes = "@-webkit-keyframes anim1 " + keyframes;
+ var box2Keyframes = "@-webkit-keyframes anim2 " + keyframes;
+ var box3Keyframes = "@-webkit-keyframes anim3 " + keyframes;
+
+ style.sheet.insertRule(box1Keyframes, 0);
+ var box2Index = style.sheet.insertRule(box2Keyframes, 0);
+ var box3Index = style.sheet.insertRule(box3Keyframes, 0);
+
+ var box1 = document.getElementById("box1");
+ var box2 = document.getElementById("box2");
+ var box3 = document.getElementById("box3");
+
+ box1.style.webkitAnimationName = 'anim1';
+ box2.style.webkitAnimationName = 'anim2';
+ box3.style.webkitAnimationName = 'anim3';
+
+ box2.addEventListener('webkitAnimationStart',
+ function() { style.sheet.removeRule(box2Index); }, true);
+
+ style.sheet.removeRule(box3Index);
+
+ runAnimationTest(expectedValues);
+
+ if (window.testRunner) {
+ if (internals.pauseAnimationAtTimeOnElement("anim3", 0.1, box3))
+ result += "FAIL - box3 animation was running<br>";
+ else
+ result += "PASS - box3 animation was not running<br>";
+ }
+ }
+
+ window.addEventListener('DOMContentLoaded', addKeyframes, false);
+
+ </script>
+</head>
+<body>
+This test performs an animation of the left property. It should stop for 100ms at 100px and 200px
+We test for those values 50ms after it has stopped at each position. The animations for the three
+boxes are inserted by _javascript_. The first box's keyframes remain in the stylesheet. The second
+box's keyframes are removed after its animation starts (but it should animate). The third box's
+keyframes are removed before its animation starts, and it should not animate.
+<div class="box" id="box1">
+</div>
+<div class="box" id="box2">
+</div>
+<div class="box" id="box3">
+</div>
+<div id="result">
+</div>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (156911 => 156912)
--- trunk/Source/WebCore/ChangeLog 2013-10-04 20:37:53 UTC (rev 156911)
+++ trunk/Source/WebCore/ChangeLog 2013-10-04 20:46:57 UTC (rev 156912)
@@ -1,3 +1,21 @@
+2013-10-04 Ralph Thomas <[email protected]>
+
+ Inserting a JS generated keyframe animation shouldn't trigger a whole document style recalc
+ https://bugs.webkit.org/show_bug.cgi?id=119479
+
+ Reviewed by Antti Koivisto.
+
+ Change CSSStyleSheet::didMutateRules to not invalidate all node's styles when inserting a
+ @-webkit-keyframes rule, and to instead insert the rule directly into the StyleResolver.
+
+ Test: animation/keyframes-dynamic.html: adds and removes keyframe rules using _javascript_ and
+ validates that the correct elements are animated.
+
+ * css/CSSStyleSheet.cpp:
+ (WebCore::CSSStyleSheet::didMutateRules):
+ (WebCore::CSSStyleSheet::insertRule):
+ * css/CSSStyleSheet.h:
+
2013-10-04 Zan Dobersek <[email protected]>
[WebIDL] Annotate IDL interfaces under Source/WebCore/fileapi/ with the OperationsNotDeletable attribute
Modified: trunk/Source/WebCore/css/CSSStyleSheet.cpp (156911 => 156912)
--- trunk/Source/WebCore/css/CSSStyleSheet.cpp 2013-10-04 20:37:53 UTC (rev 156911)
+++ trunk/Source/WebCore/css/CSSStyleSheet.cpp 2013-10-04 20:46:57 UTC (rev 156912)
@@ -37,8 +37,10 @@
#include "Node.h"
#include "SVGNames.h"
#include "SecurityOrigin.h"
+#include "StyleResolver.h"
#include "StyleRule.h"
#include "StyleSheetContents.h"
+#include "WebKitCSSKeyframesRule.h"
#include <wtf/text/StringBuilder.h>
namespace WebCore {
@@ -157,7 +159,7 @@
didMutate();
}
-void CSSStyleSheet::didMutateRules(RuleMutationType mutationType, WhetherContentsWereClonedForMutation contentsWereClonedForMutation)
+void CSSStyleSheet::didMutateRules(RuleMutationType mutationType, WhetherContentsWereClonedForMutation contentsWereClonedForMutation, StyleRuleKeyframes* insertedKeyframesRule)
{
ASSERT(m_contents->isMutable());
ASSERT(m_contents->hasOneClient());
@@ -167,6 +169,11 @@
return;
if (mutationType == RuleInsertion && !contentsWereClonedForMutation && !owner->styleSheetCollection().activeStyleSheetsContains(this)) {
+ if (insertedKeyframesRule) {
+ if (StyleResolver* resolver = owner->styleResolverIfExists())
+ resolver->addKeyframeStyle(insertedKeyframesRule);
+ return;
+ }
owner->scheduleOptimizedStyleSheetUpdate();
return;
}
@@ -295,7 +302,7 @@
return 0;
}
- RuleMutationScope mutationScope(this, RuleInsertion);
+ RuleMutationScope mutationScope(this, RuleInsertion, rule->type() == StyleRuleBase::Keyframes ? static_cast<StyleRuleKeyframes*>(rule.get()) : 0);
bool success = m_contents->wrapperInsertRule(rule, index);
if (!success) {
@@ -401,9 +408,10 @@
m_childRuleCSSOMWrappers.clear();
}
-CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSStyleSheet* sheet, RuleMutationType mutationType)
+CSSStyleSheet::RuleMutationScope::RuleMutationScope(CSSStyleSheet* sheet, RuleMutationType mutationType, StyleRuleKeyframes* insertedKeyframesRule)
: m_styleSheet(sheet)
, m_mutationType(mutationType)
+ , m_insertedKeyframesRule(insertedKeyframesRule)
{
ASSERT(m_styleSheet);
m_contentsWereClonedForMutation = m_styleSheet->willMutateRules();
@@ -413,6 +421,7 @@
: m_styleSheet(rule ? rule->parentStyleSheet() : 0)
, m_mutationType(OtherMutation)
, m_contentsWereClonedForMutation(ContentsWereNotClonedForMutation)
+ , m_insertedKeyframesRule(nullptr)
{
if (m_styleSheet)
m_contentsWereClonedForMutation = m_styleSheet->willMutateRules();
@@ -421,7 +430,7 @@
CSSStyleSheet::RuleMutationScope::~RuleMutationScope()
{
if (m_styleSheet)
- m_styleSheet->didMutateRules(m_mutationType, m_contentsWereClonedForMutation);
+ m_styleSheet->didMutateRules(m_mutationType, m_contentsWereClonedForMutation, m_insertedKeyframesRule);
}
}
Modified: trunk/Source/WebCore/css/CSSStyleSheet.h (156911 => 156912)
--- trunk/Source/WebCore/css/CSSStyleSheet.h 2013-10-04 20:37:53 UTC (rev 156911)
+++ trunk/Source/WebCore/css/CSSStyleSheet.h 2013-10-04 20:46:57 UTC (rev 156912)
@@ -40,6 +40,7 @@
class Document;
class MediaQuerySet;
class SecurityOrigin;
+class StyleRuleKeyframes;
class StyleSheetContents;
typedef int ExceptionCode;
@@ -91,7 +92,7 @@
class RuleMutationScope {
WTF_MAKE_NONCOPYABLE(RuleMutationScope);
public:
- RuleMutationScope(CSSStyleSheet*, RuleMutationType = OtherMutation);
+ RuleMutationScope(CSSStyleSheet*, RuleMutationType = OtherMutation, StyleRuleKeyframes* insertedKeyframesRule = nullptr);
RuleMutationScope(CSSRule*);
~RuleMutationScope();
@@ -99,10 +100,11 @@
CSSStyleSheet* m_styleSheet;
RuleMutationType m_mutationType;
WhetherContentsWereClonedForMutation m_contentsWereClonedForMutation;
+ StyleRuleKeyframes* m_insertedKeyframesRule;
};
WhetherContentsWereClonedForMutation willMutateRules();
- void didMutateRules(RuleMutationType, WhetherContentsWereClonedForMutation);
+ void didMutateRules(RuleMutationType, WhetherContentsWereClonedForMutation, StyleRuleKeyframes* insertedKeyframesRule);
void didMutateRuleFromCSSStyleDeclaration();
void didMutate();