Bug 1665816 - CSSOM should respect rule-level property restrictions. r=jwatt

Differential Revision: https://phabricator.services.mozilla.com/D90729
This commit is contained in:
Emilio Cobos Álvarez 2020-09-21 09:57:46 +00:00
Родитель 7c26de15f3
Коммит 3cfb419d00
19 изменённых файлов: 161 добавлений и 81 удалений

Просмотреть файл

@ -22,6 +22,7 @@
#include "mozilla/ServoUtils.h"
#include "mozilla/ShadowParts.h"
#include "mozilla/DeclarationBlock.h"
#include "mozilla/dom/CSSRuleBinding.h"
#include "nsContentUtils.h"
#include "nsReadableUtils.h"
#include "nsHTMLCSSStyleSheet.h"
@ -1732,10 +1733,10 @@ bool nsAttrValue::ParseStyleAttribute(const nsAString& aString,
nsCOMPtr<nsIReferrerInfo> referrerInfo =
dom::ReferrerInfo::CreateForInternalCSSResources(ownerDoc);
RefPtr<URLExtraData> data =
new URLExtraData(baseURI, referrerInfo, principal);
auto data = MakeRefPtr<URLExtraData>(baseURI, referrerInfo, principal);
RefPtr<DeclarationBlock> decl = DeclarationBlock::FromCssText(
aString, data, ownerDoc->GetCompatibilityMode(), ownerDoc->CSSLoader());
aString, data, ownerDoc->GetCompatibilityMode(), ownerDoc->CSSLoader(),
dom::CSSRule_Binding::STYLE_RULE);
if (!decl) {
return false;
}

Просмотреть файл

@ -2182,14 +2182,9 @@ void CanvasRenderingContext2D::SetShadowColor(const nsAString& aShadowColor) {
static already_AddRefed<RawServoDeclarationBlock> CreateDeclarationForServo(
nsCSSPropertyID aProperty, const nsAString& aPropertyValue,
Document* aDocument) {
nsCOMPtr<nsIReferrerInfo> referrerInfo =
ReferrerInfo::CreateForInternalCSSResources(aDocument);
RefPtr<URLExtraData> data = new URLExtraData(
aDocument->GetDocBaseURI(), referrerInfo, aDocument->NodePrincipal());
ServoCSSParser::ParsingEnvironment env(
data, aDocument->GetCompatibilityMode(), aDocument->CSSLoader());
ServoCSSParser::ParsingEnvironment env{aDocument->DefaultStyleAttrURLData(),
aDocument->GetCompatibilityMode(),
aDocument->CSSLoader()};
RefPtr<RawServoDeclarationBlock> servoDeclarations =
ServoCSSParser::ParseProperty(aProperty, aPropertyValue, env);
@ -2203,9 +2198,9 @@ static already_AddRefed<RawServoDeclarationBlock> CreateDeclarationForServo(
if (aProperty == eCSSProperty_font) {
const nsCString normalString = "normal"_ns;
Servo_DeclarationBlock_SetPropertyById(
servoDeclarations, eCSSProperty_line_height, &normalString, false, data,
ParsingMode::Default, aDocument->GetCompatibilityMode(),
aDocument->CSSLoader(), {});
servoDeclarations, eCSSProperty_line_height, &normalString, false,
env.mUrlExtraData, ParsingMode::Default, env.mCompatMode, env.mLoader,
env.mRuleType, {});
}
return servoDeclarations.forget();

Просмотреть файл

@ -8,6 +8,7 @@
#include "mozilla/dom/MutationEventBinding.h"
#include "mozilla/dom/MutationObservers.h"
#include "mozilla/dom/CSSRuleBinding.h"
#include "mozilla/dom/SVGElementBinding.h"
#include "mozilla/dom/SVGGeometryElement.h"
#include "mozilla/dom/SVGLengthBinding.h"
@ -1148,12 +1149,13 @@ void MappedAttrParser::ParseMappedAttrValue(nsAtom* aMappedAttrName,
nsCOMPtr<nsIReferrerInfo> referrerInfo =
ReferrerInfo::CreateForSVGResources(mElement->OwnerDoc());
RefPtr<URLExtraData> data =
new URLExtraData(mBaseURI, referrerInfo, mElement->NodePrincipal());
auto data = MakeRefPtr<URLExtraData>(mBaseURI, referrerInfo,
mElement->NodePrincipal());
changed = Servo_DeclarationBlock_SetPropertyById(
mDecl->Raw(), propertyID, &value, false, data,
ParsingMode::AllowUnitlessLength,
mElement->OwnerDoc()->GetCompatibilityMode(), mLoader, {});
mElement->OwnerDoc()->GetCompatibilityMode(), mLoader,
CSSRule_Binding::STYLE_RULE, {});
// TODO(emilio): If we want to record these from CSSOM more generally, we
// can pass the document use counters down the FFI call. For now manually

Просмотреть файл

@ -14,6 +14,7 @@
#include "nsIDOMXULSelectCntrlItemEl.h"
#include "mozilla/dom/BindContext.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/CSSRuleBinding.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/EventStateManager.h"
@ -1506,13 +1507,12 @@ nsresult nsXULPrototypeElement::SetAttrAt(uint32_t aPos,
// as has been discussed, the CSP should be checked here to see if
// inline styles are allowed to be applied.
// XXX No specific specs talk about xul and referrer policy, pass Unset
nsCOMPtr<nsIReferrerInfo> referrerInfo =
new ReferrerInfo(aDocumentURI, ReferrerPolicy::_empty);
RefPtr<URLExtraData> data =
new URLExtraData(aDocumentURI, referrerInfo, principal);
auto referrerInfo =
MakeRefPtr<ReferrerInfo>(aDocumentURI, ReferrerPolicy::_empty);
auto data = MakeRefPtr<URLExtraData>(aDocumentURI, referrerInfo, principal);
RefPtr<DeclarationBlock> declaration = DeclarationBlock::FromCssText(
aValue, data, eCompatibility_FullStandards, nullptr);
aValue, data, eCompatibility_FullStandards, nullptr,
CSSRule_Binding::STYLE_RULE);
if (declaration) {
mAttributes[aPos].mValue.SetTo(declaration.forget(), &aValue);

Просмотреть файл

@ -56,7 +56,7 @@ class CSSKeyframeDeclaration : public nsDOMCSSDeclaration {
}
ParsingEnvironment GetParsingEnvironment(
nsIPrincipal* aSubjectPrincipal) const final {
return GetParsingEnvironmentForRule(mRule);
return GetParsingEnvironmentForRule(mRule, CSSRule_Binding::KEYFRAME_RULE);
}
Document* DocToUpdate() final { return nullptr; }

Просмотреть файл

@ -73,7 +73,7 @@ nsresult CSSPageRuleDeclaration::SetCSSDeclaration(
nsDOMCSSDeclaration::ParsingEnvironment
CSSPageRuleDeclaration::GetParsingEnvironment(
nsIPrincipal* aSubjectPrincipal) const {
return GetParsingEnvironmentForRule(Rule());
return GetParsingEnvironmentForRule(Rule(), CSSRule_Binding::PAGE_RULE);
}
// -- CSSPageRule --------------------------------------------------

Просмотреть файл

@ -83,7 +83,7 @@ Document* CSSStyleRuleDeclaration::DocToUpdate() { return nullptr; }
nsDOMCSSDeclaration::ParsingEnvironment
CSSStyleRuleDeclaration::GetParsingEnvironment(
nsIPrincipal* aSubjectPrincipal) const {
return GetParsingEnvironmentForRule(Rule());
return GetParsingEnvironmentForRule(Rule(), CSSRule_Binding::STYLE_RULE);
}
// -- CSSStyleRule --------------------------------------------------

Просмотреть файл

@ -7,24 +7,12 @@
#include "mozilla/DeclarationBlock.h"
#include "mozilla/css/Rule.h"
#include "mozilla/ServoBindings.h"
#include "nsCSSProps.h"
#include "nsIMemoryReporter.h"
namespace mozilla {
/* static */
already_AddRefed<DeclarationBlock> DeclarationBlock::FromCssText(
const nsAString& aCssText, URLExtraData* aExtraData, nsCompatibility aMode,
css::Loader* aLoader) {
NS_ConvertUTF16toUTF8 value(aCssText);
RefPtr<RawServoDeclarationBlock> raw =
Servo_ParseStyleAttribute(&value, aExtraData, aMode, aLoader).Consume();
RefPtr<DeclarationBlock> decl = new DeclarationBlock(raw.forget());
return decl.forget();
}
MOZ_DEFINE_MALLOC_SIZE_OF(ServoDeclarationBlockMallocSizeOf)
MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoDeclarationBlockEnclosingSizeOf)

Просмотреть файл

@ -147,7 +147,13 @@ class DeclarationBlock final {
static already_AddRefed<DeclarationBlock> FromCssText(
const nsAString& aCssText, URLExtraData* aExtraData,
nsCompatibility aMode, css::Loader* aLoader);
nsCompatibility aMode, css::Loader* aLoader, uint16_t aRuleType) {
NS_ConvertUTF16toUTF8 value(aCssText);
RefPtr<RawServoDeclarationBlock> raw =
Servo_ParseStyleAttribute(&value, aExtraData, aMode, aLoader, aRuleType)
.Consume();
return MakeAndAddRef<DeclarationBlock>(raw.forget());
}
RawServoDeclarationBlock* Raw() const { return mRaw; }
RawServoDeclarationBlock* const* RefRaw() const {

Просмотреть файл

@ -38,7 +38,8 @@ already_AddRefed<RawServoDeclarationBlock> ServoCSSParser::ParseProperty(
NS_ConvertUTF16toUTF8 value(aValue);
return Servo_ParseProperty(
aProperty, &value, aParsingEnvironment.mUrlExtraData, aParsingMode,
aParsingEnvironment.mCompatMode, aParsingEnvironment.mLoader)
aParsingEnvironment.mCompatMode, aParsingEnvironment.mLoader,
aParsingEnvironment.mRuleType)
.Consume();
}
@ -80,7 +81,6 @@ already_AddRefed<URLExtraData> ServoCSSParser::GetURLExtraData(
/* static */ ServoCSSParser::ParsingEnvironment
ServoCSSParser::GetParsingEnvironment(Document* aDocument) {
return ParsingEnvironment(GetURLExtraData(aDocument),
aDocument->GetCompatibilityMode(),
aDocument->CSSLoader());
return {GetURLExtraData(aDocument), aDocument->GetCompatibilityMode(),
aDocument->CSSLoader()};
}

Просмотреть файл

@ -140,7 +140,8 @@ void nsDOMCSSDeclaration::SetCssText(const nsAString& aCssText,
}
RefPtr<DeclarationBlock> newdecl = DeclarationBlock::FromCssText(
aCssText, servoEnv.mUrlExtraData, servoEnv.mCompatMode, servoEnv.mLoader);
aCssText, servoEnv.mUrlExtraData, servoEnv.mCompatMode, servoEnv.mLoader,
servoEnv.mRuleType);
aRv = SetCSSDeclaration(newdecl, &closureData);
}
@ -237,10 +238,17 @@ void nsDOMCSSDeclaration::RemoveProperty(const nsACString& aPropertyName,
}
/* static */ nsDOMCSSDeclaration::ParsingEnvironment
nsDOMCSSDeclaration::GetParsingEnvironmentForRule(const css::Rule* aRule) {
StyleSheet* sheet = aRule ? aRule->GetStyleSheet() : nullptr;
nsDOMCSSDeclaration::GetParsingEnvironmentForRule(const css::Rule* aRule,
uint16_t aRuleType) {
if (!aRule) {
return {};
}
MOZ_ASSERT(aRule->Type() == aRuleType);
StyleSheet* sheet = aRule->GetStyleSheet();
if (!sheet) {
return {nullptr, eCompatibility_FullStandards, nullptr};
return {};
}
if (Document* document = sheet->GetAssociatedDocument()) {
@ -248,6 +256,7 @@ nsDOMCSSDeclaration::GetParsingEnvironmentForRule(const css::Rule* aRule) {
sheet->URLData(),
document->GetCompatibilityMode(),
document->CSSLoader(),
aRuleType,
};
}
@ -255,6 +264,7 @@ nsDOMCSSDeclaration::GetParsingEnvironmentForRule(const css::Rule* aRule) {
sheet->URLData(),
eCompatibility_FullStandards,
nullptr,
aRuleType,
};
}
@ -311,7 +321,8 @@ nsresult nsDOMCSSDeclaration::ParsePropertyValue(
[&](DeclarationBlock* decl, ParsingEnvironment& env) {
return Servo_DeclarationBlock_SetPropertyById(
decl->Raw(), aPropID, &aPropValue, aIsImportant, env.mUrlExtraData,
ParsingMode::Default, env.mCompatMode, env.mLoader, closure);
ParsingMode::Default, env.mCompatMode, env.mLoader, env.mRuleType,
closure);
});
}
@ -334,7 +345,7 @@ nsresult nsDOMCSSDeclaration::ParseCustomPropertyValue(
return Servo_DeclarationBlock_SetProperty(
decl->Raw(), &aPropertyName, &aPropValue, aIsImportant,
env.mUrlExtraData, ParsingMode::Default, env.mCompatMode,
env.mLoader, closure);
env.mLoader, env.mRuleType, closure);
});
}

Просмотреть файл

@ -125,25 +125,15 @@ class nsDOMCSSDeclaration : public nsICSSDeclaration {
virtual void IndexedGetter(uint32_t aIndex, bool& aFound,
nsACString& aPropName) override;
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
JSObject* WrapObject(JSContext*, JS::Handle<JSObject*> aGivenProto) override;
// Information needed to parse a declaration for Servo side.
// Put this in public so other Servo parsing functions can reuse this.
struct MOZ_STACK_CLASS ParsingEnvironment {
RefPtr<mozilla::URLExtraData> mUrlExtraData;
nsCompatibility mCompatMode;
mozilla::css::Loader* mLoader;
ParsingEnvironment(mozilla::URLExtraData* aUrlData,
nsCompatibility aCompatMode,
mozilla::css::Loader* aLoader)
: mUrlExtraData(aUrlData), mCompatMode(aCompatMode), mLoader(aLoader) {}
ParsingEnvironment(already_AddRefed<mozilla::URLExtraData> aUrlData,
nsCompatibility aCompatMode,
mozilla::css::Loader* aLoader)
: mUrlExtraData(aUrlData), mCompatMode(aCompatMode), mLoader(aLoader) {}
nsCompatibility mCompatMode = eCompatibility_FullStandards;
mozilla::css::Loader* mLoader = nullptr;
uint16_t mRuleType{0};
};
protected:
@ -189,8 +179,11 @@ class nsDOMCSSDeclaration : public nsICSSDeclaration {
// An implementation for GetParsingEnvironment for callers wrapping a
// css::Rule.
//
// The RuleType argument is just to avoid a virtual call, since all callers
// know it statically. Should be equal to aRule->Type().
static ParsingEnvironment GetParsingEnvironmentForRule(
const mozilla::css::Rule* aRule);
const mozilla::css::Rule* aRule, uint16_t aRuleType);
nsresult ParsePropertyValue(const nsCSSPropertyID aPropID,
const nsACString& aPropValue, bool aIsImportant,

Просмотреть файл

@ -50,6 +50,8 @@ static void ServoParsingBench(const StyleUseCounters* aCounters) {
}
}
static constexpr uint16_t STYLE_RULE = 1;
static void ServoSetPropertyByIdBench(const nsACString& css) {
RefPtr<RawServoDeclarationBlock> block =
Servo_DeclarationBlock_CreateEmpty().Consume();
@ -64,7 +66,7 @@ static void ServoSetPropertyByIdBench(const nsACString& css) {
Servo_DeclarationBlock_SetPropertyById(
block, eCSSProperty_width, &css,
/* is_important = */ false, data, ParsingMode::Default,
eCompatibility_FullStandards, nullptr, {});
eCompatibility_FullStandards, nullptr, STYLE_RULE, {});
}
}
@ -82,7 +84,7 @@ static void ServoGetPropertyValueById() {
Servo_DeclarationBlock_SetPropertyById(
block, eCSSProperty_width, &css,
/* is_important = */ false, data, ParsingMode::Default,
eCompatibility_FullStandards, nullptr, {});
eCompatibility_FullStandards, nullptr, STYLE_RULE, {});
for (int i = 0; i < GETPROPERTY_REPETITIONS; i++) {
DOMString value_;

Просмотреть файл

@ -1263,11 +1263,12 @@ pub fn parse_style_attribute(
url_data: &UrlExtraData,
error_reporter: Option<&dyn ParseErrorReporter>,
quirks_mode: QuirksMode,
rule_type: CssRuleType,
) -> PropertyDeclarationBlock {
let context = ParserContext::new(
Origin::Author,
url_data,
Some(CssRuleType::Style),
Some(rule_type),
ParsingMode::DEFAULT,
quirks_mode,
error_reporter,
@ -1291,11 +1292,12 @@ pub fn parse_one_declaration_into(
error_reporter: Option<&dyn ParseErrorReporter>,
parsing_mode: ParsingMode,
quirks_mode: QuirksMode,
rule_type: CssRuleType,
) -> Result<(), ()> {
let context = ParserContext::new(
Origin::Author,
url_data,
Some(CssRuleType::Style),
Some(rule_type),
parsing_mode,
quirks_mode,
error_reporter,

Просмотреть файл

@ -542,10 +542,12 @@ impl NonCustomPropertyId {
false
}
fn allowed_in(self, context: &ParserContext) -> bool {
/// Returns whether a given rule allows a given property.
#[inline]
pub fn allowed_in_rule(self, rule_type: CssRuleType) -> bool {
debug_assert!(
matches!(
context.rule_type(),
rule_type,
CssRuleType::Keyframe | CssRuleType::Page | CssRuleType::Style
),
"Declarations are only expected inside a keyframe, page, or style rule."
@ -559,14 +561,16 @@ impl NonCustomPropertyId {
"DISALLOWED_IN_PAGE_RULE",
lambda p: not p.allowed_in_page_rule
)}
match context.rule_type() {
CssRuleType::Keyframe if DISALLOWED_IN_KEYFRAME_BLOCK.contains(self) => {
return false;
}
CssRuleType::Page if DISALLOWED_IN_PAGE_RULE.contains(self) => {
return false;
}
_ => {}
match rule_type {
CssRuleType::Keyframe => !DISALLOWED_IN_KEYFRAME_BLOCK.contains(self),
CssRuleType::Page => !DISALLOWED_IN_PAGE_RULE.contains(self),
_ => true
}
}
fn allowed_in(self, context: &ParserContext) -> bool {
if !self.allowed_in_rule(context.rule_type()) {
return false;
}
self.allowed_in_ignoring_rule_type(context)

Просмотреть файл

@ -299,7 +299,7 @@ impl CssRule {
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, FromPrimitive, PartialEq)]
pub enum CssRuleType {
// https://drafts.csswg.org/cssom/#the-cssrule-interface
Style = 1,

Просмотреть файл

@ -4050,12 +4050,19 @@ fn parse_property_into(
data: *mut URLExtraData,
parsing_mode: structs::ParsingMode,
quirks_mode: QuirksMode,
rule_type: CssRuleType,
reporter: Option<&dyn ParseErrorReporter>,
) -> Result<(), ()> {
let value = unsafe { value.as_str_unchecked() };
let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
let parsing_mode = ParsingMode::from_bits_truncate(parsing_mode);
if let Some(non_custom) = property_id.non_custom_id() {
if !non_custom.allowed_in_rule(rule_type) {
return Err(());
}
}
parse_one_declaration_into(
declarations,
property_id,
@ -4064,6 +4071,7 @@ fn parse_property_into(
reporter,
parsing_mode,
quirks_mode,
rule_type,
)
}
@ -4075,6 +4083,7 @@ pub extern "C" fn Servo_ParseProperty(
parsing_mode: structs::ParsingMode,
quirks_mode: nsCompatibility,
loader: *mut Loader,
rule_type: u16,
) -> Strong<RawServoDeclarationBlock> {
let id = get_property_id_from_nscsspropertyid!(property, Strong::null());
let mut declarations = SourcePropertyDeclaration::new();
@ -4086,6 +4095,7 @@ pub extern "C" fn Servo_ParseProperty(
data,
parsing_mode,
quirks_mode.into(),
to_rule_type(rule_type),
reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
);
@ -4215,6 +4225,7 @@ pub unsafe extern "C" fn Servo_ParseStyleAttribute(
raw_extra_data: *mut URLExtraData,
quirks_mode: nsCompatibility,
loader: *mut Loader,
rule_type: u16,
) -> Strong<RawServoDeclarationBlock> {
let global_style_data = &*GLOBAL_STYLE_DATA;
let value = data.as_str_unchecked();
@ -4225,6 +4236,7 @@ pub unsafe extern "C" fn Servo_ParseStyleAttribute(
url_data,
reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
quirks_mode.into(),
to_rule_type(rule_type),
)))
.into_strong()
}
@ -4437,6 +4449,7 @@ fn set_property(
parsing_mode: structs::ParsingMode,
quirks_mode: QuirksMode,
loader: *mut Loader,
rule_type: CssRuleType,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
let mut source_declarations = SourcePropertyDeclaration::new();
@ -4448,6 +4461,7 @@ fn set_property(
data,
parsing_mode,
quirks_mode,
rule_type,
reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
);
@ -4469,6 +4483,12 @@ fn set_property(
)
}
#[inline]
fn to_rule_type(ty: u16) -> CssRuleType {
use num_traits::FromPrimitive;
CssRuleType::from_u16(ty).unwrap_or(CssRuleType::Style)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
declarations: &RawServoDeclarationBlock,
@ -4479,6 +4499,7 @@ pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
parsing_mode: structs::ParsingMode,
quirks_mode: nsCompatibility,
loader: *mut Loader,
rule_type: u16,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
set_property(
@ -4490,6 +4511,7 @@ pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
parsing_mode,
quirks_mode.into(),
loader,
to_rule_type(rule_type),
before_change_closure,
)
}
@ -4521,6 +4543,7 @@ pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById(
parsing_mode: structs::ParsingMode,
quirks_mode: nsCompatibility,
loader: *mut Loader,
rule_type: u16,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
set_property(
@ -4532,6 +4555,7 @@ pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById(
parsing_mode,
quirks_mode.into(),
loader,
to_rule_type(rule_type),
before_change_closure,
)
}
@ -5274,6 +5298,7 @@ pub unsafe extern "C" fn Servo_CSSSupports2(
DUMMY_URL_DATA,
structs::ParsingMode_Default,
QuirksMode::NoQuirks,
CssRuleType::Style,
None,
)
.is_ok()

Просмотреть файл

@ -95,8 +95,8 @@
test(function() {
var ruleWithPage = ruleList[3];
ruleWithPage.style = "background-color: green;"
assert_equals(ruleWithPage.style.cssText, "background-color: green;");
ruleWithPage.style = "margin-top: 10px;"
assert_equals(ruleWithPage.style.cssText, "margin-top: 10px;");
}, "CSSStyleDeclaration cssText attribute should be updated due to [PutForwards]");
test(function() {

Просмотреть файл

@ -0,0 +1,51 @@
<!doctype html>
<meta charset="utf-8">
<title>CSSOM Should correctly honor property restrictions</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1665816">
<link rel="help" href="https://drafts.csswg.org/css-page-3/#conform-partial">
<link rel="help" href="https://drafts.csswg.org/css-animations/#keyframes">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
@page {
margin-top: 10px;
transform: scale(1);
}
@keyframes foo {
from {
margin-top: 10px;
animation-name: none;
}
}
</style>
<script>
test(function() {
let rule = document.styleSheets[0].cssRules[0];
assert_equals(rule.type, CSSRule.PAGE_RULE, "Should be a page rule");
assert_equals(rule.style.length, 1, "Transform doesn't quite apply to pages");
assert_equals(rule.style.marginTop, "10px", "Should have a margin-top declaration");
rule.style.setProperty("transform", "scale(1)");
assert_equals(rule.style.getPropertyValue("transform"), "", "Shouldn't have been able to set the transform property via setProperty");
assert_equals(rule.style.length, 1, "Shouldn't have been able to set transform via setProperty");
rule.style.cssText = "margin-bottom: 10px; transform: scale(1);";
assert_equals(rule.style.length, 1, "Should not have been able to set transform via cssText");
assert_equals(rule.style.marginBottom, "10px", "Should have a margin-bottom declaration");
}, "@page");
test(function() {
let rule = document.styleSheets[0].cssRules[1].cssRules[0];
assert_equals(rule.type, CSSRule.KEYFRAME_RULE, "Should be a keyframe rule");
assert_equals(rule.style.length, 1, "animation-name doesn't apply to keyframes");
assert_equals(rule.style.marginTop, "10px", "Should have a margin-top declaration");
rule.style.setProperty("animation-name", "none");
assert_equals(rule.style.getPropertyValue("animation-name"), "", "Shouldn't have been able to set the animation-nameproperty via setProperty");
assert_equals(rule.style.length, 1, "Shouldn't have been able to set animation-name via setProperty");
rule.style.cssText = "margin-bottom: 10px; animation-name: none;";
assert_equals(rule.style.length, 1, "Should not have been able to set animation-name via cssText");
assert_equals(rule.style.marginBottom, "10px", "Should have a margin-bottom declaration");
}, "@keyframe");
</script>