Backed out 3 changesets (bug 1833471) for wpt failure on page-rule-declarations-000.html . CLOSED TREE

Backed out changeset 547eef705668 (bug 1833471)
Backed out changeset e21e18f3f729 (bug 1833471)
Backed out changeset 16164bf63457 (bug 1833471)
This commit is contained in:
Narcis Beleuzu 2023-06-21 11:24:49 +03:00
Родитель 4186df5750
Коммит 15227435c3
15 изменённых файлов: 77 добавлений и 390 удалений

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

@ -2910,8 +2910,7 @@ nsContainerFrame* nsCSSFrameConstructor::ConstructPageFrame(
"Page name from prev-in-flow should not have been null");
}
RefPtr<ComputedStyle> pageContentPseudoStyle =
styleSet->ResolvePageContentStyle(pageName,
StylePagePseudoClassFlags::NONE);
styleSet->ResolvePageContentStyle(pageName);
nsContainerFrame* pageContentFrame = NS_NewPageContentFrame(
aPresShell, pageContentPseudoStyle, pageName.forget());

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

@ -419,8 +419,7 @@ void nsPageContentFrame::EnsurePageName() {
return;
}
RefPtr<ComputedStyle> pageContentPseudoStyle =
PresShell()->StyleSet()->ResolvePageContentStyle(
mPageName, StylePagePseudoClassFlags::FIRST);
PresShell()->StyleSet()->ResolvePageContentStyle(mPageName);
SetComputedStyleWithoutNotification(pageContentPseudoStyle);
}

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

@ -1,20 +0,0 @@
<!DOCTYPE html>
<html class="reftest-paged">
<style>
@page :first {
margin: 1cm;
}
@page {
margin: 0;
}
div {
width: 1cm;
height: 1cm;
border: 2px solid red;
}
</style>
<body>
<div style="page: a; border-color: lightblue"></div>
<div style="page: b; border-color: pink"></div>
</body>
</html>

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

@ -1,23 +0,0 @@
<!DOCTYPE html>
<html class="reftest-paged">
<style>
@page b {
margin: 0;
}
@page a:first {
margin: 1cm;
}
@page :first {
margin: 2cm;
}
div {
width: 1cm;
height: 1cm;
border: 2px solid red;
}
</style>
<body>
<div style="page: a; border-color: lightblue"></div>
<div style="page: b; border-color: pink"></div>
</body>
</html>

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

@ -1,23 +0,0 @@
<!DOCTYPE html>
<html class="reftest-paged">
<style>
@page :first {
margin: 2cm;
}
@page a {
margin: 1cm;
}
@page {
margin: 0;
}
div {
width: 1cm;
height: 1cm;
border: 2px solid red;
}
</style>
<body>
<div style="page: a; border-color: lightblue"></div>
<div style="border-color: pink"></div>
</body>
</html>

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

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html class="reftest-paged">
<style>
@page {
margin: 0;
}
.block {
width: 1cm;
height: 1cm;
border: 2px solid red;
}
</style>
<body>
<div style="padding: 1cm; break-after: page">
<div class="block" style="border-color: lightblue"></div>
</div>
<div style="padding: 0">
<div class="block" style="border-color: pink"></div>
</div>
</body>
</html>

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

@ -81,6 +81,3 @@
== page-name-two-page-034.html page-name-two-page-ref.html
== page-name-two-page-035.html page-name-two-page-ref.html
== page-name-zero-height-001.html page-name-zero-height-001-ref.html
== pseudo-first-margin-001.html pseudo-first-margin-ref.html
== pseudo-first-margin-002.html pseudo-first-margin-ref.html
== pseudo-first-margin-003.html pseudo-first-margin-ref.html

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

@ -572,7 +572,7 @@ ServoStyleSet::ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType aType) {
}
already_AddRefed<ComputedStyle> ServoStyleSet::ResolvePageContentStyle(
const nsAtom* aPageName, const StylePagePseudoClassFlags& aPseudo) {
const nsAtom* aPageName) {
// The empty atom is used to indicate no specified page name, and is not
// usable as a page-rule selector. Changing this to null is a slight
// optimization to avoid the Servo code from doing an unnecessary hashtable
@ -580,12 +580,10 @@ already_AddRefed<ComputedStyle> ServoStyleSet::ResolvePageContentStyle(
if (aPageName == nsGkAtoms::_empty) {
aPageName = nullptr;
}
// Only use the cache when we are doing a lookup for page styles without a
// page-name or any pseudo classes.
const bool useCache = !aPageName && !aPseudo;
// Only use the cache if we are not doing a lookup for a named page style.
RefPtr<ComputedStyle>& cache =
mNonInheritingComputedStyles[nsCSSAnonBoxes::NonInheriting::pageContent];
if (useCache && cache) {
if (!aPageName && cache) {
RefPtr<ComputedStyle> retval = cache;
return retval.forget();
}
@ -593,11 +591,11 @@ already_AddRefed<ComputedStyle> ServoStyleSet::ResolvePageContentStyle(
UpdateStylistIfNeeded();
RefPtr<ComputedStyle> computedValues =
Servo_ComputedValues_GetForPageContent(mRawData.get(), aPageName, aPseudo)
Servo_ComputedValues_GetForPageContent(mRawData.get(), aPageName)
.Consume();
MOZ_ASSERT(computedValues);
if (useCache) {
if (!aPageName) {
cache = computedValues;
}
return computedValues.forget();
@ -687,8 +685,7 @@ StyleSheet* ServoStyleSet::SheetAt(Origin aOrigin, size_t aIndex) const {
ServoStyleSet::FirstPageSizeAndOrientation
ServoStyleSet::GetFirstPageSizeAndOrientation(const nsAtom* aFirstPageName) {
FirstPageSizeAndOrientation retval;
const RefPtr<ComputedStyle> style =
ResolvePageContentStyle(aFirstPageName, StylePagePseudoClassFlags::FIRST);
const RefPtr<ComputedStyle> style = ResolvePageContentStyle(aFirstPageName);
const StylePageSize& pageSize = style->StylePage()->mSize;
if (pageSize.IsSize()) {

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

@ -35,7 +35,6 @@ enum class StyleRuleChangeKind : uint32_t;
template <typename Integer, typename Number, typename LinearStops>
struct StyleTimingFunction;
struct StylePagePseudoClassFlags;
struct StylePiecewiseLinearFunction;
using StyleComputedTimingFunction =
StyleTimingFunction<int32_t, float, StylePiecewiseLinearFunction>;
@ -255,10 +254,9 @@ class ServoStyleSet {
PseudoStyleType aType);
// Get a ComputedStyle for a pageContent box with the specified page-name.
// A page name that is null or the empty atom and has no pseudo classes gets
// the global page style.
// A page name that is null or the empty atom gets the global page style.
already_AddRefed<ComputedStyle> ResolvePageContentStyle(
const nsAtom* aPageName, const StylePagePseudoClassFlags& aPseudo);
const nsAtom* aPageName);
already_AddRefed<ComputedStyle> ResolveXULTreePseudoStyle(
dom::Element* aParentElement, nsCSSAnonBoxPseudoStaticAtom* aPseudoTag,

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

@ -59,8 +59,8 @@ pub use self::loader::StylesheetLoader;
pub use self::media_rule::MediaRule;
pub use self::namespace_rule::NamespaceRule;
pub use self::origin::{Origin, OriginSet, OriginSetIterator, PerOrigin, PerOriginIter};
pub use self::page_rule::{PageRule, PageSelector, PageSelectors};
pub use self::property_rule::PropertyRule;
pub use self::page_rule::{PageRule, PagePseudoClassFlags, PageSelector, PageSelectors};
pub use self::rule_list::{CssRules, CssRulesHelpers};
pub use self::rule_parser::{InsertRuleContext, State, TopLevelRuleParser};
pub use self::rules_iterator::{AllRules, EffectiveRules};

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

@ -12,205 +12,28 @@ use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
use crate::str::CssStringWriter;
use crate::values::{AtomIdent, CustomIdent};
use cssparser::{Parser, SourceLocation, Token};
use cssparser::{Parser, SourceLocation};
#[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
use servo_arc::Arc;
use std::fmt::{self, Write};
use smallvec::SmallVec;
use style_traits::{CssWriter, ParseError, ToCss};
macro_rules! page_pseudo_classes {
($($(#[$($meta:tt)+])* $id:ident => $val:literal,)+) => {
/// [`@page`][page] rule pseudo-classes.
///
/// https://drafts.csswg.org/css-page-3/#page-selectors
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)]
#[repr(u8)]
pub enum PagePseudoClass {
$($(#[$($meta)+])* $id,)+
}
impl PagePseudoClass {
fn parse<'i, 't>(
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let loc = input.current_source_location();
let colon = input.next_including_whitespace()?;
if *colon != Token::Colon {
return Err(loc.new_unexpected_token_error(colon.clone()));
}
let ident = input.next_including_whitespace()?;
if let Token::Ident(s) = ident {
return match_ignore_ascii_case! { &**s,
$($val => Ok(PagePseudoClass::$id),)+
_ => Err(loc.new_unexpected_token_error(Token::Ident(s.clone()))),
};
}
Err(loc.new_unexpected_token_error(ident.clone()))
}
#[inline]
fn to_str(&self) -> &'static str {
match *self {
$(PagePseudoClass::$id => concat!(':', $val),)+
}
}
}
}
}
page_pseudo_classes! {
/// [`:first`][first] pseudo-class
///
/// [first] https://drafts.csswg.org/css-page-3/#first-pseudo
First => "first",
/// [`:blank`][blank] pseudo-class
///
/// [blank] https://drafts.csswg.org/css-page-3/#blank-pseudo
Blank => "blank",
/// [`:left`][left] pseudo-class
///
/// [left]: https://drafts.csswg.org/css-page-3/#spread-pseudos
Left => "left",
/// [`:right`][right] pseudo-class
///
/// [right]: https://drafts.csswg.org/css-page-3/#spread-pseudos
Right => "right",
}
bitflags! {
/// Bit-flags for pseudo-class. This should only be used for querying if a
/// page-rule applies.
///
/// https://drafts.csswg.org/css-page-3/#page-selectors
#[derive(Clone, Copy)]
#[repr(C)]
pub struct PagePseudoClassFlags : u8 {
/// No pseudo-classes
const NONE = 0;
/// Flag for PagePseudoClass::First
const FIRST = 1 << 0;
/// Flag for PagePseudoClass::Blank
const BLANK = 1 << 1;
/// Flag for PagePseudoClass::Left
const LEFT = 1 << 2;
/// Flag for PagePseudoClass::Right
const RIGHT = 1 << 3;
}
}
impl PagePseudoClassFlags {
/// Creates a pseudo-class flags object with a single pseudo-class.
#[inline]
pub fn new(other: &PagePseudoClass) -> Self {
match *other {
PagePseudoClass::First => PagePseudoClassFlags::FIRST,
PagePseudoClass::Blank => PagePseudoClassFlags::BLANK,
PagePseudoClass::Left => PagePseudoClassFlags::LEFT,
PagePseudoClass::Right => PagePseudoClassFlags::RIGHT,
}
}
/// Checks if the given pseudo class applies to this set of flags.
#[inline]
pub fn contains_class(self, other: &PagePseudoClass) -> bool {
self.intersects(PagePseudoClassFlags::new(other))
}
}
type PagePseudoClasses = SmallVec<[PagePseudoClass; 4]>;
/// Type of a single [`@page`][page selector]
///
/// We do not support pseudo selectors yet.
/// [page-selectors]: https://drafts.csswg.org/css2/page.html#page-selectors
#[derive(Clone, Debug, MallocSizeOf, ToShmem)]
pub struct PageSelector{
/// Page name
///
/// https://drafts.csswg.org/css-page-3/#page-type-selector
pub name: AtomIdent,
/// Pseudo-classes for [`@page`][page-selectors]
///
/// [page-selectors]: https://drafts.csswg.org/css2/page.html#page-selectors
pub pseudos: PagePseudoClasses,
}
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
pub struct PageSelector(pub AtomIdent);
impl PageSelector {
/// Checks if the ident matches a page-name's ident.
///
/// This does not take pseudo selectors into account.
/// This does not currently take pseudo selectors into account.
#[inline]
pub fn ident_matches(&self, other: &CustomIdent) -> bool {
self.name.0 == other.0
self.0 .0 == other.0
}
/// Checks that this selector matches the ident and all pseudo classes are
/// present in the provided flags.
#[inline]
pub fn matches(&self, name: &CustomIdent, flags: &PagePseudoClassFlags) -> bool {
self.ident_matches(name) && self.flags_match(flags)
}
/// Checks that all pseudo classes in this selector are present in the
/// provided flags.
///
/// Equivalent to, but may be more efficient than:
///
/// ```
/// match_specificity(flags).is_some()
/// ```
pub fn flags_match(&self, flags: &PagePseudoClassFlags) -> bool {
self.pseudos.iter().all(|pc| flags.contains_class(pc))
}
/// Implements specificity calculation for a page selector given a set of
/// page pseudo-classes to match with.
/// If this selector includes any pseudo-classes that are not in the flags,
/// then this will return None.
///
/// To fit the specificity calculation into a 32-bit value, this limits the
/// maximum count of :first and :blank to 32767, and the maximum count of
/// :left and :right to 65535.
///
/// https://drafts.csswg.org/css-page-3/#cascading-and-page-context
pub fn match_specificity(&self, flags: &PagePseudoClassFlags) -> Option<u32> {
let mut g: usize = 0;
let mut h: usize = 0;
for pc in self.pseudos.iter() {
if !flags.contains_class(pc) {
return None
}
match pc {
PagePseudoClass::First |
PagePseudoClass::Blank => g += 1,
PagePseudoClass::Left |
PagePseudoClass::Right => h += 1,
}
}
let h = h.min(0xFFFF) as u32;
let g = (g.min(0x7FFF) as u32) << 16;
let f = if self.name.0.is_empty() { 0 } else { 0x80000000 };
Some(h + g + f)
}
}
impl ToCss for PageSelector {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write
{
self.name.to_css(dest)?;
for pc in self.pseudos.iter() {
dest.write_str(pc.to_str())?;
}
Ok(())
}
}
fn parse_page_name<'i, 't>(
input: &mut Parser<'i, 't>
) -> Result<AtomIdent, ParseError<'i>> {
let s = input.expect_ident()?;
Ok(AtomIdent::from(&**s))
}
impl Parse for PageSelector {
@ -218,12 +41,8 @@ impl Parse for PageSelector {
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let name = input.try_parse(parse_page_name).unwrap_or(AtomIdent(atom!("")));
let mut pseudos = PagePseudoClasses::default();
while let Ok(pc) = input.try_parse(PagePseudoClass::parse) {
pseudos.push(pc);
}
Ok(PageSelector{name, pseudos})
let s = input.expect_ident()?;
Ok(PageSelector(AtomIdent::from(&**s)))
}
}
@ -289,22 +108,6 @@ impl PageRule {
self.block.read_with(guard).size_of(ops) +
self.selectors.size_of(ops)
}
/// Computes the specificity of this page rule when matched with flags.
///
/// Computing this value has linear-complexity with the size of the
/// selectors, so the caller should usually call this once and cache the
/// result.
///
/// Returns None if the flags do not match this page rule.
///
/// The return type is ordered by page-rule specificity.
pub fn match_specificity(&self, flags: &PagePseudoClassFlags) -> Option<u32> {
let mut specificity = None;
for s in self.selectors.0.iter().map(|s| s.match_specificity(flags)) {
specificity = s.max(specificity);
}
specificity
}
}
impl ToCssWithGuard for PageRule {

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

@ -1600,23 +1600,36 @@ pub struct PageRuleData {
pub rule: Arc<Locked<PageRule>>,
}
/// Wrapper to allow better tracking of memory usage by page rule lists.
///
/// This is meant to be used by the global page rule list which are already
/// sorted by layer ID, since all global page rules are less specific than all
/// named page rules that match a certain page.
#[derive(Clone, Debug, Deref, MallocSizeOf)]
pub struct PageRuleDataNoLayer(
#[ignore_malloc_size_of = "Arc, stylesheet measures as primary ref"] pub Arc<Locked<PageRule>>,
);
/// Stores page rules indexed by page names.
#[derive(Clone, Debug, Default, MallocSizeOf)]
pub struct PageRuleMap {
/// Page rules, indexed by page name. An empty atom indicates no page name.
pub rules: PrecomputedHashMap<Atom, SmallVec<[PageRuleData; 1]>>,
/// Global, unnamed page rules.
pub global: LayerOrderedVec<PageRuleDataNoLayer>,
/// Named page rules
pub named: PrecomputedHashMap<Atom, SmallVec<[PageRuleData; 1]>>,
}
impl PageRuleMap {
#[inline]
fn clear(&mut self) {
self.rules.clear();
self.global.clear();
self.named.clear();
}
}
impl MallocShallowSizeOf for PageRuleMap {
fn shallow_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.rules.shallow_size_of(ops)
self.global.size_of(ops) + self.named.shallow_size_of(ops)
}
}
@ -1682,15 +1695,20 @@ impl ExtraStyleData {
layer: LayerId,
) -> Result<(), AllocErr> {
let page_rule = rule.read_with(guard);
let mut add_rule = |name| {
let vec = self.pages.rules.entry(name).or_default();
vec.push(PageRuleData{layer, rule: rule.clone()});
};
if page_rule.selectors.0.is_empty() {
add_rule(atom!(""));
self.pages
.global
.push(PageRuleDataNoLayer(rule.clone()), layer);
} else {
for selector in page_rule.selectors.as_slice() {
add_rule(selector.name.0.clone());
// TODO: Handle pseudo-classes
self.pages.named.try_reserve(page_rule.selectors.0.len())?;
for name in page_rule.selectors.as_slice() {
let vec = self.pages.named.entry(name.0 .0.clone()).or_default();
vec.try_reserve(1)?;
vec.push(PageRuleData {
layer,
rule: rule.clone(),
});
}
}
Ok(())
@ -1701,6 +1719,7 @@ impl ExtraStyleData {
self.font_feature_values.sort(layers);
self.font_palette_values.sort(layers);
self.counter_styles.sort(layers);
self.pages.global.sort(layers);
}
fn clear(&mut self) {

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

@ -106,7 +106,7 @@ use style::properties::{PropertyDeclarationId, ShorthandId};
use style::properties::{SourcePropertyDeclaration, StyleBuilder};
use style::properties_and_values::rule::Inherits as PropertyInherits;
use style::rule_cache::RuleCacheConditions;
use style::rule_tree::{CascadeLevel, StrongRuleNode, StyleSource};
use style::rule_tree::{CascadeLevel, StrongRuleNode};
use style::selector_parser::PseudoElementCascadeType;
use style::shared_lock::{
Locked, SharedRwLock, SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard,
@ -122,9 +122,8 @@ use style::stylesheets::{
AllowImportRules, ContainerRule, CounterStyleRule, CssRule, CssRuleType, CssRules,
CssRulesHelpers, DocumentRule, FontFaceRule, FontFeatureValuesRule, FontPaletteValuesRule,
ImportRule, KeyframesRule, LayerBlockRule, LayerStatementRule, MediaRule, NamespaceRule,
Origin, OriginSet, PageRule, PagePseudoClassFlags, PropertyRule, SanitizationData,
SanitizationKind, StyleRule, StylesheetContents, StylesheetLoader as StyleStylesheetLoader,
SupportsRule, UrlExtraData,
Origin, OriginSet, PageRule, PropertyRule, SanitizationData, SanitizationKind, StyleRule,
StylesheetContents, StylesheetLoader as StyleStylesheetLoader, SupportsRule, UrlExtraData,
};
use style::stylist::{add_size_of_ua_cache, AuthorStylesEnabled, RuleInclusion, Stylist};
use style::thread_state;
@ -3864,7 +3863,6 @@ counter_style_descriptors! {
pub unsafe extern "C" fn Servo_ComputedValues_GetForPageContent(
raw_data: &PerDocumentStyleData,
page_name: *const nsAtom,
flags: PagePseudoClassFlags,
) -> Strong<ComputedValues> {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
@ -3874,39 +3872,30 @@ pub unsafe extern "C" fn Servo_ComputedValues_GetForPageContent(
let mut extra_declarations = vec![];
let iter = data.stylist.iter_extra_data_origins_rev();
for (data, origin) in iter {
let start = extra_declarations.len();
let level = match origin {
Origin::UserAgent => CascadeLevel::UANormal,
Origin::User => CascadeLevel::UserNormal,
Origin::Author => CascadeLevel::same_tree_author_normal(),
};
let mut add_rule_with_name = |name: &Atom| {
if let Some(rules) = data.pages.rules.get(name) {
for rule_data in rules.iter() {
let rule = rule_data.rule.read_with(level.guard(&guards));
if let Some(s) = rule.match_specificity(&flags) {
let block = rule.block.clone();
extra_declarations.push(ApplicableDeclarationBlock::new(
StyleSource::from_declarations(block),
0,
level,
s,
LayerOrder::root(),
));
}
}
}
extra_declarations.reserve(data.pages.global.len());
let mut add_rule = |rule: &Arc<Locked<PageRule>>| {
extra_declarations.push(ApplicableDeclarationBlock::from_declarations(
rule.read_with(level.guard(&guards)).block.clone(),
level,
LayerOrder::root(),
));
};
// Add any nameless rules that match pseudo classes.
let empty_ = atom!("");
add_rule_with_name(&empty_);
// Add any rules that match the name.
if !page_name.is_null() {
Atom::with(page_name, add_rule_with_name);
for &(ref rule, _layer_id) in data.pages.global.iter() {
add_rule(&rule.0);
}
if !page_name.is_null() {
Atom::with(page_name, |name| {
if let Some(rules) = data.pages.named.get(name) {
// Rules are already sorted by source order.
rules.iter().for_each(|d| add_rule(&d.rule));
}
});
}
extra_declarations[start..].sort_unstable_by_key(|block| {
(block.layer_order(), block.specificity, block.source_order())
});
}
let rule_node = data.stylist.rule_node_for_precomputed_pseudo(

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

@ -0,0 +1,8 @@
[cssom-pagerule.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Set selectorText to :left pseudo page]
expected: FAIL
[Set selectorText to named page with :first pseudo page]
expected: FAIL

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

@ -34,40 +34,6 @@
assert_equals(rule.selectorText, "named:first");
}, "Set selectorText to named page with :first pseudo page");
test(() => {
rule.selectorText = "named:First";
assert_equals(rule.selectorText, "named:first");
}, "Set selectorText to named page with case insensitive :first pseudo page");
test(() => {
rule.selectorText = "named:first:first";
assert_equals(rule.selectorText, "named:first:first");
}, "Set selectorText to named page with two :first pseudo page");
test(() => {
rule.selectorText = "named:first:left:right:first";
assert_equals(rule.selectorText, "named:first:left:right:first");
}, "Set selectorText to named page with pseudo pages of " +
":first, :left, :right, :first in order.");
test(() => {
rule.selectorText = "";
rule.selectorText = "named :first";
assert_equals(rule.selectorText, "");
}, "Cannot set selectorText to named page with pseudo, whitespace between");
test(() => {
rule.selectorText = "";
rule.selectorText = ":first :left";
assert_equals(rule.selectorText, "");
}, "Cannot set selectorText to two pseudos, whitespace between");
test(() => {
rule.selectorText = "";
rule.selectorText = ":notapagepseudo";
assert_equals(rule.selectorText, "");
}, "Cannot set selectorText to invalid pseudo page");
test(() => {
assert_equals(rule.parentStyleSheet, sheet);
sheet.deleteRule(0);