mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Auto merge of #15856 - servo:dedup, r=Manishearth
Deduplicate declarations on insertion, not at the end of parsing a block <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #15558 (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15856) <!-- Reviewable:end -->
This commit is contained in:
commit
4fc7034370
18 changed files with 531 additions and 574 deletions
|
@ -62,15 +62,12 @@ impl CSSStyleOwner {
|
|||
let result = f(&mut pdb, &mut changed);
|
||||
result
|
||||
} else {
|
||||
let mut pdb = PropertyDeclarationBlock {
|
||||
important_count: 0,
|
||||
declarations: vec![],
|
||||
};
|
||||
let mut pdb = PropertyDeclarationBlock::new();
|
||||
let result = f(&mut pdb, &mut changed);
|
||||
|
||||
// Here `changed` is somewhat silly, because we know the
|
||||
// exact conditions under it changes.
|
||||
changed = !pdb.declarations.is_empty();
|
||||
changed = !pdb.declarations().is_empty();
|
||||
if changed {
|
||||
attr = Some(Arc::new(RwLock::new(pdb)));
|
||||
}
|
||||
|
@ -116,10 +113,7 @@ impl CSSStyleOwner {
|
|||
match *el.style_attribute().borrow() {
|
||||
Some(ref pdb) => f(&pdb.read()),
|
||||
None => {
|
||||
let pdb = PropertyDeclarationBlock {
|
||||
important_count: 0,
|
||||
declarations: vec![],
|
||||
};
|
||||
let pdb = PropertyDeclarationBlock::new();
|
||||
f(&pdb)
|
||||
}
|
||||
}
|
||||
|
@ -250,14 +244,14 @@ impl CSSStyleDeclaration {
|
|||
|
||||
// Step 6
|
||||
let window = self.owner.window();
|
||||
let declarations =
|
||||
let result =
|
||||
parse_one_declaration(id, &value, &self.owner.base_url(),
|
||||
window.css_error_reporter(),
|
||||
ParserContextExtraData::default());
|
||||
|
||||
// Step 7
|
||||
let declarations = match declarations {
|
||||
Ok(declarations) => declarations,
|
||||
let parsed = match result {
|
||||
Ok(parsed) => parsed,
|
||||
Err(_) => {
|
||||
*changed = false;
|
||||
return Ok(());
|
||||
|
@ -267,9 +261,9 @@ impl CSSStyleDeclaration {
|
|||
// Step 8
|
||||
// Step 9
|
||||
*changed = false;
|
||||
for declaration in declarations {
|
||||
*changed |= pdb.set_parsed_declaration(declaration.0, importance);
|
||||
}
|
||||
parsed.expand(|declaration| {
|
||||
*changed |= pdb.set_parsed_declaration(declaration, importance);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
})
|
||||
|
@ -280,7 +274,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
|||
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-length
|
||||
fn Length(&self) -> u32 {
|
||||
self.owner.with_block(|pdb| {
|
||||
pdb.declarations.len() as u32
|
||||
pdb.declarations().len() as u32
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -405,7 +399,7 @@ impl CSSStyleDeclarationMethods for CSSStyleDeclaration {
|
|||
// https://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
|
||||
fn IndexedGetter(&self, index: u32) -> Option<DOMString> {
|
||||
self.owner.with_block(|pdb| {
|
||||
pdb.declarations.get(index as usize).map(|entry| {
|
||||
pdb.declarations().get(index as usize).map(|entry| {
|
||||
let (ref declaration, importance) = *entry;
|
||||
let mut css = declaration.to_css_string();
|
||||
if importance.important() {
|
||||
|
|
|
@ -385,10 +385,9 @@ impl LayoutElementHelpers for LayoutJS<Element> {
|
|||
#[inline]
|
||||
fn from_declaration(declaration: PropertyDeclaration) -> ApplicableDeclarationBlock {
|
||||
ApplicableDeclarationBlock::from_declarations(
|
||||
Arc::new(RwLock::new(PropertyDeclarationBlock {
|
||||
declarations: vec![(declaration, Importance::Normal)],
|
||||
important_count: 0,
|
||||
})),
|
||||
Arc::new(RwLock::new(PropertyDeclarationBlock::with_one(
|
||||
declaration, Importance::Normal
|
||||
))),
|
||||
CascadeLevel::PresHints)
|
||||
}
|
||||
|
||||
|
|
|
@ -418,11 +418,11 @@ fn compute_style_for_animation_step(context: &SharedStyleContext,
|
|||
let guard = declarations.read();
|
||||
|
||||
// No !important in keyframes.
|
||||
debug_assert!(guard.declarations.iter()
|
||||
debug_assert!(guard.declarations().iter()
|
||||
.all(|&(_, importance)| importance == Importance::Normal));
|
||||
|
||||
let iter = || {
|
||||
guard.declarations.iter().rev().map(|&(ref decl, _importance)| decl)
|
||||
guard.declarations().iter().rev().map(|&(ref decl, _importance)| decl)
|
||||
};
|
||||
|
||||
let computed =
|
||||
|
|
|
@ -21,7 +21,7 @@ use values::specified::url::SpecifiedUrl;
|
|||
|
||||
/// A source for a font-face rule.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
|
||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
||||
pub enum Source {
|
||||
/// A `url()` source.
|
||||
Url(UrlSource),
|
||||
|
@ -54,7 +54,7 @@ impl OneOrMoreCommaSeparated for Source {}
|
|||
///
|
||||
/// https://drafts.csswg.org/css-fonts/#src-desc
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
|
||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
||||
pub struct UrlSource {
|
||||
/// The specified url.
|
||||
pub url: SpecifiedUrl,
|
||||
|
@ -184,7 +184,6 @@ macro_rules! font_face_descriptors {
|
|||
///
|
||||
/// https://drafts.csswg.org/css-fonts/#font-face-rule
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct FontFaceRule {
|
||||
$(
|
||||
#[$m_doc]
|
||||
|
|
|
@ -11,9 +11,8 @@ use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule};
|
|||
use parking_lot::RwLock;
|
||||
use parser::{ParserContext, ParserContextExtraData, log_css_error};
|
||||
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, PropertyId};
|
||||
use properties::{PropertyDeclarationId, LonghandId, DeclaredValue};
|
||||
use properties::{PropertyDeclarationId, LonghandId, DeclaredValue, ParsedDeclaration};
|
||||
use properties::LonghandIdSet;
|
||||
use properties::PropertyDeclarationParseResult;
|
||||
use properties::animated_properties::TransitionProperty;
|
||||
use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction;
|
||||
use std::fmt;
|
||||
|
@ -71,8 +70,7 @@ impl KeyframePercentage {
|
|||
|
||||
/// A keyframes selector is a list of percentages or from/to symbols, which are
|
||||
/// converted at parse time to percentages.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct KeyframeSelector(Vec<KeyframePercentage>);
|
||||
impl KeyframeSelector {
|
||||
/// Return the list of percentages this selector contains.
|
||||
|
@ -94,8 +92,7 @@ impl KeyframeSelector {
|
|||
}
|
||||
|
||||
/// A keyframe.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Debug)]
|
||||
pub struct Keyframe {
|
||||
/// The selector this keyframe was specified from.
|
||||
pub selector: KeyframeSelector,
|
||||
|
@ -104,7 +101,6 @@ pub struct Keyframe {
|
|||
///
|
||||
/// Note that `!important` rules in keyframes don't apply, but we keep this
|
||||
/// `Arc` just for convenience.
|
||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
|
||||
pub block: Arc<RwLock<PropertyDeclarationBlock>>,
|
||||
}
|
||||
|
||||
|
@ -149,7 +145,7 @@ impl Keyframe {
|
|||
/// declarations to apply.
|
||||
///
|
||||
/// TODO: Find a better name for this?
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum KeyframesStepValue {
|
||||
/// A step formed by a declaration block specified by the CSS.
|
||||
|
@ -164,7 +160,7 @@ pub enum KeyframesStepValue {
|
|||
}
|
||||
|
||||
/// A single step from a keyframe animation.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct KeyframesStep {
|
||||
/// The percentage of the animation duration when this step starts.
|
||||
|
@ -185,7 +181,7 @@ impl KeyframesStep {
|
|||
value: KeyframesStepValue) -> Self {
|
||||
let declared_timing_function = match value {
|
||||
KeyframesStepValue::Declarations { ref block } => {
|
||||
block.read().declarations.iter().any(|&(ref prop_decl, _)| {
|
||||
block.read().declarations().iter().any(|&(ref prop_decl, _)| {
|
||||
match *prop_decl {
|
||||
PropertyDeclaration::AnimationTimingFunction(..) => true,
|
||||
_ => false,
|
||||
|
@ -236,7 +232,7 @@ impl KeyframesStep {
|
|||
/// of keyframes, in order.
|
||||
///
|
||||
/// It only takes into account animable properties.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct KeyframesAnimation {
|
||||
/// The difference steps of the animation.
|
||||
|
@ -253,7 +249,7 @@ fn get_animated_properties(keyframes: &[Arc<RwLock<Keyframe>>]) -> Vec<Transitio
|
|||
// it here.
|
||||
for keyframe in keyframes {
|
||||
let keyframe = keyframe.read();
|
||||
for &(ref declaration, importance) in keyframe.block.read().declarations.iter() {
|
||||
for &(ref declaration, importance) in keyframe.block.read().declarations().iter() {
|
||||
assert!(!importance.important());
|
||||
|
||||
if let Some(property) = TransitionProperty::from_declaration(declaration) {
|
||||
|
@ -364,12 +360,12 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
|
|||
-> Result<Self::QualifiedRule, ()> {
|
||||
let parser = KeyframeDeclarationParser {
|
||||
context: self.context,
|
||||
declarations: vec![],
|
||||
};
|
||||
let mut iter = DeclarationListParser::new(input, parser);
|
||||
let mut block = PropertyDeclarationBlock::new();
|
||||
while let Some(declaration) = iter.next() {
|
||||
match declaration {
|
||||
Ok(_) => (),
|
||||
Ok(parsed) => parsed.expand(|d| block.push(d, Importance::Normal)),
|
||||
Err(range) => {
|
||||
let pos = range.start;
|
||||
let message = format!("Unsupported keyframe property declaration: '{}'",
|
||||
|
@ -381,45 +377,36 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
|
|||
}
|
||||
Ok(Arc::new(RwLock::new(Keyframe {
|
||||
selector: prelude,
|
||||
block: Arc::new(RwLock::new(PropertyDeclarationBlock {
|
||||
declarations: iter.parser.declarations,
|
||||
important_count: 0,
|
||||
})),
|
||||
block: Arc::new(RwLock::new(block)),
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
struct KeyframeDeclarationParser<'a, 'b: 'a> {
|
||||
context: &'a ParserContext<'b>,
|
||||
declarations: Vec<(PropertyDeclaration, Importance)>
|
||||
}
|
||||
|
||||
/// Default methods reject all at rules.
|
||||
impl<'a, 'b> AtRuleParser for KeyframeDeclarationParser<'a, 'b> {
|
||||
type Prelude = ();
|
||||
type AtRule = ();
|
||||
type AtRule = ParsedDeclaration;
|
||||
}
|
||||
|
||||
impl<'a, 'b> DeclarationParser for KeyframeDeclarationParser<'a, 'b> {
|
||||
/// We parse rules directly into the declarations object
|
||||
type Declaration = ();
|
||||
type Declaration = ParsedDeclaration;
|
||||
|
||||
fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> {
|
||||
fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<ParsedDeclaration, ()> {
|
||||
let id = try!(PropertyId::parse(name.into()));
|
||||
let old_len = self.declarations.len();
|
||||
match PropertyDeclaration::parse(id, self.context, input, &mut self.declarations, true) {
|
||||
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {}
|
||||
_ => {
|
||||
self.declarations.truncate(old_len);
|
||||
return Err(());
|
||||
match ParsedDeclaration::parse(id, self.context, input, true) {
|
||||
Ok(parsed) => {
|
||||
// In case there is still unparsed text in the declaration, we should roll back.
|
||||
if !input.is_exhausted() {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(parsed)
|
||||
}
|
||||
}
|
||||
}
|
||||
// In case there is still unparsed text in the declaration, we should roll back.
|
||||
if !input.is_exhausted() {
|
||||
self.declarations.truncate(old_len);
|
||||
Err(())
|
||||
} else {
|
||||
Ok(())
|
||||
Err(_) => Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,28 +40,54 @@ impl Importance {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for Importance {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Importance::Normal
|
||||
}
|
||||
}
|
||||
|
||||
/// Overridden declarations are skipped.
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Clone)]
|
||||
pub struct PropertyDeclarationBlock {
|
||||
/// The group of declarations, along with their importance.
|
||||
///
|
||||
/// Only deduplicated declarations appear here.
|
||||
#[cfg_attr(feature = "servo", ignore_heap_size_of = "#7038")]
|
||||
pub declarations: Vec<(PropertyDeclaration, Importance)>,
|
||||
declarations: Vec<(PropertyDeclaration, Importance)>,
|
||||
|
||||
/// The number of entries in `self.declaration` with `Importance::Important`
|
||||
pub important_count: u32,
|
||||
important_count: usize,
|
||||
|
||||
longhands: LonghandIdSet,
|
||||
}
|
||||
|
||||
impl fmt::Debug for PropertyDeclarationBlock {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.declarations.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl PropertyDeclarationBlock {
|
||||
/// Create an empty block
|
||||
pub fn new() -> Self {
|
||||
PropertyDeclarationBlock {
|
||||
declarations: Vec::new(),
|
||||
important_count: 0,
|
||||
longhands: LonghandIdSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a block with a single declaration
|
||||
pub fn with_one(declaration: PropertyDeclaration, importance: Importance) -> Self {
|
||||
let mut longhands = LonghandIdSet::new();
|
||||
if let PropertyDeclarationId::Longhand(id) = declaration.id() {
|
||||
longhands.insert(id);
|
||||
}
|
||||
PropertyDeclarationBlock {
|
||||
declarations: vec![(declaration, importance)],
|
||||
important_count: if importance.important() { 1 } else { 0 },
|
||||
longhands: longhands,
|
||||
}
|
||||
}
|
||||
|
||||
/// The declarations in this block
|
||||
pub fn declarations(&self) -> &[(PropertyDeclaration, Importance)] {
|
||||
&self.declarations
|
||||
}
|
||||
|
||||
/// Returns wheather this block contains any declaration with `!important`.
|
||||
///
|
||||
/// This is based on the `important_count` counter,
|
||||
|
@ -77,7 +103,7 @@ impl PropertyDeclarationBlock {
|
|||
/// which should be maintained whenever `declarations` is changed.
|
||||
// FIXME: make fields private and maintain it here in methods?
|
||||
pub fn any_normal(&self) -> bool {
|
||||
self.declarations.len() > self.important_count as usize
|
||||
self.declarations.len() > self.important_count
|
||||
}
|
||||
|
||||
/// Get a declaration for a given property.
|
||||
|
@ -171,29 +197,54 @@ impl PropertyDeclarationBlock {
|
|||
}
|
||||
|
||||
/// Adds or overrides the declaration for a given property in this block,
|
||||
/// without taking into account any kind of priority. Returns whether the
|
||||
/// declaration block is actually changed.
|
||||
/// except if an existing declaration for the same property is more important.
|
||||
pub fn push(&mut self, declaration: PropertyDeclaration, importance: Importance) {
|
||||
self.push_common(declaration, importance, false);
|
||||
}
|
||||
|
||||
/// Adds or overrides the declaration for a given property in this block,
|
||||
/// Returns whether the declaration block is actually changed.
|
||||
pub fn set_parsed_declaration(&mut self,
|
||||
declaration: PropertyDeclaration,
|
||||
importance: Importance) -> bool {
|
||||
for slot in &mut *self.declarations {
|
||||
if slot.0.id() == declaration.id() {
|
||||
match (slot.1, importance) {
|
||||
(Importance::Normal, Importance::Important) => {
|
||||
self.important_count += 1;
|
||||
}
|
||||
(Importance::Important, Importance::Normal) => {
|
||||
self.important_count -= 1;
|
||||
}
|
||||
_ => if slot.0 == declaration {
|
||||
return false;
|
||||
self.push_common(declaration, importance, true)
|
||||
}
|
||||
|
||||
fn push_common(&mut self, declaration: PropertyDeclaration, importance: Importance,
|
||||
overwrite_more_important: bool) -> bool {
|
||||
let definitely_new = if let PropertyDeclarationId::Longhand(id) = declaration.id() {
|
||||
!self.longhands.contains(id)
|
||||
} else {
|
||||
false // For custom properties, always scan
|
||||
};
|
||||
|
||||
if !definitely_new {
|
||||
for slot in &mut *self.declarations {
|
||||
if slot.0.id() == declaration.id() {
|
||||
match (slot.1, importance) {
|
||||
(Importance::Normal, Importance::Important) => {
|
||||
self.important_count += 1;
|
||||
}
|
||||
(Importance::Important, Importance::Normal) => {
|
||||
if overwrite_more_important {
|
||||
self.important_count -= 1;
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
_ => if slot.0 == declaration {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*slot = (declaration, importance);
|
||||
return true
|
||||
}
|
||||
*slot = (declaration, importance);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if let PropertyDeclarationId::Longhand(id) = declaration.id() {
|
||||
self.longhands.insert(id);
|
||||
}
|
||||
self.declarations.push((declaration, importance));
|
||||
if importance.important() {
|
||||
self.important_count += 1;
|
||||
|
@ -230,6 +281,11 @@ impl PropertyDeclarationBlock {
|
|||
///
|
||||
/// Returns whether any declaration was actually removed.
|
||||
pub fn remove_property(&mut self, property: &PropertyId) -> bool {
|
||||
if let PropertyId::Longhand(id) = *property {
|
||||
if !self.longhands.contains(id) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
let important_count = &mut self.important_count;
|
||||
let mut removed_at_least_one = false;
|
||||
self.declarations.retain(|&(ref declaration, importance)| {
|
||||
|
@ -243,6 +299,10 @@ impl PropertyDeclarationBlock {
|
|||
!remove
|
||||
});
|
||||
|
||||
if let PropertyId::Longhand(id) = *property {
|
||||
debug_assert!(removed_at_least_one);
|
||||
self.longhands.remove(id);
|
||||
}
|
||||
removed_at_least_one
|
||||
}
|
||||
|
||||
|
@ -278,39 +338,6 @@ impl PropertyDeclarationBlock {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Only keep the "winning" declaration for any given property, by importance then source order.
|
||||
pub fn deduplicate(&mut self) {
|
||||
let mut deduplicated = Vec::with_capacity(self.declarations.len());
|
||||
let mut seen_normal = PropertyDeclarationIdSet::new();
|
||||
let mut seen_important = PropertyDeclarationIdSet::new();
|
||||
|
||||
for (declaration, importance) in self.declarations.drain(..).rev() {
|
||||
if importance.important() {
|
||||
let id = declaration.id();
|
||||
if seen_important.contains(id) {
|
||||
self.important_count -= 1;
|
||||
continue
|
||||
}
|
||||
if seen_normal.contains(id) {
|
||||
let previous_len = deduplicated.len();
|
||||
deduplicated.retain(|&(ref d, _)| PropertyDeclaration::id(d) != id);
|
||||
debug_assert_eq!(deduplicated.len(), previous_len - 1);
|
||||
}
|
||||
seen_important.insert(id);
|
||||
} else {
|
||||
let id = declaration.id();
|
||||
if seen_normal.contains(id) ||
|
||||
seen_important.contains(id) {
|
||||
continue
|
||||
}
|
||||
seen_normal.insert(id)
|
||||
}
|
||||
deduplicated.push((declaration, importance))
|
||||
}
|
||||
deduplicated.reverse();
|
||||
self.declarations = deduplicated;
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for PropertyDeclarationBlock {
|
||||
|
@ -556,65 +583,46 @@ pub fn parse_one_declaration(id: PropertyId,
|
|||
base_url: &ServoUrl,
|
||||
error_reporter: StdBox<ParseErrorReporter + Send>,
|
||||
extra_data: ParserContextExtraData)
|
||||
-> Result<Vec<(PropertyDeclaration, Importance)>, ()> {
|
||||
-> Result<ParsedDeclaration, ()> {
|
||||
let context = ParserContext::new_with_extra_data(Origin::Author, base_url, error_reporter, extra_data);
|
||||
Parser::new(input).parse_entirely(|parser| {
|
||||
let mut results = vec![];
|
||||
match PropertyDeclaration::parse(id, &context, parser, &mut results, false) {
|
||||
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => Ok(results),
|
||||
_ => Err(())
|
||||
}
|
||||
ParsedDeclaration::parse(id, &context, parser, false)
|
||||
.map_err(|_| ())
|
||||
})
|
||||
}
|
||||
|
||||
/// A struct to parse property declarations.
|
||||
struct PropertyDeclarationParser<'a, 'b: 'a> {
|
||||
context: &'a ParserContext<'b>,
|
||||
declarations: Vec<(PropertyDeclaration, Importance)>
|
||||
}
|
||||
|
||||
|
||||
/// Default methods reject all at rules.
|
||||
impl<'a, 'b> AtRuleParser for PropertyDeclarationParser<'a, 'b> {
|
||||
type Prelude = ();
|
||||
type AtRule = (u32, Importance);
|
||||
type AtRule = (ParsedDeclaration, Importance);
|
||||
}
|
||||
|
||||
|
||||
impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
|
||||
/// Declarations are pushed to the internal vector. This will only
|
||||
/// let you know if the decl was !important and how many longhands
|
||||
/// it expanded to
|
||||
type Declaration = (u32, Importance);
|
||||
type Declaration = (ParsedDeclaration, Importance);
|
||||
|
||||
fn parse_value(&mut self, name: &str, input: &mut Parser)
|
||||
-> Result<(u32, Importance), ()> {
|
||||
-> Result<(ParsedDeclaration, Importance), ()> {
|
||||
let id = try!(PropertyId::parse(name.into()));
|
||||
let old_len = self.declarations.len();
|
||||
let parse_result = input.parse_until_before(Delimiter::Bang, |input| {
|
||||
match PropertyDeclaration::parse(id, self.context, input, &mut self.declarations, false) {
|
||||
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => Ok(()),
|
||||
_ => Err(())
|
||||
}
|
||||
});
|
||||
if let Err(_) = parse_result {
|
||||
// rollback
|
||||
self.declarations.truncate(old_len);
|
||||
return Err(())
|
||||
}
|
||||
let parsed = input.parse_until_before(Delimiter::Bang, |input| {
|
||||
ParsedDeclaration::parse(id, self.context, input, false)
|
||||
.map_err(|_| ())
|
||||
})?;
|
||||
let importance = match input.try(parse_important) {
|
||||
Ok(()) => Importance::Important,
|
||||
Err(()) => Importance::Normal,
|
||||
};
|
||||
// In case there is still unparsed text in the declaration, we should roll back.
|
||||
if !input.is_exhausted() {
|
||||
self.declarations.truncate(old_len);
|
||||
return Err(())
|
||||
}
|
||||
for decl in &mut self.declarations[old_len..] {
|
||||
decl.1 = importance
|
||||
}
|
||||
Ok(((self.declarations.len() - old_len) as u32, importance))
|
||||
Ok((parsed, importance))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -624,19 +632,14 @@ impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
|
|||
pub fn parse_property_declaration_list(context: &ParserContext,
|
||||
input: &mut Parser)
|
||||
-> PropertyDeclarationBlock {
|
||||
let mut important_count = 0;
|
||||
let mut block = PropertyDeclarationBlock::new();
|
||||
let parser = PropertyDeclarationParser {
|
||||
context: context,
|
||||
declarations: vec![],
|
||||
};
|
||||
let mut iter = DeclarationListParser::new(input, parser);
|
||||
while let Some(declaration) = iter.next() {
|
||||
match declaration {
|
||||
Ok((count, importance)) => {
|
||||
if importance.important() {
|
||||
important_count += count;
|
||||
}
|
||||
}
|
||||
Ok((parsed, importance)) => parsed.expand(|d| block.push(d, importance)),
|
||||
Err(range) => {
|
||||
let pos = range.start;
|
||||
let message = format!("Unsupported property declaration: '{}'",
|
||||
|
@ -645,10 +648,5 @@ pub fn parse_property_declaration_list(context: &ParserContext,
|
|||
}
|
||||
}
|
||||
}
|
||||
let mut block = PropertyDeclarationBlock {
|
||||
declarations: iter.parser.declarations,
|
||||
important_count: important_count,
|
||||
};
|
||||
block.deduplicate();
|
||||
block
|
||||
}
|
||||
|
|
|
@ -168,23 +168,19 @@ impl ComputedValues {
|
|||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
PropertyDeclarationId::Longhand(LonghandId::${prop.camel_case}) => {
|
||||
PropertyDeclarationBlock {
|
||||
declarations: vec![
|
||||
(PropertyDeclaration::${prop.camel_case}(DeclaredValue::Value(
|
||||
% if prop.boxed:
|
||||
Box::new(
|
||||
% endif
|
||||
longhands::${prop.ident}::SpecifiedValue::from_computed_value(
|
||||
&self.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}())
|
||||
% if prop.boxed:
|
||||
)
|
||||
% endif
|
||||
|
||||
)),
|
||||
Importance::Normal)
|
||||
],
|
||||
important_count: 0
|
||||
}
|
||||
PropertyDeclarationBlock::with_one(
|
||||
PropertyDeclaration::${prop.camel_case}(DeclaredValue::Value(
|
||||
% if prop.boxed:
|
||||
Box::new(
|
||||
% endif
|
||||
longhands::${prop.ident}::SpecifiedValue::from_computed_value(
|
||||
&self.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}())
|
||||
% if prop.boxed:
|
||||
)
|
||||
% endif
|
||||
)),
|
||||
Importance::Normal
|
||||
)
|
||||
},
|
||||
% endif
|
||||
% endfor
|
||||
|
|
|
@ -339,7 +339,7 @@
|
|||
input.reset(start);
|
||||
let (first_token_type, css) = try!(
|
||||
::custom_properties::parse_non_custom_with_var(input));
|
||||
return Ok(DeclaredValue::WithVariables(Box::new(UnparsedValue {
|
||||
return Ok(DeclaredValue::WithVariables(Arc::new(UnparsedValue {
|
||||
css: css.into_owned(),
|
||||
first_token_type: first_token_type,
|
||||
base_url: context.base_url.clone(),
|
||||
|
@ -483,10 +483,10 @@
|
|||
#[allow(unused_imports)]
|
||||
use cssparser::Parser;
|
||||
use parser::ParserContext;
|
||||
use properties::{DeclaredValue, PropertyDeclaration};
|
||||
use properties::{DeclaredValue, PropertyDeclaration, ParsedDeclaration};
|
||||
use properties::{ShorthandId, UnparsedValue, longhands};
|
||||
use properties::declaration_block::Importance;
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use style_traits::ToCss;
|
||||
|
||||
pub struct Longhands {
|
||||
|
@ -551,10 +551,7 @@
|
|||
|
||||
/// Parse the given shorthand and fill the result into the
|
||||
/// `declarations` vector.
|
||||
pub fn parse(context: &ParserContext,
|
||||
input: &mut Parser,
|
||||
declarations: &mut Vec<(PropertyDeclaration, Importance)>)
|
||||
-> Result<(), ()> {
|
||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<ParsedDeclaration, ()> {
|
||||
input.look_for_var_functions();
|
||||
let start = input.position();
|
||||
let value = input.parse_entirely(|input| parse_value(context, input));
|
||||
|
@ -563,31 +560,17 @@
|
|||
}
|
||||
let var = input.seen_var_functions();
|
||||
if let Ok(value) = value {
|
||||
% for sub_property in shorthand.sub_properties:
|
||||
declarations.push((PropertyDeclaration::${sub_property.camel_case}(
|
||||
% if sub_property.boxed:
|
||||
DeclaredValue::Value(Box::new(value.${sub_property.ident}))
|
||||
% else:
|
||||
DeclaredValue::Value(value.${sub_property.ident})
|
||||
% endif
|
||||
), Importance::Normal));
|
||||
% endfor
|
||||
Ok(())
|
||||
Ok(ParsedDeclaration::${shorthand.camel_case}(value))
|
||||
} else if var {
|
||||
input.reset(start);
|
||||
let (first_token_type, css) = try!(
|
||||
::custom_properties::parse_non_custom_with_var(input));
|
||||
% for sub_property in shorthand.sub_properties:
|
||||
declarations.push((PropertyDeclaration::${sub_property.camel_case}(
|
||||
DeclaredValue::WithVariables(Box::new(UnparsedValue {
|
||||
css: css.clone().into_owned(),
|
||||
first_token_type: first_token_type,
|
||||
base_url: context.base_url.clone(),
|
||||
from_shorthand: Some(ShorthandId::${shorthand.camel_case}),
|
||||
}))
|
||||
), Importance::Normal));
|
||||
% endfor
|
||||
Ok(())
|
||||
Ok(ParsedDeclaration::${shorthand.camel_case}WithVariables(Arc::new(UnparsedValue {
|
||||
css: css.into_owned(),
|
||||
first_token_type: first_token_type,
|
||||
base_url: context.base_url.clone(),
|
||||
from_shorthand: Some(ShorthandId::${shorthand.camel_case}),
|
||||
})))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
|
|
|
@ -177,6 +177,7 @@ pub mod animated_properties {
|
|||
}
|
||||
|
||||
/// A set of longhand properties
|
||||
#[derive(Clone)]
|
||||
pub struct LonghandIdSet {
|
||||
storage: [u32; (${len(data.longhands)} - 1 + 32) / 32]
|
||||
}
|
||||
|
@ -202,6 +203,13 @@ impl LonghandIdSet {
|
|||
self.storage[bit / 32] |= 1 << (bit % 32);
|
||||
}
|
||||
|
||||
/// Remove the given property from the set
|
||||
#[inline]
|
||||
pub fn remove(&mut self, id: LonghandId) {
|
||||
let bit = id as usize;
|
||||
self.storage[bit / 32] &= !(1 << (bit % 32));
|
||||
}
|
||||
|
||||
/// Set the corresponding bit of TransitionProperty.
|
||||
/// This function will panic if TransitionProperty::All is given.
|
||||
pub fn set_transition_property_bit(&mut self, property: &TransitionProperty) {
|
||||
|
@ -563,19 +571,17 @@ impl ShorthandId {
|
|||
/// Servo's representation of a declared value for a given `T`, which is the
|
||||
/// declared value for that property.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum DeclaredValue<T> {
|
||||
/// A known specified value from the stylesheet.
|
||||
Value(T),
|
||||
/// An unparsed value that contains `var()` functions.
|
||||
WithVariables(Box<UnparsedValue>),
|
||||
WithVariables(Arc<UnparsedValue>),
|
||||
/// An CSS-wide keyword.
|
||||
CSSWideKeyword(CSSWideKeyword),
|
||||
}
|
||||
|
||||
/// An unparsed property value that contains `var()` functions.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub struct UnparsedValue {
|
||||
/// The css serialization for this value.
|
||||
css: String,
|
||||
|
@ -797,9 +803,158 @@ impl PropertyId {
|
|||
}
|
||||
}
|
||||
|
||||
/// Includes shorthands before expansion
|
||||
pub enum ParsedDeclaration {
|
||||
% for shorthand in data.shorthands:
|
||||
/// ${shorthand.name}
|
||||
${shorthand.camel_case}(shorthands::${shorthand.ident}::Longhands),
|
||||
|
||||
/// ${shorthand.name} with a CSS-wide keyword
|
||||
${shorthand.camel_case}CSSWideKeyword(CSSWideKeyword),
|
||||
|
||||
/// ${shorthand.name} with var() functions
|
||||
${shorthand.camel_case}WithVariables(Arc<UnparsedValue>),
|
||||
% endfor
|
||||
|
||||
/// Not a shorthand
|
||||
LonghandOrCustom(PropertyDeclaration),
|
||||
}
|
||||
|
||||
impl ParsedDeclaration {
|
||||
/// Transform this ParsedDeclaration into a sequence of PropertyDeclaration
|
||||
/// by expanding shorthand declarations into their corresponding longhands
|
||||
pub fn expand<F>(self, mut push: F) where F: FnMut(PropertyDeclaration) {
|
||||
match self {
|
||||
% for shorthand in data.shorthands:
|
||||
ParsedDeclaration::${shorthand.camel_case}(
|
||||
shorthands::${shorthand.ident}::Longhands {
|
||||
% for sub_property in shorthand.sub_properties:
|
||||
${sub_property.ident},
|
||||
% endfor
|
||||
}
|
||||
) => {
|
||||
% for sub_property in shorthand.sub_properties:
|
||||
push(PropertyDeclaration::${sub_property.camel_case}(
|
||||
% if sub_property.boxed:
|
||||
DeclaredValue::Value(Box::new(${sub_property.ident}))
|
||||
% else:
|
||||
DeclaredValue::Value(${sub_property.ident})
|
||||
% endif
|
||||
));
|
||||
% endfor
|
||||
}
|
||||
ParsedDeclaration::${shorthand.camel_case}CSSWideKeyword(keyword) => {
|
||||
% for sub_property in shorthand.sub_properties:
|
||||
push(PropertyDeclaration::${sub_property.camel_case}(
|
||||
DeclaredValue::CSSWideKeyword(keyword)
|
||||
));
|
||||
% endfor
|
||||
}
|
||||
ParsedDeclaration::${shorthand.camel_case}WithVariables(value) => {
|
||||
debug_assert_eq!(
|
||||
value.from_shorthand,
|
||||
Some(ShorthandId::${shorthand.camel_case})
|
||||
);
|
||||
% for sub_property in shorthand.sub_properties:
|
||||
push(PropertyDeclaration::${sub_property.camel_case}(
|
||||
DeclaredValue::WithVariables(value.clone())
|
||||
));
|
||||
% endfor
|
||||
}
|
||||
% endfor
|
||||
ParsedDeclaration::LonghandOrCustom(declaration) => push(declaration),
|
||||
}
|
||||
}
|
||||
|
||||
/// The `in_keyframe_block` parameter controls this:
|
||||
///
|
||||
/// https://drafts.csswg.org/css-animations/#keyframes
|
||||
/// > The <declaration-list> inside of <keyframe-block> accepts any CSS property
|
||||
/// > except those defined in this specification,
|
||||
/// > but does accept the `animation-play-state` property and interprets it specially.
|
||||
///
|
||||
/// This will not actually parse Importance values, and will always set things
|
||||
/// to Importance::Normal. Parsing Importance values is the job of PropertyDeclarationParser,
|
||||
/// we only set them here so that we don't have to reallocate
|
||||
pub fn parse(id: PropertyId, context: &ParserContext, input: &mut Parser,
|
||||
in_keyframe_block: bool)
|
||||
-> Result<ParsedDeclaration, PropertyDeclarationParseError> {
|
||||
match id {
|
||||
PropertyId::Custom(name) => {
|
||||
let value = match input.try(|i| CSSWideKeyword::parse(context, i)) {
|
||||
Ok(keyword) => DeclaredValue::CSSWideKeyword(keyword),
|
||||
Err(()) => match ::custom_properties::SpecifiedValue::parse(context, input) {
|
||||
Ok(value) => DeclaredValue::Value(value),
|
||||
Err(()) => return Err(PropertyDeclarationParseError::InvalidValue),
|
||||
}
|
||||
};
|
||||
Ok(ParsedDeclaration::LonghandOrCustom(PropertyDeclaration::Custom(name, value)))
|
||||
}
|
||||
PropertyId::Longhand(id) => match id {
|
||||
% for property in data.longhands:
|
||||
LonghandId::${property.camel_case} => {
|
||||
% if not property.derived_from:
|
||||
% if not property.allowed_in_keyframe_block:
|
||||
if in_keyframe_block {
|
||||
return Err(PropertyDeclarationParseError::AnimationPropertyInKeyframeBlock)
|
||||
}
|
||||
% endif
|
||||
% if property.internal:
|
||||
if context.stylesheet_origin != Origin::UserAgent {
|
||||
return Err(PropertyDeclarationParseError::UnknownProperty)
|
||||
}
|
||||
% endif
|
||||
|
||||
${property_pref_check(property)}
|
||||
|
||||
match longhands::${property.ident}::parse_declared(context, input) {
|
||||
Ok(value) => {
|
||||
Ok(ParsedDeclaration::LonghandOrCustom(
|
||||
PropertyDeclaration::${property.camel_case}(value)
|
||||
))
|
||||
},
|
||||
Err(()) => Err(PropertyDeclarationParseError::InvalidValue),
|
||||
}
|
||||
% else:
|
||||
Err(PropertyDeclarationParseError::UnknownProperty)
|
||||
% endif
|
||||
}
|
||||
% endfor
|
||||
},
|
||||
PropertyId::Shorthand(id) => match id {
|
||||
% for shorthand in data.shorthands:
|
||||
ShorthandId::${shorthand.camel_case} => {
|
||||
% if not shorthand.allowed_in_keyframe_block:
|
||||
if in_keyframe_block {
|
||||
return Err(PropertyDeclarationParseError::AnimationPropertyInKeyframeBlock)
|
||||
}
|
||||
% endif
|
||||
% if shorthand.internal:
|
||||
if context.stylesheet_origin != Origin::UserAgent {
|
||||
return Err(PropertyDeclarationParseError::UnknownProperty)
|
||||
}
|
||||
% endif
|
||||
|
||||
${property_pref_check(shorthand)}
|
||||
|
||||
match input.try(|i| CSSWideKeyword::parse(context, i)) {
|
||||
Ok(keyword) => {
|
||||
Ok(ParsedDeclaration::${shorthand.camel_case}CSSWideKeyword(keyword))
|
||||
},
|
||||
Err(()) => {
|
||||
shorthands::${shorthand.ident}::parse(context, input)
|
||||
.map_err(|()| PropertyDeclarationParseError::InvalidValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
% endfor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Servo's representation for a property declaration.
|
||||
#[derive(PartialEq, Clone)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum PropertyDeclaration {
|
||||
% for property in data.longhands:
|
||||
/// ${property.name}
|
||||
|
@ -831,7 +986,7 @@ impl HasViewportPercentage for PropertyDeclaration {
|
|||
|
||||
/// The result of parsing a property declaration.
|
||||
#[derive(Eq, PartialEq, Copy, Clone)]
|
||||
pub enum PropertyDeclarationParseResult {
|
||||
pub enum PropertyDeclarationParseError {
|
||||
/// The property declaration was for an unknown property.
|
||||
UnknownProperty,
|
||||
/// The property declaration was for a disabled experimental property.
|
||||
|
@ -843,8 +998,6 @@ pub enum PropertyDeclarationParseResult {
|
|||
///
|
||||
/// See: https://drafts.csswg.org/css-animations/#keyframes
|
||||
AnimationPropertyInKeyframeBlock,
|
||||
/// The declaration was either valid or ignored.
|
||||
ValidOrIgnoredDeclaration,
|
||||
}
|
||||
|
||||
impl fmt::Debug for PropertyDeclaration {
|
||||
|
@ -878,7 +1031,7 @@ impl ToCss for PropertyDeclaration {
|
|||
% if property.experimental and product == "servo":
|
||||
if !PREFS.get("${property.experimental}")
|
||||
.as_boolean().unwrap_or(false) {
|
||||
return PropertyDeclarationParseResult::ExperimentalProperty
|
||||
return Err(PropertyDeclarationParseError::ExperimentalProperty)
|
||||
}
|
||||
% endif
|
||||
% if product == "gecko":
|
||||
|
@ -895,7 +1048,7 @@ impl ToCss for PropertyDeclaration {
|
|||
let id = structs::${helpers.to_nscsspropertyid(property.ident)};
|
||||
let enabled = unsafe { bindings::Gecko_PropertyId_IsPrefEnabled(id) };
|
||||
if !enabled {
|
||||
return PropertyDeclarationParseResult::ExperimentalProperty
|
||||
return Err(PropertyDeclarationParseError::ExperimentalProperty)
|
||||
}
|
||||
}
|
||||
% endif
|
||||
|
@ -992,100 +1145,6 @@ impl PropertyDeclaration {
|
|||
}
|
||||
}
|
||||
|
||||
/// The `in_keyframe_block` parameter controls this:
|
||||
///
|
||||
/// https://drafts.csswg.org/css-animations/#keyframes
|
||||
/// > The <declaration-list> inside of <keyframe-block> accepts any CSS property
|
||||
/// > except those defined in this specification,
|
||||
/// > but does accept the `animation-play-state` property and interprets it specially.
|
||||
///
|
||||
/// This will not actually parse Importance values, and will always set things
|
||||
/// to Importance::Normal. Parsing Importance values is the job of PropertyDeclarationParser,
|
||||
/// we only set them here so that we don't have to reallocate
|
||||
pub fn parse(id: PropertyId, context: &ParserContext, input: &mut Parser,
|
||||
result_list: &mut Vec<(PropertyDeclaration, Importance)>,
|
||||
in_keyframe_block: bool)
|
||||
-> PropertyDeclarationParseResult {
|
||||
match id {
|
||||
PropertyId::Custom(name) => {
|
||||
let value = match input.try(|i| CSSWideKeyword::parse(context, i)) {
|
||||
Ok(keyword) => DeclaredValue::CSSWideKeyword(keyword),
|
||||
Err(()) => match ::custom_properties::SpecifiedValue::parse(context, input) {
|
||||
Ok(value) => DeclaredValue::Value(value),
|
||||
Err(()) => return PropertyDeclarationParseResult::InvalidValue,
|
||||
}
|
||||
};
|
||||
result_list.push((PropertyDeclaration::Custom(name, value),
|
||||
Importance::Normal));
|
||||
return PropertyDeclarationParseResult::ValidOrIgnoredDeclaration;
|
||||
}
|
||||
PropertyId::Longhand(id) => match id {
|
||||
% for property in data.longhands:
|
||||
LonghandId::${property.camel_case} => {
|
||||
% if not property.derived_from:
|
||||
% if not property.allowed_in_keyframe_block:
|
||||
if in_keyframe_block {
|
||||
return PropertyDeclarationParseResult::AnimationPropertyInKeyframeBlock
|
||||
}
|
||||
% endif
|
||||
% if property.internal:
|
||||
if context.stylesheet_origin != Origin::UserAgent {
|
||||
return PropertyDeclarationParseResult::UnknownProperty
|
||||
}
|
||||
% endif
|
||||
|
||||
${property_pref_check(property)}
|
||||
|
||||
match longhands::${property.ident}::parse_declared(context, input) {
|
||||
Ok(value) => {
|
||||
result_list.push((PropertyDeclaration::${property.camel_case}(value),
|
||||
Importance::Normal));
|
||||
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
|
||||
},
|
||||
Err(()) => PropertyDeclarationParseResult::InvalidValue,
|
||||
}
|
||||
% else:
|
||||
PropertyDeclarationParseResult::UnknownProperty
|
||||
% endif
|
||||
}
|
||||
% endfor
|
||||
},
|
||||
PropertyId::Shorthand(id) => match id {
|
||||
% for shorthand in data.shorthands:
|
||||
ShorthandId::${shorthand.camel_case} => {
|
||||
% if not shorthand.allowed_in_keyframe_block:
|
||||
if in_keyframe_block {
|
||||
return PropertyDeclarationParseResult::AnimationPropertyInKeyframeBlock
|
||||
}
|
||||
% endif
|
||||
% if shorthand.internal:
|
||||
if context.stylesheet_origin != Origin::UserAgent {
|
||||
return PropertyDeclarationParseResult::UnknownProperty
|
||||
}
|
||||
% endif
|
||||
|
||||
${property_pref_check(shorthand)}
|
||||
|
||||
match input.try(|i| CSSWideKeyword::parse(context, i)) {
|
||||
Ok(keyword) => {
|
||||
% for sub_property in shorthand.sub_properties:
|
||||
result_list.push((
|
||||
PropertyDeclaration::${sub_property.camel_case}(
|
||||
DeclaredValue::CSSWideKeyword(keyword)), Importance::Normal));
|
||||
% endfor
|
||||
PropertyDeclarationParseResult::ValidOrIgnoredDeclaration
|
||||
},
|
||||
Err(()) => match shorthands::${shorthand.ident}::parse(context, input, result_list) {
|
||||
Ok(()) => PropertyDeclarationParseResult::ValidOrIgnoredDeclaration,
|
||||
Err(()) => PropertyDeclarationParseResult::InvalidValue,
|
||||
}
|
||||
}
|
||||
}
|
||||
% endfor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The shorthands that this longhand is part of.
|
||||
pub fn shorthands(&self) -> &'static [ShorthandId] {
|
||||
// first generate longhand to shorthands lookup map
|
||||
|
@ -1766,7 +1825,7 @@ pub fn cascade(viewport_size: Size2D<Au>,
|
|||
}).collect::<Vec<_>>();
|
||||
let iter_declarations = || {
|
||||
lock_guards.iter().flat_map(|&(ref source, source_importance)| {
|
||||
source.declarations.iter()
|
||||
source.declarations().iter()
|
||||
// Yield declarations later in source order (with more precedence) first.
|
||||
.rev()
|
||||
.filter_map(move |&(ref declaration, declaration_importance)| {
|
||||
|
|
|
@ -99,7 +99,7 @@ impl StyleSource {
|
|||
let _ = write!(writer, "{:?}", rule.read().selectors);
|
||||
}
|
||||
|
||||
let _ = write!(writer, " -> {:?}", self.read().declarations);
|
||||
let _ = write!(writer, " -> {:?}", self.read().declarations());
|
||||
}
|
||||
|
||||
/// Read the style source guard, and obtain thus read access to the
|
||||
|
|
|
@ -52,7 +52,6 @@ pub enum Origin {
|
|||
|
||||
/// A set of namespaces applying to a given stylesheet.
|
||||
#[derive(Default, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct Namespaces {
|
||||
pub default: Option<Namespace>,
|
||||
|
@ -389,7 +388,6 @@ impl ToCss for CssRule {
|
|||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct NamespaceRule {
|
||||
/// `None` for the default Namespace
|
||||
|
@ -536,7 +534,7 @@ impl ToCss for StyleRule {
|
|||
let declaration_block = self.block.read();
|
||||
try!(declaration_block.to_css(dest));
|
||||
// Step 4
|
||||
if declaration_block.declarations.len() > 0 {
|
||||
if declaration_block.declarations().len() > 0 {
|
||||
try!(write!(dest, " "));
|
||||
}
|
||||
// Step 5
|
||||
|
@ -954,7 +952,7 @@ impl<'a> QualifiedRuleParser for TopLevelRuleParser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)] // shallow, relatively cheap clone
|
||||
#[derive(Clone)] // shallow, relatively cheap .clone
|
||||
struct NestedRuleParser<'a, 'b: 'a> {
|
||||
stylesheet_origin: Origin,
|
||||
context: &'a ParserContext<'b>,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
use cssparser::{parse_important, Parser, Token};
|
||||
use parser::ParserContext;
|
||||
use properties::{PropertyDeclaration, PropertyId};
|
||||
use properties::{PropertyId, ParsedDeclaration};
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
|
||||
|
@ -205,27 +205,14 @@ impl Declaration {
|
|||
///
|
||||
/// https://drafts.csswg.org/css-conditional-3/#support-definition
|
||||
pub fn eval(&self, cx: &ParserContext) -> bool {
|
||||
use properties::PropertyDeclarationParseResult::*;
|
||||
let id = if let Ok(id) = PropertyId::parse((&*self.prop).into()) {
|
||||
id
|
||||
} else {
|
||||
return false
|
||||
};
|
||||
let mut input = Parser::new(&self.val);
|
||||
let mut list = Vec::new();
|
||||
let res = PropertyDeclaration::parse(id, cx, &mut input,
|
||||
&mut list, /* in_keyframe */ false);
|
||||
let res = ParsedDeclaration::parse(id, cx, &mut input, /* in_keyframe */ false);
|
||||
let _ = input.try(parse_important);
|
||||
if !input.is_exhausted() {
|
||||
return false;
|
||||
}
|
||||
match res {
|
||||
UnknownProperty => false,
|
||||
ExperimentalProperty => false, // only happens for experimental props
|
||||
// that haven't been enabled
|
||||
InvalidValue => false,
|
||||
AnimationPropertyInKeyframeBlock => unreachable!(),
|
||||
ValidOrIgnoredDeclaration => true,
|
||||
}
|
||||
res.is_ok() && input.is_exhausted()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue