style: Respect calc for percentages.

This commit is contained in:
Emilio Cobos Álvarez 2017-07-14 13:18:29 +02:00
parent 465e6f14fe
commit 310be02ba8
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
28 changed files with 308 additions and 176 deletions

View file

@ -14,9 +14,9 @@ use std::fmt;
use style_traits::{HasViewportPercentage, ToCss, ParseError, StyleParseError};
use style_traits::values::specified::AllowedLengthType;
use values::{CSSInteger, CSSFloat};
use values::computed;
use values::specified::{Angle, Time};
use values::specified::length::{FontRelativeLength, NoCalcLength};
use values::specified::length::{Percentage, ViewportPercentageLength};
use values::specified::length::{FontRelativeLength, NoCalcLength, ViewportPercentageLength};
/// A node inside a `Calc` expression's AST.
#[derive(Clone, Debug)]
@ -52,6 +52,8 @@ pub enum CalcUnit {
Integer,
/// `<length>`
Length,
/// `<percentage>`
Percentage,
/// `<length> | <percentage>`
LengthOrPercentage,
/// `<angle>`
@ -75,7 +77,7 @@ pub struct CalcLengthOrPercentage {
pub ex: Option<CSSFloat>,
pub ch: Option<CSSFloat>,
pub rem: Option<CSSFloat>,
pub percentage: Option<Percentage>,
pub percentage: Option<computed::Percentage>,
#[cfg(feature = "gecko")]
pub mozmm: Option<CSSFloat>,
}
@ -146,9 +148,8 @@ impl CalcNode {
fn parse_one<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
expected_unit: CalcUnit)
-> Result<Self, ParseError<'i>>
{
expected_unit: CalcUnit
) -> Result<Self, ParseError<'i>> {
match (input.next()?, expected_unit) {
(Token::Number { value, .. }, _) => Ok(CalcNode::Number(value)),
(Token::Dimension { value, ref unit, .. }, CalcUnit::Length) |
@ -167,7 +168,8 @@ impl CalcNode {
.map(CalcNode::Time)
.map_err(|()| StyleParseError::UnspecifiedError.into())
}
(Token::Percentage { unit_value, .. }, CalcUnit::LengthOrPercentage) => {
(Token::Percentage { unit_value, .. }, CalcUnit::LengthOrPercentage) |
(Token::Percentage { unit_value, .. }, CalcUnit::Percentage) => {
Ok(CalcNode::Percentage(unit_value))
}
(Token::ParenthesisBlock, _) => {
@ -283,6 +285,44 @@ impl CalcNode {
Ok(ret)
}
/// Tries to simplify this expression into a `<percentage>` value.
fn to_percentage(&self) -> Result<CSSFloat, ()> {
Ok(match *self {
CalcNode::Percentage(percentage) => percentage,
CalcNode::Sub(ref a, ref b) => {
a.to_percentage()? - b.to_percentage()?
}
CalcNode::Sum(ref a, ref b) => {
a.to_percentage()? + b.to_percentage()?
}
CalcNode::Mul(ref a, ref b) => {
match a.to_percentage() {
Ok(lhs) => {
let rhs = b.to_number()?;
lhs * rhs
}
Err(..) => {
let lhs = a.to_number()?;
let rhs = b.to_percentage()?;
lhs * rhs
}
}
}
CalcNode::Div(ref a, ref b) => {
let lhs = a.to_percentage()?;
let rhs = b.to_number()?;
if rhs == 0. {
return Err(())
}
lhs / rhs
}
CalcNode::Number(..) |
CalcNode::Length(..) |
CalcNode::Angle(..) |
CalcNode::Time(..) => return Err(()),
})
}
/// Puts this `<length>` or `<percentage>` into `ret`, or error.
///
/// `factor` is the sign or multiplicative factor to account for the sign
@ -295,7 +335,7 @@ impl CalcNode {
{
match *self {
CalcNode::Percentage(pct) => {
ret.percentage = Some(Percentage(
ret.percentage = Some(computed::Percentage(
ret.percentage.map_or(0., |p| p.0) + pct * factor,
));
}
@ -495,9 +535,8 @@ impl CalcNode {
/// Convenience parsing function for integers.
pub fn parse_integer<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>)
-> Result<CSSInteger, ParseError<'i>>
{
input: &mut Parser<'i, 't>
) -> Result<CSSInteger, ParseError<'i>> {
Self::parse(context, input, CalcUnit::Integer)?
.to_number()
.map(|n| n as CSSInteger)
@ -508,21 +547,29 @@ impl CalcNode {
pub fn parse_length_or_percentage<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
clamping_mode: AllowedLengthType)
-> Result<CalcLengthOrPercentage, ParseError<'i>>
{
clamping_mode: AllowedLengthType
) -> Result<CalcLengthOrPercentage, ParseError<'i>> {
Self::parse(context, input, CalcUnit::LengthOrPercentage)?
.to_length_or_percentage(clamping_mode)
.map_err(|()| StyleParseError::UnspecifiedError.into())
}
/// Convenience parsing function for percentages.
pub fn parse_percentage<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<CSSFloat, ParseError<'i>> {
Self::parse(context, input, CalcUnit::Percentage)?
.to_percentage()
.map_err(|()| StyleParseError::UnspecifiedError.into())
}
/// Convenience parsing function for `<length>`.
pub fn parse_length<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
clamping_mode: AllowedLengthType)
-> Result<CalcLengthOrPercentage, ParseError<'i>>
{
clamping_mode: AllowedLengthType
) -> Result<CalcLengthOrPercentage, ParseError<'i>> {
Self::parse(context, input, CalcUnit::Length)?
.to_length_or_percentage(clamping_mode)
.map_err(|()| StyleParseError::UnspecifiedError.into())
@ -531,9 +578,8 @@ impl CalcNode {
/// Convenience parsing function for `<number>`.
pub fn parse_number<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>)
-> Result<CSSFloat, ParseError<'i>>
{
input: &mut Parser<'i, 't>
) -> Result<CSSFloat, ParseError<'i>> {
Self::parse(context, input, CalcUnit::Number)?
.to_number()
.map_err(|()| StyleParseError::UnspecifiedError.into())
@ -542,9 +588,8 @@ impl CalcNode {
/// Convenience parsing function for `<angle>`.
pub fn parse_angle<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>)
-> Result<Angle, ParseError<'i>>
{
input: &mut Parser<'i, 't>
) -> Result<Angle, ParseError<'i>> {
Self::parse(context, input, CalcUnit::Angle)?
.to_angle()
.map_err(|()| StyleParseError::UnspecifiedError.into())
@ -553,9 +598,8 @@ impl CalcNode {
/// Convenience parsing function for `<time>`.
pub fn parse_time<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>)
-> Result<Time, ParseError<'i>>
{
input: &mut Parser<'i, 't>
) -> Result<Time, ParseError<'i>> {
Self::parse(context, input, CalcUnit::Time)?
.to_time()
.map_err(|()| StyleParseError::UnspecifiedError.into())