Auto merge of #14801 - emilio:no-missing-docs, r=mbrubeck,Manishearth,Wafflespeanut

style: Document and force documentation in a big chunk of the style crate.

Style no forced docs for the properties code and similar, but I ran out of time, and I think it's a nice improvement.

I'd appreciate a fast-ish turn-around time because this is pretty much prone to bitrot.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/14801)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-12-31 03:19:02 -08:00 committed by GitHub
commit bd67163438
44 changed files with 1216 additions and 462 deletions

View file

@ -88,7 +88,7 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
if let Animation::Transition(_, unsafe_node, _, ref frame, _) = running_animation { if let Animation::Transition(_, unsafe_node, _, ref frame, _) = running_animation {
script_chan.send(ConstellationControlMsg::TransitionEnd(unsafe_node, script_chan.send(ConstellationControlMsg::TransitionEnd(unsafe_node,
frame.property_animation frame.property_animation
.property_name(), .property_name().into(),
frame.duration)) frame.duration))
.unwrap(); .unwrap();
} }

View file

@ -2005,7 +2005,7 @@ impl Fragment {
} }
// See CSS 2.1 § 10.8.1. // See CSS 2.1 § 10.8.1.
let font_metrics = text::font_metrics_for_style(&mut layout_context.font_context(), let font_metrics = text::font_metrics_for_style(&mut layout_context.font_context(),
self.style.get_font_arc()); self.style.clone_font());
let line_height = text::line_height_from_style(&*self.style, &font_metrics); let line_height = text::line_height_from_style(&*self.style, &font_metrics);
InlineMetrics::from_font_metrics(&info.run.font_metrics, line_height) InlineMetrics::from_font_metrics(&info.run.font_metrics, line_height)
} }
@ -2085,7 +2085,7 @@ impl Fragment {
vertical_align::T::middle => { vertical_align::T::middle => {
let font_metrics = let font_metrics =
text::font_metrics_for_style(&mut layout_context.font_context(), text::font_metrics_for_style(&mut layout_context.font_context(),
style.get_font_arc()); style.clone_font());
offset += (content_inline_metrics.ascent - offset += (content_inline_metrics.ascent -
content_inline_metrics.space_below_baseline - content_inline_metrics.space_below_baseline -
font_metrics.x_height).scale_by(0.5) font_metrics.x_height).scale_by(0.5)

View file

@ -1089,7 +1089,7 @@ impl InlineFlow {
return LineMetrics::new(Au(0), Au(0)) return LineMetrics::new(Au(0), Au(0))
} }
let font_style = style.get_font_arc(); let font_style = style.clone_font();
let font_metrics = text::font_metrics_for_style(font_context, font_style); let font_metrics = text::font_metrics_for_style(font_context, font_style);
let line_height = text::line_height_from_style(style, &font_metrics); let line_height = text::line_height_from_style(style, &font_metrics);
let inline_metrics = InlineMetrics::from_font_metrics(&font_metrics, line_height); let inline_metrics = InlineMetrics::from_font_metrics(&font_metrics, line_height);
@ -1112,7 +1112,7 @@ impl InlineFlow {
for inline_context in fragments.iter() for inline_context in fragments.iter()
.filter_map(|fragment| fragment.inline_context.as_ref()) { .filter_map(|fragment| fragment.inline_context.as_ref()) {
for node in &inline_context.nodes { for node in &inline_context.nodes {
let font_style = node.style.get_font_arc(); let font_style = node.style.clone_font();
let font_metrics = text::font_metrics_for_style(font_context, font_style); let font_metrics = text::font_metrics_for_style(font_context, font_style);
let line_height = text::line_height_from_style(&*node.style, &font_metrics); let line_height = text::line_height_from_style(&*node.style, &font_metrics);
let inline_metrics = InlineMetrics::from_font_metrics(&font_metrics, line_height); let inline_metrics = InlineMetrics::from_font_metrics(&font_metrics, line_height);

View file

@ -154,7 +154,7 @@ impl TextRunScanner {
let word_break; let word_break;
{ {
let in_fragment = self.clump.front().unwrap(); let in_fragment = self.clump.front().unwrap();
let font_style = in_fragment.style().get_font_arc(); let font_style = in_fragment.style().clone_font();
let inherited_text_style = in_fragment.style().get_inheritedtext(); let inherited_text_style = in_fragment.style().get_inheritedtext();
fontgroup = font_context.layout_font_group_for_style(font_style); fontgroup = font_context.layout_font_group_for_style(font_style);
compression = match in_fragment.white_space() { compression = match in_fragment.white_space() {

View file

@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! CSS transitions and animations. //! CSS transitions and animations.
#![deny(missing_docs)]
use Atom; use Atom;
use bezier::Bezier; use bezier::Bezier;
@ -28,8 +29,9 @@ use values::computed::Time;
/// have to keep track the current iteration and the max iteration count. /// have to keep track the current iteration and the max iteration count.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum KeyframesIterationState { pub enum KeyframesIterationState {
/// Infinite iterations, so no need to track a state.
Infinite, Infinite,
// current, max /// Current and max iterations.
Finite(u32, u32), Finite(u32, u32),
} }
@ -192,6 +194,7 @@ pub enum Animation {
} }
impl Animation { impl Animation {
/// Mark this animation as expired.
#[inline] #[inline]
pub fn mark_as_expired(&mut self) { pub fn mark_as_expired(&mut self) {
debug_assert!(!self.is_expired()); debug_assert!(!self.is_expired());
@ -201,6 +204,7 @@ impl Animation {
} }
} }
/// Whether this animation is expired.
#[inline] #[inline]
pub fn is_expired(&self) -> bool { pub fn is_expired(&self) -> bool {
match *self { match *self {
@ -209,6 +213,7 @@ impl Animation {
} }
} }
/// The opaque node that owns the animation.
#[inline] #[inline]
pub fn node(&self) -> &OpaqueNode { pub fn node(&self) -> &OpaqueNode {
match *self { match *self {
@ -217,6 +222,7 @@ impl Animation {
} }
} }
/// Whether this animation is paused. A transition can never be paused.
#[inline] #[inline]
pub fn is_paused(&self) -> bool { pub fn is_paused(&self) -> bool {
match *self { match *self {
@ -237,6 +243,7 @@ pub struct AnimationFrame {
pub duration: f64, pub duration: f64,
} }
/// Represents an animation for a given property.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PropertyAnimation { pub struct PropertyAnimation {
property: AnimatedProperty, property: AnimatedProperty,
@ -245,13 +252,15 @@ pub struct PropertyAnimation {
} }
impl PropertyAnimation { impl PropertyAnimation {
pub fn property_name(&self) -> String { /// Returns the given property name.
pub fn property_name(&self) -> &'static str {
self.property.name() self.property.name()
} }
/// Creates a new property animation for the given transition index and old and new styles. /// Creates a new property animation for the given transition index and old
/// Any number of animations may be returned, from zero (if the property did not animate) to /// and new styles. Any number of animations may be returned, from zero (if
/// one (for a single transition property) to arbitrarily many (for `all`). /// the property did not animate) to one (for a single transition property)
/// to arbitrarily many (for `all`).
pub fn from_transition(transition_index: usize, pub fn from_transition(transition_index: usize,
old_style: &ComputedValues, old_style: &ComputedValues,
new_style: &mut ComputedValues) new_style: &mut ComputedValues)
@ -312,6 +321,7 @@ impl PropertyAnimation {
} }
} }
/// Update the given animation at a given point of progress.
pub fn update(&self, style: &mut ComputedValues, time: f64) { pub fn update(&self, style: &mut ComputedValues, time: f64) {
let progress = match self.timing_function { let progress = match self.timing_function {
TransitionTimingFunction::CubicBezier(p1, p2) => { TransitionTimingFunction::CubicBezier(p1, p2) => {
@ -336,8 +346,9 @@ impl PropertyAnimation {
self.property.does_animate() && self.duration != Time(0.0) self.property.does_animate() && self.duration != Time(0.0)
} }
/// Whether this animation has the same end value as another one.
#[inline] #[inline]
pub fn has_the_same_end_value_as(&self, other: &PropertyAnimation) -> bool { pub fn has_the_same_end_value_as(&self, other: &Self) -> bool {
self.property.has_the_same_end_value_as(&other.property) self.property.has_the_same_end_value_as(&other.property)
} }
} }
@ -428,6 +439,8 @@ fn compute_style_for_animation_step(context: &SharedStyleContext,
} }
} }
/// Triggers animations for a given node looking at the animation property
/// values.
pub fn maybe_start_animations(context: &SharedStyleContext, pub fn maybe_start_animations(context: &SharedStyleContext,
new_animations_sender: &Sender<Animation>, new_animations_sender: &Sender<Animation>,
node: OpaqueNode, node: OpaqueNode,

View file

@ -2,18 +2,22 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Two simple cache data structures. //! A simple LRU cache.
#![deny(missing_docs)]
use std::collections::hash_map::RandomState;
use std::hash::{Hash, Hasher, BuildHasher};
use std::slice::{Iter, IterMut}; use std::slice::{Iter, IterMut};
/// A LRU cache used to store a set of at most `n` elements at the same time.
///
/// Currently used for the style sharing candidate cache.
pub struct LRUCache<K, V> { pub struct LRUCache<K, V> {
entries: Vec<(K, V)>, entries: Vec<(K, V)>,
cache_size: usize, cache_size: usize,
} }
impl<K: PartialEq, V: Clone> LRUCache<K, V> { impl<K: PartialEq, V: Clone> LRUCache<K, V> {
/// Create a new LRU cache with `size` elements at most.
pub fn new(size: usize) -> LRUCache<K, V> { pub fn new(size: usize) -> LRUCache<K, V> {
LRUCache { LRUCache {
entries: vec![], entries: vec![],
@ -22,6 +26,7 @@ impl<K: PartialEq, V: Clone> LRUCache<K, V> {
} }
#[inline] #[inline]
/// Touch a given position, and put it in the last item on the list.
pub fn touch(&mut self, pos: usize) -> &V { pub fn touch(&mut self, pos: usize) -> &V {
let last_index = self.entries.len() - 1; let last_index = self.entries.len() - 1;
if pos != last_index { if pos != last_index {
@ -31,14 +36,17 @@ impl<K: PartialEq, V: Clone> LRUCache<K, V> {
&self.entries[last_index].1 &self.entries[last_index].1
} }
/// Iterate over the contents of this cache.
pub fn iter(&self) -> Iter<(K, V)> { pub fn iter(&self) -> Iter<(K, V)> {
self.entries.iter() self.entries.iter()
} }
/// Iterate mutably over the contents of this cache.
pub fn iter_mut(&mut self) -> IterMut<(K, V)> { pub fn iter_mut(&mut self) -> IterMut<(K, V)> {
self.entries.iter_mut() self.entries.iter_mut()
} }
/// Insert a given key and value in the cache.
pub fn insert(&mut self, key: K, val: V) { pub fn insert(&mut self, key: K, val: V) {
if self.entries.len() == self.cache_size { if self.entries.len() == self.cache_size {
self.entries.remove(0); self.entries.remove(0);
@ -46,6 +54,7 @@ impl<K: PartialEq, V: Clone> LRUCache<K, V> {
self.entries.push((key, val)); self.entries.push((key, val));
} }
/// Try to find a key in the cache.
pub fn find(&mut self, key: &K) -> Option<V> { pub fn find(&mut self, key: &K) -> Option<V> {
match self.entries.iter().position(|&(ref k, _)| key == k) { match self.entries.iter().position(|&(ref k, _)| key == k) {
Some(pos) => Some(self.touch(pos).clone()), Some(pos) => Some(self.touch(pos).clone()),
@ -53,7 +62,11 @@ impl<K: PartialEq, V: Clone> LRUCache<K, V> {
} }
} }
pub fn find_or_create<F>(&mut self, key: K, mut blk: F) -> V where F: FnMut() -> V { /// Try to find a given key, or create a given item with that key executing
/// `blk`.
pub fn find_or_create<F>(&mut self, key: K, mut blk: F) -> V
where F: FnMut() -> V,
{
match self.entries.iter().position(|&(ref k, _)| *k == key) { match self.entries.iter().position(|&(ref k, _)| *k == key) {
Some(pos) => self.touch(pos).clone(), Some(pos) => self.touch(pos).clone(),
None => { None => {
@ -64,61 +77,8 @@ impl<K: PartialEq, V: Clone> LRUCache<K, V> {
} }
} }
/// Evict all elements from the cache.
pub fn evict_all(&mut self) { pub fn evict_all(&mut self) {
self.entries.clear(); self.entries.clear();
} }
} }
pub struct SimpleHashCache<K, V> {
entries: Vec<Option<(K, V)>>,
random: RandomState,
}
impl<K: Clone + Eq + Hash, V: Clone> SimpleHashCache<K, V> {
pub fn new(cache_size: usize) -> SimpleHashCache<K, V> {
SimpleHashCache {
entries: vec![None; cache_size],
random: RandomState::new(),
}
}
#[inline]
fn to_bucket(&self, h: usize) -> usize {
h % self.entries.len()
}
#[inline]
fn bucket_for_key<Q: Hash>(&self, key: &Q) -> usize {
let mut hasher = self.random.build_hasher();
key.hash(&mut hasher);
self.to_bucket(hasher.finish() as usize)
}
pub fn insert(&mut self, key: K, value: V) {
let bucket_index = self.bucket_for_key(&key);
self.entries[bucket_index] = Some((key, value));
}
pub fn find<Q>(&self, key: &Q) -> Option<V> where Q: PartialEq<K> + Hash + Eq {
let bucket_index = self.bucket_for_key(key);
match self.entries[bucket_index] {
Some((ref existing_key, ref value)) if key == existing_key => Some((*value).clone()),
_ => None,
}
}
pub fn find_or_create<F>(&mut self, key: K, mut blk: F) -> V where F: FnMut() -> V {
if let Some(value) = self.find(&key) {
return value;
}
let value = blk();
self.insert(key, value.clone());
value
}
pub fn evict_all(&mut self) {
for slot in &mut self.entries {
*slot = None
}
}
}

View file

@ -4,6 +4,8 @@
//! Per-node data used in style calculation. //! Per-node data used in style calculation.
#![deny(missing_docs)]
use dom::TElement; use dom::TElement;
use properties::ComputedValues; use properties::ComputedValues;
use properties::longhands::display::computed_value as display; use properties::longhands::display::computed_value as display;
@ -19,6 +21,9 @@ use std::sync::Arc;
use stylist::Stylist; use stylist::Stylist;
use thread_state; use thread_state;
/// The structure that represents the result of style computation. This is
/// effectively a tuple of rules and computed values, that is, the rule node,
/// and the result of computing that rule node's rules, the `ComputedValues`.
#[derive(Clone)] #[derive(Clone)]
pub struct ComputedStyle { pub struct ComputedStyle {
/// The rule node representing the ordered list of rules matched for this /// The rule node representing the ordered list of rules matched for this
@ -31,6 +36,7 @@ pub struct ComputedStyle {
} }
impl ComputedStyle { impl ComputedStyle {
/// Trivially construct a new `ComputedStyle`.
pub fn new(rules: StrongRuleNode, values: Arc<ComputedValues>) -> Self { pub fn new(rules: StrongRuleNode, values: Arc<ComputedValues>) -> Self {
ComputedStyle { ComputedStyle {
rules: rules, rules: rules,
@ -49,10 +55,18 @@ impl fmt::Debug for ComputedStyle {
type PseudoStylesInner = HashMap<PseudoElement, ComputedStyle, type PseudoStylesInner = HashMap<PseudoElement, ComputedStyle,
BuildHasherDefault<::fnv::FnvHasher>>; BuildHasherDefault<::fnv::FnvHasher>>;
/// A set of styles for a given element's pseudo-elements.
///
/// This is a map from pseudo-element to `ComputedStyle`.
///
/// TODO(emilio): This should probably be a small array by default instead of a
/// full-blown `HashMap`.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PseudoStyles(PseudoStylesInner); pub struct PseudoStyles(PseudoStylesInner);
impl PseudoStyles { impl PseudoStyles {
/// Construct an empty set of `PseudoStyles`.
pub fn empty() -> Self { pub fn empty() -> Self {
PseudoStyles(HashMap::with_hasher(Default::default())) PseudoStyles(HashMap::with_hasher(Default::default()))
} }
@ -71,11 +85,14 @@ impl DerefMut for PseudoStyles {
/// pseudo-elements. /// pseudo-elements.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ElementStyles { pub struct ElementStyles {
/// The element's style.
pub primary: ComputedStyle, pub primary: ComputedStyle,
/// The map of styles for the element's pseudos.
pub pseudos: PseudoStyles, pub pseudos: PseudoStyles,
} }
impl ElementStyles { impl ElementStyles {
/// Trivially construct a new `ElementStyles`.
pub fn new(primary: ComputedStyle) -> Self { pub fn new(primary: ComputedStyle) -> Self {
ElementStyles { ElementStyles {
primary: primary, primary: primary,
@ -83,6 +100,7 @@ impl ElementStyles {
} }
} }
/// Whether this element `display` value is `none`.
pub fn is_display_none(&self) -> bool { pub fn is_display_none(&self) -> bool {
self.primary.values.get_box().clone_display() == display::T::none self.primary.values.get_box().clone_display() == display::T::none
} }
@ -127,7 +145,9 @@ impl DescendantRestyleHint {
/// to provide more type safety while propagating restyle hints down the tree. /// to provide more type safety while propagating restyle hints down the tree.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct StoredRestyleHint { pub struct StoredRestyleHint {
/// Whether this element should be restyled during the traversal.
pub restyle_self: bool, pub restyle_self: bool,
/// Whether the descendants of this element need to be restyled.
pub descendants: DescendantRestyleHint, pub descendants: DescendantRestyleHint,
} }
@ -140,6 +160,7 @@ impl StoredRestyleHint {
} }
} }
/// Creates an empty `StoredRestyleHint`.
pub fn empty() -> Self { pub fn empty() -> Self {
StoredRestyleHint { StoredRestyleHint {
restyle_self: false, restyle_self: false,
@ -147,6 +168,8 @@ impl StoredRestyleHint {
} }
} }
/// Creates a restyle hint that forces the whole subtree to be restyled,
/// including the element.
pub fn subtree() -> Self { pub fn subtree() -> Self {
StoredRestyleHint { StoredRestyleHint {
restyle_self: true, restyle_self: true,
@ -154,10 +177,12 @@ impl StoredRestyleHint {
} }
} }
/// Whether the restyle hint is empty (nothing requires to be restyled).
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
!self.restyle_self && self.descendants == DescendantRestyleHint::Empty !self.restyle_self && self.descendants == DescendantRestyleHint::Empty
} }
/// Insert another restyle hint, effectively resulting in the union of both.
pub fn insert(&mut self, other: &Self) { pub fn insert(&mut self, other: &Self) {
self.restyle_self = self.restyle_self || other.restyle_self; self.restyle_self = self.restyle_self || other.restyle_self;
self.descendants = self.descendants.union(other.descendants); self.descendants = self.descendants.union(other.descendants);
@ -185,11 +210,11 @@ impl From<RestyleHint> for StoredRestyleHint {
} }
} }
// We really want to store an Option<Snapshot> here, but we can't drop Gecko
// Snapshots off-main-thread. So we make a convenient little wrapper to provide
// the semantics of Option<Snapshot>, while deferring the actual drop.
static NO_SNAPSHOT: Option<Snapshot> = None; static NO_SNAPSHOT: Option<Snapshot> = None;
/// We really want to store an Option<Snapshot> here, but we can't drop Gecko
/// Snapshots off-main-thread. So we make a convenient little wrapper to provide
/// the semantics of Option<Snapshot>, while deferring the actual drop.
#[derive(Debug)] #[derive(Debug)]
pub struct SnapshotOption { pub struct SnapshotOption {
snapshot: Option<Snapshot>, snapshot: Option<Snapshot>,
@ -197,6 +222,7 @@ pub struct SnapshotOption {
} }
impl SnapshotOption { impl SnapshotOption {
/// An empty snapshot.
pub fn empty() -> Self { pub fn empty() -> Self {
SnapshotOption { SnapshotOption {
snapshot: None, snapshot: None,
@ -204,11 +230,13 @@ impl SnapshotOption {
} }
} }
/// Destroy this snapshot.
pub fn destroy(&mut self) { pub fn destroy(&mut self) {
self.destroyed = true; self.destroyed = true;
debug_assert!(self.is_none()); debug_assert!(self.is_none());
} }
/// Ensure a snapshot is available and return a mutable reference to it.
pub fn ensure<F: FnOnce() -> Snapshot>(&mut self, create: F) -> &mut Snapshot { pub fn ensure<F: FnOnce() -> Snapshot>(&mut self, create: F) -> &mut Snapshot {
debug_assert!(thread_state::get().is_layout()); debug_assert!(thread_state::get().is_layout());
if self.is_none() { if self.is_none() {
@ -234,7 +262,12 @@ impl Deref for SnapshotOption {
/// Transient data used by the restyle algorithm. This structure is instantiated /// Transient data used by the restyle algorithm. This structure is instantiated
/// either before or during restyle traversal, and is cleared at the end of node /// either before or during restyle traversal, and is cleared at the end of node
/// processing. /// processing.
///
/// TODO(emilio): Tell bholley to document this more accurately. I can try (and
/// the fields are certainly mostly self-explanatory), but it's better if he
/// does, to avoid any misconception.
#[derive(Debug)] #[derive(Debug)]
#[allow(missing_docs)]
pub struct RestyleData { pub struct RestyleData {
pub styles: ElementStyles, pub styles: ElementStyles,
pub hint: StoredRestyleHint, pub hint: StoredRestyleHint,
@ -254,8 +287,8 @@ impl RestyleData {
} }
} }
/// Expands the snapshot (if any) into a restyle hint. Returns true if later siblings /// Expands the snapshot (if any) into a restyle hint. Returns true if later
/// must be restyled. /// siblings must be restyled.
pub fn expand_snapshot<E: TElement>(&mut self, element: E, stylist: &Stylist) -> bool { pub fn expand_snapshot<E: TElement>(&mut self, element: E, stylist: &Stylist) -> bool {
if self.snapshot.is_none() { if self.snapshot.is_none() {
return false; return false;
@ -281,14 +314,17 @@ impl RestyleData {
later_siblings later_siblings
} }
/// Return if the element style's are up to date.
pub fn has_current_styles(&self) -> bool { pub fn has_current_styles(&self) -> bool {
!(self.hint.restyle_self || self.recascade || self.snapshot.is_some()) !(self.hint.restyle_self || self.recascade || self.snapshot.is_some())
} }
/// Returns the element styles.
pub fn styles(&self) -> &ElementStyles { pub fn styles(&self) -> &ElementStyles {
&self.styles &self.styles
} }
/// Returns a mutable reference to the element styles.
pub fn styles_mut(&mut self) -> &mut ElementStyles { pub fn styles_mut(&mut self) -> &mut ElementStyles {
&mut self.styles &mut self.styles
} }
@ -317,12 +353,18 @@ impl RestyleData {
/// safety. /// safety.
#[derive(Debug)] #[derive(Debug)]
pub enum ElementData { pub enum ElementData {
/// This is the first styling for this element.
Initial(Option<ElementStyles>), Initial(Option<ElementStyles>),
/// This element has been restyled already, and all the relevant data is
/// inside the `RestyleData`.
Restyle(RestyleData), Restyle(RestyleData),
/// This element has already been restyled, and only keeps its styles
/// around.
Persistent(ElementStyles), Persistent(ElementStyles),
} }
impl ElementData { impl ElementData {
/// Trivially construct an ElementData.
pub fn new(existing: Option<ElementStyles>) -> Self { pub fn new(existing: Option<ElementStyles>) -> Self {
if let Some(s) = existing { if let Some(s) = existing {
ElementData::Persistent(s) ElementData::Persistent(s)
@ -331,6 +373,7 @@ impl ElementData {
} }
} }
/// Return whether this data is from an initial restyle.
pub fn is_initial(&self) -> bool { pub fn is_initial(&self) -> bool {
match *self { match *self {
ElementData::Initial(_) => true, ElementData::Initial(_) => true,
@ -338,6 +381,7 @@ impl ElementData {
} }
} }
/// Return whether this data is from an element that hasn't been restyled.
pub fn is_unstyled_initial(&self) -> bool { pub fn is_unstyled_initial(&self) -> bool {
match *self { match *self {
ElementData::Initial(None) => true, ElementData::Initial(None) => true,
@ -345,6 +389,8 @@ impl ElementData {
} }
} }
/// Return whether this data is from an element whose first restyle has just
/// been done.
pub fn is_styled_initial(&self) -> bool { pub fn is_styled_initial(&self) -> bool {
match *self { match *self {
ElementData::Initial(Some(_)) => true, ElementData::Initial(Some(_)) => true,
@ -352,6 +398,8 @@ impl ElementData {
} }
} }
/// Returns true if this element is being restyled and has been styled
/// before.
pub fn is_restyle(&self) -> bool { pub fn is_restyle(&self) -> bool {
match *self { match *self {
ElementData::Restyle(_) => true, ElementData::Restyle(_) => true,
@ -359,6 +407,7 @@ impl ElementData {
} }
} }
/// Returns the `RestyleData` if it exists.
pub fn as_restyle(&self) -> Option<&RestyleData> { pub fn as_restyle(&self) -> Option<&RestyleData> {
match *self { match *self {
ElementData::Restyle(ref x) => Some(x), ElementData::Restyle(ref x) => Some(x),
@ -366,6 +415,7 @@ impl ElementData {
} }
} }
/// Returns a mutable reference to the RestyleData, if it exists.
pub fn as_restyle_mut(&mut self) -> Option<&mut RestyleData> { pub fn as_restyle_mut(&mut self) -> Option<&mut RestyleData> {
match *self { match *self {
ElementData::Restyle(ref mut x) => Some(x), ElementData::Restyle(ref mut x) => Some(x),
@ -373,6 +423,7 @@ impl ElementData {
} }
} }
/// Returns whether this element's style is persistent.
pub fn is_persistent(&self) -> bool { pub fn is_persistent(&self) -> bool {
match *self { match *self {
ElementData::Persistent(_) => true, ElementData::Persistent(_) => true,
@ -428,6 +479,7 @@ impl ElementData {
*self = ElementData::Persistent(styles); *self = ElementData::Persistent(styles);
} }
/// Return the restyle damage (if any).
pub fn damage(&self) -> RestyleDamage { pub fn damage(&self) -> RestyleDamage {
use self::ElementData::*; use self::ElementData::*;
match *self { match *self {
@ -443,8 +495,8 @@ impl ElementData {
} }
} }
// A version of the above, with the assertions replaced with warnings to /// A version of the above, with the assertions replaced with warnings to
// be more robust in corner-cases. This will go away soon. /// be more robust in corner-cases. This will go away soon.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub fn damage_sloppy(&self) -> RestyleDamage { pub fn damage_sloppy(&self) -> RestyleDamage {
use self::ElementData::*; use self::ElementData::*;
@ -476,6 +528,7 @@ impl ElementData {
} }
} }
/// Get the element styles, if any.
pub fn get_styles(&self) -> Option<&ElementStyles> { pub fn get_styles(&self) -> Option<&ElementStyles> {
use self::ElementData::*; use self::ElementData::*;
match *self { match *self {
@ -485,10 +538,12 @@ impl ElementData {
} }
} }
/// Get the element styles. Panic if the element has never been styled.
pub fn styles(&self) -> &ElementStyles { pub fn styles(&self) -> &ElementStyles {
self.get_styles().expect("Calling styles() on unstyled ElementData") self.get_styles().expect("Calling styles() on unstyled ElementData")
} }
/// Get a mutable reference to the element styles, if any.
pub fn get_styles_mut(&mut self) -> Option<&mut ElementStyles> { pub fn get_styles_mut(&mut self) -> Option<&mut ElementStyles> {
use self::ElementData::*; use self::ElementData::*;
match *self { match *self {
@ -498,10 +553,14 @@ impl ElementData {
} }
} }
/// Get a mutable reference to the element styles. Panic if the element has
/// never been styled.
pub fn styles_mut(&mut self) -> &mut ElementStyles { pub fn styles_mut(&mut self) -> &mut ElementStyles {
self.get_styles_mut().expect("Calling styles_mut() on unstyled ElementData") self.get_styles_mut().expect("Calling styles_mut() on unstyled ElementData")
} }
/// Finishes the styling of the element, effectively setting the style in
/// the data.
pub fn finish_styling(&mut self, styles: ElementStyles, damage: RestyleDamage) { pub fn finish_styling(&mut self, styles: ElementStyles, damage: RestyleDamage) {
use self::ElementData::*; use self::ElementData::*;
match *self { match *self {

View file

@ -5,6 +5,7 @@
//! Types and traits used to access the DOM from style calculation. //! Types and traits used to access the DOM from style calculation.
#![allow(unsafe_code)] #![allow(unsafe_code)]
#![deny(missing_docs)]
use {Atom, Namespace, LocalName}; use {Atom, Namespace, LocalName};
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
@ -48,15 +49,24 @@ impl OpaqueNode {
/// We avoid exposing the full type id, since computing it in the general case /// We avoid exposing the full type id, since computing it in the general case
/// would be difficult for Gecko nodes. /// would be difficult for Gecko nodes.
pub trait NodeInfo { pub trait NodeInfo {
/// Whether this node is an element.
fn is_element(&self) -> bool; fn is_element(&self) -> bool;
/// Whether this node is a text node.
fn is_text_node(&self) -> bool; fn is_text_node(&self) -> bool;
// Comments, doctypes, etc are ignored by layout algorithms. /// Whether this node needs layout.
///
/// Comments, doctypes, etc are ignored by layout algorithms.
fn needs_layout(&self) -> bool { self.is_element() || self.is_text_node() } fn needs_layout(&self) -> bool { self.is_element() || self.is_text_node() }
} }
/// A node iterator that only returns node that don't need layout.
pub struct LayoutIterator<T>(pub T); pub struct LayoutIterator<T>(pub T);
impl<T, I> Iterator for LayoutIterator<T> where T: Iterator<Item=I>, I: NodeInfo {
impl<T, I> Iterator for LayoutIterator<T>
where T: Iterator<Item=I>,
I: NodeInfo,
{
type Item = I; type Item = I;
fn next(&mut self) -> Option<I> { fn next(&mut self) -> Option<I> {
loop { loop {
@ -69,11 +79,22 @@ impl<T, I> Iterator for LayoutIterator<T> where T: Iterator<Item=I>, I: NodeInfo
} }
} }
/// The `TNode` trait. This is the main generic trait over which the style
/// system can be implemented.
pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo { pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo {
/// The concrete `TElement` type.
type ConcreteElement: TElement<ConcreteNode = Self>; type ConcreteElement: TElement<ConcreteNode = Self>;
/// A concrete children iterator type in order to iterate over the `Node`s.
///
/// TODO(emilio): We should eventually replace this with the `impl Trait`
/// syntax.
type ConcreteChildrenIterator: Iterator<Item = Self>; type ConcreteChildrenIterator: Iterator<Item = Self>;
/// Convert this node in an `UnsafeNode`.
fn to_unsafe(&self) -> UnsafeNode; fn to_unsafe(&self) -> UnsafeNode;
/// Get a node back from an `UnsafeNode`.
unsafe fn from_unsafe(n: &UnsafeNode) -> Self; unsafe fn from_unsafe(n: &UnsafeNode) -> Self;
/// Returns an iterator over this node's children. /// Returns an iterator over this node's children.
@ -82,24 +103,35 @@ pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo {
/// Converts self into an `OpaqueNode`. /// Converts self into an `OpaqueNode`.
fn opaque(&self) -> OpaqueNode; fn opaque(&self) -> OpaqueNode;
/// Get this node's parent element if present.
fn parent_element(&self) -> Option<Self::ConcreteElement> { fn parent_element(&self) -> Option<Self::ConcreteElement> {
self.parent_node().and_then(|n| n.as_element()) self.parent_node().and_then(|n| n.as_element())
} }
/// A debug id, only useful, mm... for debugging.
fn debug_id(self) -> usize; fn debug_id(self) -> usize;
/// Get this node as an element, if it's one.
fn as_element(&self) -> Option<Self::ConcreteElement>; fn as_element(&self) -> Option<Self::ConcreteElement>;
/// Whether this node needs to be laid out on viewport size change.
fn needs_dirty_on_viewport_size_changed(&self) -> bool; fn needs_dirty_on_viewport_size_changed(&self) -> bool;
/// Mark this node as needing layout on viewport size change.
unsafe fn set_dirty_on_viewport_size_changed(&self); unsafe fn set_dirty_on_viewport_size_changed(&self);
/// Whether this node can be fragmented. This is used for multicol, and only
/// for Servo.
fn can_be_fragmented(&self) -> bool; fn can_be_fragmented(&self) -> bool;
/// Set whether this node can be fragmented.
unsafe fn set_can_be_fragmented(&self, value: bool); unsafe fn set_can_be_fragmented(&self, value: bool);
/// Get this node's parent node.
fn parent_node(&self) -> Option<Self>; fn parent_node(&self) -> Option<Self>;
/// Whether this node is in the document right now needed to clear the
/// restyle data appropriately on some forced restyles.
fn is_in_doc(&self) -> bool; fn is_in_doc(&self) -> bool;
} }
@ -187,14 +219,20 @@ fn fmt_subtree<F, N: TNode>(f: &mut fmt::Formatter, stringify: &F, n: N, indent:
Ok(()) Ok(())
} }
/// A trait used to synthesize presentational hints for HTML element attributes.
pub trait PresentationalHintsSynthetizer { pub trait PresentationalHintsSynthetizer {
/// Generate the proper applicable declarations due to presentational hints,
/// and insert them into `hints`.
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V) fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V)
where V: Push<ApplicableDeclarationBlock>; where V: Push<ApplicableDeclarationBlock>;
} }
/// The element trait, the main abstraction the style crate acts over.
pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer { pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer {
/// The concrete node type.
type ConcreteNode: TNode<ConcreteElement = Self>; type ConcreteNode: TNode<ConcreteElement = Self>;
/// Get this element as a node.
fn as_node(&self) -> Self::ConcreteNode; fn as_node(&self) -> Self::ConcreteNode;
/// While doing a reflow, the element at the root has no parent, as far as we're /// While doing a reflow, the element at the root has no parent, as far as we're
@ -207,16 +245,25 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
} }
} }
/// Get this element's style attribute.
fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>>; fn style_attribute(&self) -> Option<&Arc<RwLock<PropertyDeclarationBlock>>>;
/// Get this element's state, for non-tree-structural pseudos.
fn get_state(&self) -> ElementState; fn get_state(&self) -> ElementState;
/// Whether this element has an attribute with a given namespace.
fn has_attr(&self, namespace: &Namespace, attr: &LocalName) -> bool; fn has_attr(&self, namespace: &Namespace, attr: &LocalName) -> bool;
/// Whether an attribute value equals `value`.
fn attr_equals(&self, namespace: &Namespace, attr: &LocalName, value: &Atom) -> bool; fn attr_equals(&self, namespace: &Namespace, attr: &LocalName, value: &Atom) -> bool;
/// XXX: It's a bit unfortunate we need to pass the current computed values /// Get the pre-existing style to calculate restyle damage (change hints).
/// as an argument here, but otherwise Servo would crash due to double ///
/// borrows to return it. /// This needs to be generic since it varies between Servo and Gecko.
///
/// XXX(emilio): It's a bit unfortunate we need to pass the current computed
/// values as an argument here, but otherwise Servo would crash due to
/// double borrows to return it.
fn existing_style_for_restyle_damage<'a>(&'a self, fn existing_style_for_restyle_damage<'a>(&'a self,
current_computed_values: Option<&'a Arc<ComputedValues>>, current_computed_values: Option<&'a Arc<ComputedValues>>,
pseudo: Option<&PseudoElement>) pseudo: Option<&PseudoElement>)
@ -270,11 +317,13 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
/// about our parallel traversal. However, there are certain situations /// about our parallel traversal. However, there are certain situations
/// (including but not limited to the traversal) where we need to send DOM /// (including but not limited to the traversal) where we need to send DOM
/// objects to other threads. /// objects to other threads.
///
/// That's the reason why `SendNode` exists.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct SendNode<N: TNode>(N); pub struct SendNode<N: TNode>(N);
unsafe impl<N: TNode> Send for SendNode<N> {} unsafe impl<N: TNode> Send for SendNode<N> {}
impl<N: TNode> SendNode<N> { impl<N: TNode> SendNode<N> {
/// Unsafely construct a SendNode.
pub unsafe fn new(node: N) -> Self { pub unsafe fn new(node: N) -> Self {
SendNode(node) SendNode(node)
} }
@ -286,10 +335,13 @@ impl<N: TNode> Deref for SendNode<N> {
} }
} }
/// Same reason as for the existence of SendNode, SendElement does the proper
/// things for a given `TElement`.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct SendElement<E: TElement>(E); pub struct SendElement<E: TElement>(E);
unsafe impl<E: TElement> Send for SendElement<E> {} unsafe impl<E: TElement> Send for SendElement<E> {}
impl<E: TElement> SendElement<E> { impl<E: TElement> SendElement<E> {
/// Unsafely construct a SendElement.
pub unsafe fn new(el: E) -> Self { pub unsafe fn new(el: E) -> Self {
SendElement(el) SendElement(el)
} }

View file

@ -182,15 +182,24 @@ pub fn arc_ptr_eq<T: 'static>(a: &Arc<T>, b: &Arc<T>) -> bool {
(a as *const T) == (b as *const T) (a as *const T) == (b as *const T)
} }
pub fn serialize_comma_separated_list<W, T>(dest: &mut W, list: &[T]) /// Serializes as CSS a comma-separated list of any `T` that supports being
-> fmt::Result where W: fmt::Write, T: ToCss { /// serialized as CSS.
if list.len() > 0 { pub fn serialize_comma_separated_list<W, T>(dest: &mut W,
for item in &list[..list.len()-1] { list: &[T])
try!(item.to_css(dest)); -> fmt::Result
try!(write!(dest, ", ")); where W: fmt::Write,
} T: ToCss,
list[list.len()-1].to_css(dest) {
} else { if list.is_empty() {
Ok(()) return Ok(());
} }
try!(list[0].to_css(dest));
for item in list.iter().skip(1) {
try!(write!(dest, ", "));
try!(item.to_css(dest));
}
Ok(())
} }

View file

@ -20,6 +20,8 @@
//! easy to grep for. At the time of this writing, there is no other unsafe //! easy to grep for. At the time of this writing, there is no other unsafe
//! code in the parallel traversal. //! code in the parallel traversal.
#![deny(missing_docs)]
use dom::{OpaqueNode, SendNode, TElement, TNode}; use dom::{OpaqueNode, SendNode, TElement, TNode};
use rayon; use rayon;
use scoped_tls::ScopedTLS; use scoped_tls::ScopedTLS;
@ -28,8 +30,12 @@ use std::sync::atomic::Ordering;
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken}; use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};
use traversal::{STYLE_SHARING_CACHE_HITS, STYLE_SHARING_CACHE_MISSES}; use traversal::{STYLE_SHARING_CACHE_HITS, STYLE_SHARING_CACHE_MISSES};
/// The chunk size used to split the parallel traversal nodes.
///
/// We send each `CHUNK_SIZE` nodes as a different work unit to the work queue.
pub const CHUNK_SIZE: usize = 64; pub const CHUNK_SIZE: usize = 64;
/// A parallel top down traversal, generic over `D`.
#[allow(unsafe_code)] #[allow(unsafe_code)]
pub fn traverse_dom<N, D>(traversal: &D, pub fn traverse_dom<N, D>(traversal: &D,
root: N::ConcreteElement, root: N::ConcreteElement,
@ -37,7 +43,7 @@ pub fn traverse_dom<N, D>(traversal: &D,
token: PreTraverseToken, token: PreTraverseToken,
queue: &rayon::ThreadPool) queue: &rayon::ThreadPool)
where N: TNode, where N: TNode,
D: DomTraversal<N> D: DomTraversal<N>,
{ {
if opts::get().style_sharing_stats { if opts::get().style_sharing_stats {
STYLE_SHARING_CACHE_HITS.store(0, Ordering::SeqCst); STYLE_SHARING_CACHE_HITS.store(0, Ordering::SeqCst);
@ -181,7 +187,7 @@ fn bottom_up_dom<N, D>(traversal: &D,
root: OpaqueNode, root: OpaqueNode,
mut node: N) mut node: N)
where N: TNode, where N: TNode,
D: DomTraversal<N> D: DomTraversal<N>,
{ {
loop { loop {
// Perform the appropriate operation. // Perform the appropriate operation.

View file

@ -405,9 +405,10 @@ pub fn append_serialization<'a, W, I, N>(dest: &mut W,
importance: Importance, importance: Importance,
is_first_serialization: &mut bool) is_first_serialization: &mut bool)
-> fmt::Result -> fmt::Result
where W: fmt::Write, where W: fmt::Write,
I: Iterator<Item=&'a PropertyDeclaration>, I: Iterator<Item=&'a PropertyDeclaration>,
N: ToCss { N: ToCss
{
try!(handle_first_serialization(dest, is_first_serialization)); 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 // Overflow does not behave like a normal shorthand. When overflow-x and overflow-y are not of equal
@ -525,4 +526,3 @@ pub fn parse_property_declaration_list(context: &ParserContext, input: &mut Pars
super::deduplicate_property_declarations(&mut block); super::deduplicate_property_declarations(&mut block);
block block
} }

View file

@ -73,16 +73,21 @@
use values::{computed, specified}; use values::{computed, specified};
${caller.body()} ${caller.body()}
} }
/// The definition of the computed value for ${name}.
pub mod computed_value { pub mod computed_value {
pub use super::single_value::computed_value as single_value; pub use super::single_value::computed_value as single_value;
pub use self::single_value::T as SingleComputedValue; pub use self::single_value::T as SingleComputedValue;
/// The computed value, effectively a list of single values.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct T(pub Vec<single_value::T>); pub struct T(pub Vec<single_value::T>);
} }
impl ToCss for computed_value::T { impl ToCss for computed_value::T {
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 iter = self.0.iter(); let mut iter = self.0.iter();
if let Some(val) = iter.next() { if let Some(val) = iter.next() {
try!(val.to_css(dest)); try!(val.to_css(dest));
@ -101,12 +106,15 @@
} }
} }
/// The specified value of ${name}.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SpecifiedValue(pub Vec<single_value::SpecifiedValue>); pub struct SpecifiedValue(pub Vec<single_value::SpecifiedValue>);
impl ToCss for SpecifiedValue { impl ToCss for SpecifiedValue {
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 iter = self.0.iter(); let mut iter = self.0.iter();
if let Some(val) = iter.next() { if let Some(val) = iter.next() {
try!(val.to_css(dest)); try!(val.to_css(dest));
@ -405,7 +413,11 @@
} }
impl<'a> LonghandsToSerialize<'a> { impl<'a> LonghandsToSerialize<'a> {
pub fn from_iter<I: Iterator<Item=&'a PropertyDeclaration>>(iter: I) -> Result<Self, ()> { /// Tries to get a serializable set of longhands given a set of
/// property declarations.
pub fn from_iter<I>(iter: I) -> Result<Self, ()>
where I: Iterator<Item=&'a PropertyDeclaration>,
{
// Define all of the expected variables that correspond to the shorthand // Define all of the expected variables that correspond to the shorthand
% for sub_property in shorthand.sub_properties: % for sub_property in shorthand.sub_properties:
let mut ${sub_property.ident} = None; let mut ${sub_property.ident} = None;
@ -446,7 +458,9 @@
} }
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> ToCss for LonghandsToSerialize<'a> {
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 all_flags = SerializeFlags::all(); let mut all_flags = SerializeFlags::all();
let mut with_variables = false; let mut with_variables = false;
% for sub_property in shorthand.sub_properties: % for sub_property in shorthand.sub_properties:
@ -477,7 +491,10 @@
} }
pub fn parse(context: &ParserContext, input: &mut Parser, /// Parse the given shorthand and fill the result into the
/// `declarations` vector.
pub fn parse(context: &ParserContext,
input: &mut Parser,
declarations: &mut Vec<PropertyDeclaration>) declarations: &mut Vec<PropertyDeclaration>)
-> Result<(), ()> { -> Result<(), ()> {
input.look_for_var_functions(); input.look_for_var_functions();

View file

@ -32,14 +32,18 @@ use values::computed::ToComputedValue;
/// A given transition property, that is either `All`, or an animatable
/// property.
// NB: This needs to be here because it needs all the longhands generated // NB: This needs to be here because it needs all the longhands generated
// beforehand. // beforehand.
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum TransitionProperty { pub enum TransitionProperty {
/// All, any animatable property changing should generate a transition.
All, All,
% for prop in data.longhands: % for prop in data.longhands:
% if prop.animatable: % if prop.animatable:
/// ${prop.name}
${prop.camel_case}, ${prop.camel_case},
% endif % endif
% endfor % endfor
@ -55,6 +59,7 @@ impl TransitionProperty {
% endfor % endfor
} }
/// Parse a transition-property value.
pub fn parse(input: &mut Parser) -> Result<Self, ()> { pub fn parse(input: &mut Parser) -> Result<Self, ()> {
match_ignore_ascii_case! { try!(input.expect_ident()), match_ignore_ascii_case! { try!(input.expect_ident()),
"all" => Ok(TransitionProperty::All), "all" => Ok(TransitionProperty::All),
@ -67,6 +72,7 @@ impl TransitionProperty {
} }
} }
/// Get a transition property from a property declaration.
pub fn from_declaration(declaration: &PropertyDeclaration) -> Option<Self> { pub fn from_declaration(declaration: &PropertyDeclaration) -> Option<Self> {
match *declaration { match *declaration {
% for prop in data.longhands: % for prop in data.longhands:
@ -81,7 +87,9 @@ impl TransitionProperty {
} }
impl ToCss for TransitionProperty { impl ToCss for TransitionProperty {
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,
{
match *self { match *self {
TransitionProperty::All => dest.write_str("all"), TransitionProperty::All => dest.write_str("all"),
% for prop in data.longhands: % for prop in data.longhands:
@ -93,11 +101,14 @@ impl ToCss for TransitionProperty {
} }
} }
/// An animated property interpolation between two computed values for that
/// property.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum AnimatedProperty { pub enum AnimatedProperty {
% for prop in data.longhands: % for prop in data.longhands:
% if prop.animatable: % if prop.animatable:
/// ${prop.name}
${prop.camel_case}(longhands::${prop.ident}::computed_value::T, ${prop.camel_case}(longhands::${prop.ident}::computed_value::T,
longhands::${prop.ident}::computed_value::T), longhands::${prop.ident}::computed_value::T),
% endif % endif
@ -105,16 +116,19 @@ pub enum AnimatedProperty {
} }
impl AnimatedProperty { impl AnimatedProperty {
pub fn name(&self) -> String { /// Get the name of this property.
pub fn name(&self) -> &'static str {
match *self { match *self {
% for prop in data.longhands: % for prop in data.longhands:
% if prop.animatable: % if prop.animatable:
AnimatedProperty::${prop.camel_case}(..) => "${prop.name}".to_owned(), AnimatedProperty::${prop.camel_case}(..) => "${prop.name}",
% endif % endif
% endfor % endfor
} }
} }
/// Whether this interpolation does animate, that is, whether the start and
/// end values are different.
pub fn does_animate(&self) -> bool { pub fn does_animate(&self) -> bool {
match *self { match *self {
% for prop in data.longhands: % for prop in data.longhands:
@ -125,7 +139,8 @@ impl AnimatedProperty {
} }
} }
pub fn has_the_same_end_value_as(&self, other: &AnimatedProperty) -> bool { /// Whether an animated property has the same end value as another.
pub fn has_the_same_end_value_as(&self, other: &Self) -> bool {
match (self, other) { match (self, other) {
% for prop in data.longhands: % for prop in data.longhands:
% if prop.animatable: % if prop.animatable:
@ -139,6 +154,8 @@ impl AnimatedProperty {
} }
} }
/// Update `style` with the proper computed style corresponding to this
/// animation at `progress`.
pub fn update(&self, style: &mut ComputedValues, progress: f64) { pub fn update(&self, style: &mut ComputedValues, progress: f64) {
match *self { match *self {
% for prop in data.longhands: % for prop in data.longhands:
@ -153,6 +170,8 @@ impl AnimatedProperty {
} }
} }
/// Get an animatable value from a transition-property, an old style, and a
/// new style.
pub fn from_transition_property(transition_property: &TransitionProperty, pub fn from_transition_property(transition_property: &TransitionProperty,
old_style: &ComputedValues, old_style: &ComputedValues,
new_style: &ComputedValues) new_style: &ComputedValues)
@ -188,12 +207,15 @@ impl AnimatedProperty {
pub enum AnimationValue { pub enum AnimationValue {
% for prop in data.longhands: % for prop in data.longhands:
% if prop.animatable: % if prop.animatable:
/// ${prop.name}
${prop.camel_case}(longhands::${prop.ident}::computed_value::T), ${prop.camel_case}(longhands::${prop.ident}::computed_value::T),
% endif % endif
% endfor % endfor
} }
impl AnimationValue { impl AnimationValue {
/// "Uncompute" this animation value in order to be used inside the CSS
/// cascade.
pub fn uncompute(&self) -> PropertyDeclaration { pub fn uncompute(&self) -> PropertyDeclaration {
use properties::{longhands, DeclaredValue}; use properties::{longhands, DeclaredValue};
match *self { match *self {
@ -234,6 +256,7 @@ impl Interpolate for AnimationValue {
/// ///
/// [interpolated-types]: https://drafts.csswg.org/css-transitions/#interpolated-types /// [interpolated-types]: https://drafts.csswg.org/css-transitions/#interpolated-types
pub trait Interpolate: Sized { pub trait Interpolate: Sized {
/// Interpolate a value with another for a given property.
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()>; fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()>;
} }
@ -249,6 +272,7 @@ impl<T: RepeatableListInterpolate> Interpolate for Vec<T> {
}).collect() }).collect()
} }
} }
/// https://drafts.csswg.org/css-transitions/#animtype-number /// https://drafts.csswg.org/css-transitions/#animtype-number
impl Interpolate for Au { impl Interpolate for Au {
#[inline] #[inline]
@ -257,7 +281,9 @@ impl Interpolate for Au {
} }
} }
impl <T> Interpolate for Option<T> where T: Interpolate { impl <T> Interpolate for Option<T>
where T: Interpolate,
{
#[inline] #[inline]
fn interpolate(&self, other: &Option<T>, progress: f64) -> Result<Option<T>, ()> { fn interpolate(&self, other: &Option<T>, progress: f64) -> Result<Option<T>, ()> {
match (self, other) { match (self, other) {
@ -431,7 +457,7 @@ impl Interpolate for CalcLengthOrPercentage {
other: Option<T>, other: Option<T>,
progress: f64) progress: f64)
-> Result<Option<T>, ()> -> Result<Option<T>, ()>
where T: Default + Interpolate where T: Default + Interpolate,
{ {
match (this, other) { match (this, other) {
(None, None) => Ok(None), (None, None) => Ok(None),
@ -919,27 +945,36 @@ impl Interpolate for LengthOrNone {
} }
} }
/// A 2d matrix for interpolation.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct InnerMatrix2D { pub struct InnerMatrix2D {
pub m11: CSSFloat, pub m12: CSSFloat, pub m11: CSSFloat, pub m12: CSSFloat,
pub m21: CSSFloat, pub m22: CSSFloat, pub m21: CSSFloat, pub m22: CSSFloat,
} }
/// A 2d translation function.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Translate2D(f32, f32); pub struct Translate2D(f32, f32);
/// A 2d scale function.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Scale2D(f32, f32); pub struct Scale2D(f32, f32);
/// A decomposed 2d matrix.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct MatrixDecomposed2D { pub struct MatrixDecomposed2D {
/// The translation function.
pub translate: Translate2D, pub translate: Translate2D,
/// The scale function.
pub scale: Scale2D, pub scale: Scale2D,
/// The rotation angle.
pub angle: f32, pub angle: f32,
/// The inner matrix.
pub matrix: InnerMatrix2D, pub matrix: InnerMatrix2D,
} }
@ -1143,33 +1178,44 @@ impl Interpolate for LengthOrNone {
} }
} }
/// A 3d translation.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Translate3D(f32, f32, f32); pub struct Translate3D(f32, f32, f32);
/// A 3d scale function.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Scale3D(f32, f32, f32); pub struct Scale3D(f32, f32, f32);
/// A 3d skew function.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Skew(f32, f32, f32); pub struct Skew(f32, f32, f32);
/// A 3d perspective transformation.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Perspective(f32, f32, f32, f32); pub struct Perspective(f32, f32, f32, f32);
/// A quaternion used to represent a rotation.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Quaternion(f32, f32, f32, f32); pub struct Quaternion(f32, f32, f32, f32);
/// A decomposed 3d matrix.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct MatrixDecomposed3D { pub struct MatrixDecomposed3D {
/// A translation function.
pub translate: Translate3D, pub translate: Translate3D,
/// A scale function.
pub scale: Scale3D, pub scale: Scale3D,
/// The skew component of the transformation.
pub skew: Skew, pub skew: Skew,
/// The perspective component of the transformation.
pub perspective: Perspective, pub perspective: Perspective,
/// The quaternion used to represent the rotation.
pub quaternion: Quaternion, pub quaternion: Quaternion,
} }
@ -1513,7 +1559,7 @@ impl Interpolate for LengthOrNone {
self.m43 != 0.0 || self.m44 != 1.0 self.m43 != 0.0 || self.m44 != 1.0
} }
pub fn determinant(&self) -> CSSFloat { fn determinant(&self) -> CSSFloat {
self.m14 * self.m23 * self.m32 * self.m41 - self.m14 * self.m23 * self.m32 * self.m41 -
self.m13 * self.m24 * self.m32 * self.m41 - self.m13 * self.m24 * self.m32 * self.m41 -
self.m14 * self.m22 * self.m33 * self.m41 + self.m14 * self.m22 * self.m33 * self.m41 +

View file

@ -87,89 +87,102 @@ ${helpers.predefined_type("background-color", "CSSColor",
</%helpers:vector_longhand> </%helpers:vector_longhand>
<%helpers:vector_longhand name="background-position-x" animatable="True"> <%helpers:vector_longhand name="background-position-x" animatable="True">
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::ToCss;
use values::HasViewportPercentage; use values::HasViewportPercentage;
use values::specified::position::HorizontalPosition; use values::specified::position::HorizontalPosition;
pub mod computed_value { #[allow(missing_docs)]
use values::computed::position::HorizontalPosition; pub mod computed_value {
use properties::animated_properties::{Interpolate, RepeatableListInterpolate}; use values::computed::position::HorizontalPosition;
use properties::animated_properties::{Interpolate, RepeatableListInterpolate};
pub type T = HorizontalPosition; pub type T = HorizontalPosition;
} }
pub type SpecifiedValue = HorizontalPosition; #[allow(missing_docs)]
pub type SpecifiedValue = HorizontalPosition;
#[inline] #[inline]
pub fn get_initial_value() -> computed_value::T { #[allow(missing_docs)]
use values::computed::position::HorizontalPosition; pub fn get_initial_value() -> computed_value::T {
HorizontalPosition(computed::LengthOrPercentage::Percentage(0.0)) use values::computed::position::HorizontalPosition;
HorizontalPosition(computed::LengthOrPercentage::Percentage(0.0))
}
#[inline]
#[allow(missing_docs)]
pub fn get_initial_specified_value() -> SpecifiedValue {
use values::specified::position::Keyword;
HorizontalPosition {
keyword: Some(Keyword::Left),
position: None,
} }
#[inline] }
pub fn get_initial_specified_value() -> SpecifiedValue { #[inline]
use values::specified::position::Keyword; #[allow(missing_docs)]
HorizontalPosition { pub fn get_initial_position_value() -> SpecifiedValue {
keyword: Some(Keyword::Left), use values::specified::{LengthOrPercentage, Percentage};
position: None, HorizontalPosition {
} keyword: None,
} position: Some(LengthOrPercentage::Percentage(Percentage(0.0))),
#[inline]
pub fn get_initial_position_value() -> SpecifiedValue {
use values::specified::{LengthOrPercentage, Percentage};
HorizontalPosition {
keyword: None,
position: Some(LengthOrPercentage::Percentage(Percentage(0.0))),
}
} }
}
pub fn parse(context: &ParserContext, input: &mut Parser) #[allow(missing_docs)]
-> Result<SpecifiedValue, ()> { pub fn parse(context: &ParserContext, input: &mut Parser)
HorizontalPosition::parse(context, input) -> Result<SpecifiedValue, ()> {
} HorizontalPosition::parse(context, input)
}
</%helpers:vector_longhand> </%helpers:vector_longhand>
<%helpers:vector_longhand name="background-position-y" animatable="True"> <%helpers:vector_longhand name="background-position-y" animatable="True">
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::ToCss;
use values::HasViewportPercentage; use values::HasViewportPercentage;
use values::specified::position::VerticalPosition; use values::specified::position::VerticalPosition;
pub mod computed_value { #[allow(missing_docs)]
use values::computed::position::VerticalPosition; pub mod computed_value {
use properties::animated_properties::{Interpolate, RepeatableListInterpolate}; use values::computed::position::VerticalPosition;
use properties::animated_properties::{Interpolate, RepeatableListInterpolate};
pub type T = VerticalPosition; pub type T = VerticalPosition;
} }
pub type SpecifiedValue = VerticalPosition; #[allow(missing_docs)]
pub type SpecifiedValue = VerticalPosition;
#[inline] #[inline]
pub fn get_initial_value() -> computed_value::T { #[allow(missing_docs)]
use values::computed::position::VerticalPosition; pub fn get_initial_value() -> computed_value::T {
VerticalPosition(computed::LengthOrPercentage::Percentage(0.0)) use values::computed::position::VerticalPosition;
VerticalPosition(computed::LengthOrPercentage::Percentage(0.0))
}
#[inline]
#[allow(missing_docs)]
pub fn get_initial_specified_value() -> SpecifiedValue {
use values::specified::position::Keyword;
VerticalPosition {
keyword: Some(Keyword::Top),
position: None,
} }
#[inline] }
pub fn get_initial_specified_value() -> SpecifiedValue { #[inline]
use values::specified::position::Keyword; #[allow(missing_docs)]
VerticalPosition { pub fn get_initial_position_value() -> SpecifiedValue {
keyword: Some(Keyword::Top), use values::specified::{LengthOrPercentage, Percentage};
position: None, VerticalPosition {
} keyword: None,
} position: Some(LengthOrPercentage::Percentage(Percentage(0.0))),
#[inline]
pub fn get_initial_position_value() -> SpecifiedValue {
use values::specified::{LengthOrPercentage, Percentage};
VerticalPosition {
keyword: None,
position: Some(LengthOrPercentage::Percentage(Percentage(0.0))),
}
} }
}
pub fn parse(context: &ParserContext, input: &mut Parser) #[inline]
-> Result<SpecifiedValue, ()> { #[allow(missing_docs)]
VerticalPosition::parse(context, input) pub fn parse(context: &ParserContext, input: &mut Parser)
} -> Result<SpecifiedValue, ()> {
VerticalPosition::parse(context, input)
}
</%helpers:vector_longhand> </%helpers:vector_longhand>
${helpers.single_keyword("background-repeat", ${helpers.single_keyword("background-repeat",
@ -199,6 +212,7 @@ ${helpers.single_keyword("background-origin",
use style_traits::ToCss; use style_traits::ToCss;
use values::HasViewportPercentage; use values::HasViewportPercentage;
#[allow(missing_docs)]
pub mod computed_value { pub mod computed_value {
use values::computed::LengthOrPercentageOrAuto; use values::computed::LengthOrPercentageOrAuto;
use properties::animated_properties::{Interpolate, RepeatableListInterpolate}; use properties::animated_properties::{Interpolate, RepeatableListInterpolate};
@ -254,6 +268,7 @@ ${helpers.single_keyword("background-origin",
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct ExplicitSize { pub struct ExplicitSize {
pub width: specified::LengthOrPercentageOrAuto, pub width: specified::LengthOrPercentageOrAuto,
pub height: specified::LengthOrPercentageOrAuto, pub height: specified::LengthOrPercentageOrAuto,

View file

@ -46,7 +46,8 @@
impl ToCss for T { impl ToCss for T {
fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result
where W: ::std::fmt::Write { where W: ::std::fmt::Write,
{
match *self { match *self {
% for value in values: % for value in values:
T::${to_rust_ident(value)} => dest.write_str("${value}"), T::${to_rust_ident(value)} => dest.write_str("${value}"),
@ -55,9 +56,14 @@
} }
} }
} }
#[inline] pub fn get_initial_value() -> computed_value::T {
/// The initial display value.
#[inline]
pub fn get_initial_value() -> computed_value::T {
computed_value::T::${to_rust_ident(values[0])} computed_value::T::${to_rust_ident(values[0])}
} }
/// Parse a display value.
pub fn parse(_context: &ParserContext, input: &mut Parser) pub fn parse(_context: &ParserContext, input: &mut Parser)
-> Result<SpecifiedValue, ()> { -> Result<SpecifiedValue, ()> {
match_ignore_ascii_case! { try!(input.expect_ident()), match_ignore_ascii_case! { try!(input.expect_ident()),
@ -144,119 +150,128 @@ ${helpers.single_keyword("clear", "none left right both",
</%helpers:longhand> </%helpers:longhand>
<%helpers:longhand name="vertical-align" <%helpers:longhand name="vertical-align" animatable="True">
animatable="True"> use std::fmt;
use std::fmt; use style_traits::ToCss;
use style_traits::ToCss; use values::HasViewportPercentage;
use values::HasViewportPercentage;
<% vertical_align = data.longhands_by_name["vertical-align"] %> <% vertical_align = data.longhands_by_name["vertical-align"] %>
<% vertical_align.keyword = Keyword("vertical-align", <% vertical_align.keyword = Keyword("vertical-align",
"baseline sub super top text-top middle bottom text-bottom", "baseline sub super top text-top middle bottom text-bottom",
extra_gecko_values="middle-with-baseline") %> extra_gecko_values="middle-with-baseline") %>
<% vertical_align_keywords = vertical_align.keyword.values_for(product) %> <% vertical_align_keywords = vertical_align.keyword.values_for(product) %>
impl HasViewportPercentage for SpecifiedValue { impl HasViewportPercentage for SpecifiedValue {
fn has_viewport_percentage(&self) -> bool { fn has_viewport_percentage(&self) -> bool {
match *self { match *self {
SpecifiedValue::LengthOrPercentage(length) => length.has_viewport_percentage(), SpecifiedValue::LengthOrPercentage(length) => length.has_viewport_percentage(),
_ => false _ => false
} }
} }
} }
#[allow(non_camel_case_types)] /// The `vertical-align` value.
#[derive(Debug, Clone, PartialEq, Copy)] #[allow(non_camel_case_types)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[derive(Debug, Clone, PartialEq, Copy)]
pub enum SpecifiedValue { #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
% for keyword in vertical_align_keywords: pub enum SpecifiedValue {
${to_rust_ident(keyword)}, % for keyword in vertical_align_keywords:
% endfor ${to_rust_ident(keyword)},
LengthOrPercentage(specified::LengthOrPercentage), % endfor
} LengthOrPercentage(specified::LengthOrPercentage),
}
impl ToCss for SpecifiedValue { impl ToCss for SpecifiedValue {
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 {
match *self { match *self {
% for keyword in vertical_align_keywords: % for keyword in vertical_align_keywords:
SpecifiedValue::${to_rust_ident(keyword)} => dest.write_str("${keyword}"), SpecifiedValue::${to_rust_ident(keyword)} => dest.write_str("${keyword}"),
% endfor % endfor
SpecifiedValue::LengthOrPercentage(value) => value.to_css(dest), SpecifiedValue::LengthOrPercentage(value) => value.to_css(dest),
} }
} }
} }
/// baseline | sub | super | top | text-top | middle | bottom | text-bottom /// baseline | sub | super | top | text-top | middle | bottom | text-bottom
/// | <percentage> | <length> /// | <percentage> | <length>
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
input.try(|i| specified::LengthOrPercentage::parse(context, i)) input.try(|i| specified::LengthOrPercentage::parse(context, i))
.map(SpecifiedValue::LengthOrPercentage) .map(SpecifiedValue::LengthOrPercentage)
.or_else(|()| { .or_else(|_| {
match_ignore_ascii_case! { try!(input.expect_ident()), match_ignore_ascii_case! { try!(input.expect_ident()),
% for keyword in vertical_align_keywords: % for keyword in vertical_align_keywords:
"${keyword}" => Ok(SpecifiedValue::${to_rust_ident(keyword)}), "${keyword}" => Ok(SpecifiedValue::${to_rust_ident(keyword)}),
% endfor % endfor
_ => Err(()) _ => Err(())
} }
}) })
} }
pub mod computed_value {
use app_units::Au;
use std::fmt;
use style_traits::ToCss;
use values::{CSSFloat, computed};
#[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum T {
% for keyword in vertical_align_keywords:
${to_rust_ident(keyword)},
% endfor
LengthOrPercentage(computed::LengthOrPercentage),
}
impl ToCss for T {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
% for keyword in vertical_align_keywords:
T::${to_rust_ident(keyword)} => dest.write_str("${keyword}"),
% endfor
T::LengthOrPercentage(value) => value.to_css(dest),
}
}
}
}
#[inline]
pub fn get_initial_value() -> computed_value::T { computed_value::T::baseline }
impl ToComputedValue for SpecifiedValue { /// The computed value for `vertical-align`.
type ComputedValue = computed_value::T; pub mod computed_value {
use app_units::Au;
use std::fmt;
use style_traits::ToCss;
use values::{CSSFloat, computed};
#[inline] /// The keywords are the same, and the `LengthOrPercentage` is computed
fn to_computed_value(&self, context: &Context) -> computed_value::T { /// here.
match *self { #[allow(non_camel_case_types)]
% for keyword in vertical_align_keywords: #[derive(PartialEq, Copy, Clone, Debug)]
SpecifiedValue::${to_rust_ident(keyword)} => { #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
computed_value::T::${to_rust_ident(keyword)} pub enum T {
} % for keyword in vertical_align_keywords:
% endfor ${to_rust_ident(keyword)},
SpecifiedValue::LengthOrPercentage(value) => % endfor
computed_value::T::LengthOrPercentage(value.to_computed_value(context)), LengthOrPercentage(computed::LengthOrPercentage),
} }
} impl ToCss for T {
#[inline] fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
fn from_computed_value(computed: &computed_value::T) -> Self { match *self {
match *computed { % for keyword in vertical_align_keywords:
% for keyword in vertical_align_keywords: T::${to_rust_ident(keyword)} => dest.write_str("${keyword}"),
computed_value::T::${to_rust_ident(keyword)} => { % endfor
SpecifiedValue::${to_rust_ident(keyword)} T::LengthOrPercentage(value) => value.to_css(dest),
} }
% endfor }
computed_value::T::LengthOrPercentage(value) => }
SpecifiedValue::LengthOrPercentage( }
ToComputedValue::from_computed_value(&value)
), /// The initial computed value for `vertical-align`.
} #[inline]
} pub fn get_initial_value() -> computed_value::T {
} computed_value::T::baseline
}
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value(&self, context: &Context) -> computed_value::T {
match *self {
% for keyword in vertical_align_keywords:
SpecifiedValue::${to_rust_ident(keyword)} => {
computed_value::T::${to_rust_ident(keyword)}
}
% endfor
SpecifiedValue::LengthOrPercentage(value) =>
computed_value::T::LengthOrPercentage(value.to_computed_value(context)),
}
}
#[inline]
fn from_computed_value(computed: &computed_value::T) -> Self {
match *computed {
% for keyword in vertical_align_keywords:
computed_value::T::${to_rust_ident(keyword)} => {
SpecifiedValue::${to_rust_ident(keyword)}
}
% endfor
computed_value::T::LengthOrPercentage(value) =>
SpecifiedValue::LengthOrPercentage(
ToComputedValue::from_computed_value(&value)
),
}
}
}
</%helpers:longhand> </%helpers:longhand>
@ -275,44 +290,51 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
gecko_constant_prefix="NS_STYLE_OVERFLOW")} gecko_constant_prefix="NS_STYLE_OVERFLOW")}
// FIXME(pcwalton, #2742): Implement scrolling for `scroll` and `auto`. // FIXME(pcwalton, #2742): Implement scrolling for `scroll` and `auto`.
<%helpers:longhand name="overflow-y" <%helpers:longhand name="overflow-y" need_clone="True" animatable="False">
need_clone="True" use super::overflow_x;
animatable="False">
use super::overflow_x;
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::ToCss;
use values::computed::ComputedValueAsSpecified; use values::computed::ComputedValueAsSpecified;
use values::NoViewportPercentage; use values::NoViewportPercentage;
pub use self::computed_value::T as SpecifiedValue; pub use self::computed_value::T as SpecifiedValue;
impl NoViewportPercentage for SpecifiedValue {} impl NoViewportPercentage for SpecifiedValue {}
impl ToCss for SpecifiedValue { impl ToCss for SpecifiedValue {
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 {
self.0.to_css(dest) self.0.to_css(dest)
} }
} }
pub mod computed_value {
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct T(pub super::super::overflow_x::computed_value::T);
}
impl ComputedValueAsSpecified for SpecifiedValue {} /// The specified and computed value for overflow-y is a wrapper on top of
/// `overflow-x`, so we re-use the logic, but prevent errors from mistakenly
/// assign one to other.
///
/// TODO(Manishearth, emilio): We may want to just use the same value.
pub mod computed_value {
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct T(pub super::super::overflow_x::computed_value::T);
}
pub fn get_initial_value() -> computed_value::T { impl ComputedValueAsSpecified for SpecifiedValue {}
computed_value::T(overflow_x::get_initial_value())
}
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> { #[inline]
overflow_x::parse(context, input).map(SpecifiedValue) #[allow(missing_docs)]
} pub fn get_initial_value() -> computed_value::T {
computed_value::T(overflow_x::get_initial_value())
}
#[inline]
#[allow(missing_docs)]
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
overflow_x::parse(context, input).map(SpecifiedValue)
}
</%helpers:longhand> </%helpers:longhand>
// TODO(pcwalton): Multiple transitions.
<%helpers:longhand name="transition-duration" <%helpers:longhand name="transition-duration"
need_index="True" need_index="True"
animatable="False"> animatable="False">
@ -369,7 +391,6 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
</%helpers:longhand> </%helpers:longhand>
// TODO(pcwalton): Lots more timing functions. // TODO(pcwalton): Lots more timing functions.
// TODO(pcwalton): Multiple transitions.
<%helpers:longhand name="transition-timing-function" <%helpers:longhand name="transition-timing-function"
need_index="True" need_index="True"
animatable="False"> animatable="False">

View file

@ -315,7 +315,10 @@ ${helpers.single_keyword("font-variant-caps",
use app_units::Au; use app_units::Au;
pub type T = Au; pub type T = Au;
} }
#[inline] pub fn get_initial_value() -> computed_value::T {
#[inline]
#[allow(missing_docs)]
pub fn get_initial_value() -> computed_value::T {
Au::from_px(FONT_MEDIUM_PX) Au::from_px(FONT_MEDIUM_PX)
} }

View file

@ -158,7 +158,13 @@ pub mod shorthands {
<%include file="/shorthand/text.mako.rs" /> <%include file="/shorthand/text.mako.rs" />
} }
/// A module with all the code related to animated properties.
///
/// This needs to be "included" by mako at least after all longhand modules,
/// given they populate the global data.
pub mod animated_properties { pub mod animated_properties {
#![deny(missing_docs)]
<%include file="/helpers/animated_properties.mako.rs" /> <%include file="/helpers/animated_properties.mako.rs" />
} }
@ -461,15 +467,21 @@ impl ShorthandId {
} }
} }
/// Serializes possible shorthand name with value to input buffer given a list of longhand declarations. /// Serializes the possible shorthand name with value to input buffer given
/// On success, returns true if shorthand value is written and false if no shorthand value is present. /// a list of longhand declarations.
///
/// On success, returns true if the shorthand value is written, or false if
/// no shorthand value is present.
pub fn serialize_shorthand_to_buffer<'a, W, I>(self, pub fn serialize_shorthand_to_buffer<'a, W, I>(self,
dest: &mut W, dest: &mut W,
declarations: I, declarations: I,
is_first_serialization: &mut bool, is_first_serialization: &mut bool,
importance: Importance) importance: Importance)
-> Result<bool, fmt::Error> -> Result<bool, fmt::Error>
where W: Write, I: IntoIterator<Item=&'a PropertyDeclaration>, I::IntoIter: Clone { where W: Write,
I: IntoIterator<Item=&'a PropertyDeclaration>,
I::IntoIter: Clone,
{
match self.get_shorthand_appendable_value(declarations) { match self.get_shorthand_appendable_value(declarations) {
None => Ok(false), None => Ok(false),
Some(appendable_value) => { Some(appendable_value) => {
@ -484,60 +496,73 @@ impl ShorthandId {
} }
} }
fn get_shorthand_appendable_value<'a, I>(self, declarations: I) fn get_shorthand_appendable_value<'a, I>(self,
declarations: I)
-> Option<AppendableValue<'a, I::IntoIter>> -> Option<AppendableValue<'a, I::IntoIter>>
where I: IntoIterator<Item=&'a PropertyDeclaration>, I::IntoIter: Clone { where I: IntoIterator<Item=&'a PropertyDeclaration>,
let declarations = declarations.into_iter(); I::IntoIter: Clone,
{
let declarations = declarations.into_iter();
// Only cloning iterators (a few pointers each) not declarations. // Only cloning iterators (a few pointers each) not declarations.
let mut declarations2 = declarations.clone(); let mut declarations2 = declarations.clone();
let mut declarations3 = declarations.clone(); let mut declarations3 = declarations.clone();
let first_declaration = match declarations2.next() { let first_declaration = match declarations2.next() {
Some(declaration) => declaration, Some(declaration) => declaration,
None => return None None => return None
}; };
// https://drafts.csswg.org/css-variables/#variables-in-shorthands // https://drafts.csswg.org/css-variables/#variables-in-shorthands
if let Some(css) = first_declaration.with_variables_from_shorthand(self) { if let Some(css) = first_declaration.with_variables_from_shorthand(self) {
if declarations2.all(|d| d.with_variables_from_shorthand(self) == Some(css)) { if declarations2.all(|d| d.with_variables_from_shorthand(self) == Some(css)) {
return Some(AppendableValue::Css(css)); return Some(AppendableValue::Css(css));
} }
else { return None;
return None; }
}
}
if !declarations3.any(|d| d.with_variables()) { if !declarations3.any(|d| d.with_variables()) {
return Some(AppendableValue::DeclarationsForShorthand(self, declarations)); return Some(AppendableValue::DeclarationsForShorthand(self, declarations));
} }
None None
} }
} }
/// Servo's representation of a declared value for a given `T`, which is the
/// declared value for that property.
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum DeclaredValue<T> { pub enum DeclaredValue<T> {
/// A known specified value from the stylesheet.
Value(T), Value(T),
/// A value that contained any css variables.
WithVariables { WithVariables {
/// The css serialization for this value.
css: String, css: String,
/// The first token type for this serialization.
first_token_type: TokenSerializationType, first_token_type: TokenSerializationType,
/// The base url.
base_url: ServoUrl, base_url: ServoUrl,
/// The shorthand this came from.
from_shorthand: Option<ShorthandId>, from_shorthand: Option<ShorthandId>,
}, },
/// The `initial` keyword.
Initial, Initial,
/// The `inherit` keyword.
Inherit, Inherit,
/// The `unset` keyword.
Unset, Unset,
} }
impl<T: HasViewportPercentage> HasViewportPercentage for DeclaredValue<T> { impl<T: HasViewportPercentage> HasViewportPercentage for DeclaredValue<T> {
fn has_viewport_percentage(&self) -> bool { fn has_viewport_percentage(&self) -> bool {
match *self { match *self {
DeclaredValue::Value(ref v) DeclaredValue::Value(ref v) => v.has_viewport_percentage(),
=> v.has_viewport_percentage(), DeclaredValue::WithVariables { .. } => {
DeclaredValue::WithVariables { .. } panic!("DeclaredValue::has_viewport_percentage without \
=> panic!("DeclaredValue::has_viewport_percentage without resolving variables!"), resolving variables!")
},
DeclaredValue::Initial | DeclaredValue::Initial |
DeclaredValue::Inherit | DeclaredValue::Inherit |
DeclaredValue::Unset => false, DeclaredValue::Unset => false,
@ -615,7 +640,9 @@ impl fmt::Debug for PropertyId {
} }
impl ToCss for PropertyId { impl ToCss for PropertyId {
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,
{
match *self { match *self {
PropertyId::Longhand(id) => dest.write_str(id.name()), PropertyId::Longhand(id) => dest.write_str(id.name()),
PropertyId::Shorthand(id) => dest.write_str(id.name()), PropertyId::Shorthand(id) => dest.write_str(id.name()),
@ -1150,19 +1177,22 @@ pub struct ComputedValues {
% endfor % endfor
custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>, custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
shareable: bool, shareable: bool,
/// The writing mode of this computed values struct.
pub writing_mode: WritingMode, pub writing_mode: WritingMode,
/// The root element's computed font size.
pub root_font_size: Au, pub root_font_size: Au,
} }
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
impl ComputedValues { impl ComputedValues {
/// Construct a `ComputedValues` instance.
pub fn new(custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>, pub fn new(custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
shareable: bool, shareable: bool,
writing_mode: WritingMode, writing_mode: WritingMode,
root_font_size: Au, root_font_size: Au,
% for style_struct in data.active_style_structs(): % for style_struct in data.active_style_structs():
${style_struct.ident}: Arc<style_structs::${style_struct.name}>, ${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
% endfor % endfor
) -> Self { ) -> Self {
ComputedValues { ComputedValues {
custom_properties: custom_properties, custom_properties: custom_properties,
@ -1322,11 +1352,6 @@ impl ComputedValues {
)) ))
} }
#[inline]
pub fn get_font_arc(&self) -> Arc<style_structs::Font> {
self.font.clone()
}
// http://dev.w3.org/csswg/css-transforms/#grouping-property-values // http://dev.w3.org/csswg/css-transforms/#grouping-property-values
pub fn get_used_transform_style(&self) -> computed_values::transform_style::T { pub fn get_used_transform_style(&self) -> computed_values::transform_style::T {
use computed_values::mix_blend_mode; use computed_values::mix_blend_mode;
@ -1820,16 +1845,21 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
} }
if seen.get_font_style() || seen.get_font_weight() || seen.get_font_stretch() || if seen.get_font_style() || seen.get_font_weight() || seen.get_font_stretch() ||
seen.get_font_family() { seen.get_font_family() {
style.mutate_font().compute_font_hash(); style.mutate_font().compute_font_hash();
} }
style style
} }
/// Modifies the style for an anonymous flow so it resets all its non-inherited
/// style structs, and set their borders and outlines to zero.
///
/// Also, it gets a new display value, which is honored except when it's
/// `inline`.
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
pub fn modify_style_for_anonymous_flow(style: &mut Arc<ComputedValues>, pub fn modify_style_for_anonymous_flow(style: &mut Arc<ComputedValues>,
new_display_value: longhands::display::computed_value::T) { new_display_value: longhands::display::computed_value::T) {
// The 'align-self' property needs some special treatment since // The 'align-self' property needs some special treatment since
// its value depends on the 'align-items' value of its parent. // its value depends on the 'align-items' value of its parent.
% if "align-items" in data.longhands_by_name: % if "align-items" in data.longhands_by_name:
@ -1869,12 +1899,17 @@ pub fn modify_style_for_anonymous_flow(style: &mut Arc<ComputedValues>,
outline.outline_width = Au(0); outline.outline_width = Au(0);
} }
/// Alters the given style to accommodate replaced content. This is called in flow construction. It /// Alters the given style to accommodate replaced content. This is called in
/// handles cases like `<div style="position: absolute">foo bar baz</div>` (in which `foo`, `bar`, /// flow construction. It handles cases like:
/// and `baz` must not be absolutely-positioned) and cases like `<sup>Foo</sup>` (in which the
/// `vertical-align: top` style of `sup` must not propagate down into `Foo`).
/// ///
/// FIXME(#5625, pcwalton): It would probably be cleaner and faster to do this in the cascade. /// <div style="position: absolute">foo bar baz</div>
///
/// (in which `foo`, `bar`, and `baz` must not be absolutely-positioned) and
/// cases like `<sup>Foo</sup>` (in which the `vertical-align: top` style of
/// `sup` must not propagate down into `Foo`).
///
/// FIXME(#5625, pcwalton): It would probably be cleaner and faster to do this
/// in the cascade.
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
#[inline] #[inline]
pub fn modify_style_for_replaced_content(style: &mut Arc<ComputedValues>) { pub fn modify_style_for_replaced_content(style: &mut Arc<ComputedValues>) {
@ -1907,11 +1942,11 @@ pub fn modify_style_for_replaced_content(style: &mut Arc<ComputedValues>) {
} }
} }
/// Adjusts borders as appropriate to account for a fragment's status as the first or last fragment /// Adjusts borders as appropriate to account for a fragment's status as the
/// within the range of an element. /// first or last fragment within the range of an element.
/// ///
/// Specifically, this function sets border widths to zero on the sides for which the fragment is /// Specifically, this function sets border widths to zero on the sides for
/// not outermost. /// which the fragment is not outermost.
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
#[inline] #[inline]
pub fn modify_border_style_for_inline_sides(style: &mut Arc<ComputedValues>, pub fn modify_border_style_for_inline_sides(style: &mut Arc<ComputedValues>,
@ -1963,7 +1998,8 @@ pub fn modify_border_style_for_inline_sides(style: &mut Arc<ComputedValues>,
} }
} }
/// Adjusts the `position` property as necessary for the outer fragment wrapper of an inline-block. /// Adjusts the `position` property as necessary for the outer fragment wrapper
/// of an inline-block.
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
#[inline] #[inline]
pub fn modify_style_for_outer_inline_block_fragment(style: &mut Arc<ComputedValues>) { pub fn modify_style_for_outer_inline_block_fragment(style: &mut Arc<ComputedValues>) {
@ -1972,10 +2008,11 @@ pub fn modify_style_for_outer_inline_block_fragment(style: &mut Arc<ComputedValu
box_style.position = longhands::position::computed_value::T::static_ box_style.position = longhands::position::computed_value::T::static_
} }
/// Adjusts the `position` and `padding` properties as necessary to account for text. /// Adjusts the `position` and `padding` properties as necessary to account for
/// text.
/// ///
/// Text is never directly relatively positioned; it's always contained within an element that is /// Text is never directly relatively positioned; it's always contained within
/// itself relatively positioned. /// an element that is itself relatively positioned.
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
#[inline] #[inline]
pub fn modify_style_for_text(style: &mut Arc<ComputedValues>) { pub fn modify_style_for_text(style: &mut Arc<ComputedValues>) {
@ -2009,8 +2046,8 @@ pub fn modify_style_for_text(style: &mut Arc<ComputedValues>) {
} }
} }
/// Adjusts the `clip` property so that an inline absolute hypothetical fragment doesn't clip its /// Adjusts the `clip` property so that an inline absolute hypothetical fragment
/// children. /// doesn't clip its children.
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
pub fn modify_style_for_inline_absolute_hypothetical_fragment(style: &mut Arc<ComputedValues>) { pub fn modify_style_for_inline_absolute_hypothetical_fragment(style: &mut Arc<ComputedValues>) {
if style.get_effects().clip.0.is_some() { if style.get_effects().clip.0.is_some() {

View file

@ -7,8 +7,16 @@ use style_traits::ToCss;
use values::specified::{BorderStyle, CSSColor}; use values::specified::{BorderStyle, CSSColor};
use std::fmt; use std::fmt;
pub fn serialize_four_sides<W, I>(dest: &mut W, top: &I, right: &I, bottom: &I, left: &I) #[allow(missing_docs)]
-> fmt::Result where W: fmt::Write, I: ToCss + PartialEq { pub fn serialize_four_sides<W, I>(dest: &mut W,
top: &I,
right: &I,
bottom: &I,
left: &I)
-> fmt::Result
where W: fmt::Write,
I: ToCss + PartialEq,
{
if left == right { if left == right {
let horizontal_value = left; let horizontal_value = left;
@ -85,8 +93,10 @@ fn serialize_directional_border<W, I>(dest: &mut W,
} }
#[allow(missing_docs)]
pub fn is_overflow_shorthand<'a, I>(appendable_value: &AppendableValue<'a, I>) -> bool pub fn is_overflow_shorthand<'a, I>(appendable_value: &AppendableValue<'a, I>) -> bool
where I: Iterator<Item=&'a PropertyDeclaration> { where I: Iterator<Item=&'a PropertyDeclaration>
{
if let AppendableValue::DeclarationsForShorthand(shorthand, _) = *appendable_value { if let AppendableValue::DeclarationsForShorthand(shorthand, _) = *appendable_value {
if let ShorthandId::Overflow = shorthand { if let ShorthandId::Overflow = shorthand {
return true; return true;

View file

@ -3,6 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#![allow(unsafe_code)] #![allow(unsafe_code)]
#![deny(missing_docs)]
//! The rule tree.
use arc_ptr_eq; use arc_ptr_eq;
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
@ -17,15 +20,40 @@ use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
use stylesheets::StyleRule; use stylesheets::StyleRule;
use thread_state; use thread_state;
/// The rule tree, the structure servo uses to preserve the results of selector
/// matching.
///
/// This is organized as a tree of rules. When a node matches a set of rules,
/// they're inserted in order in the tree, starting with the less specific one.
///
/// When a rule is inserted in the tree, other elements may share the path up to
/// a given rule. If that's the case, we don't duplicate child nodes, but share
/// them.
///
/// When the rule node refcount drops to zero, it doesn't get freed. It gets
/// instead put into a free list, and it is potentially GC'd after a while in a
/// single-threaded fashion.
///
/// That way, a rule node that represents a likely-to-match-again rule (like a
/// :hover rule) can be reused if we haven't GC'd it yet.
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct RuleTree { pub struct RuleTree {
root: StrongRuleNode, root: StrongRuleNode,
} }
/// A style source for the rule node. It can either be a CSS style rule or a
/// declaration block.
///
/// Note that, even though the declaration block from inside the style rule
/// could be enough to implement the rule tree, keeping the whole rule provides
/// more debuggability, and also the ability of show those selectors to
/// devtools.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum StyleSource { pub enum StyleSource {
/// A style rule stable pointer.
Style(Arc<RwLock<StyleRule>>), Style(Arc<RwLock<StyleRule>>),
/// A declaration block stable pointer.
Declarations(Arc<RwLock<PropertyDeclarationBlock>>), Declarations(Arc<RwLock<PropertyDeclarationBlock>>),
} }
@ -34,8 +62,11 @@ type StyleSourceGuardHandle<'a> =
RwLockReadGuard<'a, StyleRule>, RwLockReadGuard<'a, StyleRule>,
RwLockReadGuard<'a, PropertyDeclarationBlock>>; RwLockReadGuard<'a, PropertyDeclarationBlock>>;
/// A guard for a given style source.
pub enum StyleSourceGuard<'a> { pub enum StyleSourceGuard<'a> {
/// A guard for a style rule.
Style(StyleSourceGuardHandle<'a>), Style(StyleSourceGuardHandle<'a>),
/// A guard for a declaration block.
Declarations(RwLockReadGuard<'a, PropertyDeclarationBlock>), Declarations(RwLockReadGuard<'a, PropertyDeclarationBlock>),
} }
@ -71,6 +102,8 @@ impl StyleSource {
let _ = write!(writer, " -> {:?}", self.read().declarations); let _ = write!(writer, " -> {:?}", self.read().declarations);
} }
/// Read the style source guard, and obtain thus read access to the
/// underlying property declaration block.
#[inline] #[inline]
pub fn read<'a>(&'a self) -> StyleSourceGuard<'a> { pub fn read<'a>(&'a self) -> StyleSourceGuard<'a> {
use self::StyleSource::*; use self::StyleSource::*;
@ -87,15 +120,19 @@ impl StyleSource {
/// This value exists here so a node that pushes itself to the list can know /// This value exists here so a node that pushes itself to the list can know
/// that is in the free list by looking at is next pointer, and comparing it /// that is in the free list by looking at is next pointer, and comparing it
/// with null. /// with null.
///
/// The root node doesn't have a null pointer in the free list, but this value.
const FREE_LIST_SENTINEL: *mut RuleNode = 0x01 as *mut RuleNode; const FREE_LIST_SENTINEL: *mut RuleNode = 0x01 as *mut RuleNode;
impl RuleTree { impl RuleTree {
/// Construct a new rule tree.
pub fn new() -> Self { pub fn new() -> Self {
RuleTree { RuleTree {
root: StrongRuleNode::new(Box::new(RuleNode::root())), root: StrongRuleNode::new(Box::new(RuleNode::root())),
} }
} }
/// Get the root rule node.
pub fn root(&self) -> StrongRuleNode { pub fn root(&self) -> StrongRuleNode {
self.root.clone() self.root.clone()
} }
@ -105,13 +142,16 @@ impl RuleTree {
self.root.get().dump(writer, 0); self.root.get().dump(writer, 0);
} }
/// Dump the rule tree to stdout.
pub fn dump_stdout(&self) { pub fn dump_stdout(&self) {
let mut stdout = io::stdout(); let mut stdout = io::stdout();
self.dump(&mut stdout); self.dump(&mut stdout);
} }
/// Insert the given rules, that must be in proper order by specifity, and
/// return the corresponding rule node representing the last inserted one.
pub fn insert_ordered_rules<'a, I>(&self, iter: I) -> StrongRuleNode pub fn insert_ordered_rules<'a, I>(&self, iter: I) -> StrongRuleNode
where I: Iterator<Item=(StyleSource, Importance)> where I: Iterator<Item=(StyleSource, Importance)>,
{ {
let mut current = self.root.clone(); let mut current = self.root.clone();
for (source, importance) in iter { for (source, importance) in iter {
@ -294,6 +334,7 @@ struct WeakRuleNode {
ptr: *mut RuleNode, ptr: *mut RuleNode,
} }
/// A strong reference to a rule node.
#[derive(Debug)] #[derive(Debug)]
pub struct StrongRuleNode { pub struct StrongRuleNode {
ptr: *mut RuleNode, ptr: *mut RuleNode,
@ -412,14 +453,19 @@ impl StrongRuleNode {
unsafe { &*self.ptr } unsafe { &*self.ptr }
} }
/// Get the style source corresponding to this rule node. May return `None`
/// if it's the root node, which means that the node hasn't matched any
/// rules.
pub fn style_source(&self) -> Option<&StyleSource> { pub fn style_source(&self) -> Option<&StyleSource> {
self.get().source.as_ref() self.get().source.as_ref()
} }
/// Get the importance that this rule node represents.
pub fn importance(&self) -> Importance { pub fn importance(&self) -> Importance {
self.get().importance self.get().importance
} }
/// Get an iterator for this rule node and its ancestors.
pub fn self_and_ancestors(&self) -> SelfAndAncestors { pub fn self_and_ancestors(&self) -> SelfAndAncestors {
SelfAndAncestors { SelfAndAncestors {
current: Some(self) current: Some(self)
@ -527,6 +573,7 @@ impl StrongRuleNode {
} }
} }
/// An iterator over a rule node and its ancestors.
#[derive(Clone)] #[derive(Clone)]
pub struct SelfAndAncestors<'a> { pub struct SelfAndAncestors<'a> {
current: Option<&'a StrongRuleNode>, current: Option<&'a StrongRuleNode>,

View file

@ -4,14 +4,17 @@
//! Implements sequential traversal over the DOM tree. //! Implements sequential traversal over the DOM tree.
#![deny(missing_docs)]
use dom::{TElement, TNode}; use dom::{TElement, TNode};
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken}; use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};
/// Do a sequential DOM traversal for layout or styling, generic over `D`.
pub fn traverse_dom<N, D>(traversal: &D, pub fn traverse_dom<N, D>(traversal: &D,
root: N::ConcreteElement, root: N::ConcreteElement,
token: PreTraverseToken) token: PreTraverseToken)
where N: TNode, where N: TNode,
D: DomTraversal<N> D: DomTraversal<N>,
{ {
debug_assert!(token.should_traverse()); debug_assert!(token.should_traverse());

View file

@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#![deny(missing_docs)]
//! Servo's selector parser.
use {Atom, Prefix, Namespace, LocalName}; use {Atom, Prefix, Namespace, LocalName};
use attr::{AttrIdentifier, AttrValue}; use attr::{AttrIdentifier, AttrValue};
use cssparser::ToCss; use cssparser::ToCss;
@ -15,9 +19,12 @@ use std::borrow::Cow;
use std::fmt; use std::fmt;
use std::fmt::Debug; use std::fmt::Debug;
/// A pseudo-element, both public and private.
///
/// NB: If you add to this list, be sure to update `each_pseudo_element` too. /// NB: If you add to this list, be sure to update `each_pseudo_element` too.
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum PseudoElement { pub enum PseudoElement {
Before, Before,
After, After,
@ -55,6 +62,7 @@ impl ToCss for PseudoElement {
impl PseudoElement { impl PseudoElement {
/// Whether the current pseudo element is :before or :after.
#[inline] #[inline]
pub fn is_before_or_after(&self) -> bool { pub fn is_before_or_after(&self) -> bool {
match *self { match *self {
@ -64,6 +72,9 @@ impl PseudoElement {
} }
} }
/// Returns which kind of cascade type has this pseudo.
///
/// For more info on cascade types, see docs/components/style.md
#[inline] #[inline]
pub fn cascade_type(&self) -> PseudoElementCascadeType { pub fn cascade_type(&self) -> PseudoElementCascadeType {
match *self { match *self {
@ -83,8 +94,11 @@ impl PseudoElement {
} }
} }
/// A non tree-structural pseudo-class.
/// See https://drafts.csswg.org/selectors-4/#structural-pseudos
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum NonTSPseudoClass { pub enum NonTSPseudoClass {
AnyLink, AnyLink,
Link, Link,
@ -129,6 +143,8 @@ impl ToCss for NonTSPseudoClass {
} }
impl NonTSPseudoClass { impl NonTSPseudoClass {
/// Gets a given state flag for this pseudo-class. This is used to do
/// selector matching, and it's set from the DOM.
pub fn state_flag(&self) -> ElementState { pub fn state_flag(&self) -> ElementState {
use element_state::*; use element_state::*;
use self::NonTSPseudoClass::*; use self::NonTSPseudoClass::*;
@ -153,6 +169,8 @@ impl NonTSPseudoClass {
} }
} }
/// The abstract struct we implement the selector parser implementation on top
/// of.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SelectorImpl; pub struct SelectorImpl;
@ -289,14 +307,17 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
} }
impl SelectorImpl { impl SelectorImpl {
/// Returns the pseudo-element cascade type of the given `pseudo`.
#[inline] #[inline]
pub fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType { pub fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType {
pseudo.cascade_type() pseudo.cascade_type()
} }
/// Executes `fun` for each pseudo-element.
#[inline] #[inline]
pub fn each_pseudo_element<F>(mut fun: F) pub fn each_pseudo_element<F>(mut fun: F)
where F: FnMut(PseudoElement) { where F: FnMut(PseudoElement),
{
fun(PseudoElement::Before); fun(PseudoElement::Before);
fun(PseudoElement::After); fun(PseudoElement::After);
fun(PseudoElement::DetailsContent); fun(PseudoElement::DetailsContent);
@ -311,11 +332,13 @@ impl SelectorImpl {
fun(PseudoElement::ServoAnonymousBlock); fun(PseudoElement::ServoAnonymousBlock);
} }
/// Returns the pseudo-class state flag for selector matching.
#[inline] #[inline]
pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState { pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
pc.state_flag() pc.state_flag()
} }
/// Returns whether this pseudo is either :before or :after.
#[inline] #[inline]
pub fn pseudo_is_before_or_after(pseudo: &PseudoElement) -> bool { pub fn pseudo_is_before_or_after(pseudo: &PseudoElement) -> bool {
pseudo.is_before_or_after() pseudo.is_before_or_after()
@ -326,12 +349,16 @@ impl SelectorImpl {
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct ServoElementSnapshot { pub struct ServoElementSnapshot {
/// The stored state of the element.
pub state: Option<ElementState>, pub state: Option<ElementState>,
/// The set of stored attributes and its values.
pub attrs: Option<Vec<(AttrIdentifier, AttrValue)>>, pub attrs: Option<Vec<(AttrIdentifier, AttrValue)>>,
/// Whether this element is an HTML element in an HTML document.
pub is_html_element_in_html_document: bool, pub is_html_element_in_html_document: bool,
} }
impl ServoElementSnapshot { impl ServoElementSnapshot {
/// Create an empty element snapshot.
pub fn new(is_html_element_in_html_document: bool) -> Self { pub fn new(is_html_element_in_html_document: bool) -> Self {
ServoElementSnapshot { ServoElementSnapshot {
state: None, state: None,
@ -373,7 +400,7 @@ impl ElementSnapshot for ServoElementSnapshot {
} }
fn each_class<F>(&self, mut callback: F) fn each_class<F>(&self, mut callback: F)
where F: FnMut(&Atom) where F: FnMut(&Atom),
{ {
if let Some(v) = self.get_attr(&ns!(), &local_name!("class")) { if let Some(v) = self.get_attr(&ns!(), &local_name!("class")) {
for class in v.as_tokens() { for class in v.as_tokens() {

View file

@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! String utils for attributes and similar stuff.
#![deny(missing_docs)]
use num_traits::ToPrimitive; use num_traits::ToPrimitive;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::borrow::Cow; use std::borrow::Cow;
@ -9,7 +13,10 @@ use std::convert::AsRef;
use std::iter::{Filter, Peekable}; use std::iter::{Filter, Peekable};
use std::str::Split; use std::str::Split;
/// A static slice of characters.
pub type StaticCharVec = &'static [char]; pub type StaticCharVec = &'static [char];
/// A static slice of `str`s.
pub type StaticStringVec = &'static [&'static str]; pub type StaticStringVec = &'static [&'static str];
/// A "space character" according to: /// A "space character" according to:
@ -23,23 +30,31 @@ pub static HTML_SPACE_CHARACTERS: StaticCharVec = &[
'\u{000d}', '\u{000d}',
]; ];
/// Whether a character is a HTML whitespace character.
#[inline] #[inline]
pub fn char_is_whitespace(c: char) -> bool { pub fn char_is_whitespace(c: char) -> bool {
HTML_SPACE_CHARACTERS.contains(&c) HTML_SPACE_CHARACTERS.contains(&c)
} }
/// Whether all the string is HTML whitespace.
#[inline]
pub fn is_whitespace(s: &str) -> bool { pub fn is_whitespace(s: &str) -> bool {
s.chars().all(char_is_whitespace) s.chars().all(char_is_whitespace)
} }
#[inline]
fn not_empty(&split: &&str) -> bool { !split.is_empty() }
/// Split a string on HTML whitespace.
#[inline]
pub fn split_html_space_chars<'a>(s: &'a str) -> pub fn split_html_space_chars<'a>(s: &'a str) ->
Filter<Split<'a, StaticCharVec>, fn(&&str) -> bool> { Filter<Split<'a, StaticCharVec>, fn(&&str) -> bool> {
fn not_empty(&split: &&str) -> bool { !split.is_empty() }
s.split(HTML_SPACE_CHARACTERS).filter(not_empty as fn(&&str) -> bool) s.split(HTML_SPACE_CHARACTERS).filter(not_empty as fn(&&str) -> bool)
} }
/// Split a string on commas.
#[inline]
pub fn split_commas<'a>(s: &'a str) -> Filter<Split<'a, char>, fn(&&str) -> bool> { pub fn split_commas<'a>(s: &'a str) -> Filter<Split<'a, char>, fn(&&str) -> bool> {
fn not_empty(&split: &&str) -> bool { !split.is_empty() }
s.split(',').filter(not_empty as fn(&&str) -> bool) s.split(',').filter(not_empty as fn(&&str) -> bool)
} }
@ -61,6 +76,7 @@ fn is_exponent_char(c: char) -> bool {
} }
} }
/// Read a set of ascii digits and read them into a number.
pub fn read_numbers<I: Iterator<Item=char>>(mut iter: Peekable<I>) -> (Option<i64>, usize) { pub fn read_numbers<I: Iterator<Item=char>>(mut iter: Peekable<I>) -> (Option<i64>, usize) {
match iter.peek() { match iter.peek() {
Some(c) if is_ascii_digit(c) => (), Some(c) if is_ascii_digit(c) => (),
@ -79,6 +95,7 @@ pub fn read_numbers<I: Iterator<Item=char>>(mut iter: Peekable<I>) -> (Option<i6
}) })
} }
/// Read a decimal fraction.
pub fn read_fraction<I: Iterator<Item=char>>(mut iter: Peekable<I>, pub fn read_fraction<I: Iterator<Item=char>>(mut iter: Peekable<I>,
mut divisor: f64, mut divisor: f64,
value: f64) -> (f64, usize) { value: f64) -> (f64, usize) {
@ -92,11 +109,11 @@ pub fn read_fraction<I: Iterator<Item=char>>(mut iter: Peekable<I>,
d as i64 - '0' as i64 d as i64 - '0' as i64
).fold((value, 1), |accumulator, d| { ).fold((value, 1), |accumulator, d| {
divisor *= 10f64; divisor *= 10f64;
(accumulator.0 + d as f64 / divisor, (accumulator.0 + d as f64 / divisor, accumulator.1 + 1)
accumulator.1 + 1)
}) })
} }
/// Reads an exponent from an iterator over chars, for example `e100`.
pub fn read_exponent<I: Iterator<Item=char>>(mut iter: Peekable<I>) -> Option<i32> { pub fn read_exponent<I: Iterator<Item=char>>(mut iter: Peekable<I>) -> Option<i32> {
match iter.peek() { match iter.peek() {
Some(c) if is_exponent_char(*c) => (), Some(c) if is_exponent_char(*c) => (),
@ -118,8 +135,10 @@ pub fn read_exponent<I: Iterator<Item=char>>(mut iter: Peekable<I>) -> Option<i3
} }
} }
/// Join a set of strings with a given delimiter `join`.
pub fn str_join<I, T>(strs: I, join: &str) -> String pub fn str_join<I, T>(strs: I, join: &str) -> String
where I: IntoIterator<Item=T>, T: AsRef<str>, where I: IntoIterator<Item=T>,
T: AsRef<str>,
{ {
strs.into_iter().enumerate().fold(String::new(), |mut acc, (i, s)| { strs.into_iter().enumerate().fold(String::new(), |mut acc, (i, s)| {
if i > 0 { acc.push_str(join); } if i > 0 { acc.push_str(join); }

View file

@ -4,6 +4,8 @@
//! Style sheets and their CSS rules. //! Style sheets and their CSS rules.
#![deny(missing_docs)]
use {Atom, Prefix, Namespace}; use {Atom, Prefix, Namespace};
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, decode_stylesheet_bytes}; use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, decode_stylesheet_bytes};
use cssparser::{AtRuleType, RuleListParser, SourcePosition, Token, parse_one_rule}; use cssparser::{AtRuleType, RuleListParser, SourcePosition, Token, parse_one_rule};
@ -46,22 +48,27 @@ pub enum Origin {
User, User,
} }
/// A set of namespaces applying to a given stylesheet.
#[derive(Default, Debug)] #[derive(Default, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct Namespaces { pub struct Namespaces {
pub default: Option<Namespace>, pub default: Option<Namespace>,
pub prefixes: FnvHashMap<Prefix , Namespace>, pub prefixes: FnvHashMap<Prefix , Namespace>,
} }
/// A list of CSS rules.
#[derive(Debug)] #[derive(Debug)]
pub struct CssRules(pub Vec<CssRule>); pub struct CssRules(pub Vec<CssRule>);
impl CssRules { impl CssRules {
/// Whether this CSS rules is empty.
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.0.is_empty() self.0.is_empty()
} }
} }
#[allow(missing_docs)]
pub enum RulesMutateError { pub enum RulesMutateError {
Syntax, Syntax,
IndexSize, IndexSize,
@ -79,6 +86,7 @@ impl From<SingleRuleParseError> for RulesMutateError {
} }
impl CssRules { impl CssRules {
#[allow(missing_docs)]
pub fn new(rules: Vec<CssRule>) -> Arc<RwLock<CssRules>> { pub fn new(rules: Vec<CssRule>) -> Arc<RwLock<CssRules>> {
Arc::new(RwLock::new(CssRules(rules))) Arc::new(RwLock::new(CssRules(rules)))
} }
@ -93,7 +101,7 @@ impl CssRules {
}) })
} }
// https://drafts.csswg.org/cssom/#insert-a-css-rule /// https://drafts.csswg.org/cssom/#insert-a-css-rule
pub fn insert_rule(&mut self, rule: &str, parent_stylesheet: &Stylesheet, index: usize, nested: bool) pub fn insert_rule(&mut self, rule: &str, parent_stylesheet: &Stylesheet, index: usize, nested: bool)
-> Result<CssRule, RulesMutateError> { -> Result<CssRule, RulesMutateError> {
// Step 1, 2 // Step 1, 2
@ -136,7 +144,7 @@ impl CssRules {
Ok(new_rule) Ok(new_rule)
} }
// https://drafts.csswg.org/cssom/#remove-a-css-rule /// https://drafts.csswg.org/cssom/#remove-a-css-rule
pub fn remove_rule(&mut self, index: usize) -> Result<(), RulesMutateError> { pub fn remove_rule(&mut self, index: usize) -> Result<(), RulesMutateError> {
// Step 1, 2 // Step 1, 2
if index >= self.0.len() { if index >= self.0.len() {
@ -161,6 +169,7 @@ impl CssRules {
} }
} }
/// The structure servo uses to represent a stylesheet.
#[derive(Debug)] #[derive(Debug)]
pub struct Stylesheet { pub struct Stylesheet {
/// List of rules in the order they were found (important for /// List of rules in the order they were found (important for
@ -168,22 +177,33 @@ pub struct Stylesheet {
pub rules: Arc<RwLock<CssRules>>, pub rules: Arc<RwLock<CssRules>>,
/// List of media associated with the Stylesheet. /// List of media associated with the Stylesheet.
pub media: Arc<RwLock<MediaList>>, pub media: Arc<RwLock<MediaList>>,
/// The origin of this stylesheet.
pub origin: Origin, pub origin: Origin,
/// The base url this stylesheet should use.
pub base_url: ServoUrl, pub base_url: ServoUrl,
/// The namespaces that apply to this stylesheet.
pub namespaces: RwLock<Namespaces>, pub namespaces: RwLock<Namespaces>,
/// Whether this stylesheet would be dirty when the viewport size changes.
pub dirty_on_viewport_size_change: AtomicBool, pub dirty_on_viewport_size_change: AtomicBool,
/// Whether this stylesheet should be disabled.
pub disabled: AtomicBool, pub disabled: AtomicBool,
} }
/// This structure holds the user-agent and user stylesheets. /// This structure holds the user-agent and user stylesheets.
pub struct UserAgentStylesheets { pub struct UserAgentStylesheets {
/// The user or user agent stylesheets.
pub user_or_user_agent_stylesheets: Vec<Stylesheet>, pub user_or_user_agent_stylesheets: Vec<Stylesheet>,
/// The quirks mode stylesheet.
pub quirks_mode_stylesheet: Stylesheet, pub quirks_mode_stylesheet: Stylesheet,
} }
/// A CSS rule.
///
/// TODO(emilio): Lots of spec links should be around.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[allow(missing_docs)]
pub enum CssRule { pub enum CssRule {
// No Charset here, CSSCharsetRule has been removed from CSSOM // No Charset here, CSSCharsetRule has been removed from CSSOM
// https://drafts.csswg.org/cssom/#changes-from-5-december-2013 // https://drafts.csswg.org/cssom/#changes-from-5-december-2013
@ -197,6 +217,7 @@ pub enum CssRule {
Keyframes(Arc<RwLock<KeyframesRule>>), Keyframes(Arc<RwLock<KeyframesRule>>),
} }
#[allow(missing_docs)]
pub enum CssRuleType { pub enum CssRuleType {
// https://drafts.csswg.org/cssom/#the-cssrule-interface // https://drafts.csswg.org/cssom/#the-cssrule-interface
Style = 1, Style = 1,
@ -236,12 +257,14 @@ impl ParseErrorReporter for MemoryHoleReporter {
} }
} }
#[allow(missing_docs)]
pub enum SingleRuleParseError { pub enum SingleRuleParseError {
Syntax, Syntax,
Hierarchy, Hierarchy,
} }
impl CssRule { impl CssRule {
#[allow(missing_docs)]
pub fn rule_type(&self) -> CssRuleType { pub fn rule_type(&self) -> CssRuleType {
match *self { match *self {
CssRule::Style(_) => CssRuleType::Style, CssRule::Style(_) => CssRuleType::Style,
@ -268,7 +291,8 @@ impl CssRule {
/// Note that only some types of rules can contain rules. An empty slice is /// Note that only some types of rules can contain rules. An empty slice is
/// used for others. /// used for others.
pub fn with_nested_rules_and_mq<F, R>(&self, mut f: F) -> R pub fn with_nested_rules_and_mq<F, R>(&self, mut f: F) -> R
where F: FnMut(&[CssRule], Option<&MediaList>) -> R { where F: FnMut(&[CssRule], Option<&MediaList>) -> R
{
match *self { match *self {
CssRule::Import(ref lock) => { CssRule::Import(ref lock) => {
let rule = lock.read(); let rule = lock.read();
@ -296,6 +320,7 @@ impl CssRule {
// input state is None for a nested rule // input state is None for a nested rule
// Returns a parsed CSS rule and the final state of the parser // Returns a parsed CSS rule and the final state of the parser
#[allow(missing_docs)]
pub fn parse(css: &str, pub fn parse(css: &str,
parent_stylesheet: &Stylesheet, parent_stylesheet: &Stylesheet,
extra_data: ParserContextExtraData, extra_data: ParserContextExtraData,
@ -348,6 +373,7 @@ impl ToCss for CssRule {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct NamespaceRule { pub struct NamespaceRule {
/// `None` for the default Namespace /// `None` for the default Namespace
pub prefix: Option<Prefix>, pub prefix: Option<Prefix>,
@ -374,6 +400,7 @@ impl ToCss for NamespaceRule {
/// [import]: https://drafts.csswg.org/css-cascade-3/#at-import /// [import]: https://drafts.csswg.org/css-cascade-3/#at-import
#[derive(Debug)] #[derive(Debug)]
pub struct ImportRule { pub struct ImportRule {
/// The `<url>` this `@import` rule is loading.
pub url: SpecifiedUrl, pub url: SpecifiedUrl,
/// The stylesheet is always present. /// The stylesheet is always present.
@ -396,9 +423,14 @@ impl ToCss for ImportRule {
} }
} }
/// A [`@keyframes`][keyframes] rule.
///
/// [keyframes]: https://drafts.csswg.org/css-animations/#keyframes
#[derive(Debug)] #[derive(Debug)]
pub struct KeyframesRule { pub struct KeyframesRule {
/// The name of the current animation.
pub name: Atom, pub name: Atom,
/// The keyframes specified for this CSS rule.
pub keyframes: Vec<Arc<RwLock<Keyframe>>>, pub keyframes: Vec<Arc<RwLock<Keyframe>>>,
} }
@ -417,6 +449,7 @@ impl ToCss for KeyframesRule {
} }
} }
#[allow(missing_docs)]
#[derive(Debug)] #[derive(Debug)]
pub struct MediaRule { pub struct MediaRule {
pub media_queries: Arc<RwLock<MediaList>>, pub media_queries: Arc<RwLock<MediaList>>,
@ -438,6 +471,7 @@ impl ToCss for MediaRule {
} }
} }
#[allow(missing_docs)]
#[derive(Debug)] #[derive(Debug)]
pub struct StyleRule { pub struct StyleRule {
pub selectors: SelectorList<SelectorImpl>, pub selectors: SelectorList<SelectorImpl>,
@ -465,6 +499,11 @@ impl ToCss for StyleRule {
} }
impl Stylesheet { impl Stylesheet {
/// Parse a stylesheet from a set of bytes, potentially received over the
/// network.
///
/// Takes care of decoding the network bytes and forwards the resulting
/// string to `Stylesheet::from_str`.
pub fn from_bytes(bytes: &[u8], pub fn from_bytes(bytes: &[u8],
base_url: ServoUrl, base_url: ServoUrl,
protocol_encoding_label: Option<&str>, protocol_encoding_label: Option<&str>,
@ -486,6 +525,8 @@ impl Stylesheet {
extra_data) extra_data)
} }
/// Updates an empty stylesheet with a set of bytes that reached over the
/// network.
pub fn update_from_bytes(existing: &Stylesheet, pub fn update_from_bytes(existing: &Stylesheet,
bytes: &[u8], bytes: &[u8],
protocol_encoding_label: Option<&str>, protocol_encoding_label: Option<&str>,
@ -493,7 +534,6 @@ impl Stylesheet {
stylesheet_loader: Option<&StylesheetLoader>, stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: Box<ParseErrorReporter + Send>, error_reporter: Box<ParseErrorReporter + Send>,
extra_data: ParserContextExtraData) { extra_data: ParserContextExtraData) {
assert!(existing.rules.read().is_empty());
let (string, _) = decode_stylesheet_bytes( let (string, _) = decode_stylesheet_bytes(
bytes, protocol_encoding_label, environment_encoding); bytes, protocol_encoding_label, environment_encoding);
Self::update_from_str(existing, Self::update_from_str(existing,
@ -503,6 +543,7 @@ impl Stylesheet {
extra_data) extra_data)
} }
/// Updates an empty stylesheet from a given string of text.
pub fn update_from_str(existing: &Stylesheet, pub fn update_from_str(existing: &Stylesheet,
css: &str, css: &str,
stylesheet_loader: Option<&StylesheetLoader>, stylesheet_loader: Option<&StylesheetLoader>,
@ -545,7 +586,14 @@ impl Stylesheet {
.store(input.seen_viewport_percentages(), Ordering::Release); .store(input.seen_viewport_percentages(), Ordering::Release);
} }
pub fn from_str(css: &str, base_url: ServoUrl, origin: Origin, /// Creates an empty stylesheet and parses it with a given base url, origin
/// and media.
///
/// Effectively creates a new stylesheet and forwards the hard work to
/// `Stylesheet::update_from_str`.
pub fn from_str(css: &str,
base_url: ServoUrl,
origin: Origin,
media: MediaList, media: MediaList,
stylesheet_loader: Option<&StylesheetLoader>, stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: Box<ParseErrorReporter + Send>, error_reporter: Box<ParseErrorReporter + Send>,
@ -569,6 +617,7 @@ impl Stylesheet {
s s
} }
/// Whether this stylesheet can be dirty on viewport size change.
pub fn dirty_on_viewport_size_change(&self) -> bool { pub fn dirty_on_viewport_size_change(&self) -> bool {
self.dirty_on_viewport_size_change.load(Ordering::SeqCst) self.dirty_on_viewport_size_change.load(Ordering::SeqCst)
} }
@ -607,16 +656,19 @@ impl Stylesheet {
effective_rules(&self.rules.read().0, device, &mut f); effective_rules(&self.rules.read().0, device, &mut f);
} }
/// Returns whether the stylesheet has been explicitly disabled through the CSSOM. /// Returns whether the stylesheet has been explicitly disabled through the
/// CSSOM.
pub fn disabled(&self) -> bool { pub fn disabled(&self) -> bool {
self.disabled.load(Ordering::SeqCst) self.disabled.load(Ordering::SeqCst)
} }
/// Records that the stylesheet has been explicitly disabled through the CSSOM. /// Records that the stylesheet has been explicitly disabled through the
/// CSSOM.
///
/// Returns whether the the call resulted in a change in disabled state. /// Returns whether the the call resulted in a change in disabled state.
/// ///
/// Disabled stylesheets remain in the document, but their rules are not added to /// Disabled stylesheets remain in the document, but their rules are not
/// the Stylist. /// added to the Stylist.
pub fn set_disabled(&self, disabled: bool) -> bool { pub fn set_disabled(&self, disabled: bool) -> bool {
self.disabled.swap(disabled, Ordering::SeqCst) != disabled self.disabled.swap(disabled, Ordering::SeqCst) != disabled
} }
@ -640,6 +692,7 @@ macro_rules! rule_filter {
($( $method: ident($variant:ident => $rule_type: ident), )+) => { ($( $method: ident($variant:ident => $rule_type: ident), )+) => {
impl Stylesheet { impl Stylesheet {
$( $(
#[allow(missing_docs)]
pub fn $method<F>(&self, device: &Device, mut f: F) where F: FnMut(&$rule_type) { pub fn $method<F>(&self, device: &Device, mut f: F) where F: FnMut(&$rule_type) {
self.effective_rules(device, |rule| { self.effective_rules(device, |rule| {
if let CssRule::$variant(ref lock) = *rule { if let CssRule::$variant(ref lock) = *rule {
@ -690,6 +743,7 @@ impl<'b> TopLevelRuleParser<'b> {
} }
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)] #[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
#[allow(missing_docs)]
pub enum State { pub enum State {
Start = 1, Start = 1,
Imports = 2, Imports = 2,

View file

@ -8,32 +8,42 @@
//! In release builds, `get` returns 0. All of the other functions inline //! In release builds, `get` returns 0. All of the other functions inline
//! away to nothing. //! away to nothing.
#![deny(missing_docs)]
pub use self::imp::{enter, exit, get, initialize}; pub use self::imp::{enter, exit, get, initialize};
bitflags! { bitflags! {
/// A thread state flag, used for multiple assertions.
pub flags ThreadState: u32 { pub flags ThreadState: u32 {
/// Whether we're in a script thread.
const SCRIPT = 0x01, const SCRIPT = 0x01,
/// Whether we're in a layout thread.
const LAYOUT = 0x02, const LAYOUT = 0x02,
const PAINT = 0x04,
/// Whether we're in a script worker thread (actual web workers), or in
/// a layout worker thread.
const IN_WORKER = 0x0100, const IN_WORKER = 0x0100,
/// Whether the current thread is going through a GC.
const IN_GC = 0x0200, const IN_GC = 0x0200,
const IN_HTML_PARSER = 0x0400,
} }
} }
macro_rules! thread_types ( ( $( $fun:ident = $flag:ident ; )* ) => ( macro_rules! thread_types ( ( $( $fun:ident = $flag:ident ; )* ) => (
impl ThreadState { impl ThreadState {
/// Whether the current thread is a worker thread.
pub fn is_worker(self) -> bool { pub fn is_worker(self) -> bool {
self.contains(IN_WORKER) self.contains(IN_WORKER)
} }
$( $(
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
#[allow(missing_docs)]
pub fn $fun(self) -> bool { pub fn $fun(self) -> bool {
self.contains($flag) self.contains($flag)
} }
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
#[allow(missing_docs)]
pub fn $fun(self) -> bool { pub fn $fun(self) -> bool {
true true
} }
@ -48,7 +58,6 @@ macro_rules! thread_types ( ( $( $fun:ident = $flag:ident ; )* ) => (
thread_types! { thread_types! {
is_script = SCRIPT; is_script = SCRIPT;
is_layout = LAYOUT; is_layout = LAYOUT;
is_paint = PAINT;
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -58,6 +67,7 @@ mod imp {
thread_local!(static STATE: RefCell<Option<ThreadState>> = RefCell::new(None)); thread_local!(static STATE: RefCell<Option<ThreadState>> = RefCell::new(None));
/// Initialize the current thread state.
pub fn initialize(x: ThreadState) { pub fn initialize(x: ThreadState) {
STATE.with(|ref k| { STATE.with(|ref k| {
if let Some(ref s) = *k.borrow() { if let Some(ref s) = *k.borrow() {
@ -68,6 +78,7 @@ mod imp {
get(); // check the assertion below get(); // check the assertion below
} }
/// Get the current thread state.
pub fn get() -> ThreadState { pub fn get() -> ThreadState {
let state = STATE.with(|ref k| { let state = STATE.with(|ref k| {
match *k.borrow() { match *k.borrow() {
@ -82,6 +93,7 @@ mod imp {
state state
} }
/// Enter into a given temporary state. Panics if re-entring.
pub fn enter(x: ThreadState) { pub fn enter(x: ThreadState) {
let state = get(); let state = get();
assert!(!state.intersects(x)); assert!(!state.intersects(x));
@ -90,6 +102,7 @@ mod imp {
}) })
} }
/// Exit a given temporary state.
pub fn exit(x: ThreadState) { pub fn exit(x: ThreadState) {
let state = get(); let state = get();
assert!(state.contains(x)); assert!(state.contains(x));
@ -100,6 +113,7 @@ mod imp {
} }
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
#[allow(missing_docs)]
mod imp { mod imp {
use super::ThreadState; use super::ThreadState;
#[inline(always)] pub fn initialize(_: ThreadState) { } #[inline(always)] pub fn initialize(_: ThreadState) { }

View file

@ -1,14 +1,19 @@
/* This Source Code Form is subject to the terms of the Mozilla Public /* 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 * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#![deny(missing_docs)]
//! A timer module, used to define a `Timer` type, that is controlled by script.
use time; use time;
/// The `TimerMode` is used to determine what time should the `Timer` return, /// The `TimerMode` is used to determine what time should the `Timer` return.
/// either a fixed value (in the `Test` mode), or the actual time (in the
/// `Current` mode).
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum TimerMode { enum TimerMode {
/// The timer should return a fixed value.
Test(f64), Test(f64),
/// The timer should return the actual time.
Current, Current,
} }

View file

@ -4,6 +4,8 @@
//! Traversing the DOM tree; the bloom filter. //! Traversing the DOM tree; the bloom filter.
#![deny(missing_docs)]
use atomic_refcell::{AtomicRefCell, AtomicRefMut}; use atomic_refcell::{AtomicRefCell, AtomicRefMut};
use context::{SharedStyleContext, StyleContext}; use context::{SharedStyleContext, StyleContext};
use data::{ElementData, ElementStyles, StoredRestyleHint}; use data::{ElementData, ElementStyles, StoredRestyleHint};
@ -18,14 +20,23 @@ use std::mem;
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use stylist::Stylist; use stylist::Stylist;
/// Style sharing candidate cache stats. These are only used when /// Style sharing candidate cache hits. These are only used when
/// `-Z style-sharing-stats` is given. /// `-Z style-sharing-stats` is given.
pub static STYLE_SHARING_CACHE_HITS: AtomicUsize = ATOMIC_USIZE_INIT; pub static STYLE_SHARING_CACHE_HITS: AtomicUsize = ATOMIC_USIZE_INIT;
/// Style sharing candidate cache misses.
pub static STYLE_SHARING_CACHE_MISSES: AtomicUsize = ATOMIC_USIZE_INIT; pub static STYLE_SHARING_CACHE_MISSES: AtomicUsize = ATOMIC_USIZE_INIT;
// NB: Keep this as small as possible, please! /// A per-traversal-level chunk of data. This is sent down by the traversal, and
/// currently only holds the dom depth for the bloom filter.
///
/// NB: Keep this as small as possible, please!
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PerLevelTraversalData { pub struct PerLevelTraversalData {
/// The current dom depth, if known, or `None` otherwise.
///
/// This is kept with cooperation from the traversal code and the bloom
/// filter.
pub current_dom_depth: Option<usize>, pub current_dom_depth: Option<usize>,
} }
@ -37,10 +48,12 @@ pub struct PreTraverseToken {
} }
impl PreTraverseToken { impl PreTraverseToken {
/// Whether we should traverse children.
pub fn should_traverse(&self) -> bool { pub fn should_traverse(&self) -> bool {
self.traverse self.traverse
} }
/// Whether we should traverse only unstyled children.
pub fn traverse_unstyled_children_only(&self) -> bool { pub fn traverse_unstyled_children_only(&self) -> bool {
self.unstyled_children_only self.unstyled_children_only
} }
@ -48,15 +61,22 @@ impl PreTraverseToken {
/// Enum to prevent duplicate logging. /// Enum to prevent duplicate logging.
pub enum LogBehavior { pub enum LogBehavior {
/// We should log.
MayLog, MayLog,
/// We shouldn't log.
DontLog, DontLog,
} }
use self::LogBehavior::*; use self::LogBehavior::*;
impl LogBehavior { impl LogBehavior {
fn allow(&self) -> bool { match *self { MayLog => true, DontLog => false, } } fn allow(&self) -> bool { matches!(*self, MayLog) }
} }
/// A DOM Traversal trait, that is used to generically implement styling for
/// Gecko and Servo.
pub trait DomTraversal<N: TNode> : Sync { pub trait DomTraversal<N: TNode> : Sync {
/// The thread-local context, used to store non-thread-safe stuff that needs
/// to be used in the traversal, and of which we use one per worker, like
/// the bloom filter, for example.
type ThreadLocalContext: Send; type ThreadLocalContext: Send;
/// Process `node` on the way down, before its children have been processed. /// Process `node` on the way down, before its children have been processed.
@ -249,8 +269,10 @@ pub trait DomTraversal<N: TNode> : Sync {
/// children of |element|. /// children of |element|.
unsafe fn clear_element_data(element: &N::ConcreteElement); unsafe fn clear_element_data(element: &N::ConcreteElement);
/// Return the shared style context common to all worker threads.
fn shared_context(&self) -> &SharedStyleContext; fn shared_context(&self) -> &SharedStyleContext;
/// Create a thread-local context.
fn create_thread_local_context(&self) -> Self::ThreadLocalContext; fn create_thread_local_context(&self) -> Self::ThreadLocalContext;
} }
@ -529,6 +551,7 @@ fn preprocess_children<E, D>(traversal: &D,
} }
} }
/// Clear style data for all the subtree under `el`.
pub fn clear_descendant_data<E: TElement, F: Fn(E)>(el: E, clear_data: &F) { pub fn clear_descendant_data<E: TElement, F: Fn(E)>(el: E, clear_data: &F) {
for kid in el.as_node().children() { for kid in el.as_node().children() {
if let Some(kid) = kid.as_element() { if let Some(kid) = kid.as_element() {

View file

@ -18,6 +18,7 @@ pub use values::specified::basic_shape::{FillRule, GeometryBox, ShapeBox};
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum ShapeSource<T> { pub enum ShapeSource<T> {
Url(SpecifiedUrl), Url(SpecifiedUrl),
Shape(BasicShape, Option<T>), Shape(BasicShape, Option<T>),
@ -51,6 +52,7 @@ impl<T: ToCss> ToCss for ShapeSource<T> {
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum BasicShape { pub enum BasicShape {
Inset(InsetRect), Inset(InsetRect),
Circle(Circle), Circle(Circle),
@ -71,6 +73,7 @@ impl ToCss for BasicShape {
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct InsetRect { pub struct InsetRect {
pub top: LengthOrPercentage, pub top: LengthOrPercentage,
pub right: LengthOrPercentage, pub right: LengthOrPercentage,
@ -100,6 +103,7 @@ impl ToCss for InsetRect {
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct Circle { pub struct Circle {
pub radius: ShapeRadius, pub radius: ShapeRadius,
pub position: Position, pub position: Position,
@ -115,6 +119,7 @@ impl ToCss for Circle {
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct Ellipse { pub struct Ellipse {
pub semiaxis_x: ShapeRadius, pub semiaxis_x: ShapeRadius,
pub semiaxis_y: ShapeRadius, pub semiaxis_y: ShapeRadius,
@ -138,6 +143,7 @@ impl ToCss for Ellipse {
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
/// https://drafts.csswg.org/css-shapes/#funcdef-polygon /// https://drafts.csswg.org/css-shapes/#funcdef-polygon
pub struct Polygon { pub struct Polygon {
pub fill: FillRule, pub fill: FillRule,
@ -168,6 +174,7 @@ impl ToCss for Polygon {
/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius /// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum ShapeRadius { pub enum ShapeRadius {
Length(LengthOrPercentage), Length(LengthOrPercentage),
ClosestSide, ClosestSide,
@ -193,6 +200,7 @@ impl ToCss for ShapeRadius {
/// https://drafts.csswg.org/css-backgrounds-3/#border-radius /// https://drafts.csswg.org/css-backgrounds-3/#border-radius
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct BorderRadius { pub struct BorderRadius {
pub top_left: BorderRadiusSize, pub top_left: BorderRadiusSize,
pub top_right: BorderRadiusSize, pub top_right: BorderRadiusSize,

View file

@ -51,6 +51,7 @@ impl ToComputedValue for specified::Image {
/// https://drafts.csswg.org/css-images/#image-values /// https://drafts.csswg.org/css-images/#image-values
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum Image { pub enum Image {
Url(SpecifiedUrl), Url(SpecifiedUrl),
Gradient(Gradient), Gradient(Gradient),
@ -174,6 +175,7 @@ impl ToComputedValue for specified::Gradient {
/// https://drafts.csswg.org/css-images/#gradients /// https://drafts.csswg.org/css-images/#gradients
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum GradientKind { pub enum GradientKind {
Linear(AngleOrCorner), Linear(AngleOrCorner),
Radial(EndingShape, Position), Radial(EndingShape, Position),
@ -271,6 +273,7 @@ impl ToComputedValue for specified::ColorStop {
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-ending-shape /// https://drafts.csswg.org/css-images/#valdef-radial-gradient-ending-shape
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum EndingShape { pub enum EndingShape {
Circle(LengthOrKeyword), Circle(LengthOrKeyword),
Ellipse(LengthOrPercentageOrKeyword), Ellipse(LengthOrPercentageOrKeyword),
@ -336,6 +339,7 @@ impl ToComputedValue for specified::GradientEndingShape {
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size /// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum LengthOrKeyword { pub enum LengthOrKeyword {
Length(Length), Length(Length),
Keyword(SizeKeyword), Keyword(SizeKeyword),
@ -394,6 +398,7 @@ impl ToComputedValue for specified::LengthOrKeyword {
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size /// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum LengthOrPercentageOrKeyword { pub enum LengthOrPercentageOrKeyword {
LengthOrPercentage(LengthOrPercentage, LengthOrPercentage), LengthOrPercentage(LengthOrPercentage, LengthOrPercentage),
Keyword(SizeKeyword), Keyword(SizeKeyword),
@ -458,6 +463,7 @@ impl ToComputedValue for specified::LengthOrPercentageOrKeyword {
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum AngleOrCorner { pub enum AngleOrCorner {
Angle(Angle), Angle(Angle),
Corner(HorizontalDirection, VerticalDirection) Corner(HorizontalDirection, VerticalDirection)

View file

@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! `<length>` computed values, and related ones.
use app_units::Au; use app_units::Au;
use ordered_float::NotNaN; use ordered_float::NotNaN;
use std::fmt; use std::fmt;
@ -16,6 +18,7 @@ pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct CalcLengthOrPercentage { pub struct CalcLengthOrPercentage {
pub length: Au, pub length: Au,
pub percentage: Option<CSSFloat>, pub percentage: Option<CSSFloat>,
@ -23,11 +26,13 @@ pub struct CalcLengthOrPercentage {
impl CalcLengthOrPercentage { impl CalcLengthOrPercentage {
#[inline] #[inline]
#[allow(missing_docs)]
pub fn length(&self) -> Au { pub fn length(&self) -> Au {
self.length self.length
} }
#[inline] #[inline]
#[allow(missing_docs)]
pub fn percentage(&self) -> CSSFloat { pub fn percentage(&self) -> CSSFloat {
self.percentage.unwrap_or(0.) self.percentage.unwrap_or(0.)
} }
@ -130,6 +135,7 @@ impl ToComputedValue for specified::CalcLengthOrPercentage {
#[derive(PartialEq, Clone, Copy)] #[derive(PartialEq, Clone, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum LengthOrPercentage { pub enum LengthOrPercentage {
Length(Au), Length(Au),
Percentage(CSSFloat), Percentage(CSSFloat),
@ -138,6 +144,7 @@ pub enum LengthOrPercentage {
impl LengthOrPercentage { impl LengthOrPercentage {
#[inline] #[inline]
#[allow(missing_docs)]
pub fn zero() -> LengthOrPercentage { pub fn zero() -> LengthOrPercentage {
LengthOrPercentage::Length(Au(0)) LengthOrPercentage::Length(Au(0))
} }
@ -154,6 +161,7 @@ impl LengthOrPercentage {
} }
} }
#[allow(missing_docs)]
pub fn to_hash_key(&self) -> (Au, NotNaN<f32>) { pub fn to_hash_key(&self) -> (Au, NotNaN<f32>) {
use self::LengthOrPercentage::*; use self::LengthOrPercentage::*;
match *self { match *self {
@ -223,6 +231,7 @@ impl ToCss for LengthOrPercentage {
#[derive(PartialEq, Clone, Copy)] #[derive(PartialEq, Clone, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum LengthOrPercentageOrAuto { pub enum LengthOrPercentageOrAuto {
Length(Au), Length(Au),
Percentage(CSSFloat), Percentage(CSSFloat),
@ -311,6 +320,7 @@ impl ToCss for LengthOrPercentageOrAuto {
#[derive(PartialEq, Clone, Copy)] #[derive(PartialEq, Clone, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum LengthOrPercentageOrAutoOrContent { pub enum LengthOrPercentageOrAutoOrContent {
Length(Au), Length(Au),
Percentage(CSSFloat), Percentage(CSSFloat),
@ -397,6 +407,7 @@ impl ToCss for LengthOrPercentageOrAutoOrContent {
#[derive(PartialEq, Clone, Copy)] #[derive(PartialEq, Clone, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum LengthOrPercentageOrNone { pub enum LengthOrPercentageOrNone {
Length(Au), Length(Au),
Percentage(CSSFloat), Percentage(CSSFloat),
@ -469,12 +480,17 @@ impl ToCss for LengthOrPercentageOrNone {
} }
} }
/// A computed `<length>` value.
pub type Length = Au;
/// Either a computed `<length>` or the `none` keyword.
pub type LengthOrNone = Either<Length, None_>; pub type LengthOrNone = Either<Length, None_>;
/// Either a computed `<length>` or the `auto` keyword.
pub type LengthOrAuto = Either<Length, Auto>; pub type LengthOrAuto = Either<Length, Auto>;
/// Either a computed `<length>` or a `<number>` value.
pub type LengthOrNumber = Either<Length, Number>; pub type LengthOrNumber = Either<Length, Number>;
/// Either a computed `<length>` or the `normal` keyword.
pub type LengthOrNormal = Either<Length, Normal>; pub type LengthOrNormal = Either<Length, Normal>;
pub type Length = Au;

View file

@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Computed values.
use app_units::Au; use app_units::Au;
use euclid::size::Size2D; use euclid::size::Size2D;
use font_metrics::FontMetricsProvider; use font_metrics::FontMetricsProvider;
@ -24,23 +26,41 @@ pub mod image;
pub mod length; pub mod length;
pub mod position; pub mod position;
/// A `Context` is all the data a specified value could ever need to compute
/// itself and be transformed to a computed value.
pub struct Context<'a> { pub struct Context<'a> {
/// Whether the current element is the root element.
pub is_root_element: bool, pub is_root_element: bool,
/// The current viewport size.
pub viewport_size: Size2D<Au>, pub viewport_size: Size2D<Au>,
/// The style we're inheriting from.
pub inherited_style: &'a ComputedValues, pub inherited_style: &'a ComputedValues,
/// Values access through this need to be in the properties "computed /// Values access through this need to be in the properties "computed
/// early": color, text-decoration, font-size, display, position, float, /// early": color, text-decoration, font-size, display, position, float,
/// border-*-style, outline-style, font-family, writing-mode... /// border-*-style, outline-style, font-family, writing-mode...
pub style: ComputedValues, pub style: ComputedValues,
/// A font metrics provider, used to access font metrics to implement
/// font-relative units.
///
/// TODO(emilio): This should be required, see #14079.
pub font_metrics_provider: Option<&'a FontMetricsProvider>, pub font_metrics_provider: Option<&'a FontMetricsProvider>,
} }
impl<'a> Context<'a> { impl<'a> Context<'a> {
/// Whether the current element is the root element.
pub fn is_root_element(&self) -> bool { self.is_root_element } pub fn is_root_element(&self) -> bool { self.is_root_element }
/// The current viewport size.
pub fn viewport_size(&self) -> Size2D<Au> { self.viewport_size } pub fn viewport_size(&self) -> Size2D<Au> { self.viewport_size }
/// The style we're inheriting from.
pub fn inherited_style(&self) -> &ComputedValues { &self.inherited_style } pub fn inherited_style(&self) -> &ComputedValues { &self.inherited_style }
/// The current style. Note that only "eager" properties should be accessed
/// from here, see the comment in the member.
pub fn style(&self) -> &ComputedValues { &self.style } pub fn style(&self) -> &ComputedValues { &self.style }
/// A mutable reference to the current style.
pub fn mutate_style(&mut self) -> &mut ComputedValues { &mut self.style } pub fn mutate_style(&mut self) -> &mut ComputedValues { &mut self.style }
/// Creates a dummy computed context for use in multiple places, like /// Creates a dummy computed context for use in multiple places, like
@ -58,11 +78,15 @@ impl<'a> Context<'a> {
} }
} }
/// A trait to represent the conversion between computed and specified values.
pub trait ToComputedValue { pub trait ToComputedValue {
/// The computed value type we're going to be converted to.
type ComputedValue; type ComputedValue;
/// Convert a specified value to a computed value, using itself and the data
/// inside the `Context`.
#[inline] #[inline]
fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue; fn to_computed_value(&self, context: &Context) -> Self::ComputedValue;
#[inline] #[inline]
/// Convert a computed value to specified value form. /// Convert a computed value to specified value form.
@ -72,9 +96,13 @@ pub trait ToComputedValue {
fn from_computed_value(computed: &Self::ComputedValue) -> Self; fn from_computed_value(computed: &Self::ComputedValue) -> Self;
} }
/// A marker trait to represent that the specified value is also the computed
/// value.
pub trait ComputedValueAsSpecified {} pub trait ComputedValueAsSpecified {}
impl<T> ToComputedValue for T where T: ComputedValueAsSpecified + Clone { impl<T> ToComputedValue for T
where T: ComputedValueAsSpecified + Clone,
{
type ComputedValue = T; type ComputedValue = T;
#[inline] #[inline]
@ -133,9 +161,11 @@ impl ToComputedValue for specified::Length {
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct BorderRadiusSize(pub Size2D<LengthOrPercentage>); pub struct BorderRadiusSize(pub Size2D<LengthOrPercentage>);
impl BorderRadiusSize { impl BorderRadiusSize {
#[allow(missing_docs)]
pub fn zero() -> BorderRadiusSize { pub fn zero() -> BorderRadiusSize {
BorderRadiusSize(Size2D::new(LengthOrPercentage::Length(Au(0)), LengthOrPercentage::Length(Au(0)))) BorderRadiusSize(Size2D::new(LengthOrPercentage::Length(Au(0)), LengthOrPercentage::Length(Au(0))))
} }
@ -169,6 +199,7 @@ impl ToCss for BorderRadiusSize {
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct Shadow { pub struct Shadow {
pub offset_x: Au, pub offset_x: Au,
pub offset_y: Au, pub offset_y: Au,
@ -178,5 +209,8 @@ pub struct Shadow {
pub inset: bool, pub inset: bool,
} }
/// A `<number>` value.
pub type Number = CSSFloat; pub type Number = CSSFloat;
/// A type used for opacity.
pub type Opacity = CSSFloat; pub type Opacity = CSSFloat;

View file

@ -13,6 +13,7 @@ use values::computed::LengthOrPercentage;
#[derive(Debug, Clone, PartialEq, Copy)] #[derive(Debug, Clone, PartialEq, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct Position { pub struct Position {
pub horizontal: LengthOrPercentage, pub horizontal: LengthOrPercentage,
pub vertical: LengthOrPercentage, pub vertical: LengthOrPercentage,
@ -29,6 +30,7 @@ impl ToCss for Position {
#[derive(Debug, Clone, PartialEq, Copy)] #[derive(Debug, Clone, PartialEq, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct HorizontalPosition(pub LengthOrPercentage); pub struct HorizontalPosition(pub LengthOrPercentage);
impl ToCss for HorizontalPosition { impl ToCss for HorizontalPosition {
@ -39,6 +41,7 @@ impl ToCss for HorizontalPosition {
#[derive(Debug, Clone, PartialEq, Copy)] #[derive(Debug, Clone, PartialEq, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct VerticalPosition(pub LengthOrPercentage); pub struct VerticalPosition(pub LengthOrPercentage);
impl ToCss for VerticalPosition { impl ToCss for VerticalPosition {

View file

@ -6,6 +6,8 @@
//! //!
//! [values]: https://drafts.csswg.org/css-values/ //! [values]: https://drafts.csswg.org/css-values/
#![deny(missing_docs)]
pub use cssparser::{RGBA, Parser}; pub use cssparser::{RGBA, Parser};
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::fmt::{self, Debug}; use std::fmt::{self, Debug};
@ -16,7 +18,7 @@ macro_rules! define_numbered_css_keyword_enum {
define_numbered_css_keyword_enum!($name: $( $css => $variant = $value ),+); define_numbered_css_keyword_enum!($name: $( $css => $variant = $value ),+);
}; };
($name: ident: $( $css: expr => $variant: ident = $value: expr ),+) => { ($name: ident: $( $css: expr => $variant: ident = $value: expr ),+) => {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types, missing_docs)]
#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Copy, RustcEncodable, Debug)] #[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Copy, RustcEncodable, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
pub enum $name { pub enum $name {
@ -24,6 +26,7 @@ macro_rules! define_numbered_css_keyword_enum {
} }
impl $name { impl $name {
#[allow(missing_docs)]
pub fn parse(input: &mut ::cssparser::Parser) -> Result<$name, ()> { pub fn parse(input: &mut ::cssparser::Parser) -> Result<$name, ()> {
match_ignore_ascii_case! { try!(input.expect_ident()), match_ignore_ascii_case! { try!(input.expect_ident()),
$( $css => Ok($name::$variant), )+ $( $css => Ok($name::$variant), )+
@ -34,7 +37,8 @@ macro_rules! define_numbered_css_keyword_enum {
impl ToCss for $name { impl ToCss for $name {
fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result
where W: ::std::fmt::Write { where W: ::std::fmt::Write,
{
match *self { match *self {
$( $name::$variant => dest.write_str($css) ),+ $( $name::$variant => dest.write_str($css) ),+
} }
@ -46,17 +50,26 @@ macro_rules! define_numbered_css_keyword_enum {
pub mod computed; pub mod computed;
pub mod specified; pub mod specified;
/// A CSS float value.
pub type CSSFloat = f32; pub type CSSFloat = f32;
/// The default font size.
pub const FONT_MEDIUM_PX: i32 = 16; pub const FONT_MEDIUM_PX: i32 = 16;
/// A trait used to query whether this value has viewport units.
pub trait HasViewportPercentage { pub trait HasViewportPercentage {
/// Returns true if this value has viewport units.
fn has_viewport_percentage(&self) -> bool; fn has_viewport_percentage(&self) -> bool;
} }
/// A trait used as a marker to represent that a given type may never contain
/// viewport units.
pub trait NoViewportPercentage {} pub trait NoViewportPercentage {}
impl<T> HasViewportPercentage for T where T: NoViewportPercentage { impl<T> HasViewportPercentage for T
where T: NoViewportPercentage,
{
#[inline]
fn has_viewport_percentage(&self) -> bool { fn has_viewport_percentage(&self) -> bool {
false false
} }
@ -68,6 +81,7 @@ macro_rules! define_keyword_type {
($name: ident, $css: expr) => { ($name: ident, $css: expr) => {
#[derive(Clone, PartialEq, Copy)] #[derive(Clone, PartialEq, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct $name; pub struct $name;
impl ::style_traits::ToCss for $name { impl ::style_traits::ToCss for $name {
@ -99,8 +113,11 @@ define_keyword_type!(Normal, "normal");
#[derive(Clone, PartialEq, Copy)] #[derive(Clone, PartialEq, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A struct representing one of two kinds of values.
pub enum Either<A, B> { pub enum Either<A, B> {
/// The first value.
First(A), First(A),
/// The second kind of value.
Second(B), Second(B),
} }

View file

@ -24,6 +24,7 @@ use values::specified::url::SpecifiedUrl;
/// shape-outside uses ShapeSource<ShapeBox> /// shape-outside uses ShapeSource<ShapeBox>
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum ShapeSource<T> { pub enum ShapeSource<T> {
Url(SpecifiedUrl), Url(SpecifiedUrl),
Shape(BasicShape, Option<T>), Shape(BasicShape, Option<T>),
@ -55,6 +56,7 @@ impl<T: ToCss> ToCss for ShapeSource<T> {
} }
impl<T: Parse + PartialEq + Copy> ShapeSource<T> { impl<T: Parse + PartialEq + Copy> ShapeSource<T> {
#[allow(missing_docs)]
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
if let Ok(_) = input.try(|input| input.expect_ident_matching("none")) { if let Ok(_) = input.try(|input| input.expect_ident_matching("none")) {
Ok(ShapeSource::None) Ok(ShapeSource::None)
@ -129,6 +131,7 @@ impl<T: ToComputedValue> ToComputedValue for ShapeSource<T> {
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum BasicShape { pub enum BasicShape {
Inset(InsetRect), Inset(InsetRect),
Circle(Circle), Circle(Circle),
@ -205,6 +208,7 @@ impl ToComputedValue for BasicShape {
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// https://drafts.csswg.org/css-shapes/#funcdef-inset /// https://drafts.csswg.org/css-shapes/#funcdef-inset
#[allow(missing_docs)]
pub struct InsetRect { pub struct InsetRect {
pub top: LengthOrPercentage, pub top: LengthOrPercentage,
pub right: LengthOrPercentage, pub right: LengthOrPercentage,
@ -214,6 +218,7 @@ pub struct InsetRect {
} }
impl InsetRect { impl InsetRect {
#[allow(missing_docs)]
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<InsetRect, ()> { pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<InsetRect, ()> {
let (t, r, b, l) = try!(parse_four_sides(input, |i| LengthOrPercentage::parse(context, i))); let (t, r, b, l) = try!(parse_four_sides(input, |i| LengthOrPercentage::parse(context, i)));
let mut rect = InsetRect { let mut rect = InsetRect {
@ -373,12 +378,14 @@ fn serialize_basicshape_position<W>(position: &Position, dest: &mut W)
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// https://drafts.csswg.org/css-shapes/#funcdef-circle /// https://drafts.csswg.org/css-shapes/#funcdef-circle
#[allow(missing_docs)]
pub struct Circle { pub struct Circle {
pub radius: ShapeRadius, pub radius: ShapeRadius,
pub position: Position, pub position: Position,
} }
impl Circle { impl Circle {
#[allow(missing_docs)]
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Circle, ()> { pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Circle, ()> {
let radius = input.try(|i| ShapeRadius::parse(context, i)).ok().unwrap_or_else(Default::default); let radius = input.try(|i| ShapeRadius::parse(context, i)).ok().unwrap_or_else(Default::default);
let position = if let Ok(_) = input.try(|input| input.expect_ident_matching("at")) { let position = if let Ok(_) = input.try(|input| input.expect_ident_matching("at")) {
@ -450,6 +457,7 @@ impl ToComputedValue for Circle {
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// https://drafts.csswg.org/css-shapes/#funcdef-ellipse /// https://drafts.csswg.org/css-shapes/#funcdef-ellipse
#[allow(missing_docs)]
pub struct Ellipse { pub struct Ellipse {
pub semiaxis_x: ShapeRadius, pub semiaxis_x: ShapeRadius,
pub semiaxis_y: ShapeRadius, pub semiaxis_y: ShapeRadius,
@ -458,6 +466,7 @@ pub struct Ellipse {
impl Ellipse { impl Ellipse {
#[allow(missing_docs)]
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Ellipse, ()> { pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Ellipse, ()> {
let (a, b) = input.try(|input| -> Result<_, ()> { let (a, b) = input.try(|input| -> Result<_, ()> {
Ok((try!(ShapeRadius::parse(context, input)), try!(ShapeRadius::parse(context, input)))) Ok((try!(ShapeRadius::parse(context, input)), try!(ShapeRadius::parse(context, input))))
@ -537,12 +546,14 @@ impl ToComputedValue for Ellipse {
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// https://drafts.csswg.org/css-shapes/#funcdef-polygon /// https://drafts.csswg.org/css-shapes/#funcdef-polygon
#[allow(missing_docs)]
pub struct Polygon { pub struct Polygon {
pub fill: FillRule, pub fill: FillRule,
pub coordinates: Vec<(LengthOrPercentage, LengthOrPercentage)>, pub coordinates: Vec<(LengthOrPercentage, LengthOrPercentage)>,
} }
impl Polygon { impl Polygon {
#[allow(missing_docs)]
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Polygon, ()> { pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Polygon, ()> {
let fill = input.try(|input| { let fill = input.try(|input| {
let fill = FillRule::parse(context, input); let fill = FillRule::parse(context, input);
@ -626,6 +637,7 @@ impl ToComputedValue for Polygon {
/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius /// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum ShapeRadius { pub enum ShapeRadius {
Length(LengthOrPercentage), Length(LengthOrPercentage),
ClosestSide, ClosestSide,
@ -690,6 +702,7 @@ impl ToComputedValue for ShapeRadius {
/// https://drafts.csswg.org/css-backgrounds-3/#border-radius /// https://drafts.csswg.org/css-backgrounds-3/#border-radius
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct BorderRadius { pub struct BorderRadius {
pub top_left: BorderRadiusSize, pub top_left: BorderRadiusSize,
pub top_right: BorderRadiusSize, pub top_right: BorderRadiusSize,
@ -792,6 +805,7 @@ impl ToComputedValue for BorderRadius {
/// https://drafts.csswg.org/css-shapes/#typedef-fill-rule /// https://drafts.csswg.org/css-shapes/#typedef-fill-rule
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum FillRule { pub enum FillRule {
NonZero, NonZero,
EvenOdd, EvenOdd,
@ -830,6 +844,7 @@ impl ToCss for FillRule {
/// https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box /// https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum GeometryBox { pub enum GeometryBox {
Fill, Fill,
Stroke, Stroke,
@ -868,6 +883,7 @@ impl ComputedValueAsSpecified for GeometryBox {}
// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box // https://drafts.csswg.org/css-shapes-1/#typedef-shape-box
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum ShapeBox { pub enum ShapeBox {
Margin, Margin,
// https://drafts.csswg.org/css-backgrounds-3/#box // https://drafts.csswg.org/css-backgrounds-3/#box

View file

@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! A grid line type.
use cssparser::Parser; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::fmt; use std::fmt;
@ -9,9 +11,10 @@ use style_traits::ToCss;
use values::NoViewportPercentage; use values::NoViewportPercentage;
use values::computed::ComputedValueAsSpecified; use values::computed::ComputedValueAsSpecified;
// https://drafts.csswg.org/css-grid/#typedef-grid-row-start-grid-line
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// https://drafts.csswg.org/css-grid/#typedef-grid-row-start-grid-line
#[allow(missing_docs)]
pub struct GridLine { pub struct GridLine {
pub is_span: bool, pub is_span: bool,
pub ident: Option<String>, pub ident: Option<String>,

View file

@ -21,7 +21,9 @@ use values::specified::url::{SpecifiedUrl, UrlExtraData};
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Image { pub enum Image {
/// A `<url()>` image.
Url(SpecifiedUrl), Url(SpecifiedUrl),
/// A `<gradient>` image.
Gradient(Gradient), Gradient(Gradient),
} }
@ -35,6 +37,7 @@ impl ToCss for Image {
} }
impl Image { impl Image {
#[allow(missing_docs)]
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Image, ()> { pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Image, ()> {
if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) { if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) {
return Ok(Image::Url(url)); return Ok(Image::Url(url));
@ -151,7 +154,14 @@ impl Gradient {
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum GradientKind { pub enum GradientKind {
/// A `<linear-gradient()>`:
///
/// https://drafts.csswg.org/css-images/#funcdef-linear-gradient
Linear(AngleOrCorner), Linear(AngleOrCorner),
/// A `<radial-gradient()>`:
///
/// https://drafts.csswg.org/css-images/#radial-gradients
Radial(EndingShape, Position), Radial(EndingShape, Position),
} }
@ -234,6 +244,7 @@ fn parse_position(context: &ParserContext, input: &mut Parser) -> Result<Positio
/// Specified values for an angle or a corner in a linear gradient. /// Specified values for an angle or a corner in a linear gradient.
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum AngleOrCorner { pub enum AngleOrCorner {
Angle(Angle), Angle(Angle),
Corner(Option<HorizontalDirection>, Option<VerticalDirection>), Corner(Option<HorizontalDirection>, Option<VerticalDirection>),
@ -327,6 +338,7 @@ impl Parse for ColorStop {
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-ending-shape /// https://drafts.csswg.org/css-images/#valdef-radial-gradient-ending-shape
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum EndingShape { pub enum EndingShape {
Circle(LengthOrKeyword), Circle(LengthOrKeyword),
Ellipse(LengthOrPercentageOrKeyword), Ellipse(LengthOrPercentageOrKeyword),
@ -351,6 +363,7 @@ impl ToCss for EndingShape {
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size /// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum LengthOrKeyword { pub enum LengthOrKeyword {
Length(Length), Length(Length),
Keyword(SizeKeyword), Keyword(SizeKeyword),
@ -378,6 +391,7 @@ impl ToCss for LengthOrKeyword {
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size /// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum LengthOrPercentageOrKeyword { pub enum LengthOrPercentageOrKeyword {
LengthOrPercentage(LengthOrPercentage, LengthOrPercentage), LengthOrPercentage(LengthOrPercentage, LengthOrPercentage),
Keyword(SizeKeyword), Keyword(SizeKeyword),

View file

@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! [Length values][length].
//!
//! [length]: https://drafts.csswg.org/css-values/#lengths
use app_units::Au; use app_units::Au;
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
use euclid::size::Size2D; use euclid::size::Size2D;
@ -23,15 +27,22 @@ pub use super::image::{SizeKeyword, VerticalDirection};
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A font relative length.
pub enum FontRelativeLength { pub enum FontRelativeLength {
/// A "em" value: https://drafts.csswg.org/css-values/#em
Em(CSSFloat), Em(CSSFloat),
/// A "ex" value: https://drafts.csswg.org/css-values/#ex
Ex(CSSFloat), Ex(CSSFloat),
/// A "ch" value: https://drafts.csswg.org/css-values/#ch
Ch(CSSFloat), Ch(CSSFloat),
/// A "rem" value: https://drafts.csswg.org/css-values/#rem
Rem(CSSFloat) Rem(CSSFloat)
} }
impl ToCss for FontRelativeLength { impl ToCss for FontRelativeLength {
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
{
match *self { match *self {
FontRelativeLength::Em(length) => write!(dest, "{}em", length), FontRelativeLength::Em(length) => write!(dest, "{}em", length),
FontRelativeLength::Ex(length) => write!(dest, "{}ex", length), FontRelativeLength::Ex(length) => write!(dest, "{}ex", length),
@ -42,6 +53,8 @@ impl ToCss for FontRelativeLength {
} }
impl FontRelativeLength { impl FontRelativeLength {
/// Gets the first available font metrics from the current context's
/// font-family list.
pub fn find_first_available_font_metrics(context: &Context) -> Option<FontMetrics> { pub fn find_first_available_font_metrics(context: &Context) -> Option<FontMetrics> {
use font_metrics::FontMetricsQueryResult::*; use font_metrics::FontMetricsQueryResult::*;
if let Some(ref metrics_provider) = context.font_metrics_provider { if let Some(ref metrics_provider) = context.font_metrics_provider {
@ -55,8 +68,8 @@ impl FontRelativeLength {
None None
} }
// NB: The use_inherited flag is used to special-case the computation of /// Computes the font-relative length. We use the use_inherited flag to
// font-family. /// special-case the computation of font-size.
pub fn to_computed_value(&self, context: &Context, use_inherited: bool) -> Au { pub fn to_computed_value(&self, context: &Context, use_inherited: bool) -> Au {
let reference_font_size = if use_inherited { let reference_font_size = if use_inherited {
context.inherited_style().get_font().clone_font_size() context.inherited_style().get_font().clone_font_size()
@ -121,10 +134,17 @@ impl FontRelativeLength {
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A viewport-relative length.
///
/// https://drafts.csswg.org/css-values/#viewport-relative-lengths
pub enum ViewportPercentageLength { pub enum ViewportPercentageLength {
/// A vw unit: https://drafts.csswg.org/css-values/#vw
Vw(CSSFloat), Vw(CSSFloat),
/// A vh unit: https://drafts.csswg.org/css-values/#vh
Vh(CSSFloat), Vh(CSSFloat),
/// https://drafts.csswg.org/css-values/#vmin
Vmin(CSSFloat), Vmin(CSSFloat),
/// https://drafts.csswg.org/css-values/#vmax
Vmax(CSSFloat) Vmax(CSSFloat)
} }
@ -146,6 +166,7 @@ impl ToCss for ViewportPercentageLength {
} }
impl ViewportPercentageLength { impl ViewportPercentageLength {
/// Computes the given viewport-relative length for the given viewport size.
pub fn to_computed_value(&self, viewport_size: Size2D<Au>) -> Au { pub fn to_computed_value(&self, viewport_size: Size2D<Au>) -> Au {
macro_rules! to_unit { macro_rules! to_unit {
($viewport_dimension:expr) => { ($viewport_dimension:expr) => {
@ -167,11 +188,13 @@ impl ViewportPercentageLength {
} }
} }
/// HTML5 "character width", as defined in HTML5 § 14.5.4.
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct CharacterWidth(pub i32); pub struct CharacterWidth(pub i32);
impl CharacterWidth { impl CharacterWidth {
/// Computes the given character width.
pub fn to_computed_value(&self, reference_font_size: Au) -> Au { pub fn to_computed_value(&self, reference_font_size: Au) -> Au {
// This applies the *converting a character width to pixels* algorithm as specified // This applies the *converting a character width to pixels* algorithm as specified
// in HTML5 § 14.5.4. // in HTML5 § 14.5.4.
@ -183,11 +206,23 @@ impl CharacterWidth {
} }
} }
/// A length.
///
/// https://drafts.csswg.org/css-values/#lengths
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Length { pub enum Length {
/// An absolute length: https://drafts.csswg.org/css-values/#absolute-length
Absolute(Au), // application units Absolute(Au), // application units
/// A font-relative length:
///
/// https://drafts.csswg.org/css-values/#font-relative-lengths
FontRelative(FontRelativeLength), FontRelative(FontRelativeLength),
/// A viewport-relative length.
///
/// https://drafts.csswg.org/css-values/#viewport-relative-lengths
ViewportPercentage(ViewportPercentageLength), ViewportPercentage(ViewportPercentageLength),
/// HTML5 "character width", as defined in HTML5 § 14.5.4. /// HTML5 "character width", as defined in HTML5 § 14.5.4.
@ -196,6 +231,12 @@ pub enum Length {
/// `Stylist::synthesize_rules_for_legacy_attributes()`. /// `Stylist::synthesize_rules_for_legacy_attributes()`.
ServoCharacterWidth(CharacterWidth), ServoCharacterWidth(CharacterWidth),
/// A calc expression.
///
/// https://drafts.csswg.org/css-values/#calc-notation
///
/// TODO(emilio): We have more `Calc` variants around, we should only use
/// one.
Calc(CalcLengthOrPercentage, AllowedNumericType), Calc(CalcLengthOrPercentage, AllowedNumericType),
} }
@ -274,7 +315,7 @@ const AU_PER_PT: CSSFloat = AU_PER_IN / 72.;
const AU_PER_PC: CSSFloat = AU_PER_PT * 12.; const AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
impl Length { impl Length {
// https://drafts.csswg.org/css-fonts-3/#font-size-prop /// https://drafts.csswg.org/css-fonts-3/#font-size-prop
pub fn from_str(s: &str) -> Option<Length> { pub fn from_str(s: &str) -> Option<Length> {
Some(match_ignore_ascii_case! { s, Some(match_ignore_ascii_case! { s,
"xx-small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 5), "xx-small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 5),
@ -306,9 +347,13 @@ impl Length {
_ => Err(()) _ => Err(())
} }
} }
/// Parse a non-negative length
pub fn parse_non_negative(input: &mut Parser) -> Result<Length, ()> { pub fn parse_non_negative(input: &mut Parser) -> Result<Length, ()> {
Length::parse_internal(input, AllowedNumericType::NonNegative) Length::parse_internal(input, AllowedNumericType::NonNegative)
} }
/// Parse a given absolute or relative dimension.
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> { pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> {
match_ignore_ascii_case! { unit, match_ignore_ascii_case! { unit,
"px" => Ok(Length::from_px(value)), "px" => Ok(Length::from_px(value)),
@ -331,6 +376,8 @@ impl Length {
_ => Err(()) _ => Err(())
} }
} }
/// Get an absolute length from a px values.
#[inline] #[inline]
pub fn from_px(px_value: CSSFloat) -> Length { pub fn from_px(px_value: CSSFloat) -> Length {
Length::Absolute(Au((px_value * AU_PER_PX) as i32)) Length::Absolute(Au((px_value * AU_PER_PX) as i32))
@ -345,22 +392,29 @@ impl Parse for Length {
impl<T> Either<Length, T> { impl<T> Either<Length, T> {
#[inline] #[inline]
#[allow(missing_docs)]
pub fn parse_non_negative_length(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { pub fn parse_non_negative_length(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
Length::parse_internal(input, AllowedNumericType::NonNegative).map(Either::First) Length::parse_internal(input, AllowedNumericType::NonNegative).map(Either::First)
} }
} }
/// A calc sum expression node.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct CalcSumNode { pub struct CalcSumNode {
/// The products of this node.
pub products: Vec<CalcProductNode>, pub products: Vec<CalcProductNode>,
} }
/// A calc product expression node.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct CalcProductNode { pub struct CalcProductNode {
/// The values inside this product node.
values: Vec<CalcValueNode> values: Vec<CalcValueNode>
} }
/// A value inside a `Calc` expression.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[allow(missing_docs)]
pub enum CalcValueNode { pub enum CalcValueNode {
Length(Length), Length(Length),
Angle(Angle), Angle(Angle),
@ -371,6 +425,7 @@ pub enum CalcValueNode {
} }
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
#[allow(missing_docs)]
pub enum CalcUnit { pub enum CalcUnit {
Number, Number,
Integer, Integer,
@ -382,6 +437,7 @@ pub enum CalcUnit {
#[derive(Clone, PartialEq, Copy, Debug, Default)] #[derive(Clone, PartialEq, Copy, Debug, Default)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct CalcLengthOrPercentage { pub struct CalcLengthOrPercentage {
pub absolute: Option<Au>, pub absolute: Option<Au>,
pub vw: Option<ViewportPercentageLength>, pub vw: Option<ViewportPercentageLength>,
@ -396,6 +452,7 @@ pub struct CalcLengthOrPercentage {
} }
impl CalcLengthOrPercentage { impl CalcLengthOrPercentage {
/// Parse a calc sum node.
pub fn parse_sum(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcSumNode, ()> { pub fn parse_sum(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcSumNode, ()> {
let mut products = Vec::new(); let mut products = Vec::new();
products.push(try!(CalcLengthOrPercentage::parse_product(input, expected_unit))); products.push(try!(CalcLengthOrPercentage::parse_product(input, expected_unit)));
@ -516,6 +573,7 @@ impl CalcLengthOrPercentage {
} }
} }
#[allow(missing_docs)]
pub fn simplify_product(node: &CalcProductNode) -> Result<SimplifiedValueNode, ()> { pub fn simplify_product(node: &CalcProductNode) -> Result<SimplifiedValueNode, ()> {
let mut multiplier = 1.; let mut multiplier = 1.;
let mut node_with_unit = None; let mut node_with_unit = None;
@ -554,6 +612,7 @@ impl CalcLengthOrPercentage {
CalcLengthOrPercentage::parse(input, CalcUnit::LengthOrPercentage) CalcLengthOrPercentage::parse(input, CalcUnit::LengthOrPercentage)
} }
#[allow(missing_docs)]
pub fn parse(input: &mut Parser, pub fn parse(input: &mut Parser,
expected_unit: CalcUnit) -> Result<CalcLengthOrPercentage, ()> { expected_unit: CalcUnit) -> Result<CalcLengthOrPercentage, ()> {
let ast = try!(CalcLengthOrPercentage::parse_sum(input, expected_unit)); let ast = try!(CalcLengthOrPercentage::parse_sum(input, expected_unit));
@ -624,6 +683,7 @@ impl CalcLengthOrPercentage {
}) })
} }
#[allow(missing_docs)]
pub fn parse_time(input: &mut Parser) -> Result<Time, ()> { pub fn parse_time(input: &mut Parser) -> Result<Time, ()> {
let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Time)); let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Time));
@ -651,6 +711,7 @@ impl CalcLengthOrPercentage {
} }
} }
#[allow(missing_docs)]
pub fn parse_angle(input: &mut Parser) -> Result<Angle, ()> { pub fn parse_angle(input: &mut Parser) -> Result<Angle, ()> {
let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Angle)); let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Angle));
@ -740,9 +801,12 @@ impl ToCss for CalcLengthOrPercentage {
} }
} }
/// A percentage value.
///
/// [0 .. 100%] maps to [0.0 .. 1.0]
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Percentage(pub CSSFloat); // [0 .. 100%] maps to [0.0 .. 1.0] pub struct Percentage(pub CSSFloat);
impl ToCss for Percentage { impl ToCss for Percentage {
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 {
@ -762,8 +826,12 @@ impl Parse for Percentage {
} }
} }
/// A length or a percentage value.
///
/// TODO(emilio): Does this make any sense vs. CalcLengthOrPercentage?
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum LengthOrPercentage { pub enum LengthOrPercentage {
Length(Length), Length(Length),
Percentage(Percentage), Percentage(Percentage),
@ -790,6 +858,7 @@ impl ToCss for LengthOrPercentage {
} }
} }
impl LengthOrPercentage { impl LengthOrPercentage {
/// Returns a `zero` length.
pub fn zero() -> LengthOrPercentage { pub fn zero() -> LengthOrPercentage {
LengthOrPercentage::Length(Length::Absolute(Au(0))) LengthOrPercentage::Length(Length::Absolute(Au(0)))
} }
@ -812,6 +881,7 @@ impl LengthOrPercentage {
} }
} }
/// Parse a non-negative length.
#[inline] #[inline]
pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentage, ()> { pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentage, ()> {
LengthOrPercentage::parse_internal(input, AllowedNumericType::NonNegative) LengthOrPercentage::parse_internal(input, AllowedNumericType::NonNegative)
@ -825,8 +895,11 @@ impl Parse for LengthOrPercentage {
} }
} }
/// TODO(emilio): Do the Length and Percentage variants make any sense with
/// CalcLengthOrPercentage?
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum LengthOrPercentageOrAuto { pub enum LengthOrPercentageOrAuto {
Length(Length), Length(Length),
Percentage(Percentage), Percentage(Percentage),
@ -875,6 +948,8 @@ impl LengthOrPercentageOrAuto {
_ => Err(()) _ => Err(())
} }
} }
/// Parse a non-negative length, percentage, or auto.
#[inline] #[inline]
pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> { pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> {
LengthOrPercentageOrAuto::parse_internal(input, AllowedNumericType::NonNegative) LengthOrPercentageOrAuto::parse_internal(input, AllowedNumericType::NonNegative)
@ -888,8 +963,11 @@ impl Parse for LengthOrPercentageOrAuto {
} }
} }
/// TODO(emilio): Do the Length and Percentage variants make any sense with
/// CalcLengthOrPercentage?
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum LengthOrPercentageOrNone { pub enum LengthOrPercentageOrNone {
Length(Length), Length(Length),
Percentage(Percentage), Percentage(Percentage),
@ -937,6 +1015,7 @@ impl LengthOrPercentageOrNone {
_ => Err(()) _ => Err(())
} }
} }
/// Parse a non-negative LengthOrPercentageOrNone.
#[inline] #[inline]
pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrNone, ()> { pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrNone, ()> {
LengthOrPercentageOrNone::parse_internal(input, AllowedNumericType::NonNegative) LengthOrPercentageOrNone::parse_internal(input, AllowedNumericType::NonNegative)
@ -950,19 +1029,31 @@ impl Parse for LengthOrPercentageOrNone {
} }
} }
/// Either a `<length>` or the `none` keyword.
pub type LengthOrNone = Either<Length, None_>; pub type LengthOrNone = Either<Length, None_>;
/// Either a `<length>` or the `normal` keyword.
pub type LengthOrNormal = Either<Length, Normal>; pub type LengthOrNormal = Either<Length, Normal>;
/// Either a `<length>` or the `auto` keyword.
pub type LengthOrAuto = Either<Length, Auto>; pub type LengthOrAuto = Either<Length, Auto>;
/// Either a `<length>` or a `<percentage>` or the `auto` keyword or the
/// `content` keyword.
///
/// TODO(emilio): Do the Length and Percentage variants make any sense with
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum LengthOrPercentageOrAutoOrContent { pub enum LengthOrPercentageOrAutoOrContent {
/// A `<length>`.
Length(Length), Length(Length),
/// A percentage.
Percentage(Percentage), Percentage(Percentage),
/// A `calc` node.
Calc(CalcLengthOrPercentage), Calc(CalcLengthOrPercentage),
/// The `auto` keyword.
Auto, Auto,
/// The `content` keyword.
Content Content
} }
@ -1011,9 +1102,11 @@ impl Parse for LengthOrPercentageOrAutoOrContent {
} }
} }
/// Either a `<length>` or a `<number>`.
pub type LengthOrNumber = Either<Length, Number>; pub type LengthOrNumber = Either<Length, Number>;
impl LengthOrNumber { impl LengthOrNumber {
/// Parse a non-negative LengthOrNumber.
pub fn parse_non_negative(input: &mut Parser) -> Result<Self, ()> { pub fn parse_non_negative(input: &mut Parser) -> Result<Self, ()> {
if let Ok(v) = input.try(Length::parse_non_negative) { if let Ok(v) = input.try(Length::parse_non_negative) {
Ok(Either::First(v)) Ok(Either::First(v))

View file

@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Specified values.
//!
//! TODO(emilio): Enhance docs.
use app_units::Au; use app_units::Au;
use cssparser::{self, Parser, Token}; use cssparser::{self, Parser, Token};
use euclid::size::Size2D; use euclid::size::Size2D;
@ -35,6 +39,7 @@ impl NoViewportPercentage for i32 {} // For PropertyDeclaration::Order
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct CSSColor { pub struct CSSColor {
pub parsed: cssparser::Color, pub parsed: cssparser::Color,
pub authored: Option<String>, pub authored: Option<String>,
@ -68,6 +73,7 @@ impl ToCss for CSSColor {
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct CSSRGBA { pub struct CSSRGBA {
pub parsed: cssparser::RGBA, pub parsed: cssparser::RGBA,
pub authored: Option<String>, pub authored: Option<String>,
@ -85,6 +91,7 @@ impl ToCss for CSSRGBA {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[allow(missing_docs)]
pub struct SimplifiedSumNode { pub struct SimplifiedSumNode {
values: Vec<SimplifiedValueNode>, values: Vec<SimplifiedValueNode>,
} }
@ -100,6 +107,7 @@ impl<'a> Mul<CSSFloat> for &'a SimplifiedSumNode {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[allow(missing_docs)]
pub enum SimplifiedValueNode { pub enum SimplifiedValueNode {
Length(Length), Length(Length),
Angle(Angle), Angle(Angle),
@ -127,6 +135,7 @@ impl<'a> Mul<CSSFloat> for &'a SimplifiedValueNode {
} }
} }
#[allow(missing_docs)]
pub fn parse_integer(input: &mut Parser) -> Result<i32, ()> { pub fn parse_integer(input: &mut Parser) -> Result<i32, ()> {
match try!(input.next()) { match try!(input.next()) {
Token::Number(ref value) => value.int_value.ok_or(()), Token::Number(ref value) => value.int_value.ok_or(()),
@ -152,6 +161,7 @@ pub fn parse_integer(input: &mut Parser) -> Result<i32, ()> {
} }
} }
#[allow(missing_docs)]
pub fn parse_number(input: &mut Parser) -> Result<f32, ()> { pub fn parse_number(input: &mut Parser) -> Result<f32, ()> {
match try!(input.next()) { match try!(input.next()) {
Token::Number(ref value) => Ok(value.value), Token::Number(ref value) => Ok(value.value),
@ -179,20 +189,24 @@ pub fn parse_number(input: &mut Parser) -> Result<f32, ()> {
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct BorderRadiusSize(pub Size2D<LengthOrPercentage>); pub struct BorderRadiusSize(pub Size2D<LengthOrPercentage>);
impl NoViewportPercentage for BorderRadiusSize {} impl NoViewportPercentage for BorderRadiusSize {}
impl BorderRadiusSize { impl BorderRadiusSize {
#[allow(missing_docs)]
pub fn zero() -> BorderRadiusSize { pub fn zero() -> BorderRadiusSize {
let zero = LengthOrPercentage::Length(Length::Absolute(Au(0))); let zero = LengthOrPercentage::Length(Length::Absolute(Au(0)));
BorderRadiusSize(Size2D::new(zero, zero)) BorderRadiusSize(Size2D::new(zero, zero))
} }
#[allow(missing_docs)]
pub fn new(width: LengthOrPercentage, height: LengthOrPercentage) -> BorderRadiusSize { pub fn new(width: LengthOrPercentage, height: LengthOrPercentage) -> BorderRadiusSize {
BorderRadiusSize(Size2D::new(width, height)) BorderRadiusSize(Size2D::new(width, height))
} }
#[allow(missing_docs)]
pub fn circle(radius: LengthOrPercentage) -> BorderRadiusSize { pub fn circle(radius: LengthOrPercentage) -> BorderRadiusSize {
BorderRadiusSize(Size2D::new(radius, radius)) BorderRadiusSize(Size2D::new(radius, radius))
} }
@ -228,11 +242,13 @@ impl ToCss for Angle {
impl Angle { impl Angle {
#[inline] #[inline]
#[allow(missing_docs)]
pub fn radians(self) -> f32 { pub fn radians(self) -> f32 {
self.0 self.0
} }
#[inline] #[inline]
#[allow(missing_docs)]
pub fn from_radians(r: f32) -> Self { pub fn from_radians(r: f32) -> Self {
Angle(r) Angle(r)
} }
@ -257,6 +273,7 @@ impl Parse for Angle {
} }
impl Angle { impl Angle {
#[allow(missing_docs)]
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Angle, ()> { pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Angle, ()> {
match_ignore_ascii_case! { unit, match_ignore_ascii_case! { unit,
"deg" => Ok(Angle(value * RAD_PER_DEG)), "deg" => Ok(Angle(value * RAD_PER_DEG)),
@ -268,20 +285,22 @@ impl Angle {
} }
} }
#[allow(missing_docs)]
pub fn parse_border_radius(context: &ParserContext, input: &mut Parser) -> Result<BorderRadiusSize, ()> { pub fn parse_border_radius(context: &ParserContext, input: &mut Parser) -> Result<BorderRadiusSize, ()> {
input.try(|i| BorderRadiusSize::parse(context, i)).or_else(|()| { input.try(|i| BorderRadiusSize::parse(context, i)).or_else(|_| {
match_ignore_ascii_case! { try!(input.expect_ident()), match_ignore_ascii_case! { try!(input.expect_ident()),
"thin" => Ok(BorderRadiusSize::circle( "thin" => Ok(BorderRadiusSize::circle(
LengthOrPercentage::Length(Length::from_px(1.)))), LengthOrPercentage::Length(Length::from_px(1.)))),
"medium" => Ok(BorderRadiusSize::circle( "medium" => Ok(BorderRadiusSize::circle(
LengthOrPercentage::Length(Length::from_px(3.)))), LengthOrPercentage::Length(Length::from_px(3.)))),
"thick" => Ok(BorderRadiusSize::circle( "thick" => Ok(BorderRadiusSize::circle(
LengthOrPercentage::Length(Length::from_px(5.)))), LengthOrPercentage::Length(Length::from_px(5.)))),
_ => Err(()) _ => Err(())
} }
}) })
} }
#[allow(missing_docs)]
pub fn parse_border_width(input: &mut Parser) -> Result<Length, ()> { pub fn parse_border_width(input: &mut Parser) -> Result<Length, ()> {
input.try(Length::parse_non_negative).or_else(|()| { input.try(Length::parse_non_negative).or_else(|()| {
match_ignore_ascii_case! { try!(input.expect_ident()), match_ignore_ascii_case! { try!(input.expect_ident()),
@ -295,6 +314,7 @@ pub fn parse_border_width(input: &mut Parser) -> Result<Length, ()> {
#[derive(Clone, PartialEq, Copy, Debug)] #[derive(Clone, PartialEq, Copy, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum BorderWidth { pub enum BorderWidth {
Thin, Thin,
Medium, Medium,
@ -317,6 +337,7 @@ impl Parse for BorderWidth {
} }
impl BorderWidth { impl BorderWidth {
#[allow(missing_docs)]
pub fn from_length(length: Length) -> Self { pub fn from_length(length: Length) -> Self {
BorderWidth::Width(length) BorderWidth::Width(length)
} }
@ -382,6 +403,7 @@ define_numbered_css_keyword_enum! { BorderStyle:
impl NoViewportPercentage for BorderStyle {} impl NoViewportPercentage for BorderStyle {}
impl BorderStyle { impl BorderStyle {
/// Whether this border style is either none or hidden.
pub fn none_or_hidden(&self) -> bool { pub fn none_or_hidden(&self) -> bool {
matches!(*self, BorderStyle::none | BorderStyle::hidden) matches!(*self, BorderStyle::none | BorderStyle::hidden)
} }
@ -435,6 +457,7 @@ impl ToCss for Time {
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct Number(pub CSSFloat); pub struct Number(pub CSSFloat);
impl NoViewportPercentage for Number {} impl NoViewportPercentage for Number {}
@ -453,10 +476,12 @@ impl Number {
} }
} }
#[allow(missing_docs)]
pub fn parse_non_negative(input: &mut Parser) -> Result<Number, ()> { pub fn parse_non_negative(input: &mut Parser) -> Result<Number, ()> {
Number::parse_with_minimum(input, 0.0) Number::parse_with_minimum(input, 0.0)
} }
#[allow(missing_docs)]
pub fn parse_at_least_one(input: &mut Parser) -> Result<Number, ()> { pub fn parse_at_least_one(input: &mut Parser) -> Result<Number, ()> {
Number::parse_with_minimum(input, 1.0) Number::parse_with_minimum(input, 1.0)
} }
@ -482,6 +507,7 @@ impl ToCss for Number {
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct Opacity(pub CSSFloat); pub struct Opacity(pub CSSFloat);
impl NoViewportPercentage for Opacity {} impl NoViewportPercentage for Opacity {}
@ -518,10 +544,12 @@ impl ToCss for Opacity {
} }
} }
#[allow(missing_docs)]
pub type UrlOrNone = Either<SpecifiedUrl, None_>; pub type UrlOrNone = Either<SpecifiedUrl, None_>;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct Shadow { pub struct Shadow {
pub offset_x: Length, pub offset_x: Length,
pub offset_y: Length, pub offset_y: Length,
@ -573,6 +601,7 @@ impl ToComputedValue for Shadow {
impl Shadow { impl Shadow {
// disable_spread_and_inset is for filter: drop-shadow(...) // disable_spread_and_inset is for filter: drop-shadow(...)
#[allow(missing_docs)]
pub fn parse(context: &ParserContext, input: &mut Parser, disable_spread_and_inset: bool) -> Result<Shadow, ()> { pub fn parse(context: &ParserContext, input: &mut Parser, disable_spread_and_inset: bool) -> Result<Shadow, ()> {
use app_units::Au; use app_units::Au;
let length_count = if disable_spread_and_inset { 3 } else { 4 }; let length_count = if disable_spread_and_inset { 3 } else { 4 };

View file

@ -20,8 +20,13 @@ use values::specified::{LengthOrPercentage, Percentage};
#[derive(Debug, Clone, PartialEq, Copy)] #[derive(Debug, Clone, PartialEq, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A [position][pos].
///
/// [pos]: https://drafts.csswg.org/css-values/#position
pub struct Position { pub struct Position {
/// The horizontal component.
pub horizontal: HorizontalPosition, pub horizontal: HorizontalPosition,
/// The vertical component.
pub vertical: VerticalPosition, pub vertical: VerticalPosition,
} }
@ -59,9 +64,12 @@ impl HasViewportPercentage for Position {
} }
impl Position { impl Position {
pub fn new(mut first_position: Option<PositionComponent>, mut second_position: Option<PositionComponent>, /// Create a new position value.
first_keyword: Option<PositionComponent>, second_keyword: Option<PositionComponent>) pub fn new(mut first_position: Option<PositionComponent>,
-> Result<Position, ()> { mut second_position: Option<PositionComponent>,
first_keyword: Option<PositionComponent>,
second_keyword: Option<PositionComponent>)
-> Result<Position, ()> {
// Unwrap for checking if values are at right place. // Unwrap for checking if values are at right place.
let first_key = first_keyword.unwrap_or(PositionComponent::Keyword(Keyword::Left)); let first_key = first_keyword.unwrap_or(PositionComponent::Keyword(Keyword::Left));
let second_key = second_keyword.unwrap_or(PositionComponent::Keyword(Keyword::Top)); let second_key = second_keyword.unwrap_or(PositionComponent::Keyword(Keyword::Top));
@ -150,6 +158,7 @@ impl Position {
}) })
} }
/// Returns a "centered" position, as in "center center".
pub fn center() -> Position { pub fn center() -> Position {
Position { Position {
horizontal: HorizontalPosition { horizontal: HorizontalPosition {
@ -242,6 +251,7 @@ impl ToComputedValue for Position {
#[derive(Debug, Clone, PartialEq, Copy)] #[derive(Debug, Clone, PartialEq, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct HorizontalPosition { pub struct HorizontalPosition {
pub keyword: Option<Keyword>, pub keyword: Option<Keyword>,
pub position: Option<LengthOrPercentage>, pub position: Option<LengthOrPercentage>,
@ -249,11 +259,7 @@ pub struct HorizontalPosition {
impl HasViewportPercentage for HorizontalPosition { impl HasViewportPercentage for HorizontalPosition {
fn has_viewport_percentage(&self) -> bool { fn has_viewport_percentage(&self) -> bool {
if let Some(pos) = self.position { self.position.map_or(false, |pos| pos.has_viewport_percentage())
pos.has_viewport_percentage()
} else {
false
}
} }
} }
@ -371,6 +377,7 @@ impl ToComputedValue for HorizontalPosition {
#[derive(Debug, Clone, PartialEq, Copy)] #[derive(Debug, Clone, PartialEq, Copy)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct VerticalPosition { pub struct VerticalPosition {
pub keyword: Option<Keyword>, pub keyword: Option<Keyword>,
pub position: Option<LengthOrPercentage>, pub position: Option<LengthOrPercentage>,
@ -378,11 +385,7 @@ pub struct VerticalPosition {
impl HasViewportPercentage for VerticalPosition { impl HasViewportPercentage for VerticalPosition {
fn has_viewport_percentage(&self) -> bool { fn has_viewport_percentage(&self) -> bool {
if let Some(pos) = self.position { self.position.map_or(false, |pos| pos.has_viewport_percentage())
pos.has_viewport_percentage()
} else {
false
}
} }
} }
@ -510,6 +513,7 @@ define_css_keyword_enum!(Keyword:
"y-end" => YEnd); "y-end" => YEnd);
impl Keyword { impl Keyword {
/// Convert the given keyword to a length or a percentage.
pub fn to_length_or_percentage(self) -> LengthOrPercentage { pub fn to_length_or_percentage(self) -> LengthOrPercentage {
match self { match self {
Keyword::Center => LengthOrPercentage::Percentage(Percentage(0.5)), Keyword::Center => LengthOrPercentage::Percentage(Percentage(0.5)),
@ -532,10 +536,14 @@ enum PositionCategory {
LengthOrPercentage, LengthOrPercentage,
} }
// http://dev.w3.org/csswg/css2/colors.html#propdef-background-position /// A position component.
///
/// http://dev.w3.org/csswg/css2/colors.html#propdef-background-position
#[derive(Clone, PartialEq, Copy)] #[derive(Clone, PartialEq, Copy)]
pub enum PositionComponent { pub enum PositionComponent {
/// A `<length>`
Length(LengthOrPercentage), Length(LengthOrPercentage),
/// A position keyword.
Keyword(Keyword), Keyword(Keyword),
} }
@ -568,6 +576,7 @@ impl HasViewportPercentage for PositionComponent {
} }
impl PositionComponent { impl PositionComponent {
/// Convert the given position component to a length or a percentage.
#[inline] #[inline]
pub fn to_length_or_percentage(self) -> LengthOrPercentage { pub fn to_length_or_percentage(self) -> LengthOrPercentage {
match self { match self {

View file

@ -18,23 +18,29 @@ use style_traits::ToCss;
use values::NoViewportPercentage; use values::NoViewportPercentage;
use values::computed::ComputedValueAsSpecified; use values::computed::ComputedValueAsSpecified;
/// A set of data needed in Gecko to represent a URL.
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Serialize, Deserialize, Eq))] #[cfg_attr(feature = "servo", derive(HeapSizeOf, Serialize, Deserialize, Eq))]
pub struct UrlExtraData { pub struct UrlExtraData {
/// The base URI.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub base: GeckoArcURI, pub base: GeckoArcURI,
/// The referrer.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub referrer: GeckoArcURI, pub referrer: GeckoArcURI,
/// The principal that originated this URI.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub principal: GeckoArcPrincipal, pub principal: GeckoArcPrincipal,
} }
impl UrlExtraData { impl UrlExtraData {
/// Constructs a `UrlExtraData`.
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
pub fn make_from(_: &ParserContext) -> Option<UrlExtraData> { pub fn make_from(_: &ParserContext) -> Option<UrlExtraData> {
Some(UrlExtraData { }) Some(UrlExtraData { })
} }
/// Constructs a `UrlExtraData`.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub fn make_from(context: &ParserContext) -> Option<UrlExtraData> { pub fn make_from(context: &ParserContext) -> Option<UrlExtraData> {
match context.extra_data { match context.extra_data {
@ -81,6 +87,11 @@ impl Parse for SpecifiedUrl {
} }
impl SpecifiedUrl { impl SpecifiedUrl {
/// Try to parse a URL from a string value that is a valid CSS token for a
/// URL.
///
/// Only returns `Err` for Gecko, in the case we can't construct a
/// `URLExtraData`.
pub fn parse_from_string<'a>(url: Cow<'a, str>, pub fn parse_from_string<'a>(url: Cow<'a, str>,
context: &ParserContext) context: &ParserContext)
-> Result<Self, ()> { -> Result<Self, ()> {
@ -104,14 +115,19 @@ impl SpecifiedUrl {
}) })
} }
/// Get this URL's extra data.
pub fn extra_data(&self) -> &UrlExtraData { pub fn extra_data(&self) -> &UrlExtraData {
&self.extra_data &self.extra_data
} }
/// Returns the resolved url if it was valid.
pub fn url(&self) -> Option<&ServoUrl> { pub fn url(&self) -> Option<&ServoUrl> {
self.resolved.as_ref() self.resolved.as_ref()
} }
/// Return the resolved url as string, or the empty string if it's invalid.
///
/// TODO(emilio): Should we return the original one if needed?
pub fn as_str(&self) -> &str { pub fn as_str(&self) -> &str {
match self.resolved { match self.resolved {
Some(ref url) => url.as_str(), Some(ref url) => url.as_str(),
@ -142,6 +158,7 @@ impl SpecifiedUrl {
} }
} }
/// Gets a new url from a string for unit tests.
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
pub fn new_for_testing(url: &str) -> Self { pub fn new_for_testing(url: &str) -> Self {
SpecifiedUrl { SpecifiedUrl {

View file

@ -7,6 +7,8 @@
//! [at]: https://drafts.csswg.org/css-device-adapt/#atviewport-rule //! [at]: https://drafts.csswg.org/css-device-adapt/#atviewport-rule
//! [meta]: https://drafts.csswg.org/css-device-adapt/#viewport-meta //! [meta]: https://drafts.csswg.org/css-device-adapt/#viewport-meta
#![deny(missing_docs)]
use app_units::Au; use app_units::Au;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important}; use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important};
use cssparser::ToCss as ParserToCss; use cssparser::ToCss as ParserToCss;
@ -60,6 +62,7 @@ macro_rules! declare_viewport_descriptor_inner {
) => { ) => {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum ViewportDescriptor { pub enum ViewportDescriptor {
$( $(
$assigned_variant($assigned_data), $assigned_variant($assigned_data),
@ -69,6 +72,7 @@ macro_rules! declare_viewport_descriptor_inner {
const VIEWPORT_DESCRIPTOR_VARIANTS: usize = $number_of_variants; const VIEWPORT_DESCRIPTOR_VARIANTS: usize = $number_of_variants;
impl ViewportDescriptor { impl ViewportDescriptor {
#[allow(missing_docs)]
pub fn discriminant_value(&self) -> usize { pub fn discriminant_value(&self) -> usize {
match *self { match *self {
$( $(
@ -114,12 +118,13 @@ trait FromMeta: Sized {
fn from_meta(value: &str) -> Option<Self>; fn from_meta(value: &str) -> Option<Self>;
} }
// ViewportLength is a length | percentage | auto | extend-to-zoom /// ViewportLength is a length | percentage | auto | extend-to-zoom
// See: /// See:
// * http://dev.w3.org/csswg/css-device-adapt/#min-max-width-desc /// * http://dev.w3.org/csswg/css-device-adapt/#min-max-width-desc
// * http://dev.w3.org/csswg/css-device-adapt/#extend-to-zoom /// * http://dev.w3.org/csswg/css-device-adapt/#extend-to-zoom
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum ViewportLength { pub enum ViewportLength {
Specified(LengthOrPercentageOrAuto), Specified(LengthOrPercentageOrAuto),
ExtendToZoom ExtendToZoom
@ -127,7 +132,7 @@ pub enum ViewportLength {
impl ToCss for ViewportLength { impl ToCss for ViewportLength {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write where W: fmt::Write,
{ {
match *self { match *self {
ViewportLength::Specified(length) => length.to_css(dest), ViewportLength::Specified(length) => length.to_css(dest),
@ -209,6 +214,7 @@ struct ViewportRuleParser<'a, 'b: 'a> {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct ViewportDescriptorDeclaration { pub struct ViewportDescriptorDeclaration {
pub origin: Origin, pub origin: Origin,
pub descriptor: ViewportDescriptor, pub descriptor: ViewportDescriptor,
@ -216,6 +222,7 @@ pub struct ViewportDescriptorDeclaration {
} }
impl ViewportDescriptorDeclaration { impl ViewportDescriptorDeclaration {
#[allow(missing_docs)]
pub fn new(origin: Origin, pub fn new(origin: Origin,
descriptor: ViewportDescriptor, descriptor: ViewportDescriptor,
important: bool) -> ViewportDescriptorDeclaration important: bool) -> ViewportDescriptorDeclaration
@ -313,9 +320,11 @@ impl<'a, 'b> DeclarationParser for ViewportRuleParser<'a, 'b> {
} }
} }
/// A `@viewport` rule.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct ViewportRule { pub struct ViewportRule {
/// The declarations contained in this @viewport rule.
pub declarations: Vec<ViewportDescriptorDeclaration> pub declarations: Vec<ViewportDescriptorDeclaration>
} }
@ -333,6 +342,7 @@ fn is_whitespace_separator_or_equals(c: &char) -> bool {
} }
impl ViewportRule { impl ViewportRule {
#[allow(missing_docs)]
pub fn parse(input: &mut Parser, context: &ParserContext) pub fn parse(input: &mut Parser, context: &ParserContext)
-> Result<ViewportRule, ()> -> Result<ViewportRule, ()>
{ {
@ -358,6 +368,7 @@ impl ViewportRule {
Ok(ViewportRule { declarations: cascade.finish() }) Ok(ViewportRule { declarations: cascade.finish() })
} }
#[allow(missing_docs)]
pub fn from_meta(content: &str) -> Option<ViewportRule> { pub fn from_meta(content: &str) -> Option<ViewportRule> {
let mut declarations = vec![None; VIEWPORT_DESCRIPTOR_VARIANTS]; let mut declarations = vec![None; VIEWPORT_DESCRIPTOR_VARIANTS];
macro_rules! push_descriptor { macro_rules! push_descriptor {
@ -531,11 +542,13 @@ impl ViewportDescriptorDeclaration {
} }
} }
#[allow(missing_docs)]
pub struct Cascade { pub struct Cascade {
declarations: Vec<Option<(usize, ViewportDescriptorDeclaration)>>, declarations: Vec<Option<(usize, ViewportDescriptorDeclaration)>>,
count_so_far: usize, count_so_far: usize,
} }
#[allow(missing_docs)]
impl Cascade { impl Cascade {
pub fn new() -> Self { pub fn new() -> Self {
Cascade { Cascade {
@ -545,7 +558,9 @@ impl Cascade {
} }
pub fn from_stylesheets<'a, I>(stylesheets: I, device: &Device) -> Self pub fn from_stylesheets<'a, I>(stylesheets: I, device: &Device) -> Self
where I: IntoIterator, I::Item: AsRef<Stylesheet> { where I: IntoIterator,
I::Item: AsRef<Stylesheet>,
{
let mut cascade = Self::new(); let mut cascade = Self::new();
for stylesheet in stylesheets { for stylesheet in stylesheets {
stylesheet.as_ref().effective_viewport_rules(device, |rule| { stylesheet.as_ref().effective_viewport_rules(device, |rule| {
@ -581,10 +596,13 @@ impl Cascade {
} }
} }
/// Just a helper trait to be able to implement methods on ViewportConstraints.
pub trait MaybeNew { pub trait MaybeNew {
/// Create a ViewportConstraints from a viewport size and a `@viewport`
/// rule.
fn maybe_new(initial_viewport: TypedSize2D<f32, ViewportPx>, fn maybe_new(initial_viewport: TypedSize2D<f32, ViewportPx>,
rule: &ViewportRule) rule: &ViewportRule)
-> Option<ViewportConstraints>; -> Option<ViewportConstraints>;
} }
impl MaybeNew for ViewportConstraints { impl MaybeNew for ViewportConstraints {

View file

@ -8,14 +8,17 @@ use super::ToCss;
macro_rules! define_cursor { macro_rules! define_cursor {
($( $css: expr => $variant: ident = $value: expr, )+) => { ($( $css: expr => $variant: ident = $value: expr, )+) => {
/// https://drafts.csswg.org/css-ui/#cursor
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize, HeapSizeOf))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize, HeapSizeOf))]
#[repr(u8)] #[repr(u8)]
#[allow(missing_docs)]
pub enum Cursor { pub enum Cursor {
$( $variant = $value ),+ $( $variant = $value ),+
} }
impl Cursor { impl Cursor {
/// Given a CSS keyword, get the corresponding cursor enum.
pub fn from_css_keyword(keyword: &str) -> Result<Cursor, ()> { pub fn from_css_keyword(keyword: &str) -> Result<Cursor, ()> {
match_ignore_ascii_case! { keyword, match_ignore_ascii_case! { keyword,
$( concat!($css) => Ok(Cursor::$variant), )+ $( concat!($css) => Ok(Cursor::$variant), )+

View file

@ -9,7 +9,7 @@
#![crate_name = "style_traits"] #![crate_name = "style_traits"]
#![crate_type = "rlib"] #![crate_type = "rlib"]
#![deny(unsafe_code)] #![deny(unsafe_code, missing_docs)]
#![cfg_attr(feature = "servo", feature(plugin))] #![cfg_attr(feature = "servo", feature(plugin))]
#![cfg_attr(feature = "servo", feature(proc_macro))] #![cfg_attr(feature = "servo", feature(proc_macro))]

View file

@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Helper types and traits for the handling of CSS values.
use app_units::Au; use app_units::Au;
use std::fmt; use std::fmt;
@ -78,13 +80,14 @@ macro_rules! __define_css_keyword_enum__add_optional_traits {
#[macro_export] #[macro_export]
macro_rules! __define_css_keyword_enum__actual { macro_rules! __define_css_keyword_enum__actual {
($name: ident [ $( $derived_trait: ident),* ] [ $( $css: expr => $variant: ident ),+ ]) => { ($name: ident [ $( $derived_trait: ident),* ] [ $( $css: expr => $variant: ident ),+ ]) => {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types, missing_docs)]
#[derive(Clone, Eq, PartialEq, Copy, Hash, RustcEncodable, Debug $(, $derived_trait )* )] #[derive(Clone, Eq, PartialEq, Copy, Hash, RustcEncodable, Debug $(, $derived_trait )* )]
pub enum $name { pub enum $name {
$( $variant ),+ $( $variant ),+
} }
impl $name { impl $name {
/// Parse this property from a CSS input stream.
pub fn parse(input: &mut ::cssparser::Parser) -> Result<$name, ()> { pub fn parse(input: &mut ::cssparser::Parser) -> Result<$name, ()> {
match_ignore_ascii_case! { try!(input.expect_ident()), match_ignore_ascii_case! { try!(input.expect_ident()),
$( $css => Ok($name::$variant), )+ $( $css => Ok($name::$variant), )+
@ -95,27 +98,33 @@ macro_rules! __define_css_keyword_enum__actual {
impl ToCss for $name { impl ToCss for $name {
fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result
where W: ::std::fmt::Write { where W: ::std::fmt::Write
match *self { {
$( $name::$variant => dest.write_str($css) ),+ match *self {
} $( $name::$variant => dest.write_str($css) ),+
} }
}
} }
} }
} }
/// Helper types for the handling of specified values.
pub mod specified { pub mod specified {
use app_units::Au; use app_units::Au;
/// Whether to allow negative values or not.
#[repr(u8)] #[repr(u8)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AllowedNumericType { pub enum AllowedNumericType {
/// Allow all kind of numeric values.
All, All,
/// Allow only non-negative values.
NonNegative NonNegative
} }
impl AllowedNumericType { impl AllowedNumericType {
/// Whether value is valid for this allowed numeric type.
#[inline] #[inline]
pub fn is_ok(&self, value: f32) -> bool { pub fn is_ok(&self, value: f32) -> bool {
match *self { match *self {
@ -124,6 +133,7 @@ pub mod specified {
} }
} }
/// Clamp the value following the rules of this numeric type.
#[inline] #[inline]
pub fn clamp(&self, val: Au) -> Au { pub fn clamp(&self, val: Au) -> Au {
use std::cmp; use std::cmp;

View file

@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Helper types for the `@viewport` rule.
use {PagePx, ViewportPx}; use {PagePx, ViewportPx};
use cssparser::{Parser, ToCss}; use cssparser::{Parser, ToCss};
use euclid::scale_factor::ScaleFactor; use euclid::scale_factor::ScaleFactor;
@ -20,16 +22,25 @@ define_css_keyword_enum!(Orientation:
"landscape" => Landscape); "landscape" => Landscape);
/// A set of viewport descriptors:
///
/// https://drafts.csswg.org/css-device-adapt/#viewport-desc
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize, HeapSizeOf))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize, HeapSizeOf))]
pub struct ViewportConstraints { pub struct ViewportConstraints {
/// Width and height:
/// * https://drafts.csswg.org/css-device-adapt/#width-desc
/// * https://drafts.csswg.org/css-device-adapt/#height-desc
pub size: TypedSize2D<f32, ViewportPx>, pub size: TypedSize2D<f32, ViewportPx>,
/// https://drafts.csswg.org/css-device-adapt/#zoom-desc
pub initial_zoom: ScaleFactor<f32, PagePx, ViewportPx>, pub initial_zoom: ScaleFactor<f32, PagePx, ViewportPx>,
/// https://drafts.csswg.org/css-device-adapt/#min-max-width-desc
pub min_zoom: Option<ScaleFactor<f32, PagePx, ViewportPx>>, pub min_zoom: Option<ScaleFactor<f32, PagePx, ViewportPx>>,
/// https://drafts.csswg.org/css-device-adapt/#min-max-width-desc
pub max_zoom: Option<ScaleFactor<f32, PagePx, ViewportPx>>, pub max_zoom: Option<ScaleFactor<f32, PagePx, ViewportPx>>,
/// https://drafts.csswg.org/css-device-adapt/#user-zoom-desc
pub user_zoom: UserZoom, pub user_zoom: UserZoom,
/// https://drafts.csswg.org/css-device-adapt/#orientation-desc
pub orientation: Orientation pub orientation: Orientation
} }
@ -53,19 +64,21 @@ impl ToCss for ViewportConstraints {
} }
} }
/// Zoom is a number | percentage | auto /// https://drafts.csswg.org/css-device-adapt/#descdef-viewport-zoom
/// See http://dev.w3.org/csswg/css-device-adapt/#descdef-viewport-zoom
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Zoom { pub enum Zoom {
/// A number value.
Number(f32), Number(f32),
/// A percentage value.
Percentage(f32), Percentage(f32),
/// The `auto` keyword.
Auto, Auto,
} }
impl ToCss for Zoom { impl ToCss for Zoom {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write where W: fmt::Write,
{ {
match *self { match *self {
Zoom::Number(number) => write!(dest, "{}", number), Zoom::Number(number) => write!(dest, "{}", number),
@ -76,6 +89,9 @@ impl ToCss for Zoom {
} }
impl Zoom { impl Zoom {
/// Parse a zoom value per:
///
/// https://drafts.csswg.org/css-device-adapt/#descdef-viewport-zoom
pub fn parse(input: &mut Parser) -> Result<Zoom, ()> { pub fn parse(input: &mut Parser) -> Result<Zoom, ()> {
use cssparser::Token; use cssparser::Token;
@ -90,6 +106,8 @@ impl Zoom {
} }
} }
/// Get this zoom value as a float value. Returns `None` if the value is the
/// `auto` keyword.
#[inline] #[inline]
pub fn to_f32(&self) -> Option<f32> { pub fn to_f32(&self) -> Option<f32> {
match *self { match *self {