Bug 978648: Handle dynamic changes to @keyframes rules and keyframe rules better. r=heycam

This commit is contained in:
L. David Baron 2014-03-04 20:13:20 -08:00
parent af015e471f
commit 99fe2c6a0f
2 changed files with 84 additions and 3 deletions

View File

@ -37,6 +37,7 @@
#include "StyleRule.h"
#include "nsFont.h"
#include "nsIURI.h"
#include "mozAutoDocUpdate.h"
using namespace mozilla;
@ -2374,15 +2375,23 @@ nsCSSKeyframeRule::SetKeyText(const nsAString& aKeyText)
InfallibleTArray<float> newSelectors;
// FIXME: pass filename and line number
if (parser.ParseKeyframeSelectorString(aKeyText, nullptr, 0, newSelectors)) {
newSelectors.SwapElements(mKeys);
} else {
if (!parser.ParseKeyframeSelectorString(aKeyText, nullptr, 0, newSelectors)) {
// for now, we don't do anything if the parse fails
return NS_OK;
}
nsIDocument* doc = GetDocument();
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, true);
newSelectors.SwapElements(mKeys);
nsCSSStyleSheet* sheet = GetStyleSheet();
if (sheet) {
sheet->SetModifiedByChildRule();
if (doc) {
doc->StyleRuleChanged(sheet, this, this);
}
}
return NS_OK;
@ -2401,6 +2410,12 @@ nsCSSKeyframeRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
void
nsCSSKeyframeRule::ChangeDeclaration(css::Declaration* aDeclaration)
{
// Our caller already did a BeginUpdate/EndUpdate, but with
// UPDATE_CONTENT, and we need UPDATE_STYLE to trigger work in
// PresShell::EndUpdate.
nsIDocument* doc = GetDocument();
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, true);
// Be careful to not assign to an nsAutoPtr if we would be assigning
// the thing it already holds.
if (aDeclaration != mDeclaration) {
@ -2410,6 +2425,10 @@ nsCSSKeyframeRule::ChangeDeclaration(css::Declaration* aDeclaration)
nsCSSStyleSheet* sheet = GetStyleSheet();
if (sheet) {
sheet->SetModifiedByChildRule();
if (doc) {
doc->StyleRuleChanged(sheet, this, this);
}
}
}
@ -2533,11 +2552,22 @@ nsCSSKeyframesRule::GetName(nsAString& aName)
NS_IMETHODIMP
nsCSSKeyframesRule::SetName(const nsAString& aName)
{
if (mName == aName) {
return NS_OK;
}
nsIDocument* doc = GetDocument();
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, true);
mName = aName;
nsCSSStyleSheet* sheet = GetStyleSheet();
if (sheet) {
sheet->SetModifiedByChildRule();
if (doc) {
doc->StyleRuleChanged(sheet, this, this);
}
}
return NS_OK;
@ -2561,7 +2591,19 @@ nsCSSKeyframesRule::AppendRule(const nsAString& aRule)
nsRefPtr<nsCSSKeyframeRule> rule =
parser.ParseKeyframeRule(aRule, nullptr, 0);
if (rule) {
nsIDocument* doc = GetDocument();
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, true);
AppendStyleRule(rule);
nsCSSStyleSheet* sheet = GetStyleSheet();
if (sheet) {
sheet->SetModifiedByChildRule();
if (doc) {
doc->StyleRuleChanged(sheet, this, this);
}
}
}
return NS_OK;
@ -2597,10 +2639,18 @@ nsCSSKeyframesRule::DeleteRule(const nsAString& aKey)
{
uint32_t index = FindRuleIndexForKey(aKey);
if (index != RULE_NOT_FOUND) {
nsIDocument* doc = GetDocument();
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, true);
mRules.RemoveObjectAt(index);
nsCSSStyleSheet* sheet = GetStyleSheet();
if (sheet) {
sheet->SetModifiedByChildRule();
if (doc) {
doc->StyleRuleChanged(sheet, this, this);
}
}
}
return NS_OK;

View File

@ -1497,6 +1497,37 @@ is(cs.marginRight, "75px", "animation-name list length is the length that matter
is(cs.marginTop, "25px", "animation-name list length is the length that matters");
done_div();
var dyn_sheet_elt = document.createElement("style");
document.head.appendChild(dyn_sheet_elt);
var dyn_sheet = dyn_sheet_elt.sheet;
dyn_sheet.insertRule("@keyframes dyn1 { from { margin-left: 0 } 50% { margin-left: 50px } to { margin-left: 100px } }", 0);
dyn_sheet.insertRule("@keyframes dyn2 { from { margin-left: 100px } to { margin-left: 200px } }", 1);
var dyn1 = dyn_sheet.cssRules[0];
var dyn2 = dyn_sheet.cssRules[1];
new_div("animation: dyn1 1s linear");
is(cs.marginLeft, "0px", "dynamic rule change test, initial state");
advance_clock(250);
is(cs.marginLeft, "25px", "dynamic rule change test, 250ms");
dyn2.name = "dyn1";
is(cs.marginLeft, "125px", "dynamic rule change test, change in @keyframes name applies");
dyn2.appendRule("50% { margin-left: 0px }");
is(cs.marginLeft, "50px", "dynamic rule change test, @keyframes appendRule");
var dyn2_kf1 = dyn2.cssRules[0]; // currently 0% { margin-left: 100px }
dyn2_kf1.style.marginLeft = "-100px";
// FIXME: Bug 978833 (keyframe rules used as nsIStyleRule but doesn't follow immutability contract)
todo_is(cs.marginLeft, "-50px", "dynamic rule change test, keyframe style set");
dyn2.name = "dyn2";
is(cs.marginLeft, "25px", "dynamic rule change test, change in @keyframes name applies (second time)");
var dyn1_kf2 = dyn1.cssRules[1]; // currently 50% { margin-left: 50px }
dyn1_kf2.keyText = "25%";
is(cs.marginLeft, "50px", "dynamic rule change test, change in keyframe keyText");
dyn1.deleteRule("25%");
is(cs.marginLeft, "25px", "dynamic rule change test, @keyframes deleteRule");
done_div();
dyn_sheet_elt.parentNode.removeChild(dyn_sheet_elt);
dyn_sheet_elt = null;
dyn_sheet = null;
SpecialPowers.DOMWindowUtils.restoreNormalRefresh();
</script>