mirror of
https://github.com/servo/servo.git
synced 2025-06-09 09:03:23 +00:00
auto merge of #5154 : luniv/servo/viewpoint-percent-lengths, r=SimonSapin
Spec: http://dev.w3.org/csswg/css-values-3/#viewport-relative-lengths
This commit is contained in:
commit
a557b51c28
7 changed files with 254 additions and 117 deletions
|
@ -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,6 +642,7 @@ 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,
|
||||
|
@ -642,6 +650,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
|
|||
applicable_declarations.normal_shareable);
|
||||
if applicable_declarations.before.len() > 0 {
|
||||
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,
|
||||
|
@ -650,6 +659,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
|
|||
}
|
||||
if applicable_declarations.after.len() > 0 {
|
||||
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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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)))));
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue