mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
style: Fix anonymous name handling in presence of stylesheet sharing
We need to compute the anonymous name on the fly while building the CascadeData, otherwise we may see the same layer rule in two places due to stylehseet sharing and make them incorrectly share a name. Differential Revision: https://phabricator.services.mozilla.com/D125175
This commit is contained in:
parent
5fe148d5f1
commit
3e251f50fc
4 changed files with 65 additions and 60 deletions
|
@ -137,12 +137,10 @@ impl DeepCloneWithLock for ImportSheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The layer keyword or function in an import rule.
|
/// The layer keyword or function in an import rule.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ImportLayer {
|
pub struct ImportLayer {
|
||||||
/// Whether the layer is anonymous.
|
/// The layer name, or None for an anonymous layer.
|
||||||
pub is_anonymous: bool,
|
pub name: Option<LayerName>,
|
||||||
/// The layer name.
|
|
||||||
pub name: LayerName,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -151,12 +149,13 @@ impl ToCss for ImportLayer {
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
if self.is_anonymous {
|
match self.name {
|
||||||
dest.write_str("layer")
|
None => dest.write_str("layer"),
|
||||||
} else {
|
Some(ref name) => {
|
||||||
dest.write_str("layer(")?;
|
dest.write_str("layer(")?;
|
||||||
self.name.to_css(dest)?;
|
name.to_css(dest)?;
|
||||||
dest.write_char(')')
|
dest.write_char(')')
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,16 +198,7 @@ impl DeepCloneWithLock for ImportRule {
|
||||||
ImportRule {
|
ImportRule {
|
||||||
url: self.url.clone(),
|
url: self.url.clone(),
|
||||||
stylesheet: self.stylesheet.deep_clone_with_lock(lock, guard, params),
|
stylesheet: self.stylesheet.deep_clone_with_lock(lock, guard, params),
|
||||||
layer: self.layer.as_ref().map(|layer| {
|
layer: self.layer.clone(),
|
||||||
ImportLayer {
|
|
||||||
is_anonymous: layer.is_anonymous,
|
|
||||||
name: if layer.is_anonymous {
|
|
||||||
LayerName::new_anonymous()
|
|
||||||
} else {
|
|
||||||
layer.name.clone()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
source_location: self.source_location.clone(),
|
source_location: self.source_location.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,13 +202,10 @@ impl ToCss for LayerName {
|
||||||
pub enum LayerRuleKind {
|
pub enum LayerRuleKind {
|
||||||
/// A block `@layer <name>? { ... }`
|
/// A block `@layer <name>? { ... }`
|
||||||
Block {
|
Block {
|
||||||
/// The layer name.
|
/// The layer name, or `None` if anonymous.
|
||||||
name: LayerName,
|
name: Option<LayerName>,
|
||||||
/// The nested rules.
|
/// The nested rules.
|
||||||
rules: Arc<Locked<CssRules>>,
|
rules: Arc<Locked<CssRules>>,
|
||||||
/// Whether the layer name is synthesized (and thus shouldn't be
|
|
||||||
/// serialized).
|
|
||||||
is_anonymous: bool,
|
|
||||||
},
|
},
|
||||||
/// A statement `@layer <name>, <name>, <name>;`
|
/// A statement `@layer <name>, <name>, <name>;`
|
||||||
Statement {
|
Statement {
|
||||||
|
@ -239,9 +236,8 @@ impl ToCssWithGuard for LayerRule {
|
||||||
LayerRuleKind::Block {
|
LayerRuleKind::Block {
|
||||||
ref name,
|
ref name,
|
||||||
ref rules,
|
ref rules,
|
||||||
ref is_anonymous,
|
|
||||||
} => {
|
} => {
|
||||||
if !*is_anonymous {
|
if let Some(ref name) = *name {
|
||||||
dest.write_char(' ')?;
|
dest.write_char(' ')?;
|
||||||
name.to_css(&mut CssWriter::new(dest))?;
|
name.to_css(&mut CssWriter::new(dest))?;
|
||||||
}
|
}
|
||||||
|
@ -277,13 +273,8 @@ impl DeepCloneWithLock for LayerRule {
|
||||||
LayerRuleKind::Block {
|
LayerRuleKind::Block {
|
||||||
ref name,
|
ref name,
|
||||||
ref rules,
|
ref rules,
|
||||||
ref is_anonymous,
|
|
||||||
} => LayerRuleKind::Block {
|
} => LayerRuleKind::Block {
|
||||||
name: if *is_anonymous {
|
name: name.clone(),
|
||||||
LayerName::new_anonymous()
|
|
||||||
} else {
|
|
||||||
name.clone()
|
|
||||||
},
|
|
||||||
rules: Arc::new(
|
rules: Arc::new(
|
||||||
lock.wrap(
|
lock.wrap(
|
||||||
rules
|
rules
|
||||||
|
@ -291,7 +282,6 @@ impl DeepCloneWithLock for LayerRule {
|
||||||
.deep_clone_with_lock(lock, guard, params),
|
.deep_clone_with_lock(lock, guard, params),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
is_anonymous: *is_anonymous,
|
|
||||||
},
|
},
|
||||||
LayerRuleKind::Statement { ref names } => LayerRuleKind::Statement {
|
LayerRuleKind::Statement { ref names } => LayerRuleKind::Statement {
|
||||||
names: names.clone(),
|
names: names.clone(),
|
||||||
|
|
|
@ -216,8 +216,7 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
|
||||||
None
|
None
|
||||||
} else if input.try_parse(|input| input.expect_ident_matching("layer")).is_ok() {
|
} else if input.try_parse(|input| input.expect_ident_matching("layer")).is_ok() {
|
||||||
Some(ImportLayer {
|
Some(ImportLayer {
|
||||||
is_anonymous: true,
|
name: None,
|
||||||
name: LayerName::new_anonymous(),
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
input.try_parse(|input| {
|
input.try_parse(|input| {
|
||||||
|
@ -225,8 +224,7 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
|
||||||
input.parse_nested_block(|input| {
|
input.parse_nested_block(|input| {
|
||||||
LayerName::parse(&self.context, input)
|
LayerName::parse(&self.context, input)
|
||||||
}).map(|name| ImportLayer {
|
}).map(|name| ImportLayer {
|
||||||
is_anonymous: false,
|
name: Some(name),
|
||||||
name,
|
|
||||||
})
|
})
|
||||||
}).ok()
|
}).ok()
|
||||||
};
|
};
|
||||||
|
@ -603,9 +601,8 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
|
||||||
))))
|
))))
|
||||||
},
|
},
|
||||||
AtRulePrelude::Layer(names) => {
|
AtRulePrelude::Layer(names) => {
|
||||||
let (name, is_anonymous) = match names.len() {
|
let name = match names.len() {
|
||||||
0 => (LayerName::new_anonymous(), true),
|
0 | 1 => names.into_iter().next(),
|
||||||
1 => (names.into_iter().next().unwrap(), false),
|
|
||||||
_ => return Err(input.new_error(BasicParseErrorKind::AtRuleBodyInvalid)),
|
_ => return Err(input.new_error(BasicParseErrorKind::AtRuleBodyInvalid)),
|
||||||
};
|
};
|
||||||
Ok(CssRule::Layer(Arc::new(self.shared_lock.wrap(
|
Ok(CssRule::Layer(Arc::new(self.shared_lock.wrap(
|
||||||
|
@ -613,7 +610,6 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
|
||||||
kind: LayerRuleKind::Block {
|
kind: LayerRuleKind::Block {
|
||||||
name,
|
name,
|
||||||
rules: self.parse_nested_rules(input, CssRuleType::Layer),
|
rules: self.parse_nested_rules(input, CssRuleType::Layer),
|
||||||
is_anonymous,
|
|
||||||
},
|
},
|
||||||
source_location: start.source_location(),
|
source_location: start.source_location(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -2150,7 +2150,7 @@ impl CascadeData {
|
||||||
stylesheet: &S,
|
stylesheet: &S,
|
||||||
guard: &SharedRwLockReadGuard,
|
guard: &SharedRwLockReadGuard,
|
||||||
rebuild_kind: SheetRebuildKind,
|
rebuild_kind: SheetRebuildKind,
|
||||||
current_layer: &mut LayerName,
|
mut current_layer: &mut LayerName,
|
||||||
current_layer_order: LayerOrder,
|
current_layer_order: LayerOrder,
|
||||||
mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>,
|
mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>,
|
||||||
) -> Result<(), FailedAllocationError>
|
) -> Result<(), FailedAllocationError>
|
||||||
|
@ -2337,7 +2337,6 @@ impl CascadeData {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn maybe_register_layer(data: &mut CascadeData, layer: &LayerName) -> LayerOrder {
|
fn maybe_register_layer(data: &mut CascadeData, layer: &LayerName) -> LayerOrder {
|
||||||
// TODO: Measure what's more common / expensive, if
|
// TODO: Measure what's more common / expensive, if
|
||||||
// layer.clone() or the double hash lookup in the insert
|
// layer.clone() or the double hash lookup in the insert
|
||||||
|
@ -2366,6 +2365,31 @@ impl CascadeData {
|
||||||
order
|
order
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn maybe_register_layers(
|
||||||
|
data: &mut CascadeData,
|
||||||
|
name: Option<&LayerName>,
|
||||||
|
current_layer: &mut LayerName,
|
||||||
|
pushed_layers: &mut usize,
|
||||||
|
) -> LayerOrder {
|
||||||
|
let anon_name;
|
||||||
|
let name = match name {
|
||||||
|
Some(name) => name,
|
||||||
|
None => {
|
||||||
|
anon_name = LayerName::new_anonymous();
|
||||||
|
&anon_name
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut order = LayerOrder::top_level();
|
||||||
|
for name in name.layer_names() {
|
||||||
|
current_layer.0.push(name.clone());
|
||||||
|
order = maybe_register_layer(data, ¤t_layer);
|
||||||
|
*pushed_layers += 1;
|
||||||
|
}
|
||||||
|
debug_assert_ne!(order, LayerOrder::top_level());
|
||||||
|
order
|
||||||
|
}
|
||||||
|
|
||||||
let mut layer_names_to_pop = 0;
|
let mut layer_names_to_pop = 0;
|
||||||
let mut children_layer_order = current_layer_order;
|
let mut children_layer_order = current_layer_order;
|
||||||
match *rule {
|
match *rule {
|
||||||
|
@ -2376,11 +2400,12 @@ impl CascadeData {
|
||||||
.saw_effective(import_rule);
|
.saw_effective(import_rule);
|
||||||
}
|
}
|
||||||
if let Some(ref layer) = import_rule.layer {
|
if let Some(ref layer) = import_rule.layer {
|
||||||
for name in layer.name.layer_names() {
|
children_layer_order = maybe_register_layers(
|
||||||
current_layer.0.push(name.clone());
|
self,
|
||||||
children_layer_order = maybe_register_layer(self, ¤t_layer);
|
layer.name.as_ref(),
|
||||||
layer_names_to_pop += 1;
|
&mut current_layer,
|
||||||
}
|
&mut layer_names_to_pop,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
@ -2396,20 +2421,24 @@ impl CascadeData {
|
||||||
let layer_rule = lock.read_with(guard);
|
let layer_rule = lock.read_with(guard);
|
||||||
match layer_rule.kind {
|
match layer_rule.kind {
|
||||||
LayerRuleKind::Block { ref name, .. } => {
|
LayerRuleKind::Block { ref name, .. } => {
|
||||||
for name in name.layer_names() {
|
children_layer_order = maybe_register_layers(
|
||||||
current_layer.0.push(name.clone());
|
self,
|
||||||
children_layer_order = maybe_register_layer(self, ¤t_layer);
|
name.as_ref(),
|
||||||
layer_names_to_pop += 1;
|
&mut current_layer,
|
||||||
}
|
&mut layer_names_to_pop,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
LayerRuleKind::Statement { ref names } => {
|
LayerRuleKind::Statement { ref names } => {
|
||||||
for name in &**names {
|
for name in &**names {
|
||||||
let mut pushed = 0;
|
let mut pushed = 0;
|
||||||
for name in name.layer_names() {
|
// There are no children, so we can ignore the
|
||||||
current_layer.0.push(name.clone());
|
// return value.
|
||||||
maybe_register_layer(self, ¤t_layer);
|
maybe_register_layers(
|
||||||
pushed += 1;
|
self,
|
||||||
}
|
Some(name),
|
||||||
|
&mut current_layer,
|
||||||
|
&mut pushed,
|
||||||
|
);
|
||||||
for _ in 0..pushed {
|
for _ in 0..pushed {
|
||||||
current_layer.0.pop();
|
current_layer.0.pop();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue