зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
4186df5750
Коммит
15227435c3
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче