зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #14801 - style: Document and force documentation in a big chunk of the style crate (from emilio:no-missing-docs); r=mbrubeck,Manishearth,Wafflespeanut
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. Source-Repo: https://github.com/servo/servo Source-Revision: bd67163438317daa711b2411ce302aaf5bf4136a
This commit is contained in:
Родитель
199f5d426d
Коммит
89013f9ba5
|
@ -88,7 +88,7 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
|
|||
if let Animation::Transition(_, unsafe_node, _, ref frame, _) = running_animation {
|
||||
script_chan.send(ConstellationControlMsg::TransitionEnd(unsafe_node,
|
||||
frame.property_animation
|
||||
.property_name(),
|
||||
.property_name().into(),
|
||||
frame.duration))
|
||||
.unwrap();
|
||||
}
|
||||
|
|
|
@ -2005,7 +2005,7 @@ impl Fragment {
|
|||
}
|
||||
// See CSS 2.1 § 10.8.1.
|
||||
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);
|
||||
InlineMetrics::from_font_metrics(&info.run.font_metrics, line_height)
|
||||
}
|
||||
|
@ -2085,7 +2085,7 @@ impl Fragment {
|
|||
vertical_align::T::middle => {
|
||||
let font_metrics =
|
||||
text::font_metrics_for_style(&mut layout_context.font_context(),
|
||||
style.get_font_arc());
|
||||
style.clone_font());
|
||||
offset += (content_inline_metrics.ascent -
|
||||
content_inline_metrics.space_below_baseline -
|
||||
font_metrics.x_height).scale_by(0.5)
|
||||
|
|
|
@ -1089,7 +1089,7 @@ impl InlineFlow {
|
|||
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 line_height = text::line_height_from_style(style, &font_metrics);
|
||||
let inline_metrics = InlineMetrics::from_font_metrics(&font_metrics, line_height);
|
||||
|
@ -1112,7 +1112,7 @@ impl InlineFlow {
|
|||
for inline_context in fragments.iter()
|
||||
.filter_map(|fragment| fragment.inline_context.as_ref()) {
|
||||
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 line_height = text::line_height_from_style(&*node.style, &font_metrics);
|
||||
let inline_metrics = InlineMetrics::from_font_metrics(&font_metrics, line_height);
|
||||
|
|
|
@ -154,7 +154,7 @@ impl TextRunScanner {
|
|||
let word_break;
|
||||
{
|
||||
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();
|
||||
fontgroup = font_context.layout_font_group_for_style(font_style);
|
||||
compression = match in_fragment.white_space() {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! CSS transitions and animations.
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use Atom;
|
||||
use bezier::Bezier;
|
||||
|
@ -28,8 +29,9 @@ use values::computed::Time;
|
|||
/// have to keep track the current iteration and the max iteration count.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum KeyframesIterationState {
|
||||
/// Infinite iterations, so no need to track a state.
|
||||
Infinite,
|
||||
// current, max
|
||||
/// Current and max iterations.
|
||||
Finite(u32, u32),
|
||||
}
|
||||
|
||||
|
@ -192,6 +194,7 @@ pub enum Animation {
|
|||
}
|
||||
|
||||
impl Animation {
|
||||
/// Mark this animation as expired.
|
||||
#[inline]
|
||||
pub fn mark_as_expired(&mut self) {
|
||||
debug_assert!(!self.is_expired());
|
||||
|
@ -201,6 +204,7 @@ impl Animation {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether this animation is expired.
|
||||
#[inline]
|
||||
pub fn is_expired(&self) -> bool {
|
||||
match *self {
|
||||
|
@ -209,6 +213,7 @@ impl Animation {
|
|||
}
|
||||
}
|
||||
|
||||
/// The opaque node that owns the animation.
|
||||
#[inline]
|
||||
pub fn node(&self) -> &OpaqueNode {
|
||||
match *self {
|
||||
|
@ -217,6 +222,7 @@ impl Animation {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether this animation is paused. A transition can never be paused.
|
||||
#[inline]
|
||||
pub fn is_paused(&self) -> bool {
|
||||
match *self {
|
||||
|
@ -237,6 +243,7 @@ pub struct AnimationFrame {
|
|||
pub duration: f64,
|
||||
}
|
||||
|
||||
/// Represents an animation for a given property.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PropertyAnimation {
|
||||
property: AnimatedProperty,
|
||||
|
@ -245,13 +252,15 @@ pub struct PropertyAnimation {
|
|||
}
|
||||
|
||||
impl PropertyAnimation {
|
||||
pub fn property_name(&self) -> String {
|
||||
/// Returns the given property name.
|
||||
pub fn property_name(&self) -> &'static str {
|
||||
self.property.name()
|
||||
}
|
||||
|
||||
/// Creates a new property animation for the given transition index and old and new styles.
|
||||
/// Any number of animations may be returned, from zero (if the property did not animate) to
|
||||
/// one (for a single transition property) to arbitrarily many (for `all`).
|
||||
/// Creates a new property animation for the given transition index and old
|
||||
/// and new styles. Any number of animations may be returned, from zero (if
|
||||
/// the property did not animate) to one (for a single transition property)
|
||||
/// to arbitrarily many (for `all`).
|
||||
pub fn from_transition(transition_index: usize,
|
||||
old_style: &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) {
|
||||
let progress = match self.timing_function {
|
||||
TransitionTimingFunction::CubicBezier(p1, p2) => {
|
||||
|
@ -336,8 +346,9 @@ impl PropertyAnimation {
|
|||
self.property.does_animate() && self.duration != Time(0.0)
|
||||
}
|
||||
|
||||
/// Whether this animation has the same end value as another one.
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
new_animations_sender: &Sender<Animation>,
|
||||
node: OpaqueNode,
|
||||
|
|
|
@ -2,18 +2,22 @@
|
|||
* 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/. */
|
||||
|
||||
//! 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};
|
||||
|
||||
/// 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> {
|
||||
entries: Vec<(K, V)>,
|
||||
cache_size: usize,
|
||||
}
|
||||
|
||||
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> {
|
||||
LRUCache {
|
||||
entries: vec![],
|
||||
|
@ -22,6 +26,7 @@ impl<K: PartialEq, V: Clone> LRUCache<K, V> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
/// Touch a given position, and put it in the last item on the list.
|
||||
pub fn touch(&mut self, pos: usize) -> &V {
|
||||
let last_index = self.entries.len() - 1;
|
||||
if pos != last_index {
|
||||
|
@ -31,14 +36,17 @@ impl<K: PartialEq, V: Clone> LRUCache<K, V> {
|
|||
&self.entries[last_index].1
|
||||
}
|
||||
|
||||
/// Iterate over the contents of this cache.
|
||||
pub fn iter(&self) -> Iter<(K, V)> {
|
||||
self.entries.iter()
|
||||
}
|
||||
|
||||
/// Iterate mutably over the contents of this cache.
|
||||
pub fn iter_mut(&mut self) -> IterMut<(K, V)> {
|
||||
self.entries.iter_mut()
|
||||
}
|
||||
|
||||
/// Insert a given key and value in the cache.
|
||||
pub fn insert(&mut self, key: K, val: V) {
|
||||
if self.entries.len() == self.cache_size {
|
||||
self.entries.remove(0);
|
||||
|
@ -46,6 +54,7 @@ impl<K: PartialEq, V: Clone> LRUCache<K, V> {
|
|||
self.entries.push((key, val));
|
||||
}
|
||||
|
||||
/// Try to find a key in the cache.
|
||||
pub fn find(&mut self, key: &K) -> Option<V> {
|
||||
match self.entries.iter().position(|&(ref k, _)| key == k) {
|
||||
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) {
|
||||
Some(pos) => self.touch(pos).clone(),
|
||||
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) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
//! Per-node data used in style calculation.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use dom::TElement;
|
||||
use properties::ComputedValues;
|
||||
use properties::longhands::display::computed_value as display;
|
||||
|
@ -19,6 +21,9 @@ use std::sync::Arc;
|
|||
use stylist::Stylist;
|
||||
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)]
|
||||
pub struct ComputedStyle {
|
||||
/// The rule node representing the ordered list of rules matched for this
|
||||
|
@ -31,6 +36,7 @@ pub struct ComputedStyle {
|
|||
}
|
||||
|
||||
impl ComputedStyle {
|
||||
/// Trivially construct a new `ComputedStyle`.
|
||||
pub fn new(rules: StrongRuleNode, values: Arc<ComputedValues>) -> Self {
|
||||
ComputedStyle {
|
||||
rules: rules,
|
||||
|
@ -49,10 +55,18 @@ impl fmt::Debug for ComputedStyle {
|
|||
|
||||
type PseudoStylesInner = HashMap<PseudoElement, ComputedStyle,
|
||||
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)]
|
||||
pub struct PseudoStyles(PseudoStylesInner);
|
||||
|
||||
impl PseudoStyles {
|
||||
/// Construct an empty set of `PseudoStyles`.
|
||||
pub fn empty() -> Self {
|
||||
PseudoStyles(HashMap::with_hasher(Default::default()))
|
||||
}
|
||||
|
@ -71,11 +85,14 @@ impl DerefMut for PseudoStyles {
|
|||
/// pseudo-elements.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ElementStyles {
|
||||
/// The element's style.
|
||||
pub primary: ComputedStyle,
|
||||
/// The map of styles for the element's pseudos.
|
||||
pub pseudos: PseudoStyles,
|
||||
}
|
||||
|
||||
impl ElementStyles {
|
||||
/// Trivially construct a new `ElementStyles`.
|
||||
pub fn new(primary: ComputedStyle) -> Self {
|
||||
ElementStyles {
|
||||
primary: primary,
|
||||
|
@ -83,6 +100,7 @@ impl ElementStyles {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether this element `display` value is `none`.
|
||||
pub fn is_display_none(&self) -> bool {
|
||||
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.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StoredRestyleHint {
|
||||
/// Whether this element should be restyled during the traversal.
|
||||
pub restyle_self: bool,
|
||||
/// Whether the descendants of this element need to be restyled.
|
||||
pub descendants: DescendantRestyleHint,
|
||||
}
|
||||
|
||||
|
@ -140,6 +160,7 @@ impl StoredRestyleHint {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates an empty `StoredRestyleHint`.
|
||||
pub fn empty() -> Self {
|
||||
StoredRestyleHint {
|
||||
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 {
|
||||
StoredRestyleHint {
|
||||
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 {
|
||||
!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) {
|
||||
self.restyle_self = self.restyle_self || other.restyle_self;
|
||||
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;
|
||||
|
||||
/// 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)]
|
||||
pub struct SnapshotOption {
|
||||
snapshot: Option<Snapshot>,
|
||||
|
@ -197,6 +222,7 @@ pub struct SnapshotOption {
|
|||
}
|
||||
|
||||
impl SnapshotOption {
|
||||
/// An empty snapshot.
|
||||
pub fn empty() -> Self {
|
||||
SnapshotOption {
|
||||
snapshot: None,
|
||||
|
@ -204,11 +230,13 @@ impl SnapshotOption {
|
|||
}
|
||||
}
|
||||
|
||||
/// Destroy this snapshot.
|
||||
pub fn destroy(&mut self) {
|
||||
self.destroyed = true;
|
||||
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 {
|
||||
debug_assert!(thread_state::get().is_layout());
|
||||
if self.is_none() {
|
||||
|
@ -234,7 +262,12 @@ impl Deref for SnapshotOption {
|
|||
/// 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
|
||||
/// 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)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct RestyleData {
|
||||
pub styles: ElementStyles,
|
||||
pub hint: StoredRestyleHint,
|
||||
|
@ -254,8 +287,8 @@ impl RestyleData {
|
|||
}
|
||||
}
|
||||
|
||||
/// Expands the snapshot (if any) into a restyle hint. Returns true if later siblings
|
||||
/// must be restyled.
|
||||
/// Expands the snapshot (if any) into a restyle hint. Returns true if later
|
||||
/// siblings must be restyled.
|
||||
pub fn expand_snapshot<E: TElement>(&mut self, element: E, stylist: &Stylist) -> bool {
|
||||
if self.snapshot.is_none() {
|
||||
return false;
|
||||
|
@ -281,14 +314,17 @@ impl RestyleData {
|
|||
later_siblings
|
||||
}
|
||||
|
||||
/// Return if the element style's are up to date.
|
||||
pub fn has_current_styles(&self) -> bool {
|
||||
!(self.hint.restyle_self || self.recascade || self.snapshot.is_some())
|
||||
}
|
||||
|
||||
/// Returns the element styles.
|
||||
pub fn styles(&self) -> &ElementStyles {
|
||||
&self.styles
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the element styles.
|
||||
pub fn styles_mut(&mut self) -> &mut ElementStyles {
|
||||
&mut self.styles
|
||||
}
|
||||
|
@ -317,12 +353,18 @@ impl RestyleData {
|
|||
/// safety.
|
||||
#[derive(Debug)]
|
||||
pub enum ElementData {
|
||||
/// This is the first styling for this element.
|
||||
Initial(Option<ElementStyles>),
|
||||
/// This element has been restyled already, and all the relevant data is
|
||||
/// inside the `RestyleData`.
|
||||
Restyle(RestyleData),
|
||||
/// This element has already been restyled, and only keeps its styles
|
||||
/// around.
|
||||
Persistent(ElementStyles),
|
||||
}
|
||||
|
||||
impl ElementData {
|
||||
/// Trivially construct an ElementData.
|
||||
pub fn new(existing: Option<ElementStyles>) -> Self {
|
||||
if let Some(s) = existing {
|
||||
ElementData::Persistent(s)
|
||||
|
@ -331,6 +373,7 @@ impl ElementData {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return whether this data is from an initial restyle.
|
||||
pub fn is_initial(&self) -> bool {
|
||||
match *self {
|
||||
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 {
|
||||
match *self {
|
||||
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 {
|
||||
match *self {
|
||||
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 {
|
||||
match *self {
|
||||
ElementData::Restyle(_) => true,
|
||||
|
@ -359,6 +407,7 @@ impl ElementData {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the `RestyleData` if it exists.
|
||||
pub fn as_restyle(&self) -> Option<&RestyleData> {
|
||||
match *self {
|
||||
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> {
|
||||
match *self {
|
||||
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 {
|
||||
match *self {
|
||||
ElementData::Persistent(_) => true,
|
||||
|
@ -428,6 +479,7 @@ impl ElementData {
|
|||
*self = ElementData::Persistent(styles);
|
||||
}
|
||||
|
||||
/// Return the restyle damage (if any).
|
||||
pub fn damage(&self) -> RestyleDamage {
|
||||
use self::ElementData::*;
|
||||
match *self {
|
||||
|
@ -443,8 +495,8 @@ impl ElementData {
|
|||
}
|
||||
}
|
||||
|
||||
// A version of the above, with the assertions replaced with warnings to
|
||||
// be more robust in corner-cases. This will go away soon.
|
||||
/// A version of the above, with the assertions replaced with warnings to
|
||||
/// be more robust in corner-cases. This will go away soon.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub fn damage_sloppy(&self) -> RestyleDamage {
|
||||
use self::ElementData::*;
|
||||
|
@ -476,6 +528,7 @@ impl ElementData {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get the element styles, if any.
|
||||
pub fn get_styles(&self) -> Option<&ElementStyles> {
|
||||
use self::ElementData::*;
|
||||
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 {
|
||||
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> {
|
||||
use self::ElementData::*;
|
||||
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 {
|
||||
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) {
|
||||
use self::ElementData::*;
|
||||
match *self {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
//! Types and traits used to access the DOM from style calculation.
|
||||
|
||||
#![allow(unsafe_code)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use {Atom, Namespace, LocalName};
|
||||
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
|
||||
/// would be difficult for Gecko nodes.
|
||||
pub trait NodeInfo {
|
||||
/// Whether this node is an element.
|
||||
fn is_element(&self) -> bool;
|
||||
/// Whether this node is a text node.
|
||||
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() }
|
||||
}
|
||||
|
||||
/// A node iterator that only returns node that don't need layout.
|
||||
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;
|
||||
fn next(&mut self) -> Option<I> {
|
||||
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 {
|
||||
/// The concrete `TElement` type.
|
||||
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>;
|
||||
|
||||
/// Convert this node in an `UnsafeNode`.
|
||||
fn to_unsafe(&self) -> UnsafeNode;
|
||||
|
||||
/// Get a node back from an `UnsafeNode`.
|
||||
unsafe fn from_unsafe(n: &UnsafeNode) -> Self;
|
||||
|
||||
/// 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`.
|
||||
fn opaque(&self) -> OpaqueNode;
|
||||
|
||||
/// Get this node's parent element if present.
|
||||
fn parent_element(&self) -> Option<Self::ConcreteElement> {
|
||||
self.parent_node().and_then(|n| n.as_element())
|
||||
}
|
||||
|
||||
/// A debug id, only useful, mm... for debugging.
|
||||
fn debug_id(self) -> usize;
|
||||
|
||||
/// Get this node as an element, if it's one.
|
||||
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;
|
||||
|
||||
/// Mark this node as needing layout on viewport size change.
|
||||
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;
|
||||
|
||||
/// Set whether this node can be fragmented.
|
||||
unsafe fn set_can_be_fragmented(&self, value: bool);
|
||||
|
||||
/// Get this node's parent node.
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -187,14 +219,20 @@ fn fmt_subtree<F, N: TNode>(f: &mut fmt::Formatter, stringify: &F, n: N, indent:
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// A trait used to synthesize presentational hints for HTML element attributes.
|
||||
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)
|
||||
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 {
|
||||
/// The concrete node type.
|
||||
type ConcreteNode: TNode<ConcreteElement = Self>;
|
||||
|
||||
/// Get this element as a node.
|
||||
fn as_node(&self) -> Self::ConcreteNode;
|
||||
|
||||
/// 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>>>;
|
||||
|
||||
/// Get this element's state, for non-tree-structural pseudos.
|
||||
fn get_state(&self) -> ElementState;
|
||||
|
||||
/// Whether this element has an attribute with a given namespace.
|
||||
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;
|
||||
|
||||
/// XXX: 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.
|
||||
/// Get the pre-existing style to calculate restyle damage (change hints).
|
||||
///
|
||||
/// 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,
|
||||
current_computed_values: Option<&'a Arc<ComputedValues>>,
|
||||
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
|
||||
/// (including but not limited to the traversal) where we need to send DOM
|
||||
/// objects to other threads.
|
||||
|
||||
///
|
||||
/// That's the reason why `SendNode` exists.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct SendNode<N: TNode>(N);
|
||||
unsafe impl<N: TNode> Send for SendNode<N> {}
|
||||
impl<N: TNode> SendNode<N> {
|
||||
/// Unsafely construct a SendNode.
|
||||
pub unsafe fn new(node: N) -> Self {
|
||||
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)]
|
||||
pub struct SendElement<E: TElement>(E);
|
||||
unsafe impl<E: TElement> Send for SendElement<E> {}
|
||||
impl<E: TElement> SendElement<E> {
|
||||
/// Unsafely construct a SendElement.
|
||||
pub unsafe fn new(el: E) -> Self {
|
||||
SendElement(el)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
pub fn serialize_comma_separated_list<W, T>(dest: &mut W, list: &[T])
|
||||
-> fmt::Result where W: fmt::Write, T: ToCss {
|
||||
if list.len() > 0 {
|
||||
for item in &list[..list.len()-1] {
|
||||
try!(item.to_css(dest));
|
||||
try!(write!(dest, ", "));
|
||||
}
|
||||
list[list.len()-1].to_css(dest)
|
||||
} else {
|
||||
Ok(())
|
||||
/// Serializes as CSS a comma-separated list of any `T` that supports being
|
||||
/// serialized as CSS.
|
||||
pub fn serialize_comma_separated_list<W, T>(dest: &mut W,
|
||||
list: &[T])
|
||||
-> fmt::Result
|
||||
where W: fmt::Write,
|
||||
T: ToCss,
|
||||
{
|
||||
if list.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
try!(list[0].to_css(dest));
|
||||
|
||||
for item in list.iter().skip(1) {
|
||||
try!(write!(dest, ", "));
|
||||
try!(item.to_css(dest));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
//! easy to grep for. At the time of this writing, there is no other unsafe
|
||||
//! code in the parallel traversal.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use dom::{OpaqueNode, SendNode, TElement, TNode};
|
||||
use rayon;
|
||||
use scoped_tls::ScopedTLS;
|
||||
|
@ -28,8 +30,12 @@ use std::sync::atomic::Ordering;
|
|||
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};
|
||||
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;
|
||||
|
||||
/// A parallel top down traversal, generic over `D`.
|
||||
#[allow(unsafe_code)]
|
||||
pub fn traverse_dom<N, D>(traversal: &D,
|
||||
root: N::ConcreteElement,
|
||||
|
@ -37,7 +43,7 @@ pub fn traverse_dom<N, D>(traversal: &D,
|
|||
token: PreTraverseToken,
|
||||
queue: &rayon::ThreadPool)
|
||||
where N: TNode,
|
||||
D: DomTraversal<N>
|
||||
D: DomTraversal<N>,
|
||||
{
|
||||
if opts::get().style_sharing_stats {
|
||||
STYLE_SHARING_CACHE_HITS.store(0, Ordering::SeqCst);
|
||||
|
@ -181,7 +187,7 @@ fn bottom_up_dom<N, D>(traversal: &D,
|
|||
root: OpaqueNode,
|
||||
mut node: N)
|
||||
where N: TNode,
|
||||
D: DomTraversal<N>
|
||||
D: DomTraversal<N>,
|
||||
{
|
||||
loop {
|
||||
// Perform the appropriate operation.
|
||||
|
|
|
@ -405,9 +405,10 @@ pub fn append_serialization<'a, W, I, N>(dest: &mut W,
|
|||
importance: Importance,
|
||||
is_first_serialization: &mut bool)
|
||||
-> fmt::Result
|
||||
where W: fmt::Write,
|
||||
I: Iterator<Item=&'a PropertyDeclaration>,
|
||||
N: ToCss {
|
||||
where W: fmt::Write,
|
||||
I: Iterator<Item=&'a PropertyDeclaration>,
|
||||
N: ToCss
|
||||
{
|
||||
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
|
||||
|
@ -525,4 +526,3 @@ pub fn parse_property_declaration_list(context: &ParserContext, input: &mut Pars
|
|||
super::deduplicate_property_declarations(&mut block);
|
||||
block
|
||||
}
|
||||
|
||||
|
|
|
@ -73,16 +73,21 @@
|
|||
use values::{computed, specified};
|
||||
${caller.body()}
|
||||
}
|
||||
|
||||
/// The definition of the computed value for ${name}.
|
||||
pub mod computed_value {
|
||||
pub use super::single_value::computed_value as single_value;
|
||||
pub use self::single_value::T as SingleComputedValue;
|
||||
/// The computed value, effectively a list of single values.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct T(pub Vec<single_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();
|
||||
if let Some(val) = iter.next() {
|
||||
try!(val.to_css(dest));
|
||||
|
@ -101,12 +106,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
/// The specified value of ${name}.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct SpecifiedValue(pub Vec<single_value::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();
|
||||
if let Some(val) = iter.next() {
|
||||
try!(val.to_css(dest));
|
||||
|
@ -405,7 +413,11 @@
|
|||
}
|
||||
|
||||
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
|
||||
% for sub_property in shorthand.sub_properties:
|
||||
let mut ${sub_property.ident} = None;
|
||||
|
@ -446,7 +458,9 @@
|
|||
}
|
||||
|
||||
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 with_variables = false;
|
||||
% 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>)
|
||||
-> Result<(), ()> {
|
||||
input.look_for_var_functions();
|
||||
|
|
|
@ -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
|
||||
// beforehand.
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum TransitionProperty {
|
||||
/// All, any animatable property changing should generate a transition.
|
||||
All,
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
/// ${prop.name}
|
||||
${prop.camel_case},
|
||||
% endif
|
||||
% endfor
|
||||
|
@ -55,6 +59,7 @@ impl TransitionProperty {
|
|||
% endfor
|
||||
}
|
||||
|
||||
/// Parse a transition-property value.
|
||||
pub fn parse(input: &mut Parser) -> Result<Self, ()> {
|
||||
match_ignore_ascii_case! { try!(input.expect_ident()),
|
||||
"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> {
|
||||
match *declaration {
|
||||
% for prop in data.longhands:
|
||||
|
@ -81,7 +87,9 @@ impl 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 {
|
||||
TransitionProperty::All => dest.write_str("all"),
|
||||
% 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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum AnimatedProperty {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
/// ${prop.name}
|
||||
${prop.camel_case}(longhands::${prop.ident}::computed_value::T,
|
||||
longhands::${prop.ident}::computed_value::T),
|
||||
% endif
|
||||
|
@ -105,16 +116,19 @@ pub enum AnimatedProperty {
|
|||
}
|
||||
|
||||
impl AnimatedProperty {
|
||||
pub fn name(&self) -> String {
|
||||
/// Get the name of this property.
|
||||
pub fn name(&self) -> &'static str {
|
||||
match *self {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
AnimatedProperty::${prop.camel_case}(..) => "${prop.name}".to_owned(),
|
||||
AnimatedProperty::${prop.camel_case}(..) => "${prop.name}",
|
||||
% endif
|
||||
% endfor
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this interpolation does animate, that is, whether the start and
|
||||
/// end values are different.
|
||||
pub fn does_animate(&self) -> bool {
|
||||
match *self {
|
||||
% 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) {
|
||||
% for prop in data.longhands:
|
||||
% 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) {
|
||||
match *self {
|
||||
% 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,
|
||||
old_style: &ComputedValues,
|
||||
new_style: &ComputedValues)
|
||||
|
@ -188,12 +207,15 @@ impl AnimatedProperty {
|
|||
pub enum AnimationValue {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
/// ${prop.name}
|
||||
${prop.camel_case}(longhands::${prop.ident}::computed_value::T),
|
||||
% endif
|
||||
% endfor
|
||||
}
|
||||
|
||||
impl AnimationValue {
|
||||
/// "Uncompute" this animation value in order to be used inside the CSS
|
||||
/// cascade.
|
||||
pub fn uncompute(&self) -> PropertyDeclaration {
|
||||
use properties::{longhands, DeclaredValue};
|
||||
match *self {
|
||||
|
@ -234,6 +256,7 @@ impl Interpolate for AnimationValue {
|
|||
///
|
||||
/// [interpolated-types]: https://drafts.csswg.org/css-transitions/#interpolated-types
|
||||
pub trait Interpolate: Sized {
|
||||
/// Interpolate a value with another for a given property.
|
||||
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()>;
|
||||
}
|
||||
|
||||
|
@ -249,6 +272,7 @@ impl<T: RepeatableListInterpolate> Interpolate for Vec<T> {
|
|||
}).collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/css-transitions/#animtype-number
|
||||
impl Interpolate for Au {
|
||||
#[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]
|
||||
fn interpolate(&self, other: &Option<T>, progress: f64) -> Result<Option<T>, ()> {
|
||||
match (self, other) {
|
||||
|
@ -431,7 +457,7 @@ impl Interpolate for CalcLengthOrPercentage {
|
|||
other: Option<T>,
|
||||
progress: f64)
|
||||
-> Result<Option<T>, ()>
|
||||
where T: Default + Interpolate
|
||||
where T: Default + Interpolate,
|
||||
{
|
||||
match (this, other) {
|
||||
(None, None) => Ok(None),
|
||||
|
@ -919,27 +945,36 @@ impl Interpolate for LengthOrNone {
|
|||
}
|
||||
}
|
||||
|
||||
/// A 2d matrix for interpolation.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct InnerMatrix2D {
|
||||
pub m11: CSSFloat, pub m12: CSSFloat,
|
||||
pub m21: CSSFloat, pub m22: CSSFloat,
|
||||
}
|
||||
|
||||
/// A 2d translation function.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct Translate2D(f32, f32);
|
||||
|
||||
/// A 2d scale function.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct Scale2D(f32, f32);
|
||||
|
||||
/// A decomposed 2d matrix.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct MatrixDecomposed2D {
|
||||
/// The translation function.
|
||||
pub translate: Translate2D,
|
||||
/// The scale function.
|
||||
pub scale: Scale2D,
|
||||
/// The rotation angle.
|
||||
pub angle: f32,
|
||||
/// The inner matrix.
|
||||
pub matrix: InnerMatrix2D,
|
||||
}
|
||||
|
||||
|
@ -1143,33 +1178,44 @@ impl Interpolate for LengthOrNone {
|
|||
}
|
||||
}
|
||||
|
||||
/// A 3d translation.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct Translate3D(f32, f32, f32);
|
||||
|
||||
/// A 3d scale function.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct Scale3D(f32, f32, f32);
|
||||
|
||||
/// A 3d skew function.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct Skew(f32, f32, f32);
|
||||
|
||||
/// A 3d perspective transformation.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct Perspective(f32, f32, f32, f32);
|
||||
|
||||
/// A quaternion used to represent a rotation.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct Quaternion(f32, f32, f32, f32);
|
||||
|
||||
/// A decomposed 3d matrix.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct MatrixDecomposed3D {
|
||||
/// A translation function.
|
||||
pub translate: Translate3D,
|
||||
/// A scale function.
|
||||
pub scale: Scale3D,
|
||||
/// The skew component of the transformation.
|
||||
pub skew: Skew,
|
||||
/// The perspective component of the transformation.
|
||||
pub perspective: Perspective,
|
||||
/// The quaternion used to represent the rotation.
|
||||
pub quaternion: Quaternion,
|
||||
}
|
||||
|
||||
|
@ -1513,7 +1559,7 @@ impl Interpolate for LengthOrNone {
|
|||
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.m13 * self.m24 * self.m32 * self.m41 -
|
||||
self.m14 * self.m22 * self.m33 * self.m41 +
|
||||
|
|
|
@ -87,89 +87,102 @@ ${helpers.predefined_type("background-color", "CSSColor",
|
|||
</%helpers:vector_longhand>
|
||||
|
||||
<%helpers:vector_longhand name="background-position-x" animatable="True">
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use values::HasViewportPercentage;
|
||||
use values::specified::position::HorizontalPosition;
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use values::HasViewportPercentage;
|
||||
use values::specified::position::HorizontalPosition;
|
||||
|
||||
pub mod computed_value {
|
||||
use values::computed::position::HorizontalPosition;
|
||||
use properties::animated_properties::{Interpolate, RepeatableListInterpolate};
|
||||
#[allow(missing_docs)]
|
||||
pub mod computed_value {
|
||||
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]
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
use values::computed::position::HorizontalPosition;
|
||||
HorizontalPosition(computed::LengthOrPercentage::Percentage(0.0))
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
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 {
|
||||
use values::specified::position::Keyword;
|
||||
HorizontalPosition {
|
||||
keyword: Some(Keyword::Left),
|
||||
position: None,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_initial_position_value() -> SpecifiedValue {
|
||||
use values::specified::{LengthOrPercentage, Percentage};
|
||||
HorizontalPosition {
|
||||
keyword: None,
|
||||
position: Some(LengthOrPercentage::Percentage(Percentage(0.0))),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
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)
|
||||
-> Result<SpecifiedValue, ()> {
|
||||
HorizontalPosition::parse(context, input)
|
||||
}
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse(context: &ParserContext, input: &mut Parser)
|
||||
-> Result<SpecifiedValue, ()> {
|
||||
HorizontalPosition::parse(context, input)
|
||||
}
|
||||
</%helpers:vector_longhand>
|
||||
|
||||
<%helpers:vector_longhand name="background-position-y" animatable="True">
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use values::HasViewportPercentage;
|
||||
use values::specified::position::VerticalPosition;
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use values::HasViewportPercentage;
|
||||
use values::specified::position::VerticalPosition;
|
||||
|
||||
pub mod computed_value {
|
||||
use values::computed::position::VerticalPosition;
|
||||
use properties::animated_properties::{Interpolate, RepeatableListInterpolate};
|
||||
#[allow(missing_docs)]
|
||||
pub mod computed_value {
|
||||
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]
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
use values::computed::position::VerticalPosition;
|
||||
VerticalPosition(computed::LengthOrPercentage::Percentage(0.0))
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
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 {
|
||||
use values::specified::position::Keyword;
|
||||
VerticalPosition {
|
||||
keyword: Some(Keyword::Top),
|
||||
position: None,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_initial_position_value() -> SpecifiedValue {
|
||||
use values::specified::{LengthOrPercentage, Percentage};
|
||||
VerticalPosition {
|
||||
keyword: None,
|
||||
position: Some(LengthOrPercentage::Percentage(Percentage(0.0))),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
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)
|
||||
-> Result<SpecifiedValue, ()> {
|
||||
VerticalPosition::parse(context, input)
|
||||
}
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse(context: &ParserContext, input: &mut Parser)
|
||||
-> Result<SpecifiedValue, ()> {
|
||||
VerticalPosition::parse(context, input)
|
||||
}
|
||||
</%helpers:vector_longhand>
|
||||
|
||||
${helpers.single_keyword("background-repeat",
|
||||
|
@ -199,6 +212,7 @@ ${helpers.single_keyword("background-origin",
|
|||
use style_traits::ToCss;
|
||||
use values::HasViewportPercentage;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub mod computed_value {
|
||||
use values::computed::LengthOrPercentageOrAuto;
|
||||
use properties::animated_properties::{Interpolate, RepeatableListInterpolate};
|
||||
|
@ -254,6 +268,7 @@ ${helpers.single_keyword("background-origin",
|
|||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct ExplicitSize {
|
||||
pub width: specified::LengthOrPercentageOrAuto,
|
||||
pub height: specified::LengthOrPercentageOrAuto,
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
|
||||
impl ToCss for T {
|
||||
fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result
|
||||
where W: ::std::fmt::Write {
|
||||
where W: ::std::fmt::Write,
|
||||
{
|
||||
match *self {
|
||||
% for value in values:
|
||||
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])}
|
||||
}
|
||||
|
||||
/// Parse a display value.
|
||||
pub fn parse(_context: &ParserContext, input: &mut Parser)
|
||||
-> Result<SpecifiedValue, ()> {
|
||||
match_ignore_ascii_case! { try!(input.expect_ident()),
|
||||
|
@ -144,119 +150,128 @@ ${helpers.single_keyword("clear", "none left right both",
|
|||
|
||||
</%helpers:longhand>
|
||||
|
||||
<%helpers:longhand name="vertical-align"
|
||||
animatable="True">
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use values::HasViewportPercentage;
|
||||
<%helpers:longhand name="vertical-align" animatable="True">
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use values::HasViewportPercentage;
|
||||
|
||||
<% vertical_align = data.longhands_by_name["vertical-align"] %>
|
||||
<% vertical_align.keyword = Keyword("vertical-align",
|
||||
"baseline sub super top text-top middle bottom text-bottom",
|
||||
extra_gecko_values="middle-with-baseline") %>
|
||||
<% vertical_align_keywords = vertical_align.keyword.values_for(product) %>
|
||||
<% vertical_align = data.longhands_by_name["vertical-align"] %>
|
||||
<% vertical_align.keyword = Keyword("vertical-align",
|
||||
"baseline sub super top text-top middle bottom text-bottom",
|
||||
extra_gecko_values="middle-with-baseline") %>
|
||||
<% vertical_align_keywords = vertical_align.keyword.values_for(product) %>
|
||||
|
||||
impl HasViewportPercentage for SpecifiedValue {
|
||||
fn has_viewport_percentage(&self) -> bool {
|
||||
match *self {
|
||||
SpecifiedValue::LengthOrPercentage(length) => length.has_viewport_percentage(),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
impl HasViewportPercentage for SpecifiedValue {
|
||||
fn has_viewport_percentage(&self) -> bool {
|
||||
match *self {
|
||||
SpecifiedValue::LengthOrPercentage(length) => length.has_viewport_percentage(),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum SpecifiedValue {
|
||||
% for keyword in vertical_align_keywords:
|
||||
${to_rust_ident(keyword)},
|
||||
% endfor
|
||||
LengthOrPercentage(specified::LengthOrPercentage),
|
||||
}
|
||||
/// The `vertical-align` value.
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum SpecifiedValue {
|
||||
% for keyword in vertical_align_keywords:
|
||||
${to_rust_ident(keyword)},
|
||||
% endfor
|
||||
LengthOrPercentage(specified::LengthOrPercentage),
|
||||
}
|
||||
|
||||
impl ToCss for SpecifiedValue {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
match *self {
|
||||
% for keyword in vertical_align_keywords:
|
||||
SpecifiedValue::${to_rust_ident(keyword)} => dest.write_str("${keyword}"),
|
||||
% endfor
|
||||
SpecifiedValue::LengthOrPercentage(value) => value.to_css(dest),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// baseline | sub | super | top | text-top | middle | bottom | text-bottom
|
||||
/// | <percentage> | <length>
|
||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
||||
input.try(|i| specified::LengthOrPercentage::parse(context, i))
|
||||
.map(SpecifiedValue::LengthOrPercentage)
|
||||
.or_else(|()| {
|
||||
match_ignore_ascii_case! { try!(input.expect_ident()),
|
||||
% for keyword in vertical_align_keywords:
|
||||
"${keyword}" => Ok(SpecifiedValue::${to_rust_ident(keyword)}),
|
||||
% endfor
|
||||
_ => 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 ToCss for SpecifiedValue {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
match *self {
|
||||
% for keyword in vertical_align_keywords:
|
||||
SpecifiedValue::${to_rust_ident(keyword)} => dest.write_str("${keyword}"),
|
||||
% endfor
|
||||
SpecifiedValue::LengthOrPercentage(value) => value.to_css(dest),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// baseline | sub | super | top | text-top | middle | bottom | text-bottom
|
||||
/// | <percentage> | <length>
|
||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
||||
input.try(|i| specified::LengthOrPercentage::parse(context, i))
|
||||
.map(SpecifiedValue::LengthOrPercentage)
|
||||
.or_else(|_| {
|
||||
match_ignore_ascii_case! { try!(input.expect_ident()),
|
||||
% for keyword in vertical_align_keywords:
|
||||
"${keyword}" => Ok(SpecifiedValue::${to_rust_ident(keyword)}),
|
||||
% endfor
|
||||
_ => Err(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
impl ToComputedValue for SpecifiedValue {
|
||||
type ComputedValue = computed_value::T;
|
||||
/// The computed value for `vertical-align`.
|
||||
pub mod computed_value {
|
||||
use app_units::Au;
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use values::{CSSFloat, computed};
|
||||
|
||||
#[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)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// The keywords are the same, and the `LengthOrPercentage` is computed
|
||||
/// here.
|
||||
#[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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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>
|
||||
|
||||
|
||||
|
@ -275,44 +290,51 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
|||
gecko_constant_prefix="NS_STYLE_OVERFLOW")}
|
||||
|
||||
// FIXME(pcwalton, #2742): Implement scrolling for `scroll` and `auto`.
|
||||
<%helpers:longhand name="overflow-y"
|
||||
need_clone="True"
|
||||
animatable="False">
|
||||
use super::overflow_x;
|
||||
<%helpers:longhand name="overflow-y" need_clone="True" animatable="False">
|
||||
use super::overflow_x;
|
||||
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use values::computed::ComputedValueAsSpecified;
|
||||
use values::NoViewportPercentage;
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use values::computed::ComputedValueAsSpecified;
|
||||
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 {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
self.0.to_css(dest)
|
||||
}
|
||||
}
|
||||
impl ToCss for SpecifiedValue {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
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 {
|
||||
computed_value::T(overflow_x::get_initial_value())
|
||||
}
|
||||
impl ComputedValueAsSpecified for SpecifiedValue {}
|
||||
|
||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
||||
overflow_x::parse(context, input).map(SpecifiedValue)
|
||||
}
|
||||
#[inline]
|
||||
#[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>
|
||||
|
||||
// TODO(pcwalton): Multiple transitions.
|
||||
<%helpers:longhand name="transition-duration"
|
||||
need_index="True"
|
||||
animatable="False">
|
||||
|
@ -369,7 +391,6 @@ ${helpers.single_keyword("overflow-x", "visible hidden scroll auto",
|
|||
</%helpers:longhand>
|
||||
|
||||
// TODO(pcwalton): Lots more timing functions.
|
||||
// TODO(pcwalton): Multiple transitions.
|
||||
<%helpers:longhand name="transition-timing-function"
|
||||
need_index="True"
|
||||
animatable="False">
|
||||
|
|
|
@ -315,7 +315,10 @@ ${helpers.single_keyword("font-variant-caps",
|
|||
use app_units::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)
|
||||
}
|
||||
|
||||
|
|
|
@ -158,7 +158,13 @@ pub mod shorthands {
|
|||
<%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 {
|
||||
#![deny(missing_docs)]
|
||||
|
||||
<%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.
|
||||
/// On success, returns true if shorthand value is written and false if no shorthand value is present.
|
||||
/// Serializes the possible shorthand name with value to input buffer given
|
||||
/// 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,
|
||||
dest: &mut W,
|
||||
declarations: I,
|
||||
is_first_serialization: &mut bool,
|
||||
importance: Importance)
|
||||
-> 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) {
|
||||
None => Ok(false),
|
||||
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>>
|
||||
where I: IntoIterator<Item=&'a PropertyDeclaration>, I::IntoIter: Clone {
|
||||
let declarations = declarations.into_iter();
|
||||
where I: IntoIterator<Item=&'a PropertyDeclaration>,
|
||||
I::IntoIter: Clone,
|
||||
{
|
||||
let declarations = declarations.into_iter();
|
||||
|
||||
// Only cloning iterators (a few pointers each) not declarations.
|
||||
let mut declarations2 = declarations.clone();
|
||||
let mut declarations3 = declarations.clone();
|
||||
// Only cloning iterators (a few pointers each) not declarations.
|
||||
let mut declarations2 = declarations.clone();
|
||||
let mut declarations3 = declarations.clone();
|
||||
|
||||
let first_declaration = match declarations2.next() {
|
||||
Some(declaration) => declaration,
|
||||
None => return None
|
||||
};
|
||||
let first_declaration = match declarations2.next() {
|
||||
Some(declaration) => declaration,
|
||||
None => return None
|
||||
};
|
||||
|
||||
// https://drafts.csswg.org/css-variables/#variables-in-shorthands
|
||||
if let Some(css) = first_declaration.with_variables_from_shorthand(self) {
|
||||
if declarations2.all(|d| d.with_variables_from_shorthand(self) == Some(css)) {
|
||||
return Some(AppendableValue::Css(css));
|
||||
}
|
||||
else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
// https://drafts.csswg.org/css-variables/#variables-in-shorthands
|
||||
if let Some(css) = first_declaration.with_variables_from_shorthand(self) {
|
||||
if declarations2.all(|d| d.with_variables_from_shorthand(self) == Some(css)) {
|
||||
return Some(AppendableValue::Css(css));
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
if !declarations3.any(|d| d.with_variables()) {
|
||||
return Some(AppendableValue::DeclarationsForShorthand(self, declarations));
|
||||
}
|
||||
if !declarations3.any(|d| d.with_variables()) {
|
||||
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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum DeclaredValue<T> {
|
||||
/// A known specified value from the stylesheet.
|
||||
Value(T),
|
||||
/// A value that contained any css variables.
|
||||
WithVariables {
|
||||
/// The css serialization for this value.
|
||||
css: String,
|
||||
/// The first token type for this serialization.
|
||||
first_token_type: TokenSerializationType,
|
||||
/// The base url.
|
||||
base_url: ServoUrl,
|
||||
/// The shorthand this came from.
|
||||
from_shorthand: Option<ShorthandId>,
|
||||
},
|
||||
/// The `initial` keyword.
|
||||
Initial,
|
||||
/// The `inherit` keyword.
|
||||
Inherit,
|
||||
/// The `unset` keyword.
|
||||
Unset,
|
||||
}
|
||||
|
||||
impl<T: HasViewportPercentage> HasViewportPercentage for DeclaredValue<T> {
|
||||
fn has_viewport_percentage(&self) -> bool {
|
||||
match *self {
|
||||
DeclaredValue::Value(ref v)
|
||||
=> v.has_viewport_percentage(),
|
||||
DeclaredValue::WithVariables { .. }
|
||||
=> panic!("DeclaredValue::has_viewport_percentage without resolving variables!"),
|
||||
DeclaredValue::Value(ref v) => v.has_viewport_percentage(),
|
||||
DeclaredValue::WithVariables { .. } => {
|
||||
panic!("DeclaredValue::has_viewport_percentage without \
|
||||
resolving variables!")
|
||||
},
|
||||
DeclaredValue::Initial |
|
||||
DeclaredValue::Inherit |
|
||||
DeclaredValue::Unset => false,
|
||||
|
@ -615,7 +640,9 @@ impl fmt::Debug 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 {
|
||||
PropertyId::Longhand(id) => dest.write_str(id.name()),
|
||||
PropertyId::Shorthand(id) => dest.write_str(id.name()),
|
||||
|
@ -1150,19 +1177,22 @@ pub struct ComputedValues {
|
|||
% endfor
|
||||
custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||
shareable: bool,
|
||||
/// The writing mode of this computed values struct.
|
||||
pub writing_mode: WritingMode,
|
||||
/// The root element's computed font size.
|
||||
pub root_font_size: Au,
|
||||
}
|
||||
|
||||
#[cfg(feature = "servo")]
|
||||
impl ComputedValues {
|
||||
/// Construct a `ComputedValues` instance.
|
||||
pub fn new(custom_properties: Option<Arc<::custom_properties::ComputedValuesMap>>,
|
||||
shareable: bool,
|
||||
writing_mode: WritingMode,
|
||||
root_font_size: Au,
|
||||
% for style_struct in data.active_style_structs():
|
||||
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
|
||||
% endfor
|
||||
shareable: bool,
|
||||
writing_mode: WritingMode,
|
||||
root_font_size: Au,
|
||||
% for style_struct in data.active_style_structs():
|
||||
${style_struct.ident}: Arc<style_structs::${style_struct.name}>,
|
||||
% endfor
|
||||
) -> Self {
|
||||
ComputedValues {
|
||||
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
|
||||
pub fn get_used_transform_style(&self) -> computed_values::transform_style::T {
|
||||
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() ||
|
||||
seen.get_font_family() {
|
||||
seen.get_font_family() {
|
||||
style.mutate_font().compute_font_hash();
|
||||
}
|
||||
|
||||
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")]
|
||||
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
|
||||
// its value depends on the 'align-items' value of its parent.
|
||||
% 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);
|
||||
}
|
||||
|
||||
/// Alters the given style to accommodate replaced content. This is called in flow construction. It
|
||||
/// handles cases like `<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`).
|
||||
/// Alters the given style to accommodate replaced content. This is called in
|
||||
/// flow construction. It handles cases like:
|
||||
///
|
||||
/// 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")]
|
||||
#[inline]
|
||||
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
|
||||
/// within the range of an element.
|
||||
/// Adjusts borders as appropriate to account for a fragment's status as the
|
||||
/// 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
|
||||
/// not outermost.
|
||||
/// Specifically, this function sets border widths to zero on the sides for
|
||||
/// which the fragment is not outermost.
|
||||
#[cfg(feature = "servo")]
|
||||
#[inline]
|
||||
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")]
|
||||
#[inline]
|
||||
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_
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// itself relatively positioned.
|
||||
/// Text is never directly relatively positioned; it's always contained within
|
||||
/// an element that is itself relatively positioned.
|
||||
#[cfg(feature = "servo")]
|
||||
#[inline]
|
||||
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
|
||||
/// children.
|
||||
/// Adjusts the `clip` property so that an inline absolute hypothetical fragment
|
||||
/// doesn't clip its children.
|
||||
#[cfg(feature = "servo")]
|
||||
pub fn modify_style_for_inline_absolute_hypothetical_fragment(style: &mut Arc<ComputedValues>) {
|
||||
if style.get_effects().clip.0.is_some() {
|
||||
|
|
|
@ -7,8 +7,16 @@ use style_traits::ToCss;
|
|||
use values::specified::{BorderStyle, CSSColor};
|
||||
use std::fmt;
|
||||
|
||||
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 {
|
||||
#[allow(missing_docs)]
|
||||
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 {
|
||||
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
|
||||
where I: Iterator<Item=&'a PropertyDeclaration> {
|
||||
where I: Iterator<Item=&'a PropertyDeclaration>
|
||||
{
|
||||
if let AppendableValue::DeclarationsForShorthand(shorthand, _) = *appendable_value {
|
||||
if let ShorthandId::Overflow = shorthand {
|
||||
return true;
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![allow(unsafe_code)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
//! The rule tree.
|
||||
|
||||
use arc_ptr_eq;
|
||||
#[cfg(feature = "servo")]
|
||||
|
@ -17,15 +20,40 @@ use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
|
|||
use stylesheets::StyleRule;
|
||||
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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct RuleTree {
|
||||
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)]
|
||||
pub enum StyleSource {
|
||||
/// A style rule stable pointer.
|
||||
Style(Arc<RwLock<StyleRule>>),
|
||||
/// A declaration block stable pointer.
|
||||
Declarations(Arc<RwLock<PropertyDeclarationBlock>>),
|
||||
}
|
||||
|
||||
|
@ -34,8 +62,11 @@ type StyleSourceGuardHandle<'a> =
|
|||
RwLockReadGuard<'a, StyleRule>,
|
||||
RwLockReadGuard<'a, PropertyDeclarationBlock>>;
|
||||
|
||||
/// A guard for a given style source.
|
||||
pub enum StyleSourceGuard<'a> {
|
||||
/// A guard for a style rule.
|
||||
Style(StyleSourceGuardHandle<'a>),
|
||||
/// A guard for a declaration block.
|
||||
Declarations(RwLockReadGuard<'a, PropertyDeclarationBlock>),
|
||||
}
|
||||
|
||||
|
@ -71,6 +102,8 @@ impl StyleSource {
|
|||
let _ = write!(writer, " -> {:?}", self.read().declarations);
|
||||
}
|
||||
|
||||
/// Read the style source guard, and obtain thus read access to the
|
||||
/// underlying property declaration block.
|
||||
#[inline]
|
||||
pub fn read<'a>(&'a self) -> StyleSourceGuard<'a> {
|
||||
use self::StyleSource::*;
|
||||
|
@ -87,15 +120,19 @@ impl StyleSource {
|
|||
/// 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
|
||||
/// 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;
|
||||
|
||||
impl RuleTree {
|
||||
/// Construct a new rule tree.
|
||||
pub fn new() -> Self {
|
||||
RuleTree {
|
||||
root: StrongRuleNode::new(Box::new(RuleNode::root())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the root rule node.
|
||||
pub fn root(&self) -> StrongRuleNode {
|
||||
self.root.clone()
|
||||
}
|
||||
|
@ -105,13 +142,16 @@ impl RuleTree {
|
|||
self.root.get().dump(writer, 0);
|
||||
}
|
||||
|
||||
/// Dump the rule tree to stdout.
|
||||
pub fn dump_stdout(&self) {
|
||||
let mut stdout = io::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
|
||||
where I: Iterator<Item=(StyleSource, Importance)>
|
||||
where I: Iterator<Item=(StyleSource, Importance)>,
|
||||
{
|
||||
let mut current = self.root.clone();
|
||||
for (source, importance) in iter {
|
||||
|
@ -294,6 +334,7 @@ struct WeakRuleNode {
|
|||
ptr: *mut RuleNode,
|
||||
}
|
||||
|
||||
/// A strong reference to a rule node.
|
||||
#[derive(Debug)]
|
||||
pub struct StrongRuleNode {
|
||||
ptr: *mut RuleNode,
|
||||
|
@ -412,14 +453,19 @@ impl StrongRuleNode {
|
|||
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> {
|
||||
self.get().source.as_ref()
|
||||
}
|
||||
|
||||
/// Get the importance that this rule node represents.
|
||||
pub fn importance(&self) -> Importance {
|
||||
self.get().importance
|
||||
}
|
||||
|
||||
/// Get an iterator for this rule node and its ancestors.
|
||||
pub fn self_and_ancestors(&self) -> SelfAndAncestors {
|
||||
SelfAndAncestors {
|
||||
current: Some(self)
|
||||
|
@ -527,6 +573,7 @@ impl StrongRuleNode {
|
|||
}
|
||||
}
|
||||
|
||||
/// An iterator over a rule node and its ancestors.
|
||||
#[derive(Clone)]
|
||||
pub struct SelfAndAncestors<'a> {
|
||||
current: Option<&'a StrongRuleNode>,
|
||||
|
|
|
@ -4,14 +4,17 @@
|
|||
|
||||
//! Implements sequential traversal over the DOM tree.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use dom::{TElement, TNode};
|
||||
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,
|
||||
root: N::ConcreteElement,
|
||||
token: PreTraverseToken)
|
||||
where N: TNode,
|
||||
D: DomTraversal<N>
|
||||
D: DomTraversal<N>,
|
||||
{
|
||||
debug_assert!(token.should_traverse());
|
||||
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
//! Servo's selector parser.
|
||||
|
||||
use {Atom, Prefix, Namespace, LocalName};
|
||||
use attr::{AttrIdentifier, AttrValue};
|
||||
use cssparser::ToCss;
|
||||
|
@ -15,9 +19,12 @@ use std::borrow::Cow;
|
|||
use std::fmt;
|
||||
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.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum PseudoElement {
|
||||
Before,
|
||||
After,
|
||||
|
@ -55,6 +62,7 @@ impl ToCss for PseudoElement {
|
|||
|
||||
|
||||
impl PseudoElement {
|
||||
/// Whether the current pseudo element is :before or :after.
|
||||
#[inline]
|
||||
pub fn is_before_or_after(&self) -> bool {
|
||||
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]
|
||||
pub fn cascade_type(&self) -> PseudoElementCascadeType {
|
||||
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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum NonTSPseudoClass {
|
||||
AnyLink,
|
||||
Link,
|
||||
|
@ -129,6 +143,8 @@ impl ToCss for 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 {
|
||||
use element_state::*;
|
||||
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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct SelectorImpl;
|
||||
|
@ -289,14 +307,17 @@ impl<'a> ::selectors::Parser for SelectorParser<'a> {
|
|||
}
|
||||
|
||||
impl SelectorImpl {
|
||||
/// Returns the pseudo-element cascade type of the given `pseudo`.
|
||||
#[inline]
|
||||
pub fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType {
|
||||
pseudo.cascade_type()
|
||||
}
|
||||
|
||||
/// Executes `fun` for each pseudo-element.
|
||||
#[inline]
|
||||
pub fn each_pseudo_element<F>(mut fun: F)
|
||||
where F: FnMut(PseudoElement) {
|
||||
where F: FnMut(PseudoElement),
|
||||
{
|
||||
fun(PseudoElement::Before);
|
||||
fun(PseudoElement::After);
|
||||
fun(PseudoElement::DetailsContent);
|
||||
|
@ -311,11 +332,13 @@ impl SelectorImpl {
|
|||
fun(PseudoElement::ServoAnonymousBlock);
|
||||
}
|
||||
|
||||
/// Returns the pseudo-class state flag for selector matching.
|
||||
#[inline]
|
||||
pub fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
|
||||
pc.state_flag()
|
||||
}
|
||||
|
||||
/// Returns whether this pseudo is either :before or :after.
|
||||
#[inline]
|
||||
pub fn pseudo_is_before_or_after(pseudo: &PseudoElement) -> bool {
|
||||
pseudo.is_before_or_after()
|
||||
|
@ -326,12 +349,16 @@ impl SelectorImpl {
|
|||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct ServoElementSnapshot {
|
||||
/// The stored state of the element.
|
||||
pub state: Option<ElementState>,
|
||||
/// The set of stored attributes and its values.
|
||||
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,
|
||||
}
|
||||
|
||||
impl ServoElementSnapshot {
|
||||
/// Create an empty element snapshot.
|
||||
pub fn new(is_html_element_in_html_document: bool) -> Self {
|
||||
ServoElementSnapshot {
|
||||
state: None,
|
||||
|
@ -373,7 +400,7 @@ impl ElementSnapshot for ServoElementSnapshot {
|
|||
}
|
||||
|
||||
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")) {
|
||||
for class in v.as_tokens() {
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! String utils for attributes and similar stuff.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use num_traits::ToPrimitive;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::borrow::Cow;
|
||||
|
@ -9,7 +13,10 @@ use std::convert::AsRef;
|
|||
use std::iter::{Filter, Peekable};
|
||||
use std::str::Split;
|
||||
|
||||
/// A static slice of characters.
|
||||
pub type StaticCharVec = &'static [char];
|
||||
|
||||
/// A static slice of `str`s.
|
||||
pub type StaticStringVec = &'static [&'static str];
|
||||
|
||||
/// A "space character" according to:
|
||||
|
@ -23,23 +30,31 @@ pub static HTML_SPACE_CHARACTERS: StaticCharVec = &[
|
|||
'\u{000d}',
|
||||
];
|
||||
|
||||
/// Whether a character is a HTML whitespace character.
|
||||
#[inline]
|
||||
pub fn char_is_whitespace(c: char) -> bool {
|
||||
HTML_SPACE_CHARACTERS.contains(&c)
|
||||
}
|
||||
|
||||
/// Whether all the string is HTML whitespace.
|
||||
#[inline]
|
||||
pub fn is_whitespace(s: &str) -> bool {
|
||||
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) ->
|
||||
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)
|
||||
}
|
||||
|
||||
/// Split a string on commas.
|
||||
#[inline]
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
match iter.peek() {
|
||||
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>,
|
||||
mut divisor: f64,
|
||||
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
|
||||
).fold((value, 1), |accumulator, d| {
|
||||
divisor *= 10f64;
|
||||
(accumulator.0 + d as f64 / divisor,
|
||||
accumulator.1 + 1)
|
||||
(accumulator.0 + d as f64 / divisor, 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> {
|
||||
match iter.peek() {
|
||||
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
|
||||
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)| {
|
||||
if i > 0 { acc.push_str(join); }
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
//! Style sheets and their CSS rules.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use {Atom, Prefix, Namespace};
|
||||
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, decode_stylesheet_bytes};
|
||||
use cssparser::{AtRuleType, RuleListParser, SourcePosition, Token, parse_one_rule};
|
||||
|
@ -46,22 +48,27 @@ pub enum Origin {
|
|||
User,
|
||||
}
|
||||
|
||||
/// A set of namespaces applying to a given stylesheet.
|
||||
#[derive(Default, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct Namespaces {
|
||||
pub default: Option<Namespace>,
|
||||
pub prefixes: FnvHashMap<Prefix , Namespace>,
|
||||
}
|
||||
|
||||
/// A list of CSS rules.
|
||||
#[derive(Debug)]
|
||||
pub struct CssRules(pub Vec<CssRule>);
|
||||
|
||||
impl CssRules {
|
||||
/// Whether this CSS rules is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub enum RulesMutateError {
|
||||
Syntax,
|
||||
IndexSize,
|
||||
|
@ -79,6 +86,7 @@ impl From<SingleRuleParseError> for RulesMutateError {
|
|||
}
|
||||
|
||||
impl CssRules {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(rules: Vec<CssRule>) -> Arc<RwLock<CssRules>> {
|
||||
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)
|
||||
-> Result<CssRule, RulesMutateError> {
|
||||
// Step 1, 2
|
||||
|
@ -136,7 +144,7 @@ impl CssRules {
|
|||
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> {
|
||||
// Step 1, 2
|
||||
if index >= self.0.len() {
|
||||
|
@ -161,6 +169,7 @@ impl CssRules {
|
|||
}
|
||||
}
|
||||
|
||||
/// The structure servo uses to represent a stylesheet.
|
||||
#[derive(Debug)]
|
||||
pub struct Stylesheet {
|
||||
/// List of rules in the order they were found (important for
|
||||
|
@ -168,22 +177,33 @@ pub struct Stylesheet {
|
|||
pub rules: Arc<RwLock<CssRules>>,
|
||||
/// List of media associated with the Stylesheet.
|
||||
pub media: Arc<RwLock<MediaList>>,
|
||||
/// The origin of this stylesheet.
|
||||
pub origin: Origin,
|
||||
/// The base url this stylesheet should use.
|
||||
pub base_url: ServoUrl,
|
||||
/// The namespaces that apply to this stylesheet.
|
||||
pub namespaces: RwLock<Namespaces>,
|
||||
/// Whether this stylesheet would be dirty when the viewport size changes.
|
||||
pub dirty_on_viewport_size_change: AtomicBool,
|
||||
/// Whether this stylesheet should be disabled.
|
||||
pub disabled: AtomicBool,
|
||||
}
|
||||
|
||||
|
||||
/// This structure holds the user-agent and user stylesheets.
|
||||
pub struct UserAgentStylesheets {
|
||||
/// The user or user agent stylesheets.
|
||||
pub user_or_user_agent_stylesheets: Vec<Stylesheet>,
|
||||
/// The quirks mode stylesheet.
|
||||
pub quirks_mode_stylesheet: Stylesheet,
|
||||
}
|
||||
|
||||
|
||||
/// A CSS rule.
|
||||
///
|
||||
/// TODO(emilio): Lots of spec links should be around.
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum CssRule {
|
||||
// No Charset here, CSSCharsetRule has been removed from CSSOM
|
||||
// https://drafts.csswg.org/cssom/#changes-from-5-december-2013
|
||||
|
@ -197,6 +217,7 @@ pub enum CssRule {
|
|||
Keyframes(Arc<RwLock<KeyframesRule>>),
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub enum CssRuleType {
|
||||
// https://drafts.csswg.org/cssom/#the-cssrule-interface
|
||||
Style = 1,
|
||||
|
@ -236,12 +257,14 @@ impl ParseErrorReporter for MemoryHoleReporter {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub enum SingleRuleParseError {
|
||||
Syntax,
|
||||
Hierarchy,
|
||||
}
|
||||
|
||||
impl CssRule {
|
||||
#[allow(missing_docs)]
|
||||
pub fn rule_type(&self) -> CssRuleType {
|
||||
match *self {
|
||||
CssRule::Style(_) => CssRuleType::Style,
|
||||
|
@ -268,7 +291,8 @@ impl CssRule {
|
|||
/// Note that only some types of rules can contain rules. An empty slice is
|
||||
/// used for others.
|
||||
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 {
|
||||
CssRule::Import(ref lock) => {
|
||||
let rule = lock.read();
|
||||
|
@ -296,6 +320,7 @@ impl CssRule {
|
|||
|
||||
// input state is None for a nested rule
|
||||
// Returns a parsed CSS rule and the final state of the parser
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse(css: &str,
|
||||
parent_stylesheet: &Stylesheet,
|
||||
extra_data: ParserContextExtraData,
|
||||
|
@ -348,6 +373,7 @@ impl ToCss for CssRule {
|
|||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct NamespaceRule {
|
||||
/// `None` for the default Namespace
|
||||
pub prefix: Option<Prefix>,
|
||||
|
@ -374,6 +400,7 @@ impl ToCss for NamespaceRule {
|
|||
/// [import]: https://drafts.csswg.org/css-cascade-3/#at-import
|
||||
#[derive(Debug)]
|
||||
pub struct ImportRule {
|
||||
/// The `<url>` this `@import` rule is loading.
|
||||
pub url: SpecifiedUrl,
|
||||
|
||||
/// 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)]
|
||||
pub struct KeyframesRule {
|
||||
/// The name of the current animation.
|
||||
pub name: Atom,
|
||||
/// The keyframes specified for this CSS rule.
|
||||
pub keyframes: Vec<Arc<RwLock<Keyframe>>>,
|
||||
}
|
||||
|
||||
|
@ -417,6 +449,7 @@ impl ToCss for KeyframesRule {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug)]
|
||||
pub struct MediaRule {
|
||||
pub media_queries: Arc<RwLock<MediaList>>,
|
||||
|
@ -438,6 +471,7 @@ impl ToCss for MediaRule {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug)]
|
||||
pub struct StyleRule {
|
||||
pub selectors: SelectorList<SelectorImpl>,
|
||||
|
@ -465,6 +499,11 @@ impl ToCss for StyleRule {
|
|||
}
|
||||
|
||||
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],
|
||||
base_url: ServoUrl,
|
||||
protocol_encoding_label: Option<&str>,
|
||||
|
@ -486,6 +525,8 @@ impl Stylesheet {
|
|||
extra_data)
|
||||
}
|
||||
|
||||
/// Updates an empty stylesheet with a set of bytes that reached over the
|
||||
/// network.
|
||||
pub fn update_from_bytes(existing: &Stylesheet,
|
||||
bytes: &[u8],
|
||||
protocol_encoding_label: Option<&str>,
|
||||
|
@ -493,7 +534,6 @@ impl Stylesheet {
|
|||
stylesheet_loader: Option<&StylesheetLoader>,
|
||||
error_reporter: Box<ParseErrorReporter + Send>,
|
||||
extra_data: ParserContextExtraData) {
|
||||
assert!(existing.rules.read().is_empty());
|
||||
let (string, _) = decode_stylesheet_bytes(
|
||||
bytes, protocol_encoding_label, environment_encoding);
|
||||
Self::update_from_str(existing,
|
||||
|
@ -503,6 +543,7 @@ impl Stylesheet {
|
|||
extra_data)
|
||||
}
|
||||
|
||||
/// Updates an empty stylesheet from a given string of text.
|
||||
pub fn update_from_str(existing: &Stylesheet,
|
||||
css: &str,
|
||||
stylesheet_loader: Option<&StylesheetLoader>,
|
||||
|
@ -545,7 +586,14 @@ impl Stylesheet {
|
|||
.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,
|
||||
stylesheet_loader: Option<&StylesheetLoader>,
|
||||
error_reporter: Box<ParseErrorReporter + Send>,
|
||||
|
@ -569,6 +617,7 @@ impl Stylesheet {
|
|||
s
|
||||
}
|
||||
|
||||
/// Whether this stylesheet can be dirty on viewport size change.
|
||||
pub fn dirty_on_viewport_size_change(&self) -> bool {
|
||||
self.dirty_on_viewport_size_change.load(Ordering::SeqCst)
|
||||
}
|
||||
|
@ -607,16 +656,19 @@ impl Stylesheet {
|
|||
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 {
|
||||
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.
|
||||
///
|
||||
/// Disabled stylesheets remain in the document, but their rules are not added to
|
||||
/// the Stylist.
|
||||
/// Disabled stylesheets remain in the document, but their rules are not
|
||||
/// added to the Stylist.
|
||||
pub fn set_disabled(&self, disabled: bool) -> bool {
|
||||
self.disabled.swap(disabled, Ordering::SeqCst) != disabled
|
||||
}
|
||||
|
@ -640,6 +692,7 @@ macro_rules! rule_filter {
|
|||
($( $method: ident($variant:ident => $rule_type: ident), )+) => {
|
||||
impl Stylesheet {
|
||||
$(
|
||||
#[allow(missing_docs)]
|
||||
pub fn $method<F>(&self, device: &Device, mut f: F) where F: FnMut(&$rule_type) {
|
||||
self.effective_rules(device, |rule| {
|
||||
if let CssRule::$variant(ref lock) = *rule {
|
||||
|
@ -690,6 +743,7 @@ impl<'b> TopLevelRuleParser<'b> {
|
|||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum State {
|
||||
Start = 1,
|
||||
Imports = 2,
|
||||
|
|
|
@ -8,32 +8,42 @@
|
|||
//! In release builds, `get` returns 0. All of the other functions inline
|
||||
//! away to nothing.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
pub use self::imp::{enter, exit, get, initialize};
|
||||
|
||||
bitflags! {
|
||||
/// A thread state flag, used for multiple assertions.
|
||||
pub flags ThreadState: u32 {
|
||||
/// Whether we're in a script thread.
|
||||
const SCRIPT = 0x01,
|
||||
/// Whether we're in a layout thread.
|
||||
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,
|
||||
|
||||
/// Whether the current thread is going through a GC.
|
||||
const IN_GC = 0x0200,
|
||||
const IN_HTML_PARSER = 0x0400,
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! thread_types ( ( $( $fun:ident = $flag:ident ; )* ) => (
|
||||
impl ThreadState {
|
||||
/// Whether the current thread is a worker thread.
|
||||
pub fn is_worker(self) -> bool {
|
||||
self.contains(IN_WORKER)
|
||||
}
|
||||
|
||||
$(
|
||||
#[cfg(debug_assertions)]
|
||||
#[allow(missing_docs)]
|
||||
pub fn $fun(self) -> bool {
|
||||
self.contains($flag)
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[allow(missing_docs)]
|
||||
pub fn $fun(self) -> bool {
|
||||
true
|
||||
}
|
||||
|
@ -48,7 +58,6 @@ macro_rules! thread_types ( ( $( $fun:ident = $flag:ident ; )* ) => (
|
|||
thread_types! {
|
||||
is_script = SCRIPT;
|
||||
is_layout = LAYOUT;
|
||||
is_paint = PAINT;
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
|
@ -58,6 +67,7 @@ mod imp {
|
|||
|
||||
thread_local!(static STATE: RefCell<Option<ThreadState>> = RefCell::new(None));
|
||||
|
||||
/// Initialize the current thread state.
|
||||
pub fn initialize(x: ThreadState) {
|
||||
STATE.with(|ref k| {
|
||||
if let Some(ref s) = *k.borrow() {
|
||||
|
@ -68,6 +78,7 @@ mod imp {
|
|||
get(); // check the assertion below
|
||||
}
|
||||
|
||||
/// Get the current thread state.
|
||||
pub fn get() -> ThreadState {
|
||||
let state = STATE.with(|ref k| {
|
||||
match *k.borrow() {
|
||||
|
@ -82,6 +93,7 @@ mod imp {
|
|||
state
|
||||
}
|
||||
|
||||
/// Enter into a given temporary state. Panics if re-entring.
|
||||
pub fn enter(x: ThreadState) {
|
||||
let state = get();
|
||||
assert!(!state.intersects(x));
|
||||
|
@ -90,6 +102,7 @@ mod imp {
|
|||
})
|
||||
}
|
||||
|
||||
/// Exit a given temporary state.
|
||||
pub fn exit(x: ThreadState) {
|
||||
let state = get();
|
||||
assert!(state.contains(x));
|
||||
|
@ -100,6 +113,7 @@ mod imp {
|
|||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
#[allow(missing_docs)]
|
||||
mod imp {
|
||||
use super::ThreadState;
|
||||
#[inline(always)] pub fn initialize(_: ThreadState) { }
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
//! A timer module, used to define a `Timer` type, that is controlled by script.
|
||||
|
||||
use time;
|
||||
|
||||
/// 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).
|
||||
/// The `TimerMode` is used to determine what time should the `Timer` return.
|
||||
#[derive(Debug, Clone)]
|
||||
enum TimerMode {
|
||||
/// The timer should return a fixed value.
|
||||
Test(f64),
|
||||
/// The timer should return the actual time.
|
||||
Current,
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
//! Traversing the DOM tree; the bloom filter.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use atomic_refcell::{AtomicRefCell, AtomicRefMut};
|
||||
use context::{SharedStyleContext, StyleContext};
|
||||
use data::{ElementData, ElementStyles, StoredRestyleHint};
|
||||
|
@ -18,14 +20,23 @@ use std::mem;
|
|||
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
|
||||
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.
|
||||
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;
|
||||
|
||||
// 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)]
|
||||
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>,
|
||||
}
|
||||
|
||||
|
@ -37,10 +48,12 @@ pub struct PreTraverseToken {
|
|||
}
|
||||
|
||||
impl PreTraverseToken {
|
||||
/// Whether we should traverse children.
|
||||
pub fn should_traverse(&self) -> bool {
|
||||
self.traverse
|
||||
}
|
||||
|
||||
/// Whether we should traverse only unstyled children.
|
||||
pub fn traverse_unstyled_children_only(&self) -> bool {
|
||||
self.unstyled_children_only
|
||||
}
|
||||
|
@ -48,15 +61,22 @@ impl PreTraverseToken {
|
|||
|
||||
/// Enum to prevent duplicate logging.
|
||||
pub enum LogBehavior {
|
||||
/// We should log.
|
||||
MayLog,
|
||||
/// We shouldn't log.
|
||||
DontLog,
|
||||
}
|
||||
use self::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 {
|
||||
/// 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;
|
||||
|
||||
/// 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|.
|
||||
unsafe fn clear_element_data(element: &N::ConcreteElement);
|
||||
|
||||
/// Return the shared style context common to all worker threads.
|
||||
fn shared_context(&self) -> &SharedStyleContext;
|
||||
|
||||
/// Create a thread-local context.
|
||||
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) {
|
||||
for kid in el.as_node().children() {
|
||||
if let Some(kid) = kid.as_element() {
|
||||
|
|
|
@ -18,6 +18,7 @@ pub use values::specified::basic_shape::{FillRule, GeometryBox, ShapeBox};
|
|||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ShapeSource<T> {
|
||||
Url(SpecifiedUrl),
|
||||
Shape(BasicShape, Option<T>),
|
||||
|
@ -51,6 +52,7 @@ impl<T: ToCss> ToCss for ShapeSource<T> {
|
|||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum BasicShape {
|
||||
Inset(InsetRect),
|
||||
Circle(Circle),
|
||||
|
@ -71,6 +73,7 @@ impl ToCss for BasicShape {
|
|||
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct InsetRect {
|
||||
pub top: LengthOrPercentage,
|
||||
pub right: LengthOrPercentage,
|
||||
|
@ -100,6 +103,7 @@ impl ToCss for InsetRect {
|
|||
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct Circle {
|
||||
pub radius: ShapeRadius,
|
||||
pub position: Position,
|
||||
|
@ -115,6 +119,7 @@ impl ToCss for Circle {
|
|||
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct Ellipse {
|
||||
pub semiaxis_x: ShapeRadius,
|
||||
pub semiaxis_y: ShapeRadius,
|
||||
|
@ -138,6 +143,7 @@ impl ToCss for Ellipse {
|
|||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
/// https://drafts.csswg.org/css-shapes/#funcdef-polygon
|
||||
pub struct Polygon {
|
||||
pub fill: FillRule,
|
||||
|
@ -168,6 +174,7 @@ impl ToCss for Polygon {
|
|||
/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ShapeRadius {
|
||||
Length(LengthOrPercentage),
|
||||
ClosestSide,
|
||||
|
@ -193,6 +200,7 @@ impl ToCss for ShapeRadius {
|
|||
/// https://drafts.csswg.org/css-backgrounds-3/#border-radius
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct BorderRadius {
|
||||
pub top_left: BorderRadiusSize,
|
||||
pub top_right: BorderRadiusSize,
|
||||
|
|
|
@ -51,6 +51,7 @@ impl ToComputedValue for specified::Image {
|
|||
/// https://drafts.csswg.org/css-images/#image-values
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Image {
|
||||
Url(SpecifiedUrl),
|
||||
Gradient(Gradient),
|
||||
|
@ -174,6 +175,7 @@ impl ToComputedValue for specified::Gradient {
|
|||
/// https://drafts.csswg.org/css-images/#gradients
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum GradientKind {
|
||||
Linear(AngleOrCorner),
|
||||
Radial(EndingShape, Position),
|
||||
|
@ -271,6 +273,7 @@ impl ToComputedValue for specified::ColorStop {
|
|||
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-ending-shape
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum EndingShape {
|
||||
Circle(LengthOrKeyword),
|
||||
Ellipse(LengthOrPercentageOrKeyword),
|
||||
|
@ -336,6 +339,7 @@ impl ToComputedValue for specified::GradientEndingShape {
|
|||
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum LengthOrKeyword {
|
||||
Length(Length),
|
||||
Keyword(SizeKeyword),
|
||||
|
@ -394,6 +398,7 @@ impl ToComputedValue for specified::LengthOrKeyword {
|
|||
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum LengthOrPercentageOrKeyword {
|
||||
LengthOrPercentage(LengthOrPercentage, LengthOrPercentage),
|
||||
Keyword(SizeKeyword),
|
||||
|
@ -458,6 +463,7 @@ impl ToComputedValue for specified::LengthOrPercentageOrKeyword {
|
|||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum AngleOrCorner {
|
||||
Angle(Angle),
|
||||
Corner(HorizontalDirection, VerticalDirection)
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* 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/. */
|
||||
|
||||
//! `<length>` computed values, and related ones.
|
||||
|
||||
use app_units::Au;
|
||||
use ordered_float::NotNaN;
|
||||
use std::fmt;
|
||||
|
@ -16,6 +18,7 @@ pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
|
|||
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct CalcLengthOrPercentage {
|
||||
pub length: Au,
|
||||
pub percentage: Option<CSSFloat>,
|
||||
|
@ -23,11 +26,13 @@ pub struct CalcLengthOrPercentage {
|
|||
|
||||
impl CalcLengthOrPercentage {
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub fn length(&self) -> Au {
|
||||
self.length
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub fn percentage(&self) -> CSSFloat {
|
||||
self.percentage.unwrap_or(0.)
|
||||
}
|
||||
|
@ -130,6 +135,7 @@ impl ToComputedValue for specified::CalcLengthOrPercentage {
|
|||
|
||||
#[derive(PartialEq, Clone, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum LengthOrPercentage {
|
||||
Length(Au),
|
||||
Percentage(CSSFloat),
|
||||
|
@ -138,6 +144,7 @@ pub enum LengthOrPercentage {
|
|||
|
||||
impl LengthOrPercentage {
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub fn zero() -> LengthOrPercentage {
|
||||
LengthOrPercentage::Length(Au(0))
|
||||
}
|
||||
|
@ -154,6 +161,7 @@ impl LengthOrPercentage {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn to_hash_key(&self) -> (Au, NotNaN<f32>) {
|
||||
use self::LengthOrPercentage::*;
|
||||
match *self {
|
||||
|
@ -223,6 +231,7 @@ impl ToCss for LengthOrPercentage {
|
|||
|
||||
#[derive(PartialEq, Clone, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum LengthOrPercentageOrAuto {
|
||||
Length(Au),
|
||||
Percentage(CSSFloat),
|
||||
|
@ -311,6 +320,7 @@ impl ToCss for LengthOrPercentageOrAuto {
|
|||
|
||||
#[derive(PartialEq, Clone, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum LengthOrPercentageOrAutoOrContent {
|
||||
Length(Au),
|
||||
Percentage(CSSFloat),
|
||||
|
@ -397,6 +407,7 @@ impl ToCss for LengthOrPercentageOrAutoOrContent {
|
|||
|
||||
#[derive(PartialEq, Clone, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum LengthOrPercentageOrNone {
|
||||
Length(Au),
|
||||
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_>;
|
||||
|
||||
/// Either a computed `<length>` or the `auto` keyword.
|
||||
pub type LengthOrAuto = Either<Length, Auto>;
|
||||
|
||||
/// Either a computed `<length>` or a `<number>` value.
|
||||
pub type LengthOrNumber = Either<Length, Number>;
|
||||
|
||||
/// Either a computed `<length>` or the `normal` keyword.
|
||||
pub type LengthOrNormal = Either<Length, Normal>;
|
||||
|
||||
pub type Length = Au;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* 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/. */
|
||||
|
||||
//! Computed values.
|
||||
|
||||
use app_units::Au;
|
||||
use euclid::size::Size2D;
|
||||
use font_metrics::FontMetricsProvider;
|
||||
|
@ -24,23 +26,41 @@ pub mod image;
|
|||
pub mod length;
|
||||
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> {
|
||||
/// Whether the current element is the root element.
|
||||
pub is_root_element: bool,
|
||||
|
||||
/// The current viewport size.
|
||||
pub viewport_size: Size2D<Au>,
|
||||
|
||||
/// The style we're inheriting from.
|
||||
pub inherited_style: &'a ComputedValues,
|
||||
|
||||
/// Values access through this need to be in the properties "computed
|
||||
/// early": color, text-decoration, font-size, display, position, float,
|
||||
/// border-*-style, outline-style, font-family, writing-mode...
|
||||
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>,
|
||||
}
|
||||
|
||||
impl<'a> Context<'a> {
|
||||
/// Whether the current element is the 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 }
|
||||
/// The style we're inheriting from.
|
||||
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 }
|
||||
/// A mutable reference to the current style.
|
||||
pub fn mutate_style(&mut self) -> &mut ComputedValues { &mut self.style }
|
||||
|
||||
/// 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 {
|
||||
/// The computed value type we're going to be converted to.
|
||||
type ComputedValue;
|
||||
|
||||
/// Convert a specified value to a computed value, using itself and the data
|
||||
/// inside the `Context`.
|
||||
#[inline]
|
||||
fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue;
|
||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue;
|
||||
|
||||
#[inline]
|
||||
/// Convert a computed value to specified value form.
|
||||
|
@ -72,9 +96,13 @@ pub trait ToComputedValue {
|
|||
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 {}
|
||||
|
||||
impl<T> ToComputedValue for T where T: ComputedValueAsSpecified + Clone {
|
||||
impl<T> ToComputedValue for T
|
||||
where T: ComputedValueAsSpecified + Clone,
|
||||
{
|
||||
type ComputedValue = T;
|
||||
|
||||
#[inline]
|
||||
|
@ -133,9 +161,11 @@ impl ToComputedValue for specified::Length {
|
|||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct BorderRadiusSize(pub Size2D<LengthOrPercentage>);
|
||||
|
||||
impl BorderRadiusSize {
|
||||
#[allow(missing_docs)]
|
||||
pub fn zero() -> BorderRadiusSize {
|
||||
BorderRadiusSize(Size2D::new(LengthOrPercentage::Length(Au(0)), LengthOrPercentage::Length(Au(0))))
|
||||
}
|
||||
|
@ -169,6 +199,7 @@ impl ToCss for BorderRadiusSize {
|
|||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct Shadow {
|
||||
pub offset_x: Au,
|
||||
pub offset_y: Au,
|
||||
|
@ -178,5 +209,8 @@ pub struct Shadow {
|
|||
pub inset: bool,
|
||||
}
|
||||
|
||||
/// A `<number>` value.
|
||||
pub type Number = CSSFloat;
|
||||
|
||||
/// A type used for opacity.
|
||||
pub type Opacity = CSSFloat;
|
||||
|
|
|
@ -13,6 +13,7 @@ use values::computed::LengthOrPercentage;
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct Position {
|
||||
pub horizontal: LengthOrPercentage,
|
||||
pub vertical: LengthOrPercentage,
|
||||
|
@ -29,6 +30,7 @@ impl ToCss for Position {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct HorizontalPosition(pub LengthOrPercentage);
|
||||
|
||||
impl ToCss for HorizontalPosition {
|
||||
|
@ -39,6 +41,7 @@ impl ToCss for HorizontalPosition {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct VerticalPosition(pub LengthOrPercentage);
|
||||
|
||||
impl ToCss for VerticalPosition {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
//!
|
||||
//! [values]: https://drafts.csswg.org/css-values/
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
pub use cssparser::{RGBA, Parser};
|
||||
use parser::{Parse, ParserContext};
|
||||
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 ),+);
|
||||
};
|
||||
($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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
|
||||
pub enum $name {
|
||||
|
@ -24,6 +26,7 @@ macro_rules! define_numbered_css_keyword_enum {
|
|||
}
|
||||
|
||||
impl $name {
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse(input: &mut ::cssparser::Parser) -> Result<$name, ()> {
|
||||
match_ignore_ascii_case! { try!(input.expect_ident()),
|
||||
$( $css => Ok($name::$variant), )+
|
||||
|
@ -34,7 +37,8 @@ macro_rules! define_numbered_css_keyword_enum {
|
|||
|
||||
impl ToCss for $name {
|
||||
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) ),+
|
||||
}
|
||||
|
@ -46,17 +50,26 @@ macro_rules! define_numbered_css_keyword_enum {
|
|||
pub mod computed;
|
||||
pub mod specified;
|
||||
|
||||
/// A CSS float value.
|
||||
pub type CSSFloat = f32;
|
||||
|
||||
/// The default font size.
|
||||
pub const FONT_MEDIUM_PX: i32 = 16;
|
||||
|
||||
/// A trait used to query whether this value has viewport units.
|
||||
pub trait HasViewportPercentage {
|
||||
/// Returns true if this value has viewport units.
|
||||
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 {}
|
||||
|
||||
impl<T> HasViewportPercentage for T where T: NoViewportPercentage {
|
||||
impl<T> HasViewportPercentage for T
|
||||
where T: NoViewportPercentage,
|
||||
{
|
||||
#[inline]
|
||||
fn has_viewport_percentage(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
@ -68,6 +81,7 @@ macro_rules! define_keyword_type {
|
|||
($name: ident, $css: expr) => {
|
||||
#[derive(Clone, PartialEq, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct $name;
|
||||
|
||||
impl ::style_traits::ToCss for $name {
|
||||
|
@ -99,8 +113,11 @@ define_keyword_type!(Normal, "normal");
|
|||
|
||||
#[derive(Clone, PartialEq, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
/// A struct representing one of two kinds of values.
|
||||
pub enum Either<A, B> {
|
||||
/// The first value.
|
||||
First(A),
|
||||
/// The second kind of value.
|
||||
Second(B),
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ use values::specified::url::SpecifiedUrl;
|
|||
/// shape-outside uses ShapeSource<ShapeBox>
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ShapeSource<T> {
|
||||
Url(SpecifiedUrl),
|
||||
Shape(BasicShape, Option<T>),
|
||||
|
@ -55,6 +56,7 @@ impl<T: ToCss> ToCss for ShapeSource<T> {
|
|||
}
|
||||
|
||||
impl<T: Parse + PartialEq + Copy> ShapeSource<T> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||
if let Ok(_) = input.try(|input| input.expect_ident_matching("none")) {
|
||||
Ok(ShapeSource::None)
|
||||
|
@ -129,6 +131,7 @@ impl<T: ToComputedValue> ToComputedValue for ShapeSource<T> {
|
|||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum BasicShape {
|
||||
Inset(InsetRect),
|
||||
Circle(Circle),
|
||||
|
@ -205,6 +208,7 @@ impl ToComputedValue for BasicShape {
|
|||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
/// https://drafts.csswg.org/css-shapes/#funcdef-inset
|
||||
#[allow(missing_docs)]
|
||||
pub struct InsetRect {
|
||||
pub top: LengthOrPercentage,
|
||||
pub right: LengthOrPercentage,
|
||||
|
@ -214,6 +218,7 @@ pub struct InsetRect {
|
|||
}
|
||||
|
||||
impl InsetRect {
|
||||
#[allow(missing_docs)]
|
||||
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 mut rect = InsetRect {
|
||||
|
@ -373,12 +378,14 @@ fn serialize_basicshape_position<W>(position: &Position, dest: &mut W)
|
|||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
/// https://drafts.csswg.org/css-shapes/#funcdef-circle
|
||||
#[allow(missing_docs)]
|
||||
pub struct Circle {
|
||||
pub radius: ShapeRadius,
|
||||
pub position: Position,
|
||||
}
|
||||
|
||||
impl Circle {
|
||||
#[allow(missing_docs)]
|
||||
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 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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
/// https://drafts.csswg.org/css-shapes/#funcdef-ellipse
|
||||
#[allow(missing_docs)]
|
||||
pub struct Ellipse {
|
||||
pub semiaxis_x: ShapeRadius,
|
||||
pub semiaxis_y: ShapeRadius,
|
||||
|
@ -458,6 +466,7 @@ pub struct Ellipse {
|
|||
|
||||
|
||||
impl Ellipse {
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Ellipse, ()> {
|
||||
let (a, b) = input.try(|input| -> Result<_, ()> {
|
||||
Ok((try!(ShapeRadius::parse(context, input)), try!(ShapeRadius::parse(context, input))))
|
||||
|
@ -537,12 +546,14 @@ impl ToComputedValue for Ellipse {
|
|||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
/// https://drafts.csswg.org/css-shapes/#funcdef-polygon
|
||||
#[allow(missing_docs)]
|
||||
pub struct Polygon {
|
||||
pub fill: FillRule,
|
||||
pub coordinates: Vec<(LengthOrPercentage, LengthOrPercentage)>,
|
||||
}
|
||||
|
||||
impl Polygon {
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Polygon, ()> {
|
||||
let fill = input.try(|input| {
|
||||
let fill = FillRule::parse(context, input);
|
||||
|
@ -626,6 +637,7 @@ impl ToComputedValue for Polygon {
|
|||
/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ShapeRadius {
|
||||
Length(LengthOrPercentage),
|
||||
ClosestSide,
|
||||
|
@ -690,6 +702,7 @@ impl ToComputedValue for ShapeRadius {
|
|||
/// https://drafts.csswg.org/css-backgrounds-3/#border-radius
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct BorderRadius {
|
||||
pub top_left: BorderRadiusSize,
|
||||
pub top_right: BorderRadiusSize,
|
||||
|
@ -792,6 +805,7 @@ impl ToComputedValue for BorderRadius {
|
|||
/// https://drafts.csswg.org/css-shapes/#typedef-fill-rule
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum FillRule {
|
||||
NonZero,
|
||||
EvenOdd,
|
||||
|
@ -830,6 +844,7 @@ impl ToCss for FillRule {
|
|||
/// https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum GeometryBox {
|
||||
Fill,
|
||||
Stroke,
|
||||
|
@ -868,6 +883,7 @@ impl ComputedValueAsSpecified for GeometryBox {}
|
|||
// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ShapeBox {
|
||||
Margin,
|
||||
// https://drafts.csswg.org/css-backgrounds-3/#box
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! A grid line type.
|
||||
|
||||
use cssparser::Parser;
|
||||
use parser::{Parse, ParserContext};
|
||||
use std::fmt;
|
||||
|
@ -9,9 +11,10 @@ use style_traits::ToCss;
|
|||
use values::NoViewportPercentage;
|
||||
use values::computed::ComputedValueAsSpecified;
|
||||
|
||||
// https://drafts.csswg.org/css-grid/#typedef-grid-row-start-grid-line
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
#[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 is_span: bool,
|
||||
pub ident: Option<String>,
|
||||
|
|
|
@ -21,7 +21,9 @@ use values::specified::url::{SpecifiedUrl, UrlExtraData};
|
|||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum Image {
|
||||
/// A `<url()>` image.
|
||||
Url(SpecifiedUrl),
|
||||
/// A `<gradient>` image.
|
||||
Gradient(Gradient),
|
||||
}
|
||||
|
||||
|
@ -35,6 +37,7 @@ impl ToCss for Image {
|
|||
}
|
||||
|
||||
impl Image {
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Image, ()> {
|
||||
if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) {
|
||||
return Ok(Image::Url(url));
|
||||
|
@ -151,7 +154,14 @@ impl Gradient {
|
|||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum GradientKind {
|
||||
/// A `<linear-gradient()>`:
|
||||
///
|
||||
/// https://drafts.csswg.org/css-images/#funcdef-linear-gradient
|
||||
Linear(AngleOrCorner),
|
||||
|
||||
/// A `<radial-gradient()>`:
|
||||
///
|
||||
/// https://drafts.csswg.org/css-images/#radial-gradients
|
||||
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.
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum AngleOrCorner {
|
||||
Angle(Angle),
|
||||
Corner(Option<HorizontalDirection>, Option<VerticalDirection>),
|
||||
|
@ -327,6 +338,7 @@ impl Parse for ColorStop {
|
|||
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-ending-shape
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum EndingShape {
|
||||
Circle(LengthOrKeyword),
|
||||
Ellipse(LengthOrPercentageOrKeyword),
|
||||
|
@ -351,6 +363,7 @@ impl ToCss for EndingShape {
|
|||
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum LengthOrKeyword {
|
||||
Length(Length),
|
||||
Keyword(SizeKeyword),
|
||||
|
@ -378,6 +391,7 @@ impl ToCss for LengthOrKeyword {
|
|||
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum LengthOrPercentageOrKeyword {
|
||||
LengthOrPercentage(LengthOrPercentage, LengthOrPercentage),
|
||||
Keyword(SizeKeyword),
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! [Length values][length].
|
||||
//!
|
||||
//! [length]: https://drafts.csswg.org/css-values/#lengths
|
||||
|
||||
use app_units::Au;
|
||||
use cssparser::{Parser, Token};
|
||||
use euclid::size::Size2D;
|
||||
|
@ -23,15 +27,22 @@ pub use super::image::{SizeKeyword, VerticalDirection};
|
|||
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
/// A font relative length.
|
||||
pub enum FontRelativeLength {
|
||||
/// A "em" value: https://drafts.csswg.org/css-values/#em
|
||||
Em(CSSFloat),
|
||||
/// A "ex" value: https://drafts.csswg.org/css-values/#ex
|
||||
Ex(CSSFloat),
|
||||
/// A "ch" value: https://drafts.csswg.org/css-values/#ch
|
||||
Ch(CSSFloat),
|
||||
/// A "rem" value: https://drafts.csswg.org/css-values/#rem
|
||||
Rem(CSSFloat)
|
||||
}
|
||||
|
||||
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 {
|
||||
FontRelativeLength::Em(length) => write!(dest, "{}em", length),
|
||||
FontRelativeLength::Ex(length) => write!(dest, "{}ex", length),
|
||||
|
@ -42,6 +53,8 @@ impl ToCss for 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> {
|
||||
use font_metrics::FontMetricsQueryResult::*;
|
||||
if let Some(ref metrics_provider) = context.font_metrics_provider {
|
||||
|
@ -55,8 +68,8 @@ impl FontRelativeLength {
|
|||
None
|
||||
}
|
||||
|
||||
// NB: The use_inherited flag is used to special-case the computation of
|
||||
// font-family.
|
||||
/// Computes the font-relative length. We use the use_inherited flag to
|
||||
/// special-case the computation of font-size.
|
||||
pub fn to_computed_value(&self, context: &Context, use_inherited: bool) -> Au {
|
||||
let reference_font_size = if use_inherited {
|
||||
context.inherited_style().get_font().clone_font_size()
|
||||
|
@ -121,10 +134,17 @@ impl FontRelativeLength {
|
|||
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
/// A viewport-relative length.
|
||||
///
|
||||
/// https://drafts.csswg.org/css-values/#viewport-relative-lengths
|
||||
pub enum ViewportPercentageLength {
|
||||
/// A vw unit: https://drafts.csswg.org/css-values/#vw
|
||||
Vw(CSSFloat),
|
||||
/// A vh unit: https://drafts.csswg.org/css-values/#vh
|
||||
Vh(CSSFloat),
|
||||
/// https://drafts.csswg.org/css-values/#vmin
|
||||
Vmin(CSSFloat),
|
||||
/// https://drafts.csswg.org/css-values/#vmax
|
||||
Vmax(CSSFloat)
|
||||
}
|
||||
|
||||
|
@ -146,6 +166,7 @@ impl ToCss for 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 {
|
||||
macro_rules! to_unit {
|
||||
($viewport_dimension:expr) => {
|
||||
|
@ -167,11 +188,13 @@ impl ViewportPercentageLength {
|
|||
}
|
||||
}
|
||||
|
||||
/// HTML5 "character width", as defined in HTML5 § 14.5.4.
|
||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct CharacterWidth(pub i32);
|
||||
|
||||
impl CharacterWidth {
|
||||
/// Computes the given character width.
|
||||
pub fn to_computed_value(&self, reference_font_size: Au) -> Au {
|
||||
// This applies the *converting a character width to pixels* algorithm as specified
|
||||
// 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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum Length {
|
||||
/// An absolute length: https://drafts.csswg.org/css-values/#absolute-length
|
||||
Absolute(Au), // application units
|
||||
|
||||
/// A font-relative length:
|
||||
///
|
||||
/// https://drafts.csswg.org/css-values/#font-relative-lengths
|
||||
FontRelative(FontRelativeLength),
|
||||
|
||||
/// A viewport-relative length.
|
||||
///
|
||||
/// https://drafts.csswg.org/css-values/#viewport-relative-lengths
|
||||
ViewportPercentage(ViewportPercentageLength),
|
||||
|
||||
/// HTML5 "character width", as defined in HTML5 § 14.5.4.
|
||||
|
@ -196,6 +231,12 @@ pub enum Length {
|
|||
/// `Stylist::synthesize_rules_for_legacy_attributes()`.
|
||||
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),
|
||||
}
|
||||
|
||||
|
@ -274,7 +315,7 @@ const AU_PER_PT: CSSFloat = AU_PER_IN / 72.;
|
|||
const AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
|
||||
|
||||
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> {
|
||||
Some(match_ignore_ascii_case! { s,
|
||||
"xx-small" => Length::Absolute(Au::from_px(FONT_MEDIUM_PX) * 3 / 5),
|
||||
|
@ -306,9 +347,13 @@ impl Length {
|
|||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a non-negative length
|
||||
pub fn parse_non_negative(input: &mut Parser) -> Result<Length, ()> {
|
||||
Length::parse_internal(input, AllowedNumericType::NonNegative)
|
||||
}
|
||||
|
||||
/// Parse a given absolute or relative dimension.
|
||||
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> {
|
||||
match_ignore_ascii_case! { unit,
|
||||
"px" => Ok(Length::from_px(value)),
|
||||
|
@ -331,6 +376,8 @@ impl Length {
|
|||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an absolute length from a px values.
|
||||
#[inline]
|
||||
pub fn from_px(px_value: CSSFloat) -> Length {
|
||||
Length::Absolute(Au((px_value * AU_PER_PX) as i32))
|
||||
|
@ -345,22 +392,29 @@ impl Parse for Length {
|
|||
|
||||
impl<T> Either<Length, T> {
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse_non_negative_length(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||
Length::parse_internal(input, AllowedNumericType::NonNegative).map(Either::First)
|
||||
}
|
||||
}
|
||||
|
||||
/// A calc sum expression node.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CalcSumNode {
|
||||
/// The products of this node.
|
||||
pub products: Vec<CalcProductNode>,
|
||||
}
|
||||
|
||||
/// A calc product expression node.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CalcProductNode {
|
||||
/// The values inside this product node.
|
||||
values: Vec<CalcValueNode>
|
||||
}
|
||||
|
||||
/// A value inside a `Calc` expression.
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum CalcValueNode {
|
||||
Length(Length),
|
||||
Angle(Angle),
|
||||
|
@ -371,6 +425,7 @@ pub enum CalcValueNode {
|
|||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum CalcUnit {
|
||||
Number,
|
||||
Integer,
|
||||
|
@ -382,6 +437,7 @@ pub enum CalcUnit {
|
|||
|
||||
#[derive(Clone, PartialEq, Copy, Debug, Default)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct CalcLengthOrPercentage {
|
||||
pub absolute: Option<Au>,
|
||||
pub vw: Option<ViewportPercentageLength>,
|
||||
|
@ -396,6 +452,7 @@ pub struct CalcLengthOrPercentage {
|
|||
}
|
||||
|
||||
impl CalcLengthOrPercentage {
|
||||
/// Parse a calc sum node.
|
||||
pub fn parse_sum(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcSumNode, ()> {
|
||||
let mut products = Vec::new();
|
||||
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, ()> {
|
||||
let mut multiplier = 1.;
|
||||
let mut node_with_unit = None;
|
||||
|
@ -554,6 +612,7 @@ impl CalcLengthOrPercentage {
|
|||
CalcLengthOrPercentage::parse(input, CalcUnit::LengthOrPercentage)
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse(input: &mut Parser,
|
||||
expected_unit: CalcUnit) -> Result<CalcLengthOrPercentage, ()> {
|
||||
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, ()> {
|
||||
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, ()> {
|
||||
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)]
|
||||
#[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 {
|
||||
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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum LengthOrPercentage {
|
||||
Length(Length),
|
||||
Percentage(Percentage),
|
||||
|
@ -790,6 +858,7 @@ impl ToCss for LengthOrPercentage {
|
|||
}
|
||||
}
|
||||
impl LengthOrPercentage {
|
||||
/// Returns a `zero` length.
|
||||
pub fn zero() -> LengthOrPercentage {
|
||||
LengthOrPercentage::Length(Length::Absolute(Au(0)))
|
||||
}
|
||||
|
@ -812,6 +881,7 @@ impl LengthOrPercentage {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parse a non-negative length.
|
||||
#[inline]
|
||||
pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentage, ()> {
|
||||
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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum LengthOrPercentageOrAuto {
|
||||
Length(Length),
|
||||
Percentage(Percentage),
|
||||
|
@ -875,6 +948,8 @@ impl LengthOrPercentageOrAuto {
|
|||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a non-negative length, percentage, or auto.
|
||||
#[inline]
|
||||
pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrAuto, ()> {
|
||||
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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum LengthOrPercentageOrNone {
|
||||
Length(Length),
|
||||
Percentage(Percentage),
|
||||
|
@ -937,6 +1015,7 @@ impl LengthOrPercentageOrNone {
|
|||
_ => Err(())
|
||||
}
|
||||
}
|
||||
/// Parse a non-negative LengthOrPercentageOrNone.
|
||||
#[inline]
|
||||
pub fn parse_non_negative(input: &mut Parser) -> Result<LengthOrPercentageOrNone, ()> {
|
||||
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_>;
|
||||
|
||||
/// Either a `<length>` or the `normal` keyword.
|
||||
pub type LengthOrNormal = Either<Length, Normal>;
|
||||
|
||||
/// Either a `<length>` or the `auto` keyword.
|
||||
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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum LengthOrPercentageOrAutoOrContent {
|
||||
/// A `<length>`.
|
||||
Length(Length),
|
||||
/// A percentage.
|
||||
Percentage(Percentage),
|
||||
/// A `calc` node.
|
||||
Calc(CalcLengthOrPercentage),
|
||||
/// The `auto` keyword.
|
||||
Auto,
|
||||
/// The `content` keyword.
|
||||
Content
|
||||
}
|
||||
|
||||
|
@ -1011,9 +1102,11 @@ impl Parse for LengthOrPercentageOrAutoOrContent {
|
|||
}
|
||||
}
|
||||
|
||||
/// Either a `<length>` or a `<number>`.
|
||||
pub type LengthOrNumber = Either<Length, Number>;
|
||||
|
||||
impl LengthOrNumber {
|
||||
/// Parse a non-negative LengthOrNumber.
|
||||
pub fn parse_non_negative(input: &mut Parser) -> Result<Self, ()> {
|
||||
if let Ok(v) = input.try(Length::parse_non_negative) {
|
||||
Ok(Either::First(v))
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Specified values.
|
||||
//!
|
||||
//! TODO(emilio): Enhance docs.
|
||||
|
||||
use app_units::Au;
|
||||
use cssparser::{self, Parser, Token};
|
||||
use euclid::size::Size2D;
|
||||
|
@ -35,6 +39,7 @@ impl NoViewportPercentage for i32 {} // For PropertyDeclaration::Order
|
|||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct CSSColor {
|
||||
pub parsed: cssparser::Color,
|
||||
pub authored: Option<String>,
|
||||
|
@ -68,6 +73,7 @@ impl ToCss for CSSColor {
|
|||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct CSSRGBA {
|
||||
pub parsed: cssparser::RGBA,
|
||||
pub authored: Option<String>,
|
||||
|
@ -85,6 +91,7 @@ impl ToCss for CSSRGBA {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct SimplifiedSumNode {
|
||||
values: Vec<SimplifiedValueNode>,
|
||||
}
|
||||
|
@ -100,6 +107,7 @@ impl<'a> Mul<CSSFloat> for &'a SimplifiedSumNode {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum SimplifiedValueNode {
|
||||
Length(Length),
|
||||
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, ()> {
|
||||
match try!(input.next()) {
|
||||
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, ()> {
|
||||
match try!(input.next()) {
|
||||
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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct BorderRadiusSize(pub Size2D<LengthOrPercentage>);
|
||||
|
||||
impl NoViewportPercentage for BorderRadiusSize {}
|
||||
|
||||
impl BorderRadiusSize {
|
||||
#[allow(missing_docs)]
|
||||
pub fn zero() -> BorderRadiusSize {
|
||||
let zero = LengthOrPercentage::Length(Length::Absolute(Au(0)));
|
||||
BorderRadiusSize(Size2D::new(zero, zero))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(width: LengthOrPercentage, height: LengthOrPercentage) -> BorderRadiusSize {
|
||||
BorderRadiusSize(Size2D::new(width, height))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn circle(radius: LengthOrPercentage) -> BorderRadiusSize {
|
||||
BorderRadiusSize(Size2D::new(radius, radius))
|
||||
}
|
||||
|
@ -228,11 +242,13 @@ impl ToCss for Angle {
|
|||
|
||||
impl Angle {
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub fn radians(self) -> f32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub fn from_radians(r: f32) -> Self {
|
||||
Angle(r)
|
||||
}
|
||||
|
@ -257,6 +273,7 @@ impl Parse for Angle {
|
|||
}
|
||||
|
||||
impl Angle {
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Angle, ()> {
|
||||
match_ignore_ascii_case! { unit,
|
||||
"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, ()> {
|
||||
input.try(|i| BorderRadiusSize::parse(context, i)).or_else(|()| {
|
||||
match_ignore_ascii_case! { try!(input.expect_ident()),
|
||||
"thin" => Ok(BorderRadiusSize::circle(
|
||||
LengthOrPercentage::Length(Length::from_px(1.)))),
|
||||
"medium" => Ok(BorderRadiusSize::circle(
|
||||
LengthOrPercentage::Length(Length::from_px(3.)))),
|
||||
"thick" => Ok(BorderRadiusSize::circle(
|
||||
LengthOrPercentage::Length(Length::from_px(5.)))),
|
||||
_ => Err(())
|
||||
}
|
||||
})
|
||||
input.try(|i| BorderRadiusSize::parse(context, i)).or_else(|_| {
|
||||
match_ignore_ascii_case! { try!(input.expect_ident()),
|
||||
"thin" => Ok(BorderRadiusSize::circle(
|
||||
LengthOrPercentage::Length(Length::from_px(1.)))),
|
||||
"medium" => Ok(BorderRadiusSize::circle(
|
||||
LengthOrPercentage::Length(Length::from_px(3.)))),
|
||||
"thick" => Ok(BorderRadiusSize::circle(
|
||||
LengthOrPercentage::Length(Length::from_px(5.)))),
|
||||
_ => Err(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse_border_width(input: &mut Parser) -> Result<Length, ()> {
|
||||
input.try(Length::parse_non_negative).or_else(|()| {
|
||||
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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum BorderWidth {
|
||||
Thin,
|
||||
Medium,
|
||||
|
@ -317,6 +337,7 @@ impl Parse for BorderWidth {
|
|||
}
|
||||
|
||||
impl BorderWidth {
|
||||
#[allow(missing_docs)]
|
||||
pub fn from_length(length: Length) -> Self {
|
||||
BorderWidth::Width(length)
|
||||
}
|
||||
|
@ -382,6 +403,7 @@ define_numbered_css_keyword_enum! { BorderStyle:
|
|||
impl NoViewportPercentage for BorderStyle {}
|
||||
|
||||
impl BorderStyle {
|
||||
/// Whether this border style is either none or hidden.
|
||||
pub fn none_or_hidden(&self) -> bool {
|
||||
matches!(*self, BorderStyle::none | BorderStyle::hidden)
|
||||
}
|
||||
|
@ -435,6 +457,7 @@ impl ToCss for Time {
|
|||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct Number(pub CSSFloat);
|
||||
|
||||
impl NoViewportPercentage for Number {}
|
||||
|
@ -453,10 +476,12 @@ impl Number {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse_non_negative(input: &mut Parser) -> Result<Number, ()> {
|
||||
Number::parse_with_minimum(input, 0.0)
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse_at_least_one(input: &mut Parser) -> Result<Number, ()> {
|
||||
Number::parse_with_minimum(input, 1.0)
|
||||
}
|
||||
|
@ -482,6 +507,7 @@ impl ToCss for Number {
|
|||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct Opacity(pub CSSFloat);
|
||||
|
||||
impl NoViewportPercentage for Opacity {}
|
||||
|
@ -518,10 +544,12 @@ impl ToCss for Opacity {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub type UrlOrNone = Either<SpecifiedUrl, None_>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct Shadow {
|
||||
pub offset_x: Length,
|
||||
pub offset_y: Length,
|
||||
|
@ -573,6 +601,7 @@ impl ToComputedValue for Shadow {
|
|||
|
||||
impl 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, ()> {
|
||||
use app_units::Au;
|
||||
let length_count = if disable_spread_and_inset { 3 } else { 4 };
|
||||
|
|
|
@ -20,8 +20,13 @@ use values::specified::{LengthOrPercentage, Percentage};
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
/// A [position][pos].
|
||||
///
|
||||
/// [pos]: https://drafts.csswg.org/css-values/#position
|
||||
pub struct Position {
|
||||
/// The horizontal component.
|
||||
pub horizontal: HorizontalPosition,
|
||||
/// The vertical component.
|
||||
pub vertical: VerticalPosition,
|
||||
}
|
||||
|
||||
|
@ -59,9 +64,12 @@ impl HasViewportPercentage for Position {
|
|||
}
|
||||
|
||||
impl Position {
|
||||
pub fn new(mut first_position: Option<PositionComponent>, mut second_position: Option<PositionComponent>,
|
||||
first_keyword: Option<PositionComponent>, second_keyword: Option<PositionComponent>)
|
||||
-> Result<Position, ()> {
|
||||
/// Create a new position value.
|
||||
pub fn new(mut first_position: Option<PositionComponent>,
|
||||
mut second_position: Option<PositionComponent>,
|
||||
first_keyword: Option<PositionComponent>,
|
||||
second_keyword: Option<PositionComponent>)
|
||||
-> Result<Position, ()> {
|
||||
// Unwrap for checking if values are at right place.
|
||||
let first_key = first_keyword.unwrap_or(PositionComponent::Keyword(Keyword::Left));
|
||||
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 {
|
||||
Position {
|
||||
horizontal: HorizontalPosition {
|
||||
|
@ -242,6 +251,7 @@ impl ToComputedValue for Position {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct HorizontalPosition {
|
||||
pub keyword: Option<Keyword>,
|
||||
pub position: Option<LengthOrPercentage>,
|
||||
|
@ -249,11 +259,7 @@ pub struct HorizontalPosition {
|
|||
|
||||
impl HasViewportPercentage for HorizontalPosition {
|
||||
fn has_viewport_percentage(&self) -> bool {
|
||||
if let Some(pos) = self.position {
|
||||
pos.has_viewport_percentage()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
self.position.map_or(false, |pos| pos.has_viewport_percentage())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,6 +377,7 @@ impl ToComputedValue for HorizontalPosition {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct VerticalPosition {
|
||||
pub keyword: Option<Keyword>,
|
||||
pub position: Option<LengthOrPercentage>,
|
||||
|
@ -378,11 +385,7 @@ pub struct VerticalPosition {
|
|||
|
||||
impl HasViewportPercentage for VerticalPosition {
|
||||
fn has_viewport_percentage(&self) -> bool {
|
||||
if let Some(pos) = self.position {
|
||||
pos.has_viewport_percentage()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
self.position.map_or(false, |pos| pos.has_viewport_percentage())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -510,6 +513,7 @@ define_css_keyword_enum!(Keyword:
|
|||
"y-end" => YEnd);
|
||||
|
||||
impl Keyword {
|
||||
/// Convert the given keyword to a length or a percentage.
|
||||
pub fn to_length_or_percentage(self) -> LengthOrPercentage {
|
||||
match self {
|
||||
Keyword::Center => LengthOrPercentage::Percentage(Percentage(0.5)),
|
||||
|
@ -532,10 +536,14 @@ enum PositionCategory {
|
|||
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)]
|
||||
pub enum PositionComponent {
|
||||
/// A `<length>`
|
||||
Length(LengthOrPercentage),
|
||||
/// A position keyword.
|
||||
Keyword(Keyword),
|
||||
}
|
||||
|
||||
|
@ -568,6 +576,7 @@ impl HasViewportPercentage for PositionComponent {
|
|||
}
|
||||
|
||||
impl PositionComponent {
|
||||
/// Convert the given position component to a length or a percentage.
|
||||
#[inline]
|
||||
pub fn to_length_or_percentage(self) -> LengthOrPercentage {
|
||||
match self {
|
||||
|
|
|
@ -18,23 +18,29 @@ use style_traits::ToCss;
|
|||
use values::NoViewportPercentage;
|
||||
use values::computed::ComputedValueAsSpecified;
|
||||
|
||||
/// A set of data needed in Gecko to represent a URL.
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Serialize, Deserialize, Eq))]
|
||||
pub struct UrlExtraData {
|
||||
/// The base URI.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub base: GeckoArcURI,
|
||||
/// The referrer.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub referrer: GeckoArcURI,
|
||||
/// The principal that originated this URI.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub principal: GeckoArcPrincipal,
|
||||
}
|
||||
|
||||
impl UrlExtraData {
|
||||
/// Constructs a `UrlExtraData`.
|
||||
#[cfg(feature = "servo")]
|
||||
pub fn make_from(_: &ParserContext) -> Option<UrlExtraData> {
|
||||
Some(UrlExtraData { })
|
||||
}
|
||||
|
||||
/// Constructs a `UrlExtraData`.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub fn make_from(context: &ParserContext) -> Option<UrlExtraData> {
|
||||
match context.extra_data {
|
||||
|
@ -81,6 +87,11 @@ impl Parse for 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>,
|
||||
context: &ParserContext)
|
||||
-> Result<Self, ()> {
|
||||
|
@ -104,14 +115,19 @@ impl SpecifiedUrl {
|
|||
})
|
||||
}
|
||||
|
||||
/// Get this URL's extra data.
|
||||
pub fn extra_data(&self) -> &UrlExtraData {
|
||||
&self.extra_data
|
||||
}
|
||||
|
||||
/// Returns the resolved url if it was valid.
|
||||
pub fn url(&self) -> Option<&ServoUrl> {
|
||||
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 {
|
||||
match self.resolved {
|
||||
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")]
|
||||
pub fn new_for_testing(url: &str) -> Self {
|
||||
SpecifiedUrl {
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
//! [at]: https://drafts.csswg.org/css-device-adapt/#atviewport-rule
|
||||
//! [meta]: https://drafts.csswg.org/css-device-adapt/#viewport-meta
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use app_units::Au;
|
||||
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser, parse_important};
|
||||
use cssparser::ToCss as ParserToCss;
|
||||
|
@ -60,6 +62,7 @@ macro_rules! declare_viewport_descriptor_inner {
|
|||
) => {
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ViewportDescriptor {
|
||||
$(
|
||||
$assigned_variant($assigned_data),
|
||||
|
@ -69,6 +72,7 @@ macro_rules! declare_viewport_descriptor_inner {
|
|||
const VIEWPORT_DESCRIPTOR_VARIANTS: usize = $number_of_variants;
|
||||
|
||||
impl ViewportDescriptor {
|
||||
#[allow(missing_docs)]
|
||||
pub fn discriminant_value(&self) -> usize {
|
||||
match *self {
|
||||
$(
|
||||
|
@ -114,12 +118,13 @@ trait FromMeta: Sized {
|
|||
fn from_meta(value: &str) -> Option<Self>;
|
||||
}
|
||||
|
||||
// ViewportLength is a length | percentage | auto | extend-to-zoom
|
||||
// See:
|
||||
// * http://dev.w3.org/csswg/css-device-adapt/#min-max-width-desc
|
||||
// * http://dev.w3.org/csswg/css-device-adapt/#extend-to-zoom
|
||||
/// ViewportLength is a length | percentage | auto | extend-to-zoom
|
||||
/// See:
|
||||
/// * http://dev.w3.org/csswg/css-device-adapt/#min-max-width-desc
|
||||
/// * http://dev.w3.org/csswg/css-device-adapt/#extend-to-zoom
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum ViewportLength {
|
||||
Specified(LengthOrPercentageOrAuto),
|
||||
ExtendToZoom
|
||||
|
@ -127,7 +132,7 @@ pub enum ViewportLength {
|
|||
|
||||
impl ToCss for ViewportLength {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||
where W: fmt::Write
|
||||
where W: fmt::Write,
|
||||
{
|
||||
match *self {
|
||||
ViewportLength::Specified(length) => length.to_css(dest),
|
||||
|
@ -209,6 +214,7 @@ struct ViewportRuleParser<'a, 'b: 'a> {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct ViewportDescriptorDeclaration {
|
||||
pub origin: Origin,
|
||||
pub descriptor: ViewportDescriptor,
|
||||
|
@ -216,6 +222,7 @@ pub struct ViewportDescriptorDeclaration {
|
|||
}
|
||||
|
||||
impl ViewportDescriptorDeclaration {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(origin: Origin,
|
||||
descriptor: ViewportDescriptor,
|
||||
important: bool) -> ViewportDescriptorDeclaration
|
||||
|
@ -313,9 +320,11 @@ impl<'a, 'b> DeclarationParser for ViewportRuleParser<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A `@viewport` rule.
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct ViewportRule {
|
||||
/// The declarations contained in this @viewport rule.
|
||||
pub declarations: Vec<ViewportDescriptorDeclaration>
|
||||
}
|
||||
|
||||
|
@ -333,6 +342,7 @@ fn is_whitespace_separator_or_equals(c: &char) -> bool {
|
|||
}
|
||||
|
||||
impl ViewportRule {
|
||||
#[allow(missing_docs)]
|
||||
pub fn parse(input: &mut Parser, context: &ParserContext)
|
||||
-> Result<ViewportRule, ()>
|
||||
{
|
||||
|
@ -358,6 +368,7 @@ impl ViewportRule {
|
|||
Ok(ViewportRule { declarations: cascade.finish() })
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn from_meta(content: &str) -> Option<ViewportRule> {
|
||||
let mut declarations = vec![None; VIEWPORT_DESCRIPTOR_VARIANTS];
|
||||
macro_rules! push_descriptor {
|
||||
|
@ -531,11 +542,13 @@ impl ViewportDescriptorDeclaration {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub struct Cascade {
|
||||
declarations: Vec<Option<(usize, ViewportDescriptorDeclaration)>>,
|
||||
count_so_far: usize,
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
impl Cascade {
|
||||
pub fn new() -> Self {
|
||||
Cascade {
|
||||
|
@ -545,7 +558,9 @@ impl Cascade {
|
|||
}
|
||||
|
||||
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();
|
||||
for stylesheet in stylesheets {
|
||||
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 {
|
||||
/// Create a ViewportConstraints from a viewport size and a `@viewport`
|
||||
/// rule.
|
||||
fn maybe_new(initial_viewport: TypedSize2D<f32, ViewportPx>,
|
||||
rule: &ViewportRule)
|
||||
-> Option<ViewportConstraints>;
|
||||
rule: &ViewportRule)
|
||||
-> Option<ViewportConstraints>;
|
||||
}
|
||||
|
||||
impl MaybeNew for ViewportConstraints {
|
||||
|
|
|
@ -8,14 +8,17 @@ use super::ToCss;
|
|||
|
||||
macro_rules! define_cursor {
|
||||
($( $css: expr => $variant: ident = $value: expr, )+) => {
|
||||
/// https://drafts.csswg.org/css-ui/#cursor
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize, HeapSizeOf))]
|
||||
#[repr(u8)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Cursor {
|
||||
$( $variant = $value ),+
|
||||
}
|
||||
|
||||
impl Cursor {
|
||||
/// Given a CSS keyword, get the corresponding cursor enum.
|
||||
pub fn from_css_keyword(keyword: &str) -> Result<Cursor, ()> {
|
||||
match_ignore_ascii_case! { keyword,
|
||||
$( concat!($css) => Ok(Cursor::$variant), )+
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#![crate_name = "style_traits"]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
#![deny(unsafe_code)]
|
||||
#![deny(unsafe_code, missing_docs)]
|
||||
|
||||
#![cfg_attr(feature = "servo", feature(plugin))]
|
||||
#![cfg_attr(feature = "servo", feature(proc_macro))]
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* 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/. */
|
||||
|
||||
//! Helper types and traits for the handling of CSS values.
|
||||
|
||||
use app_units::Au;
|
||||
use std::fmt;
|
||||
|
||||
|
@ -78,13 +80,14 @@ macro_rules! __define_css_keyword_enum__add_optional_traits {
|
|||
#[macro_export]
|
||||
macro_rules! __define_css_keyword_enum__actual {
|
||||
($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 )* )]
|
||||
pub enum $name {
|
||||
$( $variant ),+
|
||||
}
|
||||
|
||||
impl $name {
|
||||
/// Parse this property from a CSS input stream.
|
||||
pub fn parse(input: &mut ::cssparser::Parser) -> Result<$name, ()> {
|
||||
match_ignore_ascii_case! { try!(input.expect_ident()),
|
||||
$( $css => Ok($name::$variant), )+
|
||||
|
@ -95,27 +98,33 @@ macro_rules! __define_css_keyword_enum__actual {
|
|||
|
||||
impl ToCss for $name {
|
||||
fn to_css<W>(&self, dest: &mut W) -> ::std::fmt::Result
|
||||
where W: ::std::fmt::Write {
|
||||
match *self {
|
||||
$( $name::$variant => dest.write_str($css) ),+
|
||||
}
|
||||
where W: ::std::fmt::Write
|
||||
{
|
||||
match *self {
|
||||
$( $name::$variant => dest.write_str($css) ),+
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper types for the handling of specified values.
|
||||
pub mod specified {
|
||||
use app_units::Au;
|
||||
|
||||
/// Whether to allow negative values or not.
|
||||
#[repr(u8)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum AllowedNumericType {
|
||||
/// Allow all kind of numeric values.
|
||||
All,
|
||||
/// Allow only non-negative values.
|
||||
NonNegative
|
||||
}
|
||||
|
||||
impl AllowedNumericType {
|
||||
/// Whether value is valid for this allowed numeric type.
|
||||
#[inline]
|
||||
pub fn is_ok(&self, value: f32) -> bool {
|
||||
match *self {
|
||||
|
@ -124,6 +133,7 @@ pub mod specified {
|
|||
}
|
||||
}
|
||||
|
||||
/// Clamp the value following the rules of this numeric type.
|
||||
#[inline]
|
||||
pub fn clamp(&self, val: Au) -> Au {
|
||||
use std::cmp;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* 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/. */
|
||||
|
||||
//! Helper types for the `@viewport` rule.
|
||||
|
||||
use {PagePx, ViewportPx};
|
||||
use cssparser::{Parser, ToCss};
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
|
@ -20,16 +22,25 @@ define_css_keyword_enum!(Orientation:
|
|||
"landscape" => Landscape);
|
||||
|
||||
|
||||
/// A set of viewport descriptors:
|
||||
///
|
||||
/// https://drafts.csswg.org/css-device-adapt/#viewport-desc
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize, HeapSizeOf))]
|
||||
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>,
|
||||
|
||||
/// https://drafts.csswg.org/css-device-adapt/#zoom-desc
|
||||
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>>,
|
||||
/// https://drafts.csswg.org/css-device-adapt/#min-max-width-desc
|
||||
pub max_zoom: Option<ScaleFactor<f32, PagePx, ViewportPx>>,
|
||||
|
||||
/// https://drafts.csswg.org/css-device-adapt/#user-zoom-desc
|
||||
pub user_zoom: UserZoom,
|
||||
/// https://drafts.csswg.org/css-device-adapt/#orientation-desc
|
||||
pub orientation: Orientation
|
||||
}
|
||||
|
||||
|
@ -53,19 +64,21 @@ impl ToCss for ViewportConstraints {
|
|||
}
|
||||
}
|
||||
|
||||
/// Zoom is a number | percentage | auto
|
||||
/// See http://dev.w3.org/csswg/css-device-adapt/#descdef-viewport-zoom
|
||||
/// https://drafts.csswg.org/css-device-adapt/#descdef-viewport-zoom
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum Zoom {
|
||||
/// A number value.
|
||||
Number(f32),
|
||||
/// A percentage value.
|
||||
Percentage(f32),
|
||||
/// The `auto` keyword.
|
||||
Auto,
|
||||
}
|
||||
|
||||
impl ToCss for Zoom {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||
where W: fmt::Write
|
||||
where W: fmt::Write,
|
||||
{
|
||||
match *self {
|
||||
Zoom::Number(number) => write!(dest, "{}", number),
|
||||
|
@ -76,6 +89,9 @@ impl ToCss for 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, ()> {
|
||||
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]
|
||||
pub fn to_f32(&self) -> Option<f32> {
|
||||
match *self {
|
||||
|
|
Загрузка…
Ссылка в новой задаче