servo: Merge #14802 - Document more style modules (from emilio:no-missing-docs); r=Wafflespeanut

Source-Repo: https://github.com/servo/servo
Source-Revision: 2ebcad10f58151a1c531d80794a0211ba12cbeb0
This commit is contained in:
Emilio Cobos Álvarez 2016-12-31 15:34:51 -08:00
parent fe6309141e
commit b5757b5057
9 changed files with 285 additions and 79 deletions

View File

@ -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))

View File

@ -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>)

View File

@ -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");
}
}

View File

@ -4,6 +4,8 @@
//! States elements can be in.
#![deny(missing_docs)]
bitflags! {
#[doc = "Event-based element states."]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]

View File

@ -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) {

View File

@ -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
}

View File

@ -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>>,

View File

@ -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(())
}
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
/// 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>,
N: ToCss
{
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
where W: fmt::Write,
I: Iterator<Item=&'a PropertyDeclaration>,
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;

View File

@ -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) {