aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/style/bezier.rs6
-rw-r--r--components/style/bloom.rs48
-rw-r--r--components/style/cascade_info.rs21
-rw-r--r--components/style/element_state.rs2
-rw-r--r--components/style/error_reporting.rs13
-rw-r--r--components/style/font_metrics.rs15
-rw-r--r--components/style/matching.rs99
-rw-r--r--components/style/properties/declaration_block.rs138
-rw-r--r--components/style/properties/properties.mako.rs16
9 files changed, 282 insertions, 76 deletions
diff --git a/components/style/bezier.rs b/components/style/bezier.rs
index ba3d33a2394..0d74bf5da42 100644
--- a/components/style/bezier.rs
+++ b/components/style/bezier.rs
@@ -6,10 +6,13 @@
//!
//! This is based on `WebCore/platform/graphics/UnitBezier.h` in WebKit.
+#![deny(missing_docs)]
+
use euclid::point::Point2D;
const NEWTON_METHOD_ITERATIONS: u8 = 8;
+/// A Bézier curve.
pub struct Bezier {
ax: f64,
bx: f64,
@@ -20,6 +23,7 @@ pub struct Bezier {
}
impl Bezier {
+ /// Create a Bézier curve from two control points.
#[inline]
pub fn new(p1: Point2D<f64>, p2: Point2D<f64>) -> Bezier {
let cx = 3.0 * p1.x;
@@ -96,6 +100,8 @@ impl Bezier {
t
}
+ /// Solve the bezier curve for a given `x` and an `epsilon`, that should be
+ /// between zero and one.
#[inline]
pub fn solve(&self, x: f64, epsilon: f64) -> f64 {
self.sample_curve_y(self.solve_curve_x(x, epsilon))
diff --git a/components/style/bloom.rs b/components/style/bloom.rs
index e2f45bb6233..72e7a173de8 100644
--- a/components/style/bloom.rs
+++ b/components/style/bloom.rs
@@ -5,10 +5,43 @@
//! The style bloom filter is used as an optimization when matching deep
//! descendant selectors.
+#![deny(missing_docs)]
+
use dom::{SendElement, TElement};
use matching::MatchMethods;
use selectors::bloom::BloomFilter;
+/// A struct that allows us to fast-reject deep descendant selectors avoiding
+/// selector-matching.
+///
+/// This is implemented using a counting bloom filter, and it's a standard
+/// optimization. See Gecko's `AncestorFilter`, and Blink's and WebKit's
+/// `SelectorFilter`.
+///
+/// The constraints for Servo's style system are a bit different compared to
+/// traditional style systems given Servo does a parallel breadth-first
+/// traversal instead of a sequential depth-first traversal.
+///
+/// This implies that we need to track a bit more state than other browsers to
+/// ensure we're doing the correct thing during the traversal, and being able to
+/// apply this optimization effectively.
+///
+/// Concretely, we have a bloom filter instance per worker thread, and we track
+/// the current DOM depth in order to find a common ancestor when it doesn't
+/// match the previous element we've styled.
+///
+/// This is usually a pretty fast operation (we use to be one level deeper than
+/// the previous one), but in the case of work-stealing, we may needed to push
+/// and pop multiple elements.
+///
+/// See the `insert_parents_recovering`, where most of the magic happens.
+///
+/// Regarding thread-safety, this struct is safe because:
+///
+/// * We clear this after a restyle.
+/// * The DOM shape and attributes (and every other thing we access here) are
+/// immutable during a restyle.
+///
pub struct StyleBloom<E: TElement> {
/// The bloom filter per se.
filter: Box<BloomFilter>,
@@ -18,6 +51,7 @@ pub struct StyleBloom<E: TElement> {
}
impl<E: TElement> StyleBloom<E> {
+ /// Create an empty `StyleBloom`.
pub fn new() -> Self {
StyleBloom {
filter: Box::new(BloomFilter::new()),
@@ -25,19 +59,14 @@ impl<E: TElement> StyleBloom<E> {
}
}
+ /// Return the bloom filter used properly by the `selectors` crate.
pub fn filter(&self) -> &BloomFilter {
&*self.filter
}
- pub fn maybe_pop(&mut self, element: E) {
- if self.elements.last().map(|el| **el) == Some(element) {
- self.pop().unwrap();
- }
- }
-
/// Push an element to the bloom filter, knowing that it's a child of the
/// last element parent.
- pub fn push(&mut self, element: E) {
+ fn push(&mut self, element: E) {
if cfg!(debug_assertions) {
if self.elements.is_empty() {
assert!(element.parent_element().is_none());
@@ -78,6 +107,8 @@ impl<E: TElement> StyleBloom<E> {
/// In debug builds, asserts that all the parents of `element` are in the
/// bloom filter.
+ ///
+ /// Goes away in release builds.
pub fn assert_complete(&self, mut element: E) {
if cfg!(debug_assertions) {
let mut checked = 0;
@@ -96,7 +127,8 @@ impl<E: TElement> StyleBloom<E> {
/// Gets the element depth in the dom, to make it efficient, or if not
/// provided always rebuilds the filter from scratch.
///
- /// Returns the new bloom filter depth.
+ /// Returns the new bloom filter depth, that the traversal code is
+ /// responsible to keep around if it wants to get an effective filter.
pub fn insert_parents_recovering(&mut self,
element: E,
element_depth: Option<usize>)
diff --git a/components/style/cascade_info.rs b/components/style/cascade_info.rs
index d0c584e7e0f..5c7565909db 100644
--- a/components/style/cascade_info.rs
+++ b/components/style/cascade_info.rs
@@ -1,6 +1,11 @@
/* 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/. */
+
+//! A structure to collect information about the cascade.
+
+#![deny(missing_docs)]
+
use dom::TNode;
use properties::{DeclaredValue, PropertyDeclaration};
use values::HasViewportPercentage;
@@ -12,12 +17,17 @@ use values::HasViewportPercentage;
/// non-inherited property is explicitly inherited, in order to cut-off the
/// traversal.
pub struct CascadeInfo {
+ /// Whether we've seen viewport units so far.
pub saw_viewport_units: bool,
+ /// Whether the cascade has been marked as finished. This is a debug-only
+ /// flag to ensure `finish` is called, given it's optional to not pass a
+ /// `CascadeInfo`.
#[cfg(debug_assertions)]
finished: bool,
}
impl CascadeInfo {
+ /// Construct a new `CascadeInfo`.
#[cfg(debug_assertions)]
pub fn new() -> Self {
CascadeInfo {
@@ -26,6 +36,7 @@ impl CascadeInfo {
}
}
+ /// Construct a new `CascadeInfo`.
#[cfg(not(debug_assertions))]
pub fn new() -> Self {
CascadeInfo {
@@ -40,7 +51,7 @@ impl CascadeInfo {
pub fn on_cascade_property<T>(&mut self,
_property_declaration: &PropertyDeclaration,
value: &DeclaredValue<T>)
- where T: HasViewportPercentage
+ where T: HasViewportPercentage,
{
// TODO: we can be smarter and keep a property bitfield to keep track of
// the last applying rule.
@@ -57,6 +68,11 @@ impl CascadeInfo {
#[cfg(not(debug_assertions))]
fn mark_as_finished_if_appropriate(&mut self) {}
+ /// Called when the cascade is finished, in order to use the information
+ /// we've collected.
+ ///
+ /// Currently used for styling to mark a node as needing restyling when the
+ /// viewport size changes.
#[allow(unsafe_code)]
pub fn finish<N: TNode>(mut self, node: &N) {
self.mark_as_finished_if_appropriate();
@@ -73,6 +89,7 @@ impl CascadeInfo {
impl Drop for CascadeInfo {
fn drop(&mut self) {
debug_assert!(self.finished,
- "Didn't use the result of CascadeInfo, if you don't need it, consider passing None");
+ "Didn't use the result of CascadeInfo, if you don't need \
+ it, consider passing None");
}
}
diff --git a/components/style/element_state.rs b/components/style/element_state.rs
index ef6e9704170..9ccd08334cc 100644
--- a/components/style/element_state.rs
+++ b/components/style/element_state.rs
@@ -4,6 +4,8 @@
//! States elements can be in.
+#![deny(missing_docs)]
+
bitflags! {
#[doc = "Event-based element states."]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
diff --git a/components/style/error_reporting.rs b/components/style/error_reporting.rs
index 17d4ce7bb00..3a802bdd6c6 100644
--- a/components/style/error_reporting.rs
+++ b/components/style/error_reporting.rs
@@ -4,14 +4,27 @@
//! Types used to report parsing errors.
+#![deny(missing_docs)]
+
use cssparser::{Parser, SourcePosition};
use log;
+/// A generic trait for an error reporter.
pub trait ParseErrorReporter {
+ /// Called the style engine detects an error.
+ ///
+ /// Returns the current input being parsed, the source position it was
+ /// reported from, and a message.
fn report_error(&self, input: &mut Parser, position: SourcePosition, message: &str);
+ /// Clone this error reporter.
+ ///
+ /// TODO(emilio): I'm pretty sure all the box shenanigans can go away.
fn clone(&self) -> Box<ParseErrorReporter + Send + Sync>;
}
+/// An error reporter that reports the errors to the `info` log channel.
+///
+/// TODO(emilio): The name of this reporter is a lie, and should be renamed!
pub struct StdoutErrorReporter;
impl ParseErrorReporter for StdoutErrorReporter {
fn report_error(&self, input: &mut Parser, position: SourcePosition, message: &str) {
diff --git a/components/style/font_metrics.rs b/components/style/font_metrics.rs
index dac7a69ee29..417c7999845 100644
--- a/components/style/font_metrics.rs
+++ b/components/style/font_metrics.rs
@@ -2,6 +2,10 @@
* 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/. */
+//! Access to font metrics from the style system.
+
+#![deny(missing_docs)]
+
use Atom;
use app_units::Au;
use euclid::Size2D;
@@ -11,13 +15,19 @@ use std::fmt;
/// value of certain CSS units like `ex`.
#[derive(Debug, PartialEq, Clone)]
pub struct FontMetrics {
+ /// The x-height of the font.
pub x_height: Au,
+ /// The zero advance.
pub zero_advance_measure: Size2D<Au>,
}
+/// The result for querying font metrics for a given font family.
#[derive(Debug, PartialEq, Clone)]
pub enum FontMetricsQueryResult {
+ /// The font is available, but we may or may not have found any font metrics
+ /// for it.
Available(Option<FontMetrics>),
+ /// The font is not available.
NotAvailable,
}
@@ -26,9 +36,8 @@ pub trait FontMetricsProvider: Send + Sync + fmt::Debug {
/// Obtain the metrics for given font family.
///
/// TODO: We could make this take the full list, I guess, and save a few
- /// virtual calls.
- ///
- /// This is not too common in practice though.
+ /// virtual calls in the case we are repeatedly unable to find font metrics?
+ /// That is not too common in practice though.
fn query(&self, _font_name: &Atom) -> FontMetricsQueryResult {
FontMetricsQueryResult::NotAvailable
}
diff --git a/components/style/matching.rs b/components/style/matching.rs
index 0b06c998098..af8cd4bf627 100644
--- a/components/style/matching.rs
+++ b/components/style/matching.rs
@@ -5,6 +5,7 @@
//! High-level interface to CSS selector matching.
#![allow(unsafe_code)]
+#![deny(missing_docs)]
use {Atom, LocalName};
use animation::{self, Animation, PropertyAnimation};
@@ -49,11 +50,22 @@ fn create_common_style_affecting_attributes_from_element<E: TElement>(element: &
flags
}
+/// The rule nodes for each of the pseudo-elements of an element.
+///
+/// TODO(emilio): Probably shouldn't be a `HashMap` by default, but a smaller
+/// array.
type PseudoRuleNodes = HashMap<PseudoElement, StrongRuleNode,
BuildHasherDefault<::fnv::FnvHasher>>;
+
+/// The results of selector matching on an element.
pub struct MatchResults {
+ /// The rule node reference that represents the rules matched by the
+ /// element.
pub primary: StrongRuleNode,
+ /// A set of style relations (different hints about what rules matched or
+ /// could have matched).
pub relations: StyleRelations,
+ /// The results of selector-matching the pseudo-elements.
pub per_pseudo: PseudoRuleNodes,
}
@@ -65,7 +77,11 @@ impl MatchResults {
}
}
-/// Information regarding a candidate.
+/// Information regarding a style sharing candidate.
+///
+/// Note that this information is stored in TLS and cleared after the traversal,
+/// and once here, the style information of the element is immutable, so it's
+/// safe to access.
///
/// TODO: We can stick a lot more info here.
#[derive(Debug)]
@@ -75,7 +91,7 @@ struct StyleSharingCandidate<E: TElement> {
element: SendElement<E>,
/// The cached common style affecting attribute info.
common_style_affecting_attributes: Option<CommonStyleAffectingAttributes>,
- /// the cached class names.
+ /// The cached class names.
class_attributes: Option<Vec<Atom>>,
}
@@ -95,20 +111,39 @@ pub struct StyleSharingCandidateCache<E: TElement> {
cache: LRUCache<StyleSharingCandidate<E>, ()>,
}
+/// A cache miss result.
#[derive(Clone, Debug)]
pub enum CacheMiss {
+ /// The parents don't match.
Parent,
+ /// The local name of the element and the candidate don't match.
LocalName,
+ /// The namespace of the element and the candidate don't match.
Namespace,
+ /// One of the element or the candidate was a link, but the other one
+ /// wasn't.
Link,
+ /// The element and the candidate match different kind of rules. This can
+ /// only happen in Gecko.
UserAndAuthorRules,
+ /// The element and the candidate are in a different state.
State,
+ /// The element had an id attribute, which qualifies for a unique style.
IdAttr,
+ /// The element had a style attribute, which qualifies for a unique style.
StyleAttr,
+ /// The element and the candidate class names didn't match.
Class,
+ /// The element and the candidate common style affecting attributes didn't
+ /// match.
CommonStyleAffectingAttributes,
+ /// The presentation hints didn't match.
PresHints,
+ /// The element and the candidate didn't match the same set of
+ /// sibling-affecting rules.
SiblingRules,
+ /// The element and the candidate didn't match the same set of non-common
+ /// style affecting attribute selectors.
NonCommonAttrRules,
}
@@ -213,27 +248,43 @@ fn have_same_presentational_hints<E: TElement>(element: &E, candidate: &E) -> bo
}
bitflags! {
+ /// A set of common style-affecting attributes we check separately to
+ /// optimize the style sharing cache.
pub flags CommonStyleAffectingAttributes: u8 {
+ /// The `hidden` attribute.
const HIDDEN_ATTRIBUTE = 0x01,
+ /// The `nowrap` attribute.
const NO_WRAP_ATTRIBUTE = 0x02,
+ /// The `align="left"` attribute.
const ALIGN_LEFT_ATTRIBUTE = 0x04,
+ /// The `align="center"` attribute.
const ALIGN_CENTER_ATTRIBUTE = 0x08,
+ /// The `align="right"` attribute.
const ALIGN_RIGHT_ATTRIBUTE = 0x10,
}
}
+/// The information of how to match a given common-style affecting attribute.
pub struct CommonStyleAffectingAttributeInfo {
+ /// The attribute name.
pub attr_name: LocalName,
+ /// The matching mode for the attribute.
pub mode: CommonStyleAffectingAttributeMode,
}
+/// How should we match a given common style-affecting attribute?
#[derive(Clone)]
pub enum CommonStyleAffectingAttributeMode {
+ /// Just for presence?
IsPresent(CommonStyleAffectingAttributes),
+ /// For presence and equality with a given value.
IsEqual(Atom, CommonStyleAffectingAttributes),
}
-// NB: This must match the order in `selectors::matching::CommonStyleAffectingAttributes`.
+/// The common style affecting attribute array.
+///
+/// TODO: This should be a `const static` or similar, but couldn't be because
+/// `Atom`s have destructors.
#[inline]
pub fn common_style_affecting_attributes() -> [CommonStyleAffectingAttributeInfo; 5] {
[
@@ -260,9 +311,14 @@ pub fn common_style_affecting_attributes() -> [CommonStyleAffectingAttributeInfo
]
}
-/// Attributes that, if present, disable style sharing. All legacy HTML attributes must be in
-/// either this list or `common_style_affecting_attributes`. See the comment in
+/// Attributes that, if present, disable style sharing. All legacy HTML
+/// attributes must be in either this list or
+/// `common_style_affecting_attributes`. See the comment in
/// `synthesize_presentational_hints_for_legacy_attributes`.
+///
+/// TODO(emilio): This is not accurate now, we don't disable style sharing for
+/// this now since we check for attribute selectors in the stylesheet. Consider
+/// removing this.
pub fn rare_style_affecting_attributes() -> [LocalName; 4] {
[local_name!("bgcolor"), local_name!("border"), local_name!("colspan"), local_name!("rowspan")]
}
@@ -301,6 +357,7 @@ fn match_same_sibling_affecting_rules<E: TElement>(element: &E,
static STYLE_SHARING_CANDIDATE_CACHE_SIZE: usize = 8;
impl<E: TElement> StyleSharingCandidateCache<E> {
+ /// Create a new style sharing candidate cache.
pub fn new() -> Self {
StyleSharingCandidateCache {
cache: LRUCache::new(STYLE_SHARING_CANDIDATE_CACHE_SIZE),
@@ -311,6 +368,9 @@ impl<E: TElement> StyleSharingCandidateCache<E> {
self.cache.iter_mut()
}
+ /// Tries to insert an element in the style sharing cache.
+ ///
+ /// Fails if we know it should never be in the cache.
pub fn insert_if_possible(&mut self,
element: &E,
style: &Arc<ComputedValues>,
@@ -353,10 +413,12 @@ impl<E: TElement> StyleSharingCandidateCache<E> {
}, ());
}
+ /// Touch a given index in the style sharing candidate cache.
pub fn touch(&mut self, index: usize) {
self.cache.touch(index);
}
+ /// Clear the style sharing candidate cache.
pub fn clear(&mut self) {
self.cache.evict_all()
}
@@ -367,16 +429,14 @@ pub enum StyleSharingResult {
/// We didn't find anybody to share the style with.
CannotShare,
/// The node's style can be shared. The integer specifies the index in the
- /// LRU cache that was hit and the damage that was done, and the restyle
- /// result the original result of the candidate's styling, that is, whether
- /// it should stop the traversal or not.
+ /// LRU cache that was hit and the damage that was done.
StyleWasShared(usize),
}
-// Callers need to pass several boolean flags to cascade_node_pseudo_element.
-// We encapsulate them in this struct to avoid mixing them up.
-//
-// FIXME(pcwalton): Unify with `CascadeFlags`, perhaps?
+/// Callers need to pass several boolean flags to cascade_node_pseudo_element.
+/// We encapsulate them in this struct to avoid mixing them up.
+///
+/// FIXME(pcwalton): Unify with `CascadeFlags`, perhaps?
struct CascadeBooleans {
shareable: bool,
animate: bool,
@@ -511,7 +571,9 @@ fn compute_rule_node<E: TElement>(context: &StyleContext<E>,
impl<E: TElement> PrivateMatchMethods for E {}
+/// The public API that elements expose for selector matching.
pub trait MatchMethods : TElement {
+ /// Runs selector matching of this element, and returns the result.
fn match_element(&self, context: &StyleContext<Self>, parent_bf: Option<&BloomFilter>)
-> MatchResults
{
@@ -556,9 +618,10 @@ pub trait MatchMethods : TElement {
}
}
- /// Attempts to share a style with another node. This method is unsafe because it depends on
- /// the `style_sharing_candidate_cache` having only live nodes in it, and we have no way to
- /// guarantee that at the type system level yet.
+ /// Attempts to share a style with another node. This method is unsafe
+ /// because it depends on the `style_sharing_candidate_cache` having only
+ /// live nodes in it, and we have no way to guarantee that at the type
+ /// system level yet.
unsafe fn share_style_if_possible(&self,
style_sharing_candidate_cache:
&mut StyleSharingCandidateCache<Self>,
@@ -671,6 +734,9 @@ pub trait MatchMethods : TElement {
self.each_class(|class| bf.remove(class));
}
+ /// Given the old and new style of this element, and whether it's a
+ /// pseudo-element, compute the restyle damage used to determine which
+ /// kind of layout or painting operations we'll need.
fn compute_restyle_damage(&self,
old_style: Option<&Arc<ComputedValues>>,
new_style: &Arc<ComputedValues>,
@@ -709,6 +775,8 @@ pub trait MatchMethods : TElement {
}
}
+ /// Given the results of selector matching, run the CSS cascade and style
+ /// the node, potentially starting any new transitions or animations.
fn cascade_node(&self,
context: &StyleContext<Self>,
mut data: &mut AtomicRefMut<ElementData>,
@@ -783,6 +851,7 @@ pub trait MatchMethods : TElement {
data.finish_styling(new_styles, damage);
}
+ /// Given the old and new styling results, compute the final restyle damage.
fn compute_damage_and_cascade_pseudos(
&self,
old_primary: Option<&Arc<ComputedValues>>,
diff --git a/components/style/properties/declaration_block.rs b/components/style/properties/declaration_block.rs
index 80ba5787d96..d8638284e14 100644
--- a/components/style/properties/declaration_block.rs
+++ b/components/style/properties/declaration_block.rs
@@ -2,6 +2,10 @@
* 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/. */
+//! A property declaration block.
+
+#![deny(missing_docs)]
+
use cssparser::{DeclarationListParser, parse_important};
use cssparser::{Parser, AtRuleParser, DeclarationParser, Delimiter};
use error_reporting::ParseErrorReporter;
@@ -13,7 +17,9 @@ use style_traits::ToCss;
use stylesheets::Origin;
use super::*;
-
+/// A declaration [importance][importance].
+///
+/// [importance]: https://drafts.csswg.org/css-cascade/#importance
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Importance {
@@ -25,6 +31,7 @@ pub enum Importance {
}
impl Importance {
+ /// Return whether this is an important declaration.
pub fn important(self) -> bool {
match self {
Importance::Normal => false,
@@ -34,10 +41,12 @@ impl Importance {
}
/// 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 {
+ /// 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)>,
@@ -64,6 +73,9 @@ impl PropertyDeclarationBlock {
self.declarations.len() > self.important_count as usize
}
+ /// Get a declaration for a given property.
+ ///
+ /// NOTE: This is linear time.
pub fn get(&self, property: PropertyDeclarationId) -> Option< &(PropertyDeclaration, Importance)> {
self.declarations.iter().find(|&&(ref decl, _)| decl.id() == property)
}
@@ -72,7 +84,8 @@ impl PropertyDeclarationBlock {
///
/// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
pub fn property_value_to_css<W>(&self, property: &PropertyId, dest: &mut W) -> fmt::Result
- where W: fmt::Write {
+ where W: fmt::Write,
+ {
// Step 1: done when parsing a string to PropertyId
// Step 2
@@ -149,7 +162,11 @@ impl PropertyDeclarationBlock {
}
}
- pub fn set_parsed_declaration(&mut self, declaration: PropertyDeclaration, importance: Importance) {
+ /// Adds or overrides the declaration for a given property in this block,
+ /// without taking into account any kind of priority.
+ pub fn set_parsed_declaration(&mut self,
+ declaration: PropertyDeclaration,
+ importance: Importance) {
for slot in &mut *self.declarations {
if slot.0.id() == declaration.id() {
match (slot.1, importance) {
@@ -172,6 +189,7 @@ impl PropertyDeclarationBlock {
}
}
+ /// Set the declaration importance for a given property, if found.
pub fn set_importance(&mut self, property: &PropertyId, new_importance: Importance) {
for &mut (ref declaration, ref mut importance) in &mut self.declarations {
if declaration.id().is_or_is_longhand_of(property) {
@@ -203,7 +221,8 @@ impl PropertyDeclarationBlock {
/// Take a declaration block known to contain a single property and serialize it.
pub fn single_value_to_css<W>(&self, property: &PropertyId, dest: &mut W) -> fmt::Result
- where W: fmt::Write {
+ where W: fmt::Write,
+ {
match property.as_shorthand() {
Err(_longhand_or_custom) => {
if self.declarations.len() == 1 {
@@ -236,7 +255,9 @@ impl PropertyDeclarationBlock {
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 {
+ 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
@@ -356,15 +377,28 @@ impl ToCss for PropertyDeclarationBlock {
}
}
+/// A convenient enum to represent different kinds of stuff that can represent a
+/// _value_ in the serialization of a property declaration.
pub enum AppendableValue<'a, I>
-where I: Iterator<Item=&'a PropertyDeclaration> {
+ where I: Iterator<Item=&'a PropertyDeclaration>,
+{
+ /// A given declaration, of which we'll serialize just the value.
Declaration(&'a PropertyDeclaration),
+ /// A set of declarations for a given shorthand.
+ ///
+ /// FIXME: This needs more docs, where are the shorthands expanded? We print
+ /// the property name before-hand, don't we?
DeclarationsForShorthand(ShorthandId, I),
+ /// A raw CSS string, coming for example from a property with CSS variables.
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
+/// Potentially appends whitespace after the first (property: value;) pair.
+fn handle_first_serialization<W>(dest: &mut W,
+ is_first_serialization: &mut bool)
+ -> fmt::Result
+ where W: fmt::Write,
+{
if !*is_first_serialization {
try!(write!(dest, " "));
} else {
@@ -374,45 +408,48 @@ fn handle_first_serialization<W>(dest: &mut W, is_first_serialization: &mut bool
Ok(())
}
-pub fn append_declaration_value<'a, W, I>
- (dest: &mut W,
- appendable_value: AppendableValue<'a, I>,
- importance: Importance,
- is_overflow_with_name: bool)
- -> 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) => {
- if is_overflow_with_name {
- try!(shorthand.overflow_longhands_to_css(decls, dest));
- } else {
- try!(shorthand.longhands_to_css(decls, dest));
- }
- }
- }
-
- if importance.important() {
- try!(write!(dest, " !important"));
- }
-
- Ok(())
+/// Append a given kind of appendable value to a serialization.
+pub fn append_declaration_value<'a, W, I>(dest: &mut W,
+ appendable_value: AppendableValue<'a, I>,
+ importance: Importance,
+ is_overflow_with_name: bool)
+ -> 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) => {
+ if is_overflow_with_name {
+ try!(shorthand.overflow_longhands_to_css(decls, dest));
+ } else {
+ try!(shorthand.longhands_to_css(decls, dest));
+ }
+ }
+ }
+
+ if importance.important() {
+ try!(write!(dest, " !important"));
+ }
+
+ Ok(())
}
+/// Append a given property and value pair to a serialization.
pub fn append_serialization<'a, W, I, N>(dest: &mut W,
- property_name: &N,
- appendable_value: AppendableValue<'a, I>,
- importance: Importance,
- is_first_serialization: &mut bool)
- -> fmt::Result
+ property_name: &N,
+ appendable_value: AppendableValue<'a, I>,
+ importance: Importance,
+ is_first_serialization: &mut bool)
+ -> fmt::Result
where W: fmt::Write,
I: Iterator<Item=&'a PropertyDeclaration>,
- N: ToCss
+ N: ToCss,
{
try!(handle_first_serialization(dest, is_first_serialization));
@@ -443,6 +480,8 @@ pub fn append_serialization<'a, W, I, N>(dest: &mut W,
write!(dest, ";")
}
+/// A helper to parse the style attribute of an element, in order for this to be
+/// shared between Servo and Gecko.
pub fn parse_style_attribute(input: &str,
base_url: &ServoUrl,
error_reporter: StdBox<ParseErrorReporter + Send>,
@@ -452,6 +491,8 @@ pub fn parse_style_attribute(input: &str,
parse_property_declaration_list(&context, &mut Parser::new(input))
}
+/// Parse a given property declaration. Can result in multiple
+/// `PropertyDeclaration`s when expanding a longhand, for example.
pub fn parse_one_declaration(id: PropertyId,
input: &str,
base_url: &ServoUrl,
@@ -466,6 +507,7 @@ pub fn parse_one_declaration(id: PropertyId,
}
}
+/// A struct to parse property declarations.
struct PropertyDeclarationParser<'a, 'b: 'a> {
context: &'a ParserContext<'b>,
}
@@ -479,6 +521,11 @@ impl<'a, 'b> AtRuleParser for PropertyDeclarationParser<'a, 'b> {
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);
fn parse_value(&mut self, name: &str, input: &mut Parser)
@@ -500,7 +547,10 @@ impl<'a, 'b> DeclarationParser for PropertyDeclarationParser<'a, 'b> {
}
-pub fn parse_property_declaration_list(context: &ParserContext, input: &mut Parser)
+/// Parse a list of property declarations and return a property declaration
+/// block.
+pub fn parse_property_declaration_list(context: &ParserContext,
+ input: &mut Parser)
-> PropertyDeclarationBlock {
let mut declarations = Vec::new();
let mut important_count = 0;
diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs
index ab25f16e87d..9d7247130f2 100644
--- a/components/style/properties/properties.mako.rs
+++ b/components/style/properties/properties.mako.rs
@@ -467,10 +467,18 @@ impl ShorthandId {
}
}
- // 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".
- pub fn overflow_longhands_to_css<'a, W, I>(&self, declarations: I, dest: &mut W) -> fmt::Result
- where W: fmt::Write, I: Iterator<Item=&'a PropertyDeclaration> {
+ /// 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".
+ ///
+ /// We use this function as a special-case for that.
+ pub fn overflow_longhands_to_css<'a, W, I>(&self,
+ declarations: I,
+ dest: &mut W)
+ -> fmt::Result
+ where W: fmt::Write,
+ I: Iterator<Item=&'a PropertyDeclaration>,
+ {
match *self {
ShorthandId::Overflow => {
match shorthands::overflow::LonghandsToSerialize::from_iter(declarations) {