Bug 1852149 Part 3 - Add margin rules to servo r=firefox-style-system-reviewers,emilio

Parsing is disabled by the layout.css.margin-rules.enabled pref.
This isn't currently testable beyond a crashtest because the DOM interface for
margin rules isn't implemented yet.

Differential Revision: https://phabricator.services.mozilla.com/D187736
This commit is contained in:
Emily McDonough 2023-12-08 20:25:55 +00:00
Родитель 1568c7e499
Коммит 8ad20b2ce6
10 изменённых файлов: 231 добавлений и 7 удалений

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

@ -97,6 +97,7 @@ void ServoStyleRuleMap::RuleRemoved(StyleSheet& aStyleSheet,
case StyleCssRuleType::Property:
case StyleCssRuleType::Keyframes:
case StyleCssRuleType::Keyframe:
case StyleCssRuleType::Margin:
case StyleCssRuleType::Namespace:
case StyleCssRuleType::CounterStyle:
case StyleCssRuleType::FontFeatureValues:
@ -141,6 +142,7 @@ void ServoStyleRuleMap::FillTableFromRule(css::Rule& aRule) {
case StyleCssRuleType::Property:
case StyleCssRuleType::Keyframes:
case StyleCssRuleType::Keyframe:
case StyleCssRuleType::Margin:
case StyleCssRuleType::Namespace:
case StyleCssRuleType::CounterStyle:
case StyleCssRuleType::FontFeatureValues:

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

@ -104,6 +104,9 @@ css::Rule* ServoCSSRuleList::GetRule(uint32_t aIndex) {
case StyleCssRuleType::Keyframe:
MOZ_ASSERT_UNREACHABLE("keyframe rule cannot be here");
return nullptr;
case StyleCssRuleType::Margin:
// Margin rules not implemented yet, see bug 1864737
return nullptr;
}
rule = CastToUint(ruleObj.forget().take());
mRules[aIndex] = rule;
@ -276,6 +279,9 @@ void ServoCSSRuleList::SetRawContents(RefPtr<StyleLockedCssRules> aNewRules,
case StyleCssRuleType::Keyframe:
MOZ_ASSERT_UNREACHABLE("keyframe rule cannot be here");
break;
case StyleCssRuleType::Margin:
// Margin rules not implemented yet, see bug 1864737
break;
}
#undef RULE_CASE_WITH_PREFIX
#undef RULE_CASE_LOCKED

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

@ -1010,6 +1010,9 @@ void ServoStyleSet::RuleChangedInternal(StyleSheet& aSheet, css::Rule& aRule,
// FIXME: We should probably just forward to the parent @keyframes rule? I
// think that'd do the right thing, but meanwhile...
return MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
case StyleCssRuleType::Margin:
// Margin rules not implemented yet, see bug 1864737
break;
}
#undef CASE_FOR

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

@ -623,7 +623,7 @@ impl StylesheetInvalidationSet {
// Do nothing, @font-face doesn't affect computed style information on it's own.
// We'll restyle when the font face loads, if needed.
},
Page(..) => {
Page(..) | Margin(..) => {
// Do nothing, we don't support OM mutations on print documents, and page rules
// can't affect anything else.
},

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

@ -0,0 +1,167 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! A [`@margin`][margin] rule.
//!
//! [margin]: https://drafts.csswg.org/css-page-3/#margin-boxes
use crate::properties::PropertyDeclarationBlock;
use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
use crate::str::CssStringWriter;
use cssparser::SourceLocation;
#[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
use servo_arc::Arc;
use std::fmt::{self, Write};
macro_rules! margin_rule_types {
($($(#[$($meta:tt)+])* $id:ident => $val:literal,)+) => {
/// [`@margin`][margin] rule names.
///
/// https://drafts.csswg.org/css-page-3/#margin-at-rules
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)]
#[repr(u8)]
pub enum MarginRuleType {
$($(#[$($meta)+])* $id,)+
}
impl MarginRuleType {
#[inline]
fn to_str(&self) -> &'static str {
match *self {
$(MarginRuleType::$id => concat!('@', $val),)+
}
}
/// Matches the rule type for this name. This does not expect a
/// leading '@'.
pub fn match_name(name: &str) -> Option<Self> {
Some(match_ignore_ascii_case! { name,
$( $val => MarginRuleType::$id, )+
_ => return None,
})
}
}
}
}
margin_rule_types! {
/// [`@top-left-corner`][top-left-corner] margin rule
///
/// [top-left-corner] https://drafts.csswg.org/css-page-3/#top-left-corner-box-def
TopLeftCorner => "top-left-corner",
/// [`@top-left`][top-left] margin rule
///
/// [top-left] https://drafts.csswg.org/css-page-3/#top-left-box-def
TopLeft => "top-left",
/// [`@top-center`][top-center] margin rule
///
/// [top-center] https://drafts.csswg.org/css-page-3/#top-center-box-def
TopCenter => "top-center",
/// [`@top-right`][top-right] margin rule
///
/// [top-right] https://drafts.csswg.org/css-page-3/#top-right-box-def
TopRight => "top-right",
/// [`@top-right-corner`][top-right-corner] margin rule
///
/// [top-right-corner] https://drafts.csswg.org/css-page-3/#top-right-corner-box-def
TopRightCorner => "top-right-corner",
/// [`@bottom-left-corner`][bottom-left-corner] margin rule
///
/// [bottom-left-corner] https://drafts.csswg.org/css-page-3/#bottom-left-corner-box-def
BottomLeftCorner => "bottom-left-corner",
/// [`@bottom-left`][bottom-left] margin rule
///
/// [bottom-left] https://drafts.csswg.org/css-page-3/#bottom-left-box-def
BottomLeft => "bottom-left",
/// [`@bottom-center`][bottom-center] margin rule
///
/// [bottom-center] https://drafts.csswg.org/css-page-3/#bottom-center-box-def
BottomCenter => "bottom-center",
/// [`@bottom-right`][bottom-right] margin rule
///
/// [bottom-right] https://drafts.csswg.org/css-page-3/#bottom-right-box-def
BottomRight => "bottom-right",
/// [`@bottom-right-corner`][bottom-right-corner] margin rule
///
/// [bottom-right-corner] https://drafts.csswg.org/css-page-3/#bottom-right-corner-box-def
BottomRightCorner => "bottom-right-corner",
/// [`@left-top`][left-top] margin rule
///
/// [left-top] https://drafts.csswg.org/css-page-3/#left-top-box-def
LeftTop => "left-top",
/// [`@left-middle`][left-middle] margin rule
///
/// [left-middle] https://drafts.csswg.org/css-page-3/#left-middle-box-def
LeftMiddle => "left-middle",
/// [`@left-bottom`][left-bottom] margin rule
///
/// [left-bottom] https://drafts.csswg.org/css-page-3/#left-bottom-box-def
LeftBottom => "left-bottom",
/// [`@right-top`][right-top] margin rule
///
/// [right-top] https://drafts.csswg.org/css-page-3/#right-top-box-def
RightTop => "right-top",
/// [`@right-middle`][right-middle] margin rule
///
/// [right-middle] https://drafts.csswg.org/css-page-3/#right-middle-box-def
RightMiddle => "right-middle",
/// [`@right-bottom`][right-bottom] margin rule
///
/// [right-bottom] https://drafts.csswg.org/css-page-3/#right-bottom-box-def
RightBottom => "right-bottom",
}
/// A [`@margin`][margin] rule.
///
/// [margin]: https://drafts.csswg.org/css-page-3/#margin-at-rules
#[derive(Clone, Debug, ToShmem)]
pub struct MarginRule {
/// Type of this margin rule.
pub rule_type: MarginRuleType,
/// The declaration block this margin rule contains.
pub block: Arc<Locked<PropertyDeclarationBlock>>,
/// The source position this rule was found at.
pub source_location: SourceLocation,
}
impl MarginRule {
/// Measure heap usage.
#[cfg(feature = "gecko")]
pub fn size_of(&self, guard: &SharedRwLockReadGuard, ops: &mut MallocSizeOfOps) -> usize {
// Measurement of other fields may be added later.
self.block.unconditional_shallow_size_of(ops) +
self.block.read_with(guard).size_of(ops)
}
}
impl ToCssWithGuard for MarginRule {
/// Serialization of a margin-rule is not specced, this is adapted from how
/// page-rules and style-rules are serialized.
fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
dest.write_str(self.rule_type.to_str())?;
dest.write_str(" { ")?;
let declaration_block = self.block.read_with(guard);
declaration_block.to_css(dest)?;
if !declaration_block.declarations().is_empty() {
dest.write_char(' ')?;
}
dest.write_char('}')
}
}
impl DeepCloneWithLock for MarginRule {
fn deep_clone_with_lock(
&self,
lock: &SharedRwLock,
guard: &SharedRwLockReadGuard,
_params: &DeepCloneParams,
) -> Self {
MarginRule {
rule_type: self.rule_type,
block: Arc::new(lock.wrap(self.block.read_with(&guard).clone())),
source_location: self.source_location.clone(),
}
}
}

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

@ -18,6 +18,7 @@ mod media_rule;
mod namespace_rule;
pub mod origin;
mod page_rule;
mod margin_rule;
mod property_rule;
mod rule_list;
mod rule_parser;
@ -56,6 +57,7 @@ pub use self::import_rule::ImportRule;
pub use self::keyframes_rule::KeyframesRule;
pub use self::layer_rule::{LayerBlockRule, LayerStatementRule};
pub use self::loader::StylesheetLoader;
pub use self::margin_rule::{MarginRule, MarginRuleType};
pub use self::media_rule::MediaRule;
pub use self::namespace_rule::NamespaceRule;
pub use self::origin::{Origin, OriginSet, OriginSetIterator, PerOrigin, PerOriginIter};
@ -244,11 +246,11 @@ impl Eq for UrlExtraData {}
#[derive(Clone, Debug, ToShmem)]
#[allow(missing_docs)]
pub enum CssRule {
Style(Arc<Locked<StyleRule>>),
// No Charset here, CSSCharsetRule has been removed from CSSOM
// https://drafts.csswg.org/cssom/#changes-from-5-december-2013
Namespace(Arc<NamespaceRule>),
Import(Arc<Locked<ImportRule>>),
Style(Arc<Locked<StyleRule>>),
Media(Arc<MediaRule>),
Container(Arc<ContainerRule>),
FontFace(Arc<Locked<FontFaceRule>>),
@ -256,6 +258,7 @@ pub enum CssRule {
FontPaletteValues(Arc<FontPaletteValuesRule>),
CounterStyle(Arc<Locked<CounterStyleRule>>),
Keyframes(Arc<Locked<KeyframesRule>>),
Margin(Arc<MarginRule>),
Supports(Arc<SupportsRule>),
Page(Arc<Locked<PageRule>>),
Property(Arc<PropertyRule>),
@ -291,6 +294,9 @@ impl CssRule {
CssRule::FontPaletteValues(_) => 0,
CssRule::CounterStyle(_) => 0,
CssRule::Keyframes(_) => 0,
CssRule::Margin(ref arc) => {
arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
},
CssRule::Supports(ref arc) => {
arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops)
},
@ -325,7 +331,7 @@ pub enum CssRuleType {
Keyframes = 7,
Keyframe = 8,
// https://drafts.csswg.org/cssom/#the-cssrule-interface
// Margin = 9, // Not implemented yet.
Margin = 9,
Namespace = 10,
// https://drafts.csswg.org/css-counter-styles-3/#extentions-to-cssrule-interface
CounterStyle = 11,
@ -421,6 +427,7 @@ impl CssRule {
CssRule::FontPaletteValues(_) => CssRuleType::FontPaletteValues,
CssRule::CounterStyle(_) => CssRuleType::CounterStyle,
CssRule::Keyframes(_) => CssRuleType::Keyframes,
CssRule::Margin(_) => CssRuleType::Margin,
CssRule::Namespace(_) => CssRuleType::Namespace,
CssRule::Supports(_) => CssRuleType::Supports,
CssRule::Page(_) => CssRuleType::Page,
@ -536,6 +543,9 @@ impl DeepCloneWithLock for CssRule {
lock.wrap(rule.deep_clone_with_lock(lock, guard, params)),
))
},
CssRule::Margin(ref arc) => {
CssRule::Margin(Arc::new(arc.deep_clone_with_lock(lock, guard, params)))
},
CssRule::Supports(ref arc) => {
CssRule::Supports(Arc::new(arc.deep_clone_with_lock(lock, guard, params)))
},
@ -573,6 +583,7 @@ impl ToCssWithGuard for CssRule {
CssRule::FontPaletteValues(ref rule) => rule.to_css(guard, dest),
CssRule::CounterStyle(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest),
CssRule::Margin(ref rule) => rule.to_css(guard, dest),
CssRule::Media(ref rule) => rule.to_css(guard, dest),
CssRule::Supports(ref rule) => rule.to_css(guard, dest),
CssRule::Page(ref lock) => lock.read_with(guard).to_css(guard, dest),

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

@ -26,8 +26,9 @@ use crate::stylesheets::layer_rule::{LayerBlockRule, LayerName, LayerStatementRu
use crate::stylesheets::supports_rule::SupportsCondition;
use crate::stylesheets::{
AllowImportRules, CorsMode, CssRule, CssRuleType, CssRuleTypes, CssRules, DocumentRule,
FontFeatureValuesRule, FontPaletteValuesRule, KeyframesRule, MediaRule, NamespaceRule,
PageRule, PageSelectors, RulesMutateError, StyleRule, StylesheetLoader, SupportsRule,
FontFeatureValuesRule, FontPaletteValuesRule, KeyframesRule, MarginRule, MarginRuleType,
MediaRule, NamespaceRule, PageRule, PageSelectors, RulesMutateError, StyleRule,
StylesheetLoader, SupportsRule,
};
use crate::values::computed::font::FamilyName;
use crate::values::{CssUrl, CustomIdent, DashedIdent, KeyframesName};
@ -224,6 +225,8 @@ pub enum AtRulePrelude {
Option<ImportSupportsCondition>,
ImportLayer,
),
/// A @margin rule prelude.
Margin(MarginRuleType),
/// A @namespace rule prelude.
Namespace(Option<Prefix>, Namespace),
/// A @layer rule prelude.
@ -245,6 +248,7 @@ impl AtRulePrelude {
Self::Property(..) => "property",
Self::Document(..) => "-moz-document",
Self::Import(..) => "import",
Self::Margin(..) => "margin",
Self::Namespace(..) => "namespace",
Self::Layer(..) => "layer",
}
@ -482,6 +486,11 @@ impl<'a, 'i> NestedRuleParser<'a, 'i> {
self.context.rule_types.contains(CssRuleType::Style)
}
#[inline]
fn in_page_rule(&self) -> bool {
self.context.rule_types.contains(CssRuleType::Page)
}
#[inline]
fn in_style_or_page_rule(&self) -> bool {
let types = CssRuleTypes::from_bits(CssRuleType::Style.bit() | CssRuleType::Page.bit());
@ -509,6 +518,7 @@ impl<'a, 'i> NestedRuleParser<'a, 'i> {
AtRulePrelude::Page(..) |
AtRulePrelude::Property(..) |
AtRulePrelude::Import(..) => !self.in_style_or_page_rule(),
AtRulePrelude::Margin(..) => self.in_page_rule(),
}
}
@ -691,7 +701,14 @@ impl<'a, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'i> {
let cond = DocumentCondition::parse(&self.context, input)?;
AtRulePrelude::Document(cond)
},
_ => return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone())))
_ => {
if static_prefs::pref!("layout.css.margin-rules.enabled") {
if let Some(margin_rule_type) = MarginRuleType::match_name(&name) {
return Ok(AtRulePrelude::Margin(margin_rule_type));
}
}
return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone())))
},
})
}
@ -836,6 +853,16 @@ impl<'a, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'i> {
source_location,
}))
},
AtRulePrelude::Margin(rule_type) => {
let declarations = self.nest_for_rule(CssRuleType::Margin, |p| {
parse_property_declaration_list(&p.context, input, &[])
});
CssRule::Margin(Arc::new(MarginRule {
rule_type,
block: Arc::new(self.shared_lock.wrap(declarations)),
source_location: start.source_location(),
}))
}
AtRulePrelude::Import(..) | AtRulePrelude::Namespace(..) => {
// These rules don't have blocks.
return Err(input.new_unexpected_token_error(cssparser::Token::CurlyBracketBlock));

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

@ -66,11 +66,16 @@ where
CssRule::FontFace(_) |
CssRule::CounterStyle(_) |
CssRule::Keyframes(_) |
CssRule::Page(_) |
CssRule::Margin(_) |
CssRule::Property(_) |
CssRule::LayerStatement(_) |
CssRule::FontFeatureValues(_) |
CssRule::FontPaletteValues(_) => None,
CssRule::Page(ref page_rule) => {
let page_rule = page_rule.read_with(guard);
let rules = page_rule.rules.read_with(guard);
Some(rules.0.iter())
},
CssRule::Style(ref style_rule) => {
let style_rule = style_rule.read_with(guard);
style_rule

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

@ -339,6 +339,7 @@ impl SanitizationKind {
CssRule::Keyframes(..) |
CssRule::Page(..) |
CssRule::Margin(..) |
CssRule::Property(..) |
CssRule::FontFeatureValues(..) |
CssRule::FontPaletteValues(..) |

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

@ -3002,6 +3002,7 @@ impl CascadeData {
CssRule::Page(ref rule) => {
self.extra_data
.add_page(guard, rule, containing_rule_state.layer_id)?;
handled = false;
},
_ => {
handled = false;
@ -3243,6 +3244,7 @@ impl CascadeData {
CssRule::CounterStyle(..) |
CssRule::Supports(..) |
CssRule::Keyframes(..) |
CssRule::Margin(..) |
CssRule::Page(..) |
CssRule::Property(..) |
CssRule::Document(..) |