Bug 1830141 - Share code to parse @import layer + supports(). r=CanadaHonk

The duplication was slightly annoying me :)

Differential Revision: https://phabricator.services.mozilla.com/D176564
This commit is contained in:
Emilio Cobos Álvarez 2023-04-26 19:18:43 +00:00
parent 5d7ecd51c2
commit 3f56c738cc
3 changed files with 67 additions and 75 deletions

View file

@ -7,14 +7,17 @@
//! [import]: https://drafts.csswg.org/css-cascade-3/#at-import
use crate::media_queries::MediaList;
use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock};
use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
use crate::parser::{Parse, ParserContext};
use crate::shared_lock::{
DeepCloneParams, DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard,
};
use crate::str::CssStringWriter;
use crate::stylesheets::supports_rule::SupportsCondition;
use crate::stylesheets::layer_rule::LayerName;
use crate::stylesheets::{CssRule, StylesheetInDocument};
use crate::stylesheets::{
layer_rule::LayerName, stylesheet::Namespaces, supports_rule::SupportsCondition, CssRule,
CssRuleType, StylesheetInDocument,
};
use crate::values::CssUrl;
use cssparser::SourceLocation;
use cssparser::{Parser, SourceLocation};
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
use to_shmem::{self, SharedMemoryBuilder, ToShmem};
@ -62,8 +65,7 @@ impl ImportSheet {
}
Some(s)
},
ImportSheet::Refused |
ImportSheet::Pending => None,
ImportSheet::Refused | ImportSheet::Pending => None,
}
}
@ -150,7 +152,7 @@ pub struct ImportSupportsCondition {
pub condition: SupportsCondition,
/// If the import is enabled, from the result of the import condition.
pub enabled: bool
pub enabled: bool,
}
impl ToCss for ImportLayer {
@ -192,6 +194,54 @@ pub struct ImportRule {
pub source_location: SourceLocation,
}
impl ImportRule {
/// Parses the layer() / layer / supports() part of the import header, as per
/// https://drafts.csswg.org/css-cascade-5/#at-import:
///
/// [ layer | layer(<layer-name>) ]?
/// [ supports([ <supports-condition> | <declaration> ]) ]?
///
/// We do this here so that the import preloader can look at this without having to parse the
/// whole import rule or parse the media query list or what not.
pub fn parse_layer_and_supports<'i, 't>(
input: &mut Parser<'i, 't>,
context: &ParserContext,
namespaces: &Namespaces,
) -> (Option<ImportLayer>, Option<ImportSupportsCondition>) {
let layer = if input
.try_parse(|input| input.expect_ident_matching("layer"))
.is_ok()
{
Some(ImportLayer { name: None })
} else {
input
.try_parse(|input| {
input.expect_function_matching("layer")?;
input
.parse_nested_block(|input| LayerName::parse(context, input))
.map(|name| ImportLayer { name: Some(name) })
})
.ok()
};
let supports = if !static_prefs::pref!("layout.css.import-supports.enabled") {
None
} else {
input
.try_parse(SupportsCondition::parse_for_import)
.map(|condition| {
let eval_context =
ParserContext::new_with_rule_type(context, CssRuleType::Style, namespaces);
let enabled = condition.eval(&eval_context, namespaces);
ImportSupportsCondition { condition, enabled }
})
.ok()
};
(layer, supports)
}
}
impl ToShmem for ImportRule {
fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
Err(String::from(

View file

@ -16,7 +16,7 @@ use crate::str::starts_with_ignore_ascii_case;
use crate::stylesheets::container_rule::{ContainerCondition, ContainerRule};
use crate::stylesheets::document_rule::DocumentCondition;
use crate::stylesheets::font_feature_values_rule::parse_family_name_list;
use crate::stylesheets::import_rule::{ImportLayer, ImportSupportsCondition};
use crate::stylesheets::import_rule::{ImportRule, ImportLayer, ImportSupportsCondition};
use crate::stylesheets::keyframes_rule::parse_keyframe_list;
use crate::stylesheets::layer_rule::{LayerBlockRule, LayerName, LayerStatementRule};
use crate::stylesheets::stylesheet::Namespaces;
@ -241,38 +241,7 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
let url_string = input.expect_url_or_string()?.as_ref().to_owned();
let url = CssUrl::parse_from_string(url_string, &self.context, CorsMode::None);
let layer = if input.try_parse(|input| input.expect_ident_matching("layer")).is_ok() {
Some(ImportLayer {
name: None,
})
} else {
input.try_parse(|input| {
input.expect_function_matching("layer")?;
input.parse_nested_block(|input| {
LayerName::parse(&self.context, input)
}).map(|name| ImportLayer {
name: Some(name),
})
}).ok()
};
let supports = if !static_prefs::pref!("layout.css.import-supports.enabled") {
None
} else {
input.try_parse(SupportsCondition::parse_for_import).map(|condition| {
let eval_context = ParserContext::new_with_rule_type(
&self.context,
CssRuleType::Style,
self.namespaces,
);
let enabled = condition.eval(&eval_context, self.namespaces);
ImportSupportsCondition {
condition,
enabled
}
}).ok()
};
let (layer, supports) = ImportRule::parse_layer_and_supports(input, &self.context, self.namespaces);
let media = MediaList::parse(&self.context, input);
let media = Arc::new(self.shared_lock.wrap(media));

View file

@ -122,8 +122,8 @@ use style::style_adjuster::StyleAdjuster;
use style::stylesheets::container_rule::ContainerSizeQuery;
use style::stylesheets::import_rule::ImportSheet;
use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue};
use style::stylesheets::layer_rule::{LayerOrder, LayerName};
use style::stylesheets::supports_rule::{parse_condition_or_declaration, SupportsCondition};
use style::stylesheets::layer_rule::LayerOrder;
use style::stylesheets::supports_rule::parse_condition_or_declaration;
use style::stylesheets::{
AllowImportRules, ContainerRule, CounterStyleRule, CssRule, CssRuleType, CssRules,
CssRulesHelpers, DocumentRule, FontFaceRule, FontFeatureValuesRule, FontPaletteValuesRule,
@ -148,7 +148,7 @@ use style::values::generics::easing::BeforeFlag;
use style::values::specified::gecko::IntersectionObserverRootMargin;
use style::values::specified::source_size_list::SourceSizeList;
use style::values::{specified, AtomIdent, CustomIdent, KeyframesName};
use style_traits::{CssWriter, ParsingMode, ToCss, ParseError};
use style_traits::{CssWriter, ParsingMode, ToCss};
use to_shmem::SharedMemoryBuilder;
trait ClosureHelper {
@ -5854,37 +5854,10 @@ pub extern "C" fn Servo_CSSSupportsForImport(after_rule: &nsACString) -> bool {
None,
);
// Try to parse a layer definition first if there is one,
// the input we recieve is after the main @import value (URL),
// so we should expect, in this order:
// [ layer | layer(<layer-name>) ]?
// [ supports( [ <supports-condition> | <declaration> ] ) ]?
// <media-query-list>?
// https://drafts.csswg.org/css-cascade-5/#at-import
let _ = input.try_parse(|input| -> Result<_, ParseError> {
// Try to parse layer ident if there.
if !input.expect_ident_matching("layer").is_ok() {
// Did not get a layer ident, try to parse a function and nested instead.
input.expect_function_matching("layer")?;
input.parse_nested_block(|input| {
LayerName::parse(&context, input)
})?;
}
Ok(())
});
// supports() import conditions have to be parsed differently as:
// 1. They are wrapped in a supports(...) function
// 2. They do not have to be the entire input (supports() and media query list)
// 3. We return true by default, as an @import with no supports() should still be imported
// https://drafts.csswg.org/css-cascade-5/#typedef-import-conditions
let cond = match input.try_parse(SupportsCondition::parse_for_import) {
Ok(c) => c,
Err(..) => return true,
};
let namespaces = Default::default();
cond.eval(&context, &namespaces)
let (_layer, supports) = ImportRule::parse_layer_and_supports(&mut input, &context, &namespaces);
supports.map_or(true, |s| s.enabled)
}
#[no_mangle]