mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Reduce allocator churn when parsing property declaration blocks (fixes #15060)
This commit is contained in:
parent
f010fb58fd
commit
b5cb401aef
6 changed files with 81 additions and 49 deletions
|
@ -495,12 +495,15 @@ pub fn parse_style_attribute(input: &str,
|
|||
|
||||
/// Parse a given property declaration. Can result in multiple
|
||||
/// `PropertyDeclaration`s when expanding a shorthand, for example.
|
||||
///
|
||||
/// The vector returned will not have the importance set;
|
||||
/// this does not attempt to parse !important at all
|
||||
pub fn parse_one_declaration(id: PropertyId,
|
||||
input: &str,
|
||||
base_url: &ServoUrl,
|
||||
error_reporter: StdBox<ParseErrorReporter + Send>,
|
||||
extra_data: ParserContextExtraData)
|
||||
-> Result<Vec<PropertyDeclaration>, ()> {
|
||||
-> Result<Vec<(PropertyDeclaration, Importance)>, ()> {
|
||||
let context = ParserContext::new_with_extra_data(Origin::Author, base_url, error_reporter, extra_data);
|
||||
let mut results = vec![];
|
||||
match PropertyDeclaration::parse(id, &context, &mut Parser::new(input), &mut results, false) {
|
||||
|
@ -512,39 +515,51 @@ pub fn parse_one_declaration(id: PropertyId,
|
|||
/// 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 = (Vec<PropertyDeclaration>, Importance);
|
||||
type AtRule = (u32, Importance);
|
||||
}
|
||||
|
||||
|
||||
impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
|
||||
/// A single declaration may be expanded into multiple ones if it's a
|
||||
/// shorthand for example, so that's why this is a vector.
|
||||
///
|
||||
/// TODO(emilio): Seems like there's potentially a bunch of performance work
|
||||
/// we could do here.
|
||||
type Declaration = (Vec<PropertyDeclaration>, Importance);
|
||||
/// 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);
|
||||
|
||||
fn parse_value(&mut self, name: &str, input: &mut Parser)
|
||||
-> Result<(Vec<PropertyDeclaration>, Importance), ()> {
|
||||
-> Result<(u32, Importance), ()> {
|
||||
let id = try!(PropertyId::parse(name.into()));
|
||||
let mut results = vec![];
|
||||
try!(input.parse_until_before(Delimiter::Bang, |input| {
|
||||
match PropertyDeclaration::parse(id, self.context, input, &mut results, false) {
|
||||
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 importance = match input.try(parse_important) {
|
||||
Ok(()) => Importance::Important,
|
||||
Err(()) => Importance::Normal,
|
||||
};
|
||||
Ok((results, importance))
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,19 +569,18 @@ impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
|
|||
pub fn parse_property_declaration_list(context: &ParserContext,
|
||||
input: &mut Parser)
|
||||
-> PropertyDeclarationBlock {
|
||||
let mut declarations = Vec::new();
|
||||
let mut important_count = 0;
|
||||
let parser = PropertyDeclarationParser {
|
||||
context: context,
|
||||
declarations: vec![],
|
||||
};
|
||||
let mut iter = DeclarationListParser::new(input, parser);
|
||||
while let Some(declaration) = iter.next() {
|
||||
match declaration {
|
||||
Ok((results, importance)) => {
|
||||
Ok((count, importance)) => {
|
||||
if importance.important() {
|
||||
important_count += results.len() as u32;
|
||||
important_count += count;
|
||||
}
|
||||
declarations.extend(results.into_iter().map(|d| (d, importance)))
|
||||
}
|
||||
Err(range) => {
|
||||
let pos = range.start;
|
||||
|
@ -577,7 +591,7 @@ pub fn parse_property_declaration_list(context: &ParserContext,
|
|||
}
|
||||
}
|
||||
let mut block = PropertyDeclarationBlock {
|
||||
declarations: declarations,
|
||||
declarations: iter.parser.declarations,
|
||||
important_count: important_count,
|
||||
};
|
||||
super::deduplicate_property_declarations(&mut block);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue