aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout/css/matching.rs38
-rw-r--r--components/layout/traversal.rs3
-rw-r--r--components/style/legacy.rs12
-rw-r--r--components/style/media_queries.rs72
-rw-r--r--components/style/properties.mako.rs50
-rw-r--r--components/style/values.rs186
-rw-r--r--tests/reftest.rs10
7 files changed, 254 insertions, 117 deletions
diff --git a/components/layout/css/matching.rs b/components/layout/css/matching.rs
index 8e2002ca06f..f688be2cda5 100644
--- a/components/layout/css/matching.rs
+++ b/components/layout/css/matching.rs
@@ -6,6 +6,7 @@
#![allow(unsafe_blocks)]
+use context::SharedLayoutContext;
use css::node_style::StyledNode;
use incremental::{self, RestyleDamage};
use data::{LayoutDataAccess, LayoutDataWrapper};
@@ -391,6 +392,7 @@ pub trait MatchMethods {
-> StyleSharingResult;
unsafe fn cascade_node(&self,
+ layout_context: &SharedLayoutContext,
parent: Option<LayoutNode>,
applicable_declarations: &ApplicableDeclarations,
applicable_declarations_cache: &mut ApplicableDeclarationsCache);
@@ -398,6 +400,7 @@ pub trait MatchMethods {
trait PrivateMatchMethods {
fn cascade_node_pseudo_element(&self,
+ layout_context: &SharedLayoutContext,
parent_style: Option<&Arc<ComputedValues>>,
applicable_declarations: &[DeclarationBlock],
style: &mut Option<Arc<ComputedValues>>,
@@ -414,6 +417,7 @@ trait PrivateMatchMethods {
impl<'ln> PrivateMatchMethods for LayoutNode<'ln> {
fn cascade_node_pseudo_element(&self,
+ layout_context: &SharedLayoutContext,
parent_style: Option<&Arc<ComputedValues>>,
applicable_declarations: &[DeclarationBlock],
style: &mut Option<Arc<ComputedValues>>,
@@ -430,7 +434,8 @@ impl<'ln> PrivateMatchMethods for LayoutNode<'ln> {
None => None,
Some(ref style) => Some(&**style),
};
- let (the_style, is_cacheable) = cascade(applicable_declarations,
+ let (the_style, is_cacheable) = cascade(layout_context.screen_size,
+ applicable_declarations,
shareable,
Some(&***parent_style),
cached_computed_values);
@@ -438,7 +443,8 @@ impl<'ln> PrivateMatchMethods for LayoutNode<'ln> {
this_style = Arc::new(the_style);
}
None => {
- let (the_style, is_cacheable) = cascade(applicable_declarations,
+ let (the_style, is_cacheable) = cascade(layout_context.screen_size,
+ applicable_declarations,
shareable,
None,
None);
@@ -602,6 +608,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
}
unsafe fn cascade_node(&self,
+ layout_context: &SharedLayoutContext,
parent: Option<LayoutNode>,
applicable_declarations: &ApplicableDeclarations,
applicable_declarations_cache: &mut ApplicableDeclarationsCache) {
@@ -635,26 +642,29 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
}
_ => {
let mut damage = self.cascade_node_pseudo_element(
+ layout_context,
parent_style,
applicable_declarations.normal.as_slice(),
&mut layout_data.shared_data.style,
applicable_declarations_cache,
applicable_declarations.normal_shareable);
if applicable_declarations.before.len() > 0 {
- damage = damage | self.cascade_node_pseudo_element(
- Some(layout_data.shared_data.style.as_ref().unwrap()),
- &*applicable_declarations.before,
- &mut layout_data.data.before_style,
- applicable_declarations_cache,
- false);
+ damage = damage | self.cascade_node_pseudo_element(
+ layout_context,
+ Some(layout_data.shared_data.style.as_ref().unwrap()),
+ &*applicable_declarations.before,
+ &mut layout_data.data.before_style,
+ applicable_declarations_cache,
+ false);
}
if applicable_declarations.after.len() > 0 {
- damage = damage | self.cascade_node_pseudo_element(
- Some(layout_data.shared_data.style.as_ref().unwrap()),
- &*applicable_declarations.after,
- &mut layout_data.data.after_style,
- applicable_declarations_cache,
- false);
+ damage = damage | self.cascade_node_pseudo_element(
+ layout_context,
+ Some(layout_data.shared_data.style.as_ref().unwrap()),
+ &*applicable_declarations.after,
+ &mut layout_data.data.after_style,
+ applicable_declarations_cache,
+ false);
}
layout_data.data.restyle_damage = damage;
}
diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs
index ceb7bf78679..a31f6c9d3b6 100644
--- a/components/layout/traversal.rs
+++ b/components/layout/traversal.rs
@@ -176,7 +176,8 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> {
// Perform the CSS cascade.
unsafe {
- node.cascade_node(parent_opt,
+ node.cascade_node(self.layout_context.shared,
+ parent_opt,
&applicable_declarations,
self.layout_context.applicable_declarations_cache());
}
diff --git a/components/style/legacy.rs b/components/style/legacy.rs
index c7d974d1094..d1451ae6bc4 100644
--- a/components/style/legacy.rs
+++ b/components/style/legacy.rs
@@ -119,7 +119,7 @@ impl PresentationalHintSynthesis for Stylist {
*shareable = false
}
LengthOrPercentageOrAuto::Length(length) => {
- let width_value = specified::LengthOrPercentageOrAuto::Length(specified::Length::Au(length));
+ let width_value = specified::LengthOrPercentageOrAuto::Length(specified::Length::Absolute(length));
matching_rules_list.vec_push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(width_value))));
*shareable = false
@@ -160,9 +160,9 @@ impl PresentationalHintSynthesis for Stylist {
// FIXME(pcwalton): More use of atoms, please!
let value = match element.get_attr(&ns!(""), &atom!("type")) {
Some("text") | Some("password") => {
- specified::Length::ServoCharacterWidth(value)
+ specified::Length::ServoCharacterWidth(specified::CharacterWidth(value))
}
- _ => specified::Length::Au(Au::from_px(value as int)),
+ _ => specified::Length::Absolute(Au::from_px(value as int)),
};
matching_rules_list.vec_push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(
@@ -180,7 +180,7 @@ impl PresentationalHintSynthesis for Stylist {
// scrollbar size into consideration (but we don't have a scrollbar yet!)
//
// https://html.spec.whatwg.org/multipage/rendering.html#textarea-effective-width
- let value = specified::Length::ServoCharacterWidth(value);
+ let value = specified::Length::ServoCharacterWidth(specified::CharacterWidth(value));
matching_rules_list.vec_push(from_declaration(
PropertyDeclaration::Width(SpecifiedValue(
specified::LengthOrPercentageOrAuto::Length(value)))));
@@ -193,7 +193,7 @@ impl PresentationalHintSynthesis for Stylist {
// TODO(mttr) This should take scrollbar size into consideration.
//
// https://html.spec.whatwg.org/multipage/rendering.html#textarea-effective-height
- let value = specified::Length::Em(value as CSSFloat);
+ let value = specified::Length::FontRelative(specified::FontRelativeLength::Em(value as CSSFloat));
matching_rules_list.vec_push(from_declaration(
PropertyDeclaration::Height(SpecifiedValue(
longhands::height::SpecifiedValue(
@@ -241,7 +241,7 @@ impl PresentationalHintSynthesis for Stylist {
match element.get_unsigned_integer_attribute(UnsignedIntegerAttribute::Border) {
None => {}
Some(length) => {
- let width_value = specified::Length::Au(Au::from_px(length as int));
+ let width_value = specified::Length::Absolute(Au::from_px(length as int));
matching_rules_list.vec_push(from_declaration(
PropertyDeclaration::BorderTopWidth(SpecifiedValue(
longhands::border_top_width::SpecifiedValue(width_value)))));
diff --git a/components/style/media_queries.rs b/components/style/media_queries.rs
index 1aca08922e5..97f75104c40 100644
--- a/components/style/media_queries.rs
+++ b/components/style/media_queries.rs
@@ -5,7 +5,7 @@
use std::ascii::AsciiExt;
use cssparser::{Token, Parser, Delimiter};
-use geom::size::TypedSize2D;
+use geom::size::{Size2D, TypedSize2D};
use properties::longhands;
use util::geometry::{Au, ViewportPx};
use values::specified;
@@ -23,6 +23,31 @@ pub enum Range<T> {
//Eq(T), // FIXME: Implement parsing support for equality then re-enable this.
}
+impl Range<specified::Length> {
+ fn to_computed_range(&self, viewport_size: Size2D<Au>) -> Range<Au> {
+ let compute_width = |width| {
+ match width {
+ &specified::Length::Absolute(value) => value,
+ &specified::Length::FontRelative(value) => {
+ // http://dev.w3.org/csswg/mediaqueries3/ - Section 6
+ // em units are relative to the initial font-size.
+ let initial_font_size = longhands::font_size::get_initial_value();
+ value.to_computed_value(initial_font_size, initial_font_size)
+ }
+ &specified::Length::ViewportPercentage(value) =>
+ value.to_computed_value(viewport_size),
+ _ => unreachable!()
+ }
+ };
+
+ match *self {
+ Range::Min(ref width) => Range::Min(compute_width(width)),
+ Range::Max(ref width) => Range::Max(compute_width(width)),
+ //Range::Eq(ref width) => Range::Eq(compute_width(width))
+ }
+ }
+}
+
impl<T: Ord> Range<T> {
fn evaluate(&self, value: T) -> bool {
match *self {
@@ -33,9 +58,9 @@ impl<T: Ord> Range<T> {
}
}
-#[derive(PartialEq, Eq, Copy, Debug)]
+#[derive(PartialEq, Copy, Debug)]
pub enum Expression {
- Width(Range<Au>),
+ Width(Range<specified::Length>),
}
#[derive(PartialEq, Eq, Copy, Debug)]
@@ -91,17 +116,6 @@ impl Device {
}
}
-
-fn parse_non_negative_length(input: &mut Parser) -> Result<Au, ()> {
- let length = try!(specified::Length::parse_non_negative(input));
-
- // http://dev.w3.org/csswg/mediaqueries3/ - Section 6
- // em units are relative to the initial font-size.
- let initial_font_size = longhands::font_size::get_initial_value();
- Ok(length.to_computed_value_with_font_size(initial_font_size, initial_font_size))
-}
-
-
impl Expression {
fn parse(input: &mut Parser) -> Result<Expression, ()> {
try!(input.expect_parenthesis_block());
@@ -111,10 +125,10 @@ impl Expression {
// TODO: Handle other media features
match_ignore_ascii_case! { name,
"min-width" => {
- Ok(Expression::Width(Range::Min(try!(parse_non_negative_length(input)))))
+ Ok(Expression::Width(Range::Min(try!(specified::Length::parse_non_negative(input)))))
},
"max-width" => {
- Ok(Expression::Width(Range::Max(try!(parse_non_negative_length(input)))))
+ Ok(Expression::Width(Range::Max(try!(specified::Length::parse_non_negative(input)))))
}
_ => Err(())
}
@@ -186,6 +200,9 @@ pub fn parse_media_query_list(input: &mut Parser) -> MediaQueryList {
impl MediaQueryList {
pub fn evaluate(&self, device: &Device) -> bool {
+ let viewport_size = Size2D(Au::from_frac32_px(device.viewport_size.width.get()),
+ Au::from_frac32_px(device.viewport_size.height.get()));
+
// Check if any queries match (OR condition)
self.media_queries.iter().any(|mq| {
// Check if media matches. Unknown media never matches.
@@ -198,8 +215,8 @@ impl MediaQueryList {
// Check if all conditions match (AND condition)
let query_match = media_match && mq.expressions.iter().all(|expression| {
match expression {
- &Expression::Width(value) => value.evaluate(
- Au::from_frac_px(device.viewport_size.to_untyped().width as f64)),
+ &Expression::Width(value) =>
+ value.to_computed_range(viewport_size).evaluate(viewport_size.width),
}
});
@@ -220,6 +237,7 @@ mod tests {
use stylesheets::Origin;
use super::*;
use url::Url;
+ use values::specified;
use std::borrow::ToOwned;
fn test_media_rule<F>(css: &str, callback: F) where F: Fn(&MediaQueryList, &str) {
@@ -385,7 +403,7 @@ mod tests {
assert!(q.media_type == MediaQueryType::All, css.to_owned());
assert!(q.expressions.len() == 1, css.to_owned());
match q.expressions[0] {
- Expression::Width(Range::Min(w)) => assert!(w == Au::from_px(100)),
+ Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))),
_ => panic!("wrong expression type"),
}
});
@@ -397,7 +415,7 @@ mod tests {
assert!(q.media_type == MediaQueryType::All, css.to_owned());
assert!(q.expressions.len() == 1, css.to_owned());
match q.expressions[0] {
- Expression::Width(Range::Max(w)) => assert!(w == Au::from_px(43)),
+ Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(43))),
_ => panic!("wrong expression type"),
}
});
@@ -412,7 +430,7 @@ mod tests {
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
assert!(q.expressions.len() == 1, css.to_owned());
match q.expressions[0] {
- Expression::Width(Range::Min(w)) => assert!(w == Au::from_px(100)),
+ Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))),
_ => panic!("wrong expression type"),
}
});
@@ -424,7 +442,7 @@ mod tests {
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned());
assert!(q.expressions.len() == 1, css.to_owned());
match q.expressions[0] {
- Expression::Width(Range::Max(w)) => assert!(w == Au::from_px(43)),
+ Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(43))),
_ => panic!("wrong expression type"),
}
});
@@ -436,7 +454,7 @@ mod tests {
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned());
assert!(q.expressions.len() == 1, css.to_owned());
match q.expressions[0] {
- Expression::Width(Range::Max(w)) => assert!(w == Au::from_px(52)),
+ Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(52))),
_ => panic!("wrong expression type"),
}
});
@@ -451,11 +469,11 @@ mod tests {
assert!(q.media_type == MediaQueryType::All, css.to_owned());
assert!(q.expressions.len() == 2, css.to_owned());
match q.expressions[0] {
- Expression::Width(Range::Min(w)) => assert!(w == Au::from_px(100)),
+ Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))),
_ => panic!("wrong expression type"),
}
match q.expressions[1] {
- Expression::Width(Range::Max(w)) => assert!(w == Au::from_px(200)),
+ Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(200))),
_ => panic!("wrong expression type"),
}
});
@@ -467,11 +485,11 @@ mod tests {
assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned());
assert!(q.expressions.len() == 2, css.to_owned());
match q.expressions[0] {
- Expression::Width(Range::Min(w)) => assert!(w == Au::from_px(100)),
+ Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))),
_ => panic!("wrong expression type"),
}
match q.expressions[1] {
- Expression::Width(Range::Max(w)) => assert!(w == Au::from_px(200)),
+ Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(200))),
_ => panic!("wrong expression type"),
}
});
diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs
index 11089b165ce..5e57d9a68ad 100644
--- a/components/style/properties.mako.rs
+++ b/components/style/properties.mako.rs
@@ -19,8 +19,9 @@ use cssparser::{Parser, Color, RGBA, AtRuleParser, DeclarationParser,
DeclarationListParser, parse_important, ToCss};
use geom::num::Zero;
use geom::SideOffsets2D;
+use geom::size::Size2D;
-use values::specified::BorderStyle;
+use values::specified::{Length, BorderStyle};
use values::computed::{self, ToComputedValue};
use selectors::matching::DeclarationBlock;
use parser::{ParserContext, log_css_error};
@@ -566,7 +567,7 @@ pub mod longhands {
SpecifiedValue::Number(value) => computed_value::T::Number(value),
SpecifiedValue::Percentage(value) => {
computed_value::T::Length(
- specified::Length::Em(value).to_computed_value(context))
+ specified::Length::FontRelative(specified::FontRelativeLength::Em(value)).to_computed_value(context))
}
}
}
@@ -1475,21 +1476,21 @@ pub mod longhands {
input.try(specified::LengthOrPercentage::parse_non_negative)
.map(|value| match value {
specified::LengthOrPercentage::Length(value) => value,
- specified::LengthOrPercentage::Percentage(value) => specified::Length::Em(value)
+ specified::LengthOrPercentage::Percentage(value) => specified::Length::FontRelative(specified::FontRelativeLength::Em(value))
})
.or_else(|()| {
match_ignore_ascii_case! { try!(input.expect_ident()),
- "xx-small" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 3 / 5)),
- "x-small" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 3 / 4)),
- "small" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 8 / 9)),
- "medium" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX))),
- "large" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 6 / 5)),
- "x-large" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 3 / 2)),
- "xx-large" => Ok(specified::Length::Au(Au::from_px(MEDIUM_PX) * 2)),
+ "xx-small" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX) * 3 / 5)),
+ "x-small" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX) * 3 / 4)),
+ "small" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX) * 8 / 9)),
+ "medium" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX))),
+ "large" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX) * 6 / 5)),
+ "x-large" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX) * 3 / 2)),
+ "xx-large" => Ok(specified::Length::Absolute(Au::from_px(MEDIUM_PX) * 2)),
// https://github.com/servo/servo/issues/3423#issuecomment-56321664
- "smaller" => Ok(specified::Length::Em(0.85)),
- "larger" => Ok(specified::Length::Em(1.2))
+ "smaller" => Ok(specified::Length::FontRelative(specified::FontRelativeLength::Em(0.85))),
+ "larger" => Ok(specified::Length::FontRelative(specified::FontRelativeLength::Em(1.2)))
_ => Err(())
}
@@ -2038,7 +2039,7 @@ pub mod longhands {
pub fn parse_one_box_shadow(input: &mut Parser) -> Result<SpecifiedBoxShadow, ()> {
use util::geometry::Au;
- let mut lengths = [specified::Length::Au(Au(0)); 4];
+ let mut lengths = [specified::Length::Absolute(Au(0)); 4];
let mut lengths_parsed = false;
let mut color = None;
let mut inset = false;
@@ -2208,10 +2209,10 @@ pub mod longhands {
}));
if sides.len() == 4 {
Ok(Some(SpecifiedClipRect {
- top: sides[0].unwrap_or(Length::Au(Au(0))),
+ top: sides[0].unwrap_or(Length::Absolute(Au(0))),
right: sides[1],
bottom: sides[2],
- left: sides[3].unwrap_or(Length::Au(Au(0))),
+ left: sides[3].unwrap_or(Length::Absolute(Au(0))),
}))
} else {
Err(())
@@ -2317,7 +2318,7 @@ pub mod longhands {
fn parse_one_text_shadow(input: &mut Parser) -> Result<SpecifiedTextShadow,()> {
use util::geometry::Au;
- let mut lengths = [specified::Length::Au(Au(0)); 3];
+ let mut lengths = [specified::Length::Absolute(Au(0)); 3];
let mut lengths_parsed = false;
let mut color = None;
@@ -2855,7 +2856,7 @@ pub mod shorthands {
fn parse_one_set_of_border_radii(mut input: &mut Parser)
-> Result<[LengthOrPercentage; 4], ()> {
let mut count = 0;
- let mut values = [LengthOrPercentage::Length(Length::Au(Au(0))); 4];
+ let mut values = [LengthOrPercentage::Length(Length::Absolute(Au(0))); 4];
while count < 4 {
if let Ok(value) = input.try(LengthOrPercentage::parse) {
values[count] = value;
@@ -3699,6 +3700,8 @@ fn cascade_with_cached_declarations(applicable_declarations: &[DeclarationBlock<
/// Performs the CSS cascade, computing new styles for an element from its parent style and
/// optionally a cached related style. The arguments are:
///
+/// * `viewport_size`: The size of the initial viewport.
+///
/// * `applicable_declarations`: The list of CSS rules that matched.
///
/// * `shareable`: Whether the `ComputedValues` structure to be constructed should be considered
@@ -3712,7 +3715,8 @@ fn cascade_with_cached_declarations(applicable_declarations: &[DeclarationBlock<
/// this is ignored.
///
/// Returns the computed values and a boolean indicating whether the result is cacheable.
-pub fn cascade(applicable_declarations: &[DeclarationBlock<Vec<PropertyDeclaration>>],
+pub fn cascade(viewport_size: Size2D<Au>,
+ applicable_declarations: &[DeclarationBlock<Vec<PropertyDeclaration>>],
shareable: bool,
parent_style: Option< &ComputedValues >,
cached_style: Option< &ComputedValues >)
@@ -3727,6 +3731,7 @@ pub fn cascade(applicable_declarations: &[DeclarationBlock<Vec<PropertyDeclarati
let inherited_font_style = inherited_style.get_font();
computed::Context {
is_root_element: is_root_element,
+ viewport_size: viewport_size,
inherited_font_weight: inherited_font_style.font_weight,
inherited_font_size: inherited_font_style.font_size,
inherited_height: inherited_style.get_box().height,
@@ -3769,9 +3774,12 @@ pub fn cascade(applicable_declarations: &[DeclarationBlock<Vec<PropertyDeclarati
PropertyDeclaration::FontSize(ref value) => {
context.font_size = match *value {
DeclaredValue::SpecifiedValue(ref specified_value) => {
- specified_value.0.to_computed_value_with_font_size(
- context.inherited_font_size, context.root_font_size
- )
+ match specified_value.0 {
+ Length::FontRelative(value) => value.to_computed_value(context.inherited_font_size,
+ context.root_font_size),
+ Length::ServoCharacterWidth(value) => value.to_computed_value(context.inherited_font_size),
+ _ => specified_value.0.to_computed_value(&context)
+ }
}
DeclaredValue::Initial => longhands::font_size::get_initial_value(),
DeclaredValue::Inherit => context.inherited_font_size,
diff --git a/components/style/values.rs b/components/style/values.rs
index ae1e4bc2600..8c57af3884c 100644
--- a/components/style/values.rs
+++ b/components/style/values.rs
@@ -52,11 +52,14 @@ pub type CSSFloat = f64;
pub mod specified {
use std::ascii::AsciiExt;
+ use std::cmp;
use std::f64::consts::PI;
use std::fmt;
use std::fmt::{Formatter, Debug};
+ use std::num::{NumCast, ToPrimitive};
use url::Url;
use cssparser::{self, Token, Parser, ToCss, CssStringWriter};
+ use geom::size::Size2D;
use parser::ParserContext;
use text_writer::{self, TextWriter};
use util::geometry::Au;
@@ -114,17 +117,114 @@ pub mod specified {
}
#[derive(Clone, PartialEq, Copy)]
- pub enum Length {
- Au(Au), // application units
+ pub enum FontRelativeLength {
Em(CSSFloat),
Ex(CSSFloat),
- Rem(CSSFloat),
+ Rem(CSSFloat)
+ }
+
+ impl fmt::Debug for FontRelativeLength {
+ #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
+ }
+
+ impl ToCss for FontRelativeLength {
+ fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
+ match self {
+ &FontRelativeLength::Em(length) => write!(dest, "{}em", length),
+ &FontRelativeLength::Ex(length) => write!(dest, "{}ex", length),
+ &FontRelativeLength::Rem(length) => write!(dest, "{}rem", length)
+ }
+ }
+ }
+
+ impl FontRelativeLength {
+ pub fn to_computed_value(&self,
+ reference_font_size: Au,
+ root_font_size: Au)
+ -> Au
+ {
+ match self {
+ &FontRelativeLength::Em(length) => reference_font_size.scale_by(length),
+ &FontRelativeLength::Ex(length) => {
+ let x_height = 0.5; // TODO: find that from the font
+ reference_font_size.scale_by(length * x_height)
+ },
+ &FontRelativeLength::Rem(length) => root_font_size.scale_by(length)
+ }
+ }
+ }
+
+ #[derive(Clone, PartialEq, Copy)]
+ pub enum ViewportPercentageLength {
+ Vw(CSSFloat),
+ Vh(CSSFloat),
+ Vmin(CSSFloat),
+ Vmax(CSSFloat)
+ }
+
+ impl fmt::Debug for ViewportPercentageLength {
+ #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
+ }
+
+ impl ToCss for ViewportPercentageLength {
+ fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
+ match self {
+ &ViewportPercentageLength::Vw(length) => write!(dest, "{}vw", length),
+ &ViewportPercentageLength::Vh(length) => write!(dest, "{}vh", length),
+ &ViewportPercentageLength::Vmin(length) => write!(dest, "{}vmin", length),
+ &ViewportPercentageLength::Vmax(length) => write!(dest, "{}vmax", length)
+ }
+ }
+ }
+
+ impl ViewportPercentageLength {
+ pub fn to_computed_value(&self, viewport_size: Size2D<Au>) -> Au {
+ macro_rules! to_unit {
+ ($viewport_dimension:expr) => {
+ $viewport_dimension.to_f64().unwrap() / 100.0
+ }
+ }
+
+ let value = match self {
+ &ViewportPercentageLength::Vw(length) =>
+ length * to_unit!(viewport_size.width),
+ &ViewportPercentageLength::Vh(length) =>
+ length * to_unit!(viewport_size.height),
+ &ViewportPercentageLength::Vmin(length) =>
+ length * to_unit!(cmp::min(viewport_size.width, viewport_size.height)),
+ &ViewportPercentageLength::Vmax(length) =>
+ length * to_unit!(cmp::max(viewport_size.width, viewport_size.height)),
+ };
+ NumCast::from(value).unwrap()
+ }
+ }
+
+ #[derive(Clone, PartialEq, Copy)]
+ pub struct CharacterWidth(pub i32);
+
+ impl CharacterWidth {
+ 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.
+ //
+ // TODO(pcwalton): Find these from the font.
+ let average_advance = reference_font_size.scale_by(0.5);
+ let max_advance = reference_font_size;
+ average_advance.scale_by(self.0 as CSSFloat - 1.0) + max_advance
+ }
+ }
+
+ #[derive(Clone, PartialEq, Copy)]
+ pub enum Length {
+ Absolute(Au), // application units
+ FontRelative(FontRelativeLength),
+ ViewportPercentage(ViewportPercentageLength),
/// HTML5 "character width", as defined in HTML5 § 14.5.4.
///
/// This cannot be specified by the user directly and is only generated by
/// `Stylist::synthesize_rules_for_legacy_attributes()`.
- ServoCharacterWidth(i32),
+ ServoCharacterWidth(CharacterWidth),
}
impl fmt::Debug for Length {
@@ -134,41 +234,15 @@ pub mod specified {
impl ToCss for Length {
fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
match self {
- &Length::Au(length) => write!(dest, "{}px", length.to_subpx()),
- &Length::Em(length) => write!(dest, "{}em", length),
- &Length::Ex(length) => write!(dest, "{}ex", length),
- &Length::Rem(length) => write!(dest, "{}rem", length),
+ &Length::Absolute(length) => write!(dest, "{}px", length.to_subpx()),
+ &Length::FontRelative(length) => length.to_css(dest),
+ &Length::ViewportPercentage(length) => length.to_css(dest),
&Length::ServoCharacterWidth(_)
=> panic!("internal CSS values should never be serialized"),
}
}
}
- impl Length {
- pub fn to_computed_value_with_font_size(&self, reference_font_size: Au, root_font_size: Au)
- -> Au {
- match *self {
- Length::Au(value) => value,
- Length::Em(value) => reference_font_size.scale_by(value),
- Length::Ex(value) => {
- let x_height = 0.5; // TODO: find that from the font
- reference_font_size.scale_by(value * x_height)
- },
- Length::Rem(value) => root_font_size.scale_by(value),
- Length::ServoCharacterWidth(value) => {
- // This applies the *converting a character width to pixels* algorithm as specified
- // in HTML5 § 14.5.4.
- //
- // TODO(pcwalton): Find these from the font.
- let average_advance = reference_font_size.scale_by(0.5);
- let max_advance = reference_font_size;
- average_advance.scale_by(value as CSSFloat - 1.0) + max_advance
- }
- }
- }
- }
-
-
const AU_PER_PX: CSSFloat = 60.;
const AU_PER_IN: CSSFloat = AU_PER_PX * 96.;
const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54;
@@ -182,7 +256,7 @@ pub mod specified {
Token::Dimension(ref value, ref unit) if negative_ok || value.value >= 0. => {
Length::parse_dimension(value.value, unit)
}
- Token::Number(ref value) if value.value == 0. => Ok(Length::Au(Au(0))),
+ Token::Number(ref value) if value.value == 0. => Ok(Length::Absolute(Au(0))),
_ => Err(())
}
}
@@ -196,20 +270,26 @@ pub mod specified {
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Length, ()> {
match_ignore_ascii_case! { unit,
"px" => Ok(Length::from_px(value)),
- "in" => Ok(Length::Au(Au((value * AU_PER_IN) as i32))),
- "cm" => Ok(Length::Au(Au((value * AU_PER_CM) as i32))),
- "mm" => Ok(Length::Au(Au((value * AU_PER_MM) as i32))),
- "pt" => Ok(Length::Au(Au((value * AU_PER_PT) as i32))),
- "pc" => Ok(Length::Au(Au((value * AU_PER_PC) as i32))),
- "em" => Ok(Length::Em(value)),
- "ex" => Ok(Length::Ex(value)),
- "rem" => Ok(Length::Rem(value))
+ "in" => Ok(Length::Absolute(Au((value * AU_PER_IN) as i32))),
+ "cm" => Ok(Length::Absolute(Au((value * AU_PER_CM) as i32))),
+ "mm" => Ok(Length::Absolute(Au((value * AU_PER_MM) as i32))),
+ "pt" => Ok(Length::Absolute(Au((value * AU_PER_PT) as i32))),
+ "pc" => Ok(Length::Absolute(Au((value * AU_PER_PC) as i32))),
+ // font-relative
+ "em" => Ok(Length::FontRelative(FontRelativeLength::Em(value))),
+ "ex" => Ok(Length::FontRelative(FontRelativeLength::Ex(value))),
+ "rem" => Ok(Length::FontRelative(FontRelativeLength::Rem(value))),
+ // viewport percentages
+ "vw" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vw(value))),
+ "vh" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vh(value))),
+ "vmin" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vmin(value))),
+ "vmax" => Ok(Length::ViewportPercentage(ViewportPercentageLength::Vmax(value)))
_ => Err(())
}
}
#[inline]
pub fn from_px(px_value: CSSFloat) -> Length {
- Length::Au(Au((px_value * AU_PER_PX) as i32))
+ Length::Absolute(Au((px_value * AU_PER_PX) as i32))
}
}
@@ -245,7 +325,7 @@ pub mod specified {
Ok(LengthOrPercentage::Percentage(value.unit_value))
}
Token::Number(ref value) if value.value == 0. => {
- Ok(LengthOrPercentage::Length(Length::Au(Au(0))))
+ Ok(LengthOrPercentage::Length(Length::Absolute(Au(0))))
}
_ => Err(())
}
@@ -294,7 +374,7 @@ pub mod specified {
Ok(LengthOrPercentageOrAuto::Percentage(value.unit_value))
}
Token::Number(ref value) if value.value == 0. => {
- Ok(LengthOrPercentageOrAuto::Length(Length::Au(Au(0))))
+ Ok(LengthOrPercentageOrAuto::Length(Length::Absolute(Au(0))))
}
Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") => {
Ok(LengthOrPercentageOrAuto::Auto)
@@ -345,7 +425,7 @@ pub mod specified {
Ok(LengthOrPercentageOrNone::Percentage(value.unit_value))
}
Token::Number(ref value) if value.value == 0. => {
- Ok(LengthOrPercentageOrNone::Length(Length::Au(Au(0))))
+ Ok(LengthOrPercentageOrNone::Length(Length::Absolute(Au(0))))
}
Token::Ident(ref value) if value.eq_ignore_ascii_case("none") => {
Ok(LengthOrPercentageOrNone::None)
@@ -386,7 +466,7 @@ pub mod specified {
Ok(PositionComponent::Percentage(value.unit_value))
}
Token::Number(ref value) if value.value == 0. => {
- Ok(PositionComponent::Length(Length::Au(Au(0))))
+ Ok(PositionComponent::Length(Length::Absolute(Au(0))))
}
Token::Ident(value) => {
match_ignore_ascii_case! { value,
@@ -673,6 +753,7 @@ pub mod computed {
use super::specified::{AngleOrCorner};
use super::{specified, CSSFloat};
pub use cssparser::Color as CSSColor;
+ use geom::size::Size2D;
use properties::longhands;
use std::fmt;
use url::Url;
@@ -699,6 +780,7 @@ pub mod computed {
pub border_bottom_present: bool,
pub border_left_present: bool,
pub is_root_element: bool,
+ pub viewport_size: Size2D<Au>
// TODO, as needed: viewport size, etc.
}
@@ -736,7 +818,15 @@ pub mod computed {
#[inline]
fn to_computed_value(&self, context: &Context) -> Au {
- self.to_computed_value_with_font_size(context.font_size, context.root_font_size)
+ match self {
+ &specified::Length::Absolute(length) => length,
+ &specified::Length::FontRelative(length) =>
+ length.to_computed_value(context.font_size, context.root_font_size),
+ &specified::Length::ViewportPercentage(length) =>
+ length.to_computed_value(context.viewport_size),
+ &specified::Length::ServoCharacterWidth(length) =>
+ length.to_computed_value(context.font_size)
+ }
}
}
diff --git a/tests/reftest.rs b/tests/reftest.rs
index 3908217c556..f4fe8e51037 100644
--- a/tests/reftest.rs
+++ b/tests/reftest.rs
@@ -136,6 +136,7 @@ struct Reftest {
is_flaky: bool,
experimental: bool,
fragment_identifier: Option<String>,
+ resolution: Option<String>,
}
struct TestLine<'a> {
@@ -195,6 +196,7 @@ fn parse_lists(file: &Path, servo_args: &[String], render_mode: RenderMode, id_o
let mut flakiness = RenderMode::empty();
let mut experimental = false;
let mut fragment_identifier = None;
+ let mut resolution = None;
for condition in conditions_list {
match condition {
"flaky_cpu" => flakiness.insert(CPU_RENDERING),
@@ -207,6 +209,9 @@ fn parse_lists(file: &Path, servo_args: &[String], render_mode: RenderMode, id_o
if condition.starts_with("fragment=") {
fragment_identifier = Some(condition.slice_from("fragment=".len()).to_string());
}
+ if condition.starts_with("resolution=") {
+ resolution = Some(condition.slice_from("resolution=".len()).to_string());
+ }
}
let reftest = Reftest {
@@ -219,6 +224,7 @@ fn parse_lists(file: &Path, servo_args: &[String], render_mode: RenderMode, id_o
is_flaky: render_mode.intersects(flakiness),
experimental: experimental,
fragment_identifier: fragment_identifier,
+ resolution: resolution,
};
tests.push(make_test(reftest));
@@ -265,6 +271,10 @@ fn capture(reftest: &Reftest, side: usize) -> (u32, u32, Vec<u8>) {
if reftest.experimental {
command.arg("--experimental");
}
+ if let Some(ref resolution) = reftest.resolution {
+ command.arg("--resolution");
+ command.arg(resolution);
+ }
let retval = match command.status() {
Ok(status) => status,
Err(e) => panic!("failed to execute process: {}", e),