servo: Merge #13616 - Move PropertyDeclarationBlock into its own module (from servo:PropertyDeclarationBlock_independence_day); r=Ms2ger
authorSimon Sapin <simon.sapin@exyr.org>
Thu, 06 Oct 2016 11:13:41 -0500
changeset 339908 c9f2b5e830951cae701ce57cfdeea65d5d03bdac
parent 339907 3cce2d176a7fe234364c429b7d9918797a0792b6
child 339909 b6fea7b60f24a9432c917d7880f62e9e5a28a035
push id86548
push userkwierso@gmail.com
push dateSat, 04 Feb 2017 01:35:21 +0000
treeherdermozilla-inbound@e7b96d015d03 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMs2ger
servo: Merge #13616 - Move PropertyDeclarationBlock into its own module (from servo:PropertyDeclarationBlock_independence_day); r=Ms2ger <!-- Please describe your changes on the following line: --> `properties.mako.rs` (its previous location) is a fairly big file. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [x] These changes do not require new tests because refactor <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 3b853e57bfbd9df89aa3737080f28cdc42372c19
servo/components/style/properties/build.py
servo/components/style/properties/declaration_block.rs
servo/components/style/properties/properties.mako.rs
--- a/servo/components/style/properties/build.py
+++ b/servo/components/style/properties/build.py
@@ -24,17 +24,18 @@ def main():
     product = sys.argv[1]
     output = sys.argv[2]
     testing = sys.argv[3] == "testing"
 
     if product not in ["servo", "gecko"] or output not in ["style-crate", "geckolib", "html"]:
         abort(usage)
 
     properties = data.PropertiesData(product=product, testing=testing)
-    rust = render(os.path.join(BASE, "properties.mako.rs"), product=product, data=properties)
+    template = os.path.join(BASE, "properties.mako.rs")
+    rust = render(template, product=product, data=properties, __file__=template)
     if output == "style-crate":
         write(os.environ["OUT_DIR"], "properties.rs", rust)
         if product == "gecko":
             template = os.path.join(BASE, "gecko.mako.rs")
             rust = render(template, data=properties)
             write(os.environ["OUT_DIR"], "gecko_properties.rs", rust)
     elif output == "html":
         write_html(properties)
new file mode 100644
--- /dev/null
+++ b/servo/components/style/properties/declaration_block.rs
@@ -0,0 +1,385 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use cssparser::{DeclarationListParser, parse_important, ToCss};
+use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter};
+use error_reporting::ParseErrorReporter;
+use parser::{ParserContext, ParserContextExtraData, log_css_error};
+use std::boxed::Box as StdBox;
+use std::fmt;
+use stylesheets::Origin;
+use super::*;
+use url::Url;
+
+
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum Importance {
+    /// Indicates a declaration without `!important`.
+    Normal,
+
+    /// Indicates a declaration with `!important`.
+    Important,
+}
+
+impl Importance {
+    pub fn important(self) -> bool {
+        match self {
+            Importance::Normal => false,
+            Importance::Important => true,
+        }
+    }
+}
+
+/// Overridden declarations are skipped.
+// FIXME (https://github.com/servo/servo/issues/3426)
+#[derive(Debug, PartialEq, Clone)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct PropertyDeclarationBlock {
+    #[cfg_attr(feature = "servo", ignore_heap_size_of = "#7038")]
+    pub declarations: Vec<(PropertyDeclaration, Importance)>,
+
+    /// The number of entries in `self.declaration` with `Importance::Important`
+    pub important_count: u32,
+}
+
+impl PropertyDeclarationBlock {
+    /// Returns wheather this block contains any declaration with `!important`.
+    ///
+    /// This is based on the `important_count` counter,
+    /// which should be maintained whenever `declarations` is changed.
+    // FIXME: make fields private and maintain it here in methods?
+    pub fn any_important(&self) -> bool {
+        self.important_count > 0
+    }
+
+    /// Returns wheather this block contains any declaration without `!important`.
+    ///
+    /// This is based on the `important_count` counter,
+    /// 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
+    }
+
+    pub fn get(&self, property_name: &str) -> Option< &(PropertyDeclaration, Importance)> {
+        self.declarations.iter().find(|&&(ref decl, _)| decl.matches(property_name))
+    }
+}
+
+impl PropertyDeclarationBlock {
+    // Take a declaration block known to contain a single property,
+    // and serialize it
+    pub fn to_css_single_value<W>(&self, dest: &mut W, name: &str)
+        -> fmt::Result where W: fmt::Write {
+        match self.declarations.len() {
+            0 => Err(fmt::Error),
+            1 if self.declarations[0].0.name().eq_str_ignore_ascii_case(name) => {
+                self.declarations[0].0.to_css(dest)
+            }
+            _ => {
+                // we use this function because a closure won't be `Clone`
+                fn get_declaration(dec: &(PropertyDeclaration, Importance))
+                    -> &PropertyDeclaration {
+                    &dec.0
+                }
+                let shorthand = try!(Shorthand::from_name(name).ok_or(fmt::Error));
+                if !self.declarations.iter().all(|decl| decl.0.shorthands().contains(&shorthand)) {
+                    return Err(fmt::Error)
+                }
+                let success = try!(shorthand.serialize_shorthand_to_buffer(
+                    dest,
+                    self.declarations.iter()
+                                     .map(get_declaration as fn(_) -> _),
+                    &mut true)
+                );
+                if success {
+                    Ok(())
+                } else {
+                    Err(fmt::Error)
+                }
+            }
+        }
+    }
+}
+
+impl ToCss for PropertyDeclarationBlock {
+    // https://drafts.csswg.org/cssom/#serialize-a-css-declaration-block
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        let mut is_first_serialization = true; // trailing serializations should have a prepended space
+
+        // Step 1 -> dest = result list
+
+        // Step 2
+        let mut already_serialized = Vec::new();
+
+        // Step 3
+        for &(ref declaration, importance) in &*self.declarations {
+            // Step 3.1
+            let property = declaration.name();
+
+            // Step 3.2
+            if already_serialized.contains(&property) {
+                continue;
+            }
+
+            // Step 3.3
+            let shorthands = declaration.shorthands();
+            if !shorthands.is_empty() {
+                // Step 3.3.1
+                let mut longhands = self.declarations.iter()
+                    .filter(|d| !already_serialized.contains(&d.0.name()))
+                    .collect::<Vec<_>>();
+
+                // Step 3.3.2
+                for shorthand in shorthands {
+                    let properties = shorthand.longhands();
+
+                    // Substep 2 & 3
+                    let mut current_longhands = Vec::new();
+                    let mut important_count = 0;
+
+                    for &&(ref longhand, longhand_importance) in longhands.iter() {
+                        let longhand_name = longhand.name();
+                        if properties.iter().any(|p| &longhand_name == *p) {
+                            current_longhands.push(longhand);
+                            if longhand_importance.important() {
+                                important_count += 1;
+                            }
+                        }
+                    }
+
+                    // Substep 1
+                    /* Assuming that the PropertyDeclarationBlock contains no duplicate entries,
+                    if the current_longhands length is equal to the properties length, it means
+                    that the properties that map to shorthand are present in longhands */
+                    if current_longhands.is_empty() || current_longhands.len() != properties.len() {
+                        continue;
+                    }
+
+                    // Substep 4
+                    let is_important = important_count > 0;
+                    if is_important && important_count != current_longhands.len() {
+                        continue;
+                    }
+
+                    // TODO: serialize shorthand does not take is_important into account currently
+                    // Substep 5
+                    let was_serialized =
+                        try!(
+                            shorthand.serialize_shorthand_to_buffer(
+                                dest,
+                                current_longhands.iter().cloned(),
+                                &mut is_first_serialization
+                            )
+                        );
+                    // If serialization occured, Substep 7 & 8 will have been completed
+
+                    // Substep 6
+                    if !was_serialized {
+                        continue;
+                    }
+
+                    for current_longhand in current_longhands {
+                        // Substep 9
+                        already_serialized.push(current_longhand.name());
+                        let index_to_remove = longhands.iter().position(|l| l.0 == *current_longhand);
+                        if let Some(index) = index_to_remove {
+                            // Substep 10
+                            longhands.remove(index);
+                        }
+                     }
+                 }
+            }
+
+            // Step 3.3.4
+            if already_serialized.contains(&property) {
+                continue;
+            }
+
+            use std::iter::Cloned;
+            use std::slice;
+
+            // Steps 3.3.5, 3.3.6 & 3.3.7
+            // Need to specify an iterator type here even though it’s unused to work around
+            // "error: unable to infer enough type information about `_`;
+            //  type annotations or generic parameter binding required [E0282]"
+            // Use the same type as earlier call to reuse generated code.
+            try!(append_serialization::<W, Cloned<slice::Iter< &PropertyDeclaration>>>(
+                dest,
+                &property.to_string(),
+                AppendableValue::Declaration(declaration),
+                importance,
+                &mut is_first_serialization));
+
+            // Step 3.3.8
+            already_serialized.push(property);
+        }
+
+        // Step 4
+        Ok(())
+    }
+}
+
+pub enum AppendableValue<'a, I>
+where I: Iterator<Item=&'a PropertyDeclaration> {
+    Declaration(&'a PropertyDeclaration),
+    DeclarationsForShorthand(Shorthand, I),
+    Css(&'a str)
+}
+
+fn handle_first_serialization<W>(dest: &mut W, is_first_serialization: &mut bool) -> fmt::Result where W: fmt::Write {
+    // after first serialization(key: value;) add whitespace between the pairs
+    if !*is_first_serialization {
+        try!(write!(dest, " "));
+    } else {
+        *is_first_serialization = false;
+    }
+
+    Ok(())
+}
+
+pub fn append_declaration_value<'a, W, I>
+                           (dest: &mut W,
+                            appendable_value: AppendableValue<'a, I>,
+                            importance: Importance)
+                            -> fmt::Result
+                            where W: fmt::Write, I: Iterator<Item=&'a PropertyDeclaration> {
+  match appendable_value {
+      AppendableValue::Css(css) => {
+          try!(write!(dest, "{}", css))
+      },
+      AppendableValue::Declaration(decl) => {
+          try!(decl.to_css(dest));
+       },
+       AppendableValue::DeclarationsForShorthand(shorthand, decls) => {
+          try!(shorthand.longhands_to_css(decls, dest));
+       }
+  }
+
+  if importance.important() {
+      try!(write!(dest, " !important"));
+  }
+
+  Ok(())
+}
+
+pub fn append_serialization<'a, W, I>(dest: &mut W,
+                                  property_name: &str,
+                                  appendable_value: AppendableValue<'a, I>,
+                                  importance: Importance,
+                                  is_first_serialization: &mut bool)
+                                  -> fmt::Result
+                                  where W: fmt::Write, I: Iterator<Item=&'a PropertyDeclaration> {
+    try!(handle_first_serialization(dest, is_first_serialization));
+
+    // Overflow does not behave like a normal shorthand. When overflow-x and overflow-y are not of equal
+    // values, they no longer use the shared property name "overflow" and must be handled differently
+    if shorthands::is_overflow_shorthand(&appendable_value) {
+        return append_declaration_value(dest, appendable_value, importance);
+    }
+
+    try!(write!(dest, "{}:", property_name));
+
+    // for normal parsed values, add a space between key: and value
+    match &appendable_value {
+        &AppendableValue::Css(_) => {
+            try!(write!(dest, " "))
+        },
+        &AppendableValue::Declaration(decl) => {
+            if !decl.value_is_unparsed() {
+                // for normal parsed values, add a space between key: and value
+                try!(write!(dest, " "));
+            }
+         },
+         &AppendableValue::DeclarationsForShorthand(..) => try!(write!(dest, " "))
+    }
+
+    try!(append_declaration_value(dest, appendable_value, importance));
+    write!(dest, ";")
+}
+
+pub fn parse_style_attribute(input: &str, base_url: &Url, error_reporter: StdBox<ParseErrorReporter + Send>,
+                             extra_data: ParserContextExtraData)
+                             -> PropertyDeclarationBlock {
+    let context = ParserContext::new_with_extra_data(Origin::Author, base_url, error_reporter, extra_data);
+    parse_property_declaration_list(&context, &mut Parser::new(input))
+}
+
+pub fn parse_one_declaration(name: &str, input: &str, base_url: &Url, error_reporter: StdBox<ParseErrorReporter + Send>,
+                             extra_data: ParserContextExtraData)
+                             -> Result<Vec<PropertyDeclaration>, ()> {
+    let context = ParserContext::new_with_extra_data(Origin::Author, base_url, error_reporter, extra_data);
+    let mut results = vec![];
+    match PropertyDeclaration::parse(name, &context, &mut Parser::new(input), &mut results, false) {
+        PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => Ok(results),
+        _ => Err(())
+    }
+}
+
+struct PropertyDeclarationParser<'a, 'b: 'a> {
+    context: &'a ParserContext<'b>,
+}
+
+
+/// Default methods reject all at rules.
+impl<'a, 'b> AtRuleParser for PropertyDeclarationParser<'a, 'b> {
+    type Prelude = ();
+    type AtRule = (Vec<PropertyDeclaration>, Importance);
+}
+
+
+impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
+    type Declaration = (Vec<PropertyDeclaration>, Importance);
+
+    fn parse_value(&mut self, name: &str, input: &mut Parser)
+                   -> Result<(Vec<PropertyDeclaration>, Importance), ()> {
+        let mut results = vec![];
+        try!(input.parse_until_before(Delimiter::Bang, |input| {
+            match PropertyDeclaration::parse(name, self.context, input, &mut results, false) {
+                PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => Ok(()),
+                _ => Err(())
+            }
+        }));
+        let importance = match input.try(parse_important) {
+            Ok(()) => Importance::Important,
+            Err(()) => Importance::Normal,
+        };
+        Ok((results, importance))
+    }
+}
+
+
+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,
+    };
+    let mut iter = DeclarationListParser::new(input, parser);
+    while let Some(declaration) = iter.next() {
+        match declaration {
+            Ok((results, importance)) => {
+                if importance.important() {
+                    important_count += results.len() as u32;
+                }
+                declarations.extend(results.into_iter().map(|d| (d, importance)))
+            }
+            Err(range) => {
+                let pos = range.start;
+                let message = format!("Unsupported property declaration: '{}'",
+                                      iter.input.slice(range));
+                log_css_error(iter.input, pos, &*message, &context);
+            }
+        }
+    }
+    let mut block = PropertyDeclarationBlock {
+        declarations: declarations,
+        important_count: important_count,
+    };
+    super::deduplicate_property_declarations(&mut block);
+    block
+}
+
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -13,41 +13,45 @@
 use std::ascii::AsciiExt;
 use std::boxed::Box as StdBox;
 use std::collections::HashSet;
 use std::fmt::{self, Write};
 use std::sync::Arc;
 
 use app_units::Au;
 #[cfg(feature = "servo")] use cssparser::{Color as CSSParserColor, RGBA};
-use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter,
-                DeclarationListParser, parse_important, ToCss, TokenSerializationType};
+use cssparser::{Parser, ToCss, TokenSerializationType};
 use error_reporting::ParseErrorReporter;
 use url::Url;
 #[cfg(feature = "servo")] use euclid::side_offsets::SideOffsets2D;
 use euclid::size::Size2D;
 use string_cache::Atom;
 use computed_values;
 #[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
 use logical_geometry::WritingMode;
-use parser::{ParserContext, ParserContextExtraData, log_css_error};
+use parser::{ParserContext, ParserContextExtraData};
 use selector_matching::{ApplicableDeclarationBlock, ApplicableDeclarationBlockReadGuard};
 use stylesheets::Origin;
 use values::LocalToCss;
 use values::HasViewportPercentage;
 use values::computed::{self, ToComputedValue};
 use cascade_info::CascadeInfo;
 #[cfg(feature = "servo")] use values::specified::BorderStyle;
 
 use self::property_bit_field::PropertyBitField;
+pub use self::declaration_block::*;
 
 <%!
     from data import Method, Keyword, to_rust_ident
+    import os.path
 %>
 
+#[path="${os.path.join(os.path.dirname(__file__), 'declaration_block.rs')}"]
+pub mod declaration_block;
+
 pub mod longhands {
     use cssparser::Parser;
     use parser::ParserContext;
     use values::specified;
 
     <%include file="/longhand/background.mako.rs" />
     <%include file="/longhand/border.mako.rs" />
     <%include file="/longhand/box.mako.rs" />
@@ -257,389 +261,16 @@ mod property_bit_field {
                     // Invalid at computed-value time.
                     DeclaredValue::${"Inherit" if property.style_struct.inherited else "Initial"}
                 )
             );
         }
     % endif
 % endfor
 
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub enum Importance {
-    /// Indicates a declaration without `!important`.
-    Normal,
-
-    /// Indicates a declaration with `!important`.
-    Important,
-}
-
-impl Importance {
-    pub fn important(self) -> bool {
-        match self {
-            Importance::Normal => false,
-            Importance::Important => true,
-        }
-    }
-}
-
-/// Overridden declarations are skipped.
-// FIXME (https://github.com/servo/servo/issues/3426)
-#[derive(Debug, PartialEq, Clone)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub struct PropertyDeclarationBlock {
-    #[cfg_attr(feature = "servo", ignore_heap_size_of = "#7038")]
-    pub declarations: Vec<(PropertyDeclaration, Importance)>,
-
-    /// The number of entries in `self.declaration` with `Importance::Important`
-    pub important_count: u32,
-}
-
-impl PropertyDeclarationBlock {
-    /// Returns wheather this block contains any declaration with `!important`.
-    ///
-    /// This is based on the `important_count` counter,
-    /// which should be maintained whenever `declarations` is changed.
-    // FIXME: make fields private and maintain it here in methods?
-    pub fn any_important(&self) -> bool {
-        self.important_count > 0
-    }
-
-    /// Returns wheather this block contains any declaration without `!important`.
-    ///
-    /// This is based on the `important_count` counter,
-    /// 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
-    }
-
-    pub fn get(&self, property_name: &str) -> Option< &(PropertyDeclaration, Importance)> {
-        self.declarations.iter().find(|&&(ref decl, _)| decl.matches(property_name))
-    }
-}
-
-impl PropertyDeclarationBlock {
-    // Take a declaration block known to contain a single property,
-    // and serialize it
-    pub fn to_css_single_value<W>(&self, dest: &mut W, name: &str)
-        -> fmt::Result where W: fmt::Write {
-        match self.declarations.len() {
-            0 => Err(fmt::Error),
-            1 if self.declarations[0].0.name().eq_str_ignore_ascii_case(name) => {
-                self.declarations[0].0.to_css(dest)
-            }
-            _ => {
-                // we use this function because a closure won't be `Clone`
-                fn get_declaration(dec: &(PropertyDeclaration, Importance))
-                    -> &PropertyDeclaration {
-                    &dec.0
-                }
-                let shorthand = try!(Shorthand::from_name(name).ok_or(fmt::Error));
-                if !self.declarations.iter().all(|decl| decl.0.shorthands().contains(&shorthand)) {
-                    return Err(fmt::Error)
-                }
-                let success = try!(shorthand.serialize_shorthand_to_buffer(
-                    dest,
-                    self.declarations.iter()
-                                     .map(get_declaration as fn(_) -> _),
-                    &mut true)
-                );
-                if success {
-                    Ok(())
-                } else {
-                    Err(fmt::Error)
-                }
-            }
-        }
-    }
-}
-
-impl ToCss for PropertyDeclarationBlock {
-    // https://drafts.csswg.org/cssom/#serialize-a-css-declaration-block
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-        let mut is_first_serialization = true; // trailing serializations should have a prepended space
-
-        // Step 1 -> dest = result list
-
-        // Step 2
-        let mut already_serialized = Vec::new();
-
-        // Step 3
-        for &(ref declaration, importance) in &*self.declarations {
-            // Step 3.1
-            let property = declaration.name();
-
-            // Step 3.2
-            if already_serialized.contains(&property) {
-                continue;
-            }
-
-            // Step 3.3
-            let shorthands = declaration.shorthands();
-            if !shorthands.is_empty() {
-
-                // Step 3.3.1
-                let mut longhands = self.declarations.iter()
-                    .filter(|d| !already_serialized.contains(&d.0.name()))
-                    .collect::<Vec<_>>();
-
-                // Step 3.3.2
-                for shorthand in shorthands {
-                    let properties = shorthand.longhands();
-
-                    // Substep 2 & 3
-                    let mut current_longhands = Vec::new();
-                    let mut important_count = 0;
-
-                    for &&(ref longhand, longhand_importance) in longhands.iter() {
-                        let longhand_name = longhand.name();
-                        if properties.iter().any(|p| &longhand_name == *p) {
-                            current_longhands.push(longhand);
-                            if longhand_importance.important() {
-                                important_count += 1;
-                            }
-                        }
-                    }
-
-                    // Substep 1
-                    /* Assuming that the PropertyDeclarationBlock contains no duplicate entries,
-                    if the current_longhands length is equal to the properties length, it means
-                    that the properties that map to shorthand are present in longhands */
-                    if current_longhands.is_empty() || current_longhands.len() != properties.len() {
-                        continue;
-                    }
-
-                    // Substep 4
-                    let is_important = important_count > 0;
-                    if is_important && important_count != current_longhands.len() {
-                        continue;
-                    }
-
-                    // TODO: serialize shorthand does not take is_important into account currently
-                    // Substep 5
-                    let was_serialized =
-                        try!(
-                            shorthand.serialize_shorthand_to_buffer(
-                                dest,
-                                current_longhands.iter().cloned(),
-                                &mut is_first_serialization
-                            )
-                        );
-                    // If serialization occured, Substep 7 & 8 will have been completed
-
-                    // Substep 6
-                    if !was_serialized {
-                        continue;
-                    }
-
-                    for current_longhand in current_longhands {
-                        // Substep 9
-                        already_serialized.push(current_longhand.name());
-                        let index_to_remove = longhands.iter().position(|l| l.0 == *current_longhand);
-                        if let Some(index) = index_to_remove {
-                            // Substep 10
-                            longhands.remove(index);
-                        }
-                     }
-                 }
-            }
-
-            // Step 3.3.4
-            if already_serialized.contains(&property) {
-                continue;
-            }
-
-            use std::iter::Cloned;
-            use std::slice;
-
-            // Steps 3.3.5, 3.3.6 & 3.3.7
-            // Need to specify an iterator type here even though it’s unused to work around
-            // "error: unable to infer enough type information about `_`;
-            //  type annotations or generic parameter binding required [E0282]"
-            // Use the same type as earlier call to reuse generated code.
-            try!(append_serialization::<W, Cloned<slice::Iter< &PropertyDeclaration>>>(
-                dest,
-                &property.to_string(),
-                AppendableValue::Declaration(declaration),
-                importance,
-                &mut is_first_serialization));
-
-            // Step 3.3.8
-            already_serialized.push(property);
-        }
-
-        // Step 4
-        Ok(())
-    }
-}
-
-pub enum AppendableValue<'a, I>
-where I: Iterator<Item=&'a PropertyDeclaration> {
-    Declaration(&'a PropertyDeclaration),
-    DeclarationsForShorthand(Shorthand, I),
-    Css(&'a str)
-}
-
-fn handle_first_serialization<W>(dest: &mut W, is_first_serialization: &mut bool) -> fmt::Result where W: fmt::Write {
-    // after first serialization(key: value;) add whitespace between the pairs
-    if !*is_first_serialization {
-        try!(write!(dest, " "));
-    }
-    else {
-        *is_first_serialization = false;
-    }
-
-    Ok(())
-}
-
-fn append_declaration_value<'a, W, I>
-                           (dest: &mut W,
-                            appendable_value: AppendableValue<'a, I>,
-                            importance: Importance)
-                            -> fmt::Result
-                            where W: fmt::Write, I: Iterator<Item=&'a PropertyDeclaration> {
-  match appendable_value {
-      AppendableValue::Css(css) => {
-          try!(write!(dest, "{}", css))
-      },
-      AppendableValue::Declaration(decl) => {
-          try!(decl.to_css(dest));
-       },
-       AppendableValue::DeclarationsForShorthand(shorthand, decls) => {
-          try!(shorthand.longhands_to_css(decls, dest));
-       }
-  }
-
-  if importance.important() {
-      try!(write!(dest, " !important"));
-  }
-
-  Ok(())
-}
-
-fn append_serialization<'a, W, I>(dest: &mut W,
-                                  property_name: &str,
-                                  appendable_value: AppendableValue<'a, I>,
-                                  importance: Importance,
-                                  is_first_serialization: &mut bool)
-                                  -> fmt::Result
-                                  where W: fmt::Write, I: Iterator<Item=&'a PropertyDeclaration> {
-
-    try!(handle_first_serialization(dest, is_first_serialization));
-
-    // Overflow does not behave like a normal shorthand. When overflow-x and overflow-y are not of equal
-    // values, they no longer use the shared property name "overflow" and must be handled differently
-    if shorthands::is_overflow_shorthand(&appendable_value) {
-        return append_declaration_value(dest, appendable_value, importance);
-    }
-
-    try!(write!(dest, "{}:", property_name));
-
-    // for normal parsed values, add a space between key: and value
-    match &appendable_value {
-        &AppendableValue::Css(_) => {
-            try!(write!(dest, " "))
-        },
-        &AppendableValue::Declaration(decl) => {
-            if !decl.value_is_unparsed() {
-                // for normal parsed values, add a space between key: and value
-                try!(write!(dest, " "));
-            }
-         },
-         &AppendableValue::DeclarationsForShorthand(..) => try!(write!(dest, " "))
-    }
-
-    try!(append_declaration_value(dest, appendable_value, importance));
-    write!(dest, ";")
-}
-
-pub fn parse_style_attribute(input: &str, base_url: &Url, error_reporter: StdBox<ParseErrorReporter + Send>,
-                             extra_data: ParserContextExtraData)
-                             -> PropertyDeclarationBlock {
-    let context = ParserContext::new_with_extra_data(Origin::Author, base_url, error_reporter, extra_data);
-    parse_property_declaration_list(&context, &mut Parser::new(input))
-}
-
-pub fn parse_one_declaration(name: &str, input: &str, base_url: &Url, error_reporter: StdBox<ParseErrorReporter + Send>,
-                             extra_data: ParserContextExtraData)
-                             -> Result<Vec<PropertyDeclaration>, ()> {
-    let context = ParserContext::new_with_extra_data(Origin::Author, base_url, error_reporter, extra_data);
-    let mut results = vec![];
-    match PropertyDeclaration::parse(name, &context, &mut Parser::new(input), &mut results, false) {
-        PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => Ok(results),
-        _ => Err(())
-    }
-}
-
-struct PropertyDeclarationParser<'a, 'b: 'a> {
-    context: &'a ParserContext<'b>,
-}
-
-
-/// Default methods reject all at rules.
-impl<'a, 'b> AtRuleParser for PropertyDeclarationParser<'a, 'b> {
-    type Prelude = ();
-    type AtRule = (Vec<PropertyDeclaration>, Importance);
-}
-
-
-impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
-    type Declaration = (Vec<PropertyDeclaration>, Importance);
-
-    fn parse_value(&mut self, name: &str, input: &mut Parser)
-                   -> Result<(Vec<PropertyDeclaration>, Importance), ()> {
-        let mut results = vec![];
-        try!(input.parse_until_before(Delimiter::Bang, |input| {
-            match PropertyDeclaration::parse(name, self.context, input, &mut results, false) {
-                PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => Ok(()),
-                _ => Err(())
-            }
-        }));
-        let importance = match input.try(parse_important) {
-            Ok(()) => Importance::Important,
-            Err(()) => Importance::Normal,
-        };
-        Ok((results, importance))
-    }
-}
-
-
-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,
-    };
-    let mut iter = DeclarationListParser::new(input, parser);
-    while let Some(declaration) = iter.next() {
-        match declaration {
-            Ok((results, importance)) => {
-                if importance.important() {
-                    important_count += results.len() as u32;
-                }
-                declarations.extend(results.into_iter().map(|d| (d, importance)))
-            }
-            Err(range) => {
-                let pos = range.start;
-                let message = format!("Unsupported property declaration: '{}'",
-                                      iter.input.slice(range));
-                log_css_error(iter.input, pos, &*message, &context);
-            }
-        }
-    }
-    let mut block = PropertyDeclarationBlock {
-        declarations: declarations,
-        important_count: important_count,
-    };
-    deduplicate_property_declarations(&mut block);
-    block
-}
-
 /// Only keep the "winning" declaration for any given property, by importance then source order.
 /// The input and output are in source order
 fn deduplicate_property_declarations(block: &mut PropertyDeclarationBlock) {
     let mut deduplicated = Vec::new();
     let mut seen_normal = PropertyBitField::new();
     let mut seen_important = PropertyBitField::new();
     let mut seen_custom_normal = Vec::new();
     let mut seen_custom_important = Vec::new();