mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Implement calc expressions for more value types
This commit is contained in:
parent
35b452660b
commit
00980ea595
9 changed files with 383 additions and 312 deletions
|
@ -232,6 +232,8 @@ pub mod specified {
|
|||
/// This cannot be specified by the user directly and is only generated by
|
||||
/// `Stylist::synthesize_rules_for_legacy_attributes()`.
|
||||
ServoCharacterWidth(CharacterWidth),
|
||||
|
||||
Calc(CalcLengthOrPercentage),
|
||||
}
|
||||
|
||||
impl ToCss for Length {
|
||||
|
@ -240,6 +242,7 @@ pub mod specified {
|
|||
Length::Absolute(length) => write!(dest, "{}px", length.to_f32_px()),
|
||||
Length::FontRelative(length) => length.to_css(dest),
|
||||
Length::ViewportPercentage(length) => length.to_css(dest),
|
||||
Length::Calc(calc) => calc.to_css(dest),
|
||||
Length::ServoCharacterWidth(_)
|
||||
=> panic!("internal CSS values should never be serialized"),
|
||||
}
|
||||
|
@ -255,6 +258,7 @@ pub mod specified {
|
|||
Length::Absolute(Au(v)) => Length::Absolute(Au(((v as f32) * scalar) as i32)),
|
||||
Length::FontRelative(v) => Length::FontRelative(v * scalar),
|
||||
Length::ViewportPercentage(v) => Length::ViewportPercentage(v * scalar),
|
||||
Length::Calc(_) => panic!("Can't multiply Calc!"),
|
||||
Length::ServoCharacterWidth(_) => panic!("Can't multiply ServoCharacterWidth!"),
|
||||
}
|
||||
}
|
||||
|
@ -292,6 +296,7 @@ pub mod specified {
|
|||
const AU_PER_IN: CSSFloat = AU_PER_PX * 96.;
|
||||
const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54;
|
||||
const AU_PER_MM: CSSFloat = AU_PER_IN / 25.4;
|
||||
const AU_PER_Q: CSSFloat = AU_PER_MM / 4.;
|
||||
const AU_PER_PT: CSSFloat = AU_PER_IN / 72.;
|
||||
const AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
|
||||
impl Length {
|
||||
|
@ -320,6 +325,8 @@ pub mod specified {
|
|||
Length::parse_dimension(value.value, unit),
|
||||
Token::Number(ref value) if value.value == 0. =>
|
||||
Ok(Length::Absolute(Au(0))),
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =>
|
||||
input.parse_nested_block(CalcLengthOrPercentage::parse_length),
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
@ -335,6 +342,7 @@ pub mod specified {
|
|||
"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))),
|
||||
"q" => Ok(Length::Absolute(Au((value * AU_PER_Q) 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
|
||||
|
@ -369,6 +377,8 @@ pub mod specified {
|
|||
#[derive(Clone, Debug)]
|
||||
enum CalcValueNode {
|
||||
Length(Length),
|
||||
Angle(Angle),
|
||||
Time(Time),
|
||||
Percentage(CSSFloat),
|
||||
Number(CSSFloat),
|
||||
Sum(Box<CalcSumNode>),
|
||||
|
@ -392,6 +402,8 @@ pub mod specified {
|
|||
#[derive(Clone, Debug)]
|
||||
enum SimplifiedValueNode {
|
||||
Length(Length),
|
||||
Angle(Angle),
|
||||
Time(Time),
|
||||
Percentage(CSSFloat),
|
||||
Number(CSSFloat),
|
||||
Sum(Box<SimplifiedSumNode>),
|
||||
|
@ -404,6 +416,8 @@ pub mod specified {
|
|||
match *self {
|
||||
SimplifiedValueNode::Length(l) => SimplifiedValueNode::Length(l * scalar),
|
||||
SimplifiedValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p * scalar),
|
||||
SimplifiedValueNode::Angle(Angle(a)) => SimplifiedValueNode::Angle(Angle(a * scalar)),
|
||||
SimplifiedValueNode::Time(Time(t)) => SimplifiedValueNode::Time(Time(t * scalar)),
|
||||
SimplifiedValueNode::Number(n) => SimplifiedValueNode::Number(n * scalar),
|
||||
SimplifiedValueNode::Sum(box ref s) => {
|
||||
let sum = s * scalar;
|
||||
|
@ -413,8 +427,68 @@ pub mod specified {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_integer(input: &mut Parser) -> Result<i32, ()> {
|
||||
match try!(input.next()) {
|
||||
Token::Number(ref value) => value.int_value.ok_or(()),
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||
let ast = try!(input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, CalcUnit::Integer)));
|
||||
|
||||
let mut result = None;
|
||||
|
||||
for ref node in ast.products {
|
||||
match try!(CalcLengthOrPercentage::simplify_product(node)) {
|
||||
SimplifiedValueNode::Number(val) =>
|
||||
result = Some(result.unwrap_or(0) + val as i32),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
match result {
|
||||
Some(result) => Ok(result),
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_number(input: &mut Parser) -> Result<f32, ()> {
|
||||
match try!(input.next()) {
|
||||
Token::Number(ref value) => Ok(value.value),
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||
let ast = try!(input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, CalcUnit::Number)));
|
||||
|
||||
let mut result = None;
|
||||
|
||||
for ref node in ast.products {
|
||||
match try!(CalcLengthOrPercentage::simplify_product(node)) {
|
||||
SimplifiedValueNode::Number(val) =>
|
||||
result = Some(result.unwrap_or(0.) + val),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
match result {
|
||||
Some(result) => Ok(result),
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
enum CalcUnit {
|
||||
Number,
|
||||
Integer,
|
||||
Length,
|
||||
LengthOrPercentage,
|
||||
Angle,
|
||||
Time,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)]
|
||||
pub struct Calc {
|
||||
pub struct CalcLengthOrPercentage {
|
||||
pub absolute: Option<Au>,
|
||||
pub vw: Option<ViewportPercentageLength>,
|
||||
pub vh: Option<ViewportPercentageLength>,
|
||||
|
@ -426,18 +500,18 @@ pub mod specified {
|
|||
pub rem: Option<FontRelativeLength>,
|
||||
pub percentage: Option<Percentage>,
|
||||
}
|
||||
impl Calc {
|
||||
fn parse_sum(input: &mut Parser) -> Result<CalcSumNode, ()> {
|
||||
impl CalcLengthOrPercentage {
|
||||
fn parse_sum(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcSumNode, ()> {
|
||||
let mut products = Vec::new();
|
||||
products.push(try!(Calc::parse_product(input)));
|
||||
products.push(try!(CalcLengthOrPercentage::parse_product(input, expected_unit)));
|
||||
|
||||
loop {
|
||||
match input.next() {
|
||||
Ok(Token::Delim('+')) => {
|
||||
products.push(try!(Calc::parse_product(input)));
|
||||
products.push(try!(CalcLengthOrPercentage::parse_product(input, expected_unit)));
|
||||
}
|
||||
Ok(Token::Delim('-')) => {
|
||||
let mut right = try!(Calc::parse_product(input));
|
||||
let mut right = try!(CalcLengthOrPercentage::parse_product(input, expected_unit));
|
||||
right.values.push(CalcValueNode::Number(-1.));
|
||||
products.push(right);
|
||||
}
|
||||
|
@ -449,17 +523,17 @@ pub mod specified {
|
|||
Ok(CalcSumNode { products: products })
|
||||
}
|
||||
|
||||
fn parse_product(input: &mut Parser) -> Result<CalcProductNode, ()> {
|
||||
fn parse_product(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcProductNode, ()> {
|
||||
let mut values = Vec::new();
|
||||
values.push(try!(Calc::parse_value(input)));
|
||||
values.push(try!(CalcLengthOrPercentage::parse_value(input, expected_unit)));
|
||||
|
||||
loop {
|
||||
let position = input.position();
|
||||
match input.next() {
|
||||
Ok(Token::Delim('*')) => {
|
||||
values.push(try!(Calc::parse_value(input)));
|
||||
values.push(try!(CalcLengthOrPercentage::parse_value(input, expected_unit)));
|
||||
}
|
||||
Ok(Token::Delim('/')) => {
|
||||
Ok(Token::Delim('/')) if expected_unit != CalcUnit::Integer => {
|
||||
if let Ok(Token::Number(ref value)) = input.next() {
|
||||
if value.value == 0. {
|
||||
return Err(());
|
||||
|
@ -479,16 +553,24 @@ pub mod specified {
|
|||
Ok(CalcProductNode { values: values })
|
||||
}
|
||||
|
||||
fn parse_value(input: &mut Parser) -> Result<CalcValueNode, ()> {
|
||||
match input.next() {
|
||||
Ok(Token::Number(ref value)) => Ok(CalcValueNode::Number(value.value)),
|
||||
Ok(Token::Dimension(ref value, ref unit)) =>
|
||||
Length::parse_dimension(value.value, unit).map(CalcValueNode::Length),
|
||||
Ok(Token::Percentage(ref value)) =>
|
||||
fn parse_value(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcValueNode, ()> {
|
||||
match (try!(input.next()), expected_unit) {
|
||||
(Token::Number(ref value), _) => Ok(CalcValueNode::Number(value.value)),
|
||||
(Token::Dimension(ref value, ref unit), CalcUnit::Length) |
|
||||
(Token::Dimension(ref value, ref unit), CalcUnit::LengthOrPercentage) => {
|
||||
Length::parse_dimension(value.value, unit).map(CalcValueNode::Length)
|
||||
}
|
||||
(Token::Dimension(ref value, ref unit), CalcUnit::Angle) => {
|
||||
Angle::parse_dimension(value.value, unit).map(CalcValueNode::Angle)
|
||||
}
|
||||
(Token::Dimension(ref value, ref unit), CalcUnit::Time) => {
|
||||
Time::parse_dimension(value.value, unit).map(CalcValueNode::Time)
|
||||
}
|
||||
(Token::Percentage(ref value), CalcUnit::LengthOrPercentage) =>
|
||||
Ok(CalcValueNode::Percentage(value.unit_value)),
|
||||
Ok(Token::ParenthesisBlock) => {
|
||||
let result = try!(input.parse_nested_block(Calc::parse_sum));
|
||||
Ok(CalcValueNode::Sum(box result))
|
||||
(Token::ParenthesisBlock, _) => {
|
||||
input.parse_nested_block(|i| CalcLengthOrPercentage::parse_sum(i, expected_unit))
|
||||
.map(|result| CalcValueNode::Sum(box result))
|
||||
},
|
||||
_ => Err(())
|
||||
}
|
||||
|
@ -497,7 +579,7 @@ pub mod specified {
|
|||
fn simplify_value_to_number(node: &CalcValueNode) -> Option<CSSFloat> {
|
||||
match *node {
|
||||
CalcValueNode::Number(number) => Some(number),
|
||||
CalcValueNode::Sum(box ref sum) => Calc::simplify_sum_to_number(sum),
|
||||
CalcValueNode::Sum(box ref sum) => CalcLengthOrPercentage::simplify_sum_to_number(sum),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
@ -505,7 +587,7 @@ pub mod specified {
|
|||
fn simplify_sum_to_number(node: &CalcSumNode) -> Option<CSSFloat> {
|
||||
let mut sum = 0.;
|
||||
for ref product in &node.products {
|
||||
match Calc::simplify_product_to_number(product) {
|
||||
match CalcLengthOrPercentage::simplify_product_to_number(product) {
|
||||
Some(number) => sum += number,
|
||||
_ => return None
|
||||
}
|
||||
|
@ -516,7 +598,7 @@ pub mod specified {
|
|||
fn simplify_product_to_number(node: &CalcProductNode) -> Option<CSSFloat> {
|
||||
let mut product = 1.;
|
||||
for ref value in &node.values {
|
||||
match Calc::simplify_value_to_number(value) {
|
||||
match CalcLengthOrPercentage::simplify_value_to_number(value) {
|
||||
Some(number) => product *= number,
|
||||
_ => return None
|
||||
}
|
||||
|
@ -527,7 +609,7 @@ pub mod specified {
|
|||
fn simplify_products_in_sum(node: &CalcSumNode) -> Result<SimplifiedValueNode, ()> {
|
||||
let mut simplified = Vec::new();
|
||||
for product in &node.products {
|
||||
match try!(Calc::simplify_product(product)) {
|
||||
match try!(CalcLengthOrPercentage::simplify_product(product)) {
|
||||
SimplifiedValueNode::Sum(box sum) => simplified.push_all(&sum.values),
|
||||
val => simplified.push(val),
|
||||
}
|
||||
|
@ -544,13 +626,15 @@ pub mod specified {
|
|||
let mut multiplier = 1.;
|
||||
let mut node_with_unit = None;
|
||||
for node in &node.values {
|
||||
match Calc::simplify_value_to_number(&node) {
|
||||
match CalcLengthOrPercentage::simplify_value_to_number(&node) {
|
||||
Some(number) => multiplier *= number,
|
||||
_ if node_with_unit.is_none() => {
|
||||
node_with_unit = Some(match *node {
|
||||
CalcValueNode::Sum(box ref sum) =>
|
||||
try!(Calc::simplify_products_in_sum(sum)),
|
||||
try!(CalcLengthOrPercentage::simplify_products_in_sum(sum)),
|
||||
CalcValueNode::Length(l) => SimplifiedValueNode::Length(l),
|
||||
CalcValueNode::Angle(a) => SimplifiedValueNode::Angle(a),
|
||||
CalcValueNode::Time(t) => SimplifiedValueNode::Time(t),
|
||||
CalcValueNode::Percentage(p) => SimplifiedValueNode::Percentage(p),
|
||||
_ => unreachable!("Numbers should have been handled by simplify_value_to_nubmer")
|
||||
})
|
||||
|
@ -565,12 +649,20 @@ pub mod specified {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse(input: &mut Parser) -> Result<Calc, ()> {
|
||||
let ast = try!(Calc::parse_sum(input));
|
||||
fn parse_length(input: &mut Parser) -> Result<Length, ()> {
|
||||
CalcLengthOrPercentage::parse(input, CalcUnit::Length).map(Length::Calc)
|
||||
}
|
||||
|
||||
fn parse_length_or_percentage(input: &mut Parser) -> Result<CalcLengthOrPercentage, ()> {
|
||||
CalcLengthOrPercentage::parse(input, CalcUnit::LengthOrPercentage)
|
||||
}
|
||||
|
||||
fn parse(input: &mut Parser, expected_unit: CalcUnit) -> Result<CalcLengthOrPercentage, ()> {
|
||||
let ast = try!(CalcLengthOrPercentage::parse_sum(input, expected_unit));
|
||||
|
||||
let mut simplified = Vec::new();
|
||||
for ref node in ast.products {
|
||||
match try!(Calc::simplify_product(node)) {
|
||||
match try!(CalcLengthOrPercentage::simplify_product(node)) {
|
||||
SimplifiedValueNode::Sum(sum) => simplified.push_all(&sum.values),
|
||||
value => simplified.push(value),
|
||||
}
|
||||
|
@ -617,11 +709,11 @@ pub mod specified {
|
|||
rem = Some(rem.unwrap_or(0.) + val),
|
||||
},
|
||||
SimplifiedValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val),
|
||||
_ => unreachable!()
|
||||
_ => return Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Calc {
|
||||
Ok(CalcLengthOrPercentage {
|
||||
absolute: absolute.map(Au),
|
||||
vw: vw.map(ViewportPercentageLength::Vw),
|
||||
vh: vh.map(ViewportPercentageLength::Vh),
|
||||
|
@ -634,9 +726,66 @@ pub mod specified {
|
|||
percentage: percentage.map(Percentage),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_time(input: &mut Parser) -> Result<Time, ()> {
|
||||
let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Time));
|
||||
|
||||
let mut simplified = Vec::new();
|
||||
for ref node in ast.products {
|
||||
match try!(CalcLengthOrPercentage::simplify_product(node)) {
|
||||
SimplifiedValueNode::Sum(sum) => simplified.push_all(&sum.values),
|
||||
value => simplified.push(value),
|
||||
}
|
||||
}
|
||||
|
||||
let mut time = None;
|
||||
|
||||
for value in simplified {
|
||||
match value {
|
||||
SimplifiedValueNode::Time(Time(val)) =>
|
||||
time = Some(time.unwrap_or(0.) + val),
|
||||
_ => return Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
match time {
|
||||
Some(time) => Ok(Time(time)),
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_angle(input: &mut Parser) -> Result<Angle, ()> {
|
||||
let ast = try!(CalcLengthOrPercentage::parse_sum(input, CalcUnit::Angle));
|
||||
|
||||
let mut simplified = Vec::new();
|
||||
for ref node in ast.products {
|
||||
match try!(CalcLengthOrPercentage::simplify_product(node)) {
|
||||
SimplifiedValueNode::Sum(sum) => simplified.push_all(&sum.values),
|
||||
value => simplified.push(value),
|
||||
}
|
||||
}
|
||||
|
||||
let mut angle = None;
|
||||
let mut number = None;
|
||||
|
||||
for value in simplified {
|
||||
match value {
|
||||
SimplifiedValueNode::Angle(Angle(val)) =>
|
||||
angle = Some(angle.unwrap_or(0.) + val),
|
||||
SimplifiedValueNode::Number(val) => number = Some(number.unwrap_or(0.) + val),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
match (angle, number) {
|
||||
(Some(angle), None) => Ok(Angle(angle)),
|
||||
(None, Some(value)) if value == 0. => Ok(Angle(0.)),
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for Calc {
|
||||
impl ToCss for CalcLengthOrPercentage {
|
||||
#[allow(unused_assignments)]
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
|
||||
|
@ -701,7 +850,7 @@ pub mod specified {
|
|||
pub enum LengthOrPercentage {
|
||||
Length(Length),
|
||||
Percentage(Percentage),
|
||||
Calc(Calc),
|
||||
Calc(CalcLengthOrPercentage),
|
||||
}
|
||||
|
||||
impl ToCss for LengthOrPercentage {
|
||||
|
@ -729,7 +878,7 @@ pub mod specified {
|
|||
Token::Number(ref value) if value.value == 0. =>
|
||||
Ok(LengthOrPercentage::Length(Length::Absolute(Au(0)))),
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||
let calc = try!(input.parse_nested_block(Calc::parse));
|
||||
let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage));
|
||||
Ok(LengthOrPercentage::Calc(calc))
|
||||
},
|
||||
_ => Err(())
|
||||
|
@ -750,7 +899,7 @@ pub mod specified {
|
|||
Length(Length),
|
||||
Percentage(Percentage),
|
||||
Auto,
|
||||
Calc(Calc),
|
||||
Calc(CalcLengthOrPercentage),
|
||||
}
|
||||
|
||||
impl ToCss for LengthOrPercentageOrAuto {
|
||||
|
@ -778,7 +927,7 @@ pub mod specified {
|
|||
Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") =>
|
||||
Ok(LengthOrPercentageOrAuto::Auto),
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||
let calc = try!(input.parse_nested_block(Calc::parse));
|
||||
let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage));
|
||||
Ok(LengthOrPercentageOrAuto::Calc(calc))
|
||||
},
|
||||
_ => Err(())
|
||||
|
@ -798,6 +947,7 @@ pub mod specified {
|
|||
pub enum LengthOrPercentageOrNone {
|
||||
Length(Length),
|
||||
Percentage(Percentage),
|
||||
Calc(CalcLengthOrPercentage),
|
||||
None,
|
||||
}
|
||||
|
||||
|
@ -806,6 +956,7 @@ pub mod specified {
|
|||
match *self {
|
||||
LengthOrPercentageOrNone::Length(length) => length.to_css(dest),
|
||||
LengthOrPercentageOrNone::Percentage(percentage) => percentage.to_css(dest),
|
||||
LengthOrPercentageOrNone::Calc(calc) => calc.to_css(dest),
|
||||
LengthOrPercentageOrNone::None => dest.write_str("none"),
|
||||
}
|
||||
}
|
||||
|
@ -821,6 +972,10 @@ pub mod specified {
|
|||
Ok(LengthOrPercentageOrNone::Percentage(Percentage(value.unit_value))),
|
||||
Token::Number(ref value) if value.value == 0. =>
|
||||
Ok(LengthOrPercentageOrNone::Length(Length::Absolute(Au(0)))),
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||
let calc = try!(input.parse_nested_block(CalcLengthOrPercentage::parse_length_or_percentage));
|
||||
Ok(LengthOrPercentageOrNone::Calc(calc))
|
||||
},
|
||||
Token::Ident(ref value) if value.eq_ignore_ascii_case("none") =>
|
||||
Ok(LengthOrPercentageOrNone::None),
|
||||
_ => Err(())
|
||||
|
@ -859,6 +1014,8 @@ pub mod specified {
|
|||
Length::parse_dimension(value.value, unit).map(LengthOrNone::Length),
|
||||
Token::Number(ref value) if value.value == 0. =>
|
||||
Ok(LengthOrNone::Length(Length::Absolute(Au(0)))),
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =>
|
||||
input.parse_nested_block(CalcLengthOrPercentage::parse_length).map(LengthOrNone::Length),
|
||||
Token::Ident(ref value) if value.eq_ignore_ascii_case("none") =>
|
||||
Ok(LengthOrNone::None),
|
||||
_ => Err(())
|
||||
|
@ -911,8 +1068,7 @@ pub mod specified {
|
|||
// http://dev.w3.org/csswg/css2/colors.html#propdef-background-position
|
||||
#[derive(Clone, PartialEq, Copy)]
|
||||
pub enum PositionComponent {
|
||||
Length(Length),
|
||||
Percentage(Percentage),
|
||||
LengthOrPercentage(LengthOrPercentage),
|
||||
Center,
|
||||
Left,
|
||||
Right,
|
||||
|
@ -921,35 +1077,29 @@ pub mod specified {
|
|||
}
|
||||
impl PositionComponent {
|
||||
pub fn parse(input: &mut Parser) -> Result<PositionComponent, ()> {
|
||||
match try!(input.next()) {
|
||||
Token::Dimension(ref value, ref unit) => {
|
||||
Length::parse_dimension(value.value, unit)
|
||||
.map(PositionComponent::Length)
|
||||
|
||||
input.try(LengthOrPercentage::parse)
|
||||
.map(PositionComponent::LengthOrPercentage)
|
||||
.or_else(|()| {
|
||||
match try!(input.next()) {
|
||||
Token::Ident(value) => {
|
||||
match_ignore_ascii_case! { value,
|
||||
"center" => Ok(PositionComponent::Center),
|
||||
"left" => Ok(PositionComponent::Left),
|
||||
"right" => Ok(PositionComponent::Right),
|
||||
"top" => Ok(PositionComponent::Top),
|
||||
"bottom" => Ok(PositionComponent::Bottom)
|
||||
_ => Err(())
|
||||
}
|
||||
},
|
||||
_ => Err(())
|
||||
}
|
||||
Token::Percentage(ref value) => {
|
||||
Ok(PositionComponent::Percentage(Percentage(value.unit_value)))
|
||||
}
|
||||
Token::Number(ref value) if value.value == 0. => {
|
||||
Ok(PositionComponent::Length(Length::Absolute(Au(0))))
|
||||
}
|
||||
Token::Ident(value) => {
|
||||
match_ignore_ascii_case! { value,
|
||||
"center" => Ok(PositionComponent::Center),
|
||||
"left" => Ok(PositionComponent::Left),
|
||||
"right" => Ok(PositionComponent::Right),
|
||||
"top" => Ok(PositionComponent::Top),
|
||||
"bottom" => Ok(PositionComponent::Bottom)
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
_ => Err(())
|
||||
}
|
||||
})
|
||||
}
|
||||
#[inline]
|
||||
pub fn to_length_or_percentage(self) -> LengthOrPercentage {
|
||||
match self {
|
||||
PositionComponent::Length(x) => LengthOrPercentage::Length(x),
|
||||
PositionComponent::Percentage(x) => LengthOrPercentage::Percentage(x),
|
||||
PositionComponent::LengthOrPercentage(value) => value,
|
||||
PositionComponent::Center => LengthOrPercentage::Percentage(Percentage(0.5)),
|
||||
PositionComponent::Left |
|
||||
PositionComponent::Top => LengthOrPercentage::Percentage(Percentage(0.0)),
|
||||
|
@ -984,19 +1134,24 @@ pub mod specified {
|
|||
/// Parses an angle according to CSS-VALUES § 6.1.
|
||||
pub fn parse(input: &mut Parser) -> Result<Angle, ()> {
|
||||
match try!(input.next()) {
|
||||
Token::Dimension(value, unit) => {
|
||||
match_ignore_ascii_case! { unit,
|
||||
"deg" => Ok(Angle(value.value * RAD_PER_DEG)),
|
||||
"grad" => Ok(Angle(value.value * RAD_PER_GRAD)),
|
||||
"turn" => Ok(Angle(value.value * RAD_PER_TURN)),
|
||||
"rad" => Ok(Angle(value.value))
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
Token::Dimension(ref value, ref unit) => Angle::parse_dimension(value.value, unit),
|
||||
Token::Number(ref value) if value.value == 0. => Ok(Angle(0.)),
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||
input.parse_nested_block(CalcLengthOrPercentage::parse_angle)
|
||||
},
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_dimension(value: CSSFloat, unit: &str) -> Result<Angle, ()> {
|
||||
match_ignore_ascii_case! { unit,
|
||||
"deg" => Ok(Angle(value * RAD_PER_DEG)),
|
||||
"grad" => Ok(Angle(value * RAD_PER_GRAD)),
|
||||
"turn" => Ok(Angle(value * RAD_PER_TURN)),
|
||||
"rad" => Ok(Angle(value))
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Specified values for an image according to CSS-IMAGES.
|
||||
|
@ -1235,7 +1390,10 @@ pub mod specified {
|
|||
Ok(Token::Dimension(ref value, ref unit)) => {
|
||||
Time::parse_dimension(value.value, &unit)
|
||||
}
|
||||
_ => Err(()),
|
||||
Ok(Token::Function(ref name)) if name.eq_ignore_ascii_case("calc") => {
|
||||
input.parse_nested_block(CalcLengthOrPercentage::parse_time)
|
||||
}
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1251,7 +1409,7 @@ pub mod specified {
|
|||
|
||||
impl ToCss for Time {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
write!(dest, "{}ms", self.0)
|
||||
write!(dest, "{}s", self.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1328,6 +1486,7 @@ pub mod computed {
|
|||
fn to_computed_value(&self, context: &Context) -> Au {
|
||||
match *self {
|
||||
specified::Length::Absolute(length) => length,
|
||||
specified::Length::Calc(calc) => calc.to_computed_value(context).length(),
|
||||
specified::Length::FontRelative(length) =>
|
||||
length.to_computed_value(context.font_size, context.root_font_size),
|
||||
specified::Length::ViewportPercentage(length) =>
|
||||
|
@ -1339,12 +1498,12 @@ pub mod computed {
|
|||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Copy, Debug, HeapSizeOf)]
|
||||
pub struct Calc {
|
||||
pub struct CalcLengthOrPercentage {
|
||||
pub length: Option<Au>,
|
||||
pub percentage: Option<CSSFloat>,
|
||||
}
|
||||
|
||||
impl Calc {
|
||||
impl CalcLengthOrPercentage {
|
||||
pub fn length(&self) -> Au {
|
||||
self.length.unwrap_or(Au(0))
|
||||
}
|
||||
|
@ -1354,17 +1513,17 @@ pub mod computed {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<LengthOrPercentage> for Calc {
|
||||
fn from(len: LengthOrPercentage) -> Calc {
|
||||
impl From<LengthOrPercentage> for CalcLengthOrPercentage {
|
||||
fn from(len: LengthOrPercentage) -> CalcLengthOrPercentage {
|
||||
match len {
|
||||
LengthOrPercentage::Percentage(this) => {
|
||||
Calc {
|
||||
CalcLengthOrPercentage {
|
||||
length: None,
|
||||
percentage: Some(this),
|
||||
}
|
||||
}
|
||||
LengthOrPercentage::Length(this) => {
|
||||
Calc {
|
||||
CalcLengthOrPercentage {
|
||||
length: Some(this),
|
||||
percentage: None,
|
||||
}
|
||||
|
@ -1376,17 +1535,17 @@ pub mod computed {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<LengthOrPercentageOrAuto> for Option<Calc> {
|
||||
fn from(len: LengthOrPercentageOrAuto) -> Option<Calc> {
|
||||
impl From<LengthOrPercentageOrAuto> for Option<CalcLengthOrPercentage> {
|
||||
fn from(len: LengthOrPercentageOrAuto) -> Option<CalcLengthOrPercentage> {
|
||||
match len {
|
||||
LengthOrPercentageOrAuto::Percentage(this) => {
|
||||
Some(Calc {
|
||||
Some(CalcLengthOrPercentage {
|
||||
length: None,
|
||||
percentage: Some(this),
|
||||
})
|
||||
}
|
||||
LengthOrPercentageOrAuto::Length(this) => {
|
||||
Some(Calc {
|
||||
Some(CalcLengthOrPercentage {
|
||||
length: Some(this),
|
||||
percentage: None,
|
||||
})
|
||||
|
@ -1401,7 +1560,7 @@ pub mod computed {
|
|||
}
|
||||
}
|
||||
|
||||
impl ::cssparser::ToCss for Calc {
|
||||
impl ::cssparser::ToCss for CalcLengthOrPercentage {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
match (self.length, self.percentage) {
|
||||
(None, Some(p)) => write!(dest, "{}%", p * 100.),
|
||||
|
@ -1412,10 +1571,10 @@ pub mod computed {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToComputedValue for specified::Calc {
|
||||
type ComputedValue = Calc;
|
||||
impl ToComputedValue for specified::CalcLengthOrPercentage {
|
||||
type ComputedValue = CalcLengthOrPercentage;
|
||||
|
||||
fn to_computed_value(&self, context: &Context) -> Calc {
|
||||
fn to_computed_value(&self, context: &Context) -> CalcLengthOrPercentage {
|
||||
let mut length = None;
|
||||
|
||||
if let Some(absolute) = self.absolute {
|
||||
|
@ -1435,7 +1594,7 @@ pub mod computed {
|
|||
}
|
||||
}
|
||||
|
||||
Calc { length: length, percentage: self.percentage.map(|p| p.0) }
|
||||
CalcLengthOrPercentage { length: length, percentage: self.percentage.map(|p| p.0) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1474,7 +1633,7 @@ pub mod computed {
|
|||
pub enum LengthOrPercentage {
|
||||
Length(Au),
|
||||
Percentage(CSSFloat),
|
||||
Calc(Calc),
|
||||
Calc(CalcLengthOrPercentage),
|
||||
}
|
||||
|
||||
impl LengthOrPercentage {
|
||||
|
@ -1527,7 +1686,7 @@ pub mod computed {
|
|||
Length(Au),
|
||||
Percentage(CSSFloat),
|
||||
Auto,
|
||||
Calc(Calc),
|
||||
Calc(CalcLengthOrPercentage),
|
||||
}
|
||||
impl fmt::Debug for LengthOrPercentageOrAuto {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
@ -1578,6 +1737,7 @@ pub mod computed {
|
|||
pub enum LengthOrPercentageOrNone {
|
||||
Length(Au),
|
||||
Percentage(CSSFloat),
|
||||
Calc(CalcLengthOrPercentage),
|
||||
None,
|
||||
}
|
||||
impl fmt::Debug for LengthOrPercentageOrNone {
|
||||
|
@ -1585,6 +1745,7 @@ pub mod computed {
|
|||
match *self {
|
||||
LengthOrPercentageOrNone::Length(length) => write!(f, "{:?}", length),
|
||||
LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage * 100.),
|
||||
LengthOrPercentageOrNone::Calc(calc) => write!(f, "{:?}", calc),
|
||||
LengthOrPercentageOrNone::None => write!(f, "none"),
|
||||
}
|
||||
}
|
||||
|
@ -1602,6 +1763,9 @@ pub mod computed {
|
|||
specified::LengthOrPercentageOrNone::Percentage(value) => {
|
||||
LengthOrPercentageOrNone::Percentage(value.0)
|
||||
}
|
||||
specified::LengthOrPercentageOrNone::Calc(calc) => {
|
||||
LengthOrPercentageOrNone::Calc(calc.to_computed_value(context))
|
||||
}
|
||||
specified::LengthOrPercentageOrNone::None => {
|
||||
LengthOrPercentageOrNone::None
|
||||
}
|
||||
|
@ -1615,6 +1779,7 @@ pub mod computed {
|
|||
LengthOrPercentageOrNone::Length(length) => length.to_css(dest),
|
||||
LengthOrPercentageOrNone::Percentage(percentage) =>
|
||||
write!(dest, "{}%", percentage * 100.),
|
||||
LengthOrPercentageOrNone::Calc(calc) => calc.to_css(dest),
|
||||
LengthOrPercentageOrNone::None => dest.write_str("none"),
|
||||
}
|
||||
}
|
||||
|
@ -1640,6 +1805,9 @@ pub mod computed {
|
|||
#[inline]
|
||||
fn to_computed_value(&self, context: &Context) -> LengthOrNone {
|
||||
match *self {
|
||||
specified::LengthOrNone::Length(specified::Length::Calc(calc)) => {
|
||||
LengthOrNone::Length(calc.to_computed_value(context).length())
|
||||
}
|
||||
specified::LengthOrNone::Length(value) => {
|
||||
LengthOrNone::Length(value.to_computed_value(context))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue