mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
style: More container queries plumbing
Provide container information in computed::Context and use it to resolve the container queries. This still fails a lot of tests because we are not ensuring that layout is up-to-date when we style the container descendants, but that's expected. Differential Revision: https://phabricator.services.mozilla.com/D146478
This commit is contained in:
parent
5c2fac087f
commit
bbf10a43b8
18 changed files with 420 additions and 143 deletions
|
@ -7,7 +7,7 @@
|
|||
//! https://drafts.csswg.org/mediaqueries-4/#typedef-media-condition
|
||||
//! https://drafts.csswg.org/css-contain-3/#typedef-container-condition
|
||||
|
||||
use super::{QueryFeatureExpression, FeatureType};
|
||||
use super::{QueryFeatureExpression, FeatureType, FeatureFlags};
|
||||
use crate::parser::ParserContext;
|
||||
use crate::values::computed;
|
||||
use cssparser::{Parser, Token};
|
||||
|
@ -85,6 +85,35 @@ impl QueryCondition {
|
|||
Self::parse_internal(context, input, feature_type, AllowOr::Yes)
|
||||
}
|
||||
|
||||
fn visit<F>(&self, visitor: &mut F)
|
||||
where
|
||||
F: FnMut(&Self),
|
||||
{
|
||||
visitor(self);
|
||||
match *self {
|
||||
Self::Feature(..) => {},
|
||||
Self::Not(ref cond) => cond.visit(visitor),
|
||||
Self::Operation(ref conds, _op) => {
|
||||
for cond in conds.iter() {
|
||||
cond.visit(visitor);
|
||||
}
|
||||
},
|
||||
Self::InParens(ref cond) => cond.visit(visitor),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the union of all flags in the expression. This is useful for
|
||||
/// container queries.
|
||||
pub fn cumulative_flags(&self) -> FeatureFlags {
|
||||
let mut result = FeatureFlags::empty();
|
||||
self.visit(&mut |condition| {
|
||||
if let Self::Feature(ref f) = condition {
|
||||
result.insert(f.feature_flags())
|
||||
}
|
||||
});
|
||||
result
|
||||
}
|
||||
|
||||
/// Parse a single condition, disallowing `or` expressions.
|
||||
///
|
||||
/// To be used from the legacy query syntax.
|
||||
|
|
|
@ -101,13 +101,42 @@ macro_rules! keyword_evaluator {
|
|||
}
|
||||
|
||||
bitflags! {
|
||||
/// Different requirements or toggles that change how a expression is
|
||||
/// parsed.
|
||||
pub struct ParsingRequirements: u8 {
|
||||
/// Different flags or toggles that change how a expression is parsed or
|
||||
/// evaluated.
|
||||
#[derive(ToShmem)]
|
||||
pub struct FeatureFlags : u8 {
|
||||
/// The feature should only be parsed in chrome and ua sheets.
|
||||
const CHROME_AND_UA_ONLY = 1 << 0;
|
||||
/// The feature requires a -webkit- prefix.
|
||||
const WEBKIT_PREFIX = 1 << 1;
|
||||
/// The feature requires the inline-axis containment.
|
||||
const CONTAINER_REQUIRES_INLINE_AXIS = 1 << 2;
|
||||
/// The feature requires the block-axis containment.
|
||||
const CONTAINER_REQUIRES_BLOCK_AXIS = 1 << 3;
|
||||
/// The feature requires containment in the physical width axis.
|
||||
const CONTAINER_REQUIRES_WIDTH_AXIS = 1 << 4;
|
||||
/// The feature requires containment in the physical height axis.
|
||||
const CONTAINER_REQUIRES_HEIGHT_AXIS = 1 << 5;
|
||||
}
|
||||
}
|
||||
|
||||
impl FeatureFlags {
|
||||
/// Returns parsing requirement flags.
|
||||
pub fn parsing_requirements(self) -> Self {
|
||||
self.intersection(Self::CHROME_AND_UA_ONLY | Self::WEBKIT_PREFIX)
|
||||
}
|
||||
|
||||
/// Returns all the container axis flags.
|
||||
pub fn all_container_axes() -> Self {
|
||||
Self::CONTAINER_REQUIRES_INLINE_AXIS |
|
||||
Self::CONTAINER_REQUIRES_BLOCK_AXIS |
|
||||
Self::CONTAINER_REQUIRES_WIDTH_AXIS |
|
||||
Self::CONTAINER_REQUIRES_HEIGHT_AXIS
|
||||
}
|
||||
|
||||
/// Returns our subset of container axis flags.
|
||||
pub fn container_axes(self) -> Self {
|
||||
self.intersection(Self::all_container_axes())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,9 +157,8 @@ pub struct QueryFeatureDescription {
|
|||
/// The evaluator, which we also use to determine which kind of value to
|
||||
/// parse.
|
||||
pub evaluator: Evaluator,
|
||||
/// Different requirements that need to hold for the feature to be
|
||||
/// successfully parsed.
|
||||
pub requirements: ParsingRequirements,
|
||||
/// Different feature-specific flags.
|
||||
pub flags: FeatureFlags,
|
||||
}
|
||||
|
||||
impl QueryFeatureDescription {
|
||||
|
@ -143,12 +171,12 @@ impl QueryFeatureDescription {
|
|||
|
||||
/// A simple helper to construct a `QueryFeatureDescription`.
|
||||
macro_rules! feature {
|
||||
($name:expr, $allows_ranges:expr, $evaluator:expr, $reqs:expr,) => {
|
||||
($name:expr, $allows_ranges:expr, $evaluator:expr, $flags:expr,) => {
|
||||
$crate::queries::feature::QueryFeatureDescription {
|
||||
name: $name,
|
||||
allows_ranges: $allows_ranges,
|
||||
evaluator: $evaluator,
|
||||
requirements: $reqs,
|
||||
flags: $flags,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -158,7 +186,7 @@ impl fmt::Debug for QueryFeatureDescription {
|
|||
f.debug_struct("QueryFeatureDescription")
|
||||
.field("name", &self.name)
|
||||
.field("allows_ranges", &self.allows_ranges)
|
||||
.field("requirements", &self.requirements)
|
||||
.field("flags", &self.flags)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//! `(width >= 400px)`.
|
||||
|
||||
use super::feature::{Evaluator, QueryFeatureDescription};
|
||||
use super::feature::{KeywordDiscriminant, ParsingRequirements};
|
||||
use super::feature::{KeywordDiscriminant, FeatureFlags};
|
||||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase};
|
||||
use crate::values::computed::{self, Ratio, ToComputedValue};
|
||||
|
@ -337,10 +337,7 @@ impl QueryFeatureExpression {
|
|||
W: fmt::Write,
|
||||
{
|
||||
let feature = self.feature();
|
||||
if feature
|
||||
.requirements
|
||||
.contains(ParsingRequirements::WEBKIT_PREFIX)
|
||||
{
|
||||
if feature.flags.contains(FeatureFlags::WEBKIT_PREFIX) {
|
||||
dest.write_str("-webkit-")?;
|
||||
}
|
||||
|
||||
|
@ -361,6 +358,11 @@ impl QueryFeatureExpression {
|
|||
&self.feature_type.features()[self.feature_index]
|
||||
}
|
||||
|
||||
/// Returns the feature flags for our feature.
|
||||
pub fn feature_flags(&self) -> FeatureFlags {
|
||||
self.feature().flags
|
||||
}
|
||||
|
||||
/// Parse a feature expression of the form:
|
||||
///
|
||||
/// ```
|
||||
|
@ -382,18 +384,18 @@ impl QueryFeatureExpression {
|
|||
input: &mut Parser<'i, 't>,
|
||||
feature_type: FeatureType,
|
||||
) -> Result<(usize, Option<LegacyRange>), ParseError<'i>> {
|
||||
let mut requirements = ParsingRequirements::empty();
|
||||
let mut flags = FeatureFlags::empty();
|
||||
let location = input.current_source_location();
|
||||
let ident = input.expect_ident()?;
|
||||
|
||||
if context.in_ua_or_chrome_sheet() {
|
||||
requirements.insert(ParsingRequirements::CHROME_AND_UA_ONLY);
|
||||
flags.insert(FeatureFlags::CHROME_AND_UA_ONLY);
|
||||
}
|
||||
|
||||
let mut feature_name = &**ident;
|
||||
if starts_with_ignore_ascii_case(feature_name, "-webkit-") {
|
||||
feature_name = &feature_name[8..];
|
||||
requirements.insert(ParsingRequirements::WEBKIT_PREFIX);
|
||||
flags.insert(FeatureFlags::WEBKIT_PREFIX);
|
||||
}
|
||||
|
||||
let range = if starts_with_ignore_ascii_case(feature_name, "min-") {
|
||||
|
@ -417,7 +419,7 @@ impl QueryFeatureExpression {
|
|||
};
|
||||
|
||||
if disabled_by_pref(&feature.name, context) ||
|
||||
!requirements.contains(feature.requirements) ||
|
||||
!flags.contains(feature.flags.parsing_requirements()) ||
|
||||
(range.is_some() && !feature.allows_ranges())
|
||||
{
|
||||
return Err(location.new_custom_error(
|
||||
|
|
|
@ -15,4 +15,5 @@ pub mod feature_expression;
|
|||
pub mod values;
|
||||
|
||||
pub use self::condition::QueryCondition;
|
||||
pub use self::feature::FeatureFlags;
|
||||
pub use self::feature_expression::{QueryFeatureExpression, FeatureType};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue