mirror of
https://github.com/servo/servo.git
synced 2025-08-07 22:45:34 +01:00
Refactor how calc() clamping is done on computed values (fixes #15296)
This commit is contained in:
parent
f935f2da01
commit
d0b9bd9c64
13 changed files with 173 additions and 154 deletions
|
@ -24,7 +24,7 @@ impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
|
|||
fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
|
||||
let has_percentage = other.percentage.is_some();
|
||||
nsStyleCoord_CalcValue {
|
||||
mLength: other.length.0,
|
||||
mLength: other.length().0,
|
||||
mPercent: other.percentage.unwrap_or(0.0),
|
||||
mHasPercent: has_percentage,
|
||||
}
|
||||
|
@ -38,10 +38,7 @@ impl From<nsStyleCoord_CalcValue> for CalcLengthOrPercentage {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
CalcLengthOrPercentage {
|
||||
length: Au(other.mLength),
|
||||
percentage: percentage,
|
||||
}
|
||||
Self::new(Au(other.mLength), percentage)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1035,11 +1035,9 @@ impl Animatable for CalcLengthOrPercentage {
|
|||
}
|
||||
}
|
||||
|
||||
Ok(CalcLengthOrPercentage {
|
||||
length: try!(self.length.add_weighted(&other.length, self_portion, other_portion)),
|
||||
percentage: try!(add_weighted_half(self.percentage, other.percentage,
|
||||
self_portion, other_portion)),
|
||||
})
|
||||
let length = self.length().add_weighted(&other.length(), self_portion, other_portion)?;
|
||||
let percentage = add_weighted_half(self.percentage, other.percentage, self_portion, other_portion)?;
|
||||
Ok(CalcLengthOrPercentage::with_clamping_mode(length, percentage, self.clamping_mode))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -8,6 +8,7 @@ use app_units::{Au, AU_PER_PX};
|
|||
use ordered_float::NotNaN;
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use style_traits::values::specified::AllowedLengthType;
|
||||
use super::{Number, ToComputedValue, Context};
|
||||
use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
|
||||
use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength, ViewportPercentageLength};
|
||||
|
@ -48,7 +49,7 @@ impl ToComputedValue for specified::Length {
|
|||
fn to_computed_value(&self, context: &Context) -> Au {
|
||||
match *self {
|
||||
specified::Length::NoCalc(l) => l.to_computed_value(context),
|
||||
specified::Length::Calc(range, ref calc) => range.clamp(calc.to_computed_value(context).length()),
|
||||
specified::Length::Calc(ref calc) => calc.to_computed_value(context).length(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,15 +63,35 @@ impl ToComputedValue for specified::Length {
|
|||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct CalcLengthOrPercentage {
|
||||
pub length: Au,
|
||||
pub clamping_mode: AllowedLengthType,
|
||||
length: Au,
|
||||
pub percentage: Option<CSSFloat>,
|
||||
}
|
||||
|
||||
impl CalcLengthOrPercentage {
|
||||
/// Returns a new `CalcLengthOrPercentage`.
|
||||
#[inline]
|
||||
pub fn new(length: Au, percentage: Option<CSSFloat>) -> Self {
|
||||
Self::with_clamping_mode(length, percentage, AllowedLengthType::All)
|
||||
}
|
||||
|
||||
/// Returns a new `CalcLengthOrPercentage` with a specific clamping mode.
|
||||
#[inline]
|
||||
pub fn with_clamping_mode(length: Au,
|
||||
percentage: Option<CSSFloat>,
|
||||
clamping_mode: AllowedLengthType)
|
||||
-> Self {
|
||||
Self {
|
||||
clamping_mode: clamping_mode,
|
||||
length: length,
|
||||
percentage: percentage,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub fn length(&self) -> Au {
|
||||
self.length
|
||||
self.clamping_mode.clamp(self.length)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -81,10 +102,12 @@ impl CalcLengthOrPercentage {
|
|||
|
||||
/// If there are special rules for computing percentages in a value (e.g. the height property),
|
||||
/// they apply whenever a calc() expression contains percentages.
|
||||
pub fn to_computed(&self, container_len: Option<Au>) -> Option<Au> {
|
||||
pub fn to_used_value(&self, container_len: Option<Au>) -> Option<Au> {
|
||||
match (container_len, self.percentage) {
|
||||
(Some(len), Some(percent)) => Some(self.length + len.scale_by(percent)),
|
||||
(_, None) => Some(self.length),
|
||||
(Some(len), Some(percent)) => {
|
||||
Some(self.clamping_mode.clamp(self.length + len.scale_by(percent)))
|
||||
},
|
||||
(_, None) => Some(self.length()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -94,16 +117,10 @@ impl From<LengthOrPercentage> for CalcLengthOrPercentage {
|
|||
fn from(len: LengthOrPercentage) -> CalcLengthOrPercentage {
|
||||
match len {
|
||||
LengthOrPercentage::Percentage(this) => {
|
||||
CalcLengthOrPercentage {
|
||||
length: Au(0),
|
||||
percentage: Some(this),
|
||||
}
|
||||
CalcLengthOrPercentage::new(Au(0), Some(this))
|
||||
}
|
||||
LengthOrPercentage::Length(this) => {
|
||||
CalcLengthOrPercentage {
|
||||
length: this,
|
||||
percentage: None,
|
||||
}
|
||||
CalcLengthOrPercentage::new(this, None)
|
||||
}
|
||||
LengthOrPercentage::Calc(this) => {
|
||||
this
|
||||
|
@ -116,16 +133,10 @@ impl From<LengthOrPercentageOrAuto> for Option<CalcLengthOrPercentage> {
|
|||
fn from(len: LengthOrPercentageOrAuto) -> Option<CalcLengthOrPercentage> {
|
||||
match len {
|
||||
LengthOrPercentageOrAuto::Percentage(this) => {
|
||||
Some(CalcLengthOrPercentage {
|
||||
length: Au(0),
|
||||
percentage: Some(this),
|
||||
})
|
||||
Some(CalcLengthOrPercentage::new(Au(0), Some(this)))
|
||||
}
|
||||
LengthOrPercentageOrAuto::Length(this) => {
|
||||
Some(CalcLengthOrPercentage {
|
||||
length: this,
|
||||
percentage: None,
|
||||
})
|
||||
Some(CalcLengthOrPercentage::new(this, None))
|
||||
}
|
||||
LengthOrPercentageOrAuto::Calc(this) => {
|
||||
Some(this)
|
||||
|
@ -176,6 +187,7 @@ impl ToComputedValue for specified::CalcLengthOrPercentage {
|
|||
}
|
||||
|
||||
CalcLengthOrPercentage {
|
||||
clamping_mode: self.clamping_mode,
|
||||
length: length,
|
||||
percentage: self.percentage,
|
||||
}
|
||||
|
@ -184,6 +196,7 @@ impl ToComputedValue for specified::CalcLengthOrPercentage {
|
|||
#[inline]
|
||||
fn from_computed_value(computed: &CalcLengthOrPercentage) -> Self {
|
||||
specified::CalcLengthOrPercentage {
|
||||
clamping_mode: computed.clamping_mode,
|
||||
absolute: Some(computed.length),
|
||||
percentage: computed.percentage,
|
||||
..Default::default()
|
||||
|
@ -235,6 +248,17 @@ impl LengthOrPercentage {
|
|||
Calc(c) => (c.length(), NotNaN::new(c.percentage()).unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the used value.
|
||||
pub fn to_used_value(&self, containing_length: Au) -> Au {
|
||||
match *self {
|
||||
LengthOrPercentage::Length(length) => length,
|
||||
LengthOrPercentage::Percentage(p) => containing_length.scale_by(p),
|
||||
LengthOrPercentage::Calc(ref calc) => {
|
||||
calc.to_used_value(Some(containing_length)).unwrap()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for LengthOrPercentage {
|
||||
|
@ -481,6 +505,18 @@ pub enum LengthOrPercentageOrNone {
|
|||
None,
|
||||
}
|
||||
|
||||
impl LengthOrPercentageOrNone {
|
||||
/// Returns the used value.
|
||||
pub fn to_used_value(&self, containing_length: Au) -> Option<Au> {
|
||||
match *self {
|
||||
LengthOrPercentageOrNone::None => None,
|
||||
LengthOrPercentageOrNone::Length(length) => Some(length),
|
||||
LengthOrPercentageOrNone::Percentage(percent) => Some(containing_length.scale_by(percent)),
|
||||
LengthOrPercentageOrNone::Calc(ref calc) => calc.to_used_value(Some(containing_length)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for LengthOrPercentageOrNone {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
|
|
|
@ -12,6 +12,7 @@ use parser::ParserContext;
|
|||
use std::ascii::AsciiExt;
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use style_traits::values::specified::AllowedLengthType;
|
||||
use values::{CSSInteger, CSSFloat, HasViewportPercentage};
|
||||
use values::specified::{Angle, Time};
|
||||
use values::specified::length::{FontRelativeLength, NoCalcLength, ViewportPercentageLength};
|
||||
|
@ -63,6 +64,7 @@ pub enum CalcUnit {
|
|||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub struct CalcLengthOrPercentage {
|
||||
pub clamping_mode: AllowedLengthType,
|
||||
pub absolute: Option<Au>,
|
||||
pub vw: Option<CSSFloat>,
|
||||
pub vh: Option<CSSFloat>,
|
||||
|
@ -271,8 +273,12 @@ impl CalcNode {
|
|||
|
||||
/// Tries to simplify this expression into a `<length>` or `<percentage`>
|
||||
/// value.
|
||||
fn to_length_or_percentage(&self) -> Result<CalcLengthOrPercentage, ()> {
|
||||
let mut ret = CalcLengthOrPercentage::default();
|
||||
fn to_length_or_percentage(&self, clamping_mode: AllowedLengthType)
|
||||
-> Result<CalcLengthOrPercentage, ()> {
|
||||
let mut ret = CalcLengthOrPercentage {
|
||||
clamping_mode: clamping_mode,
|
||||
.. Default::default()
|
||||
};
|
||||
self.add_length_or_percentage_to(&mut ret, 1.0)?;
|
||||
Ok(ret)
|
||||
}
|
||||
|
@ -498,21 +504,23 @@ impl CalcNode {
|
|||
/// Convenience parsing function for `<length> | <percentage>`.
|
||||
pub fn parse_length_or_percentage(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser)
|
||||
input: &mut Parser,
|
||||
clamping_mode: AllowedLengthType)
|
||||
-> Result<CalcLengthOrPercentage, ()>
|
||||
{
|
||||
Self::parse(context, input, CalcUnit::LengthOrPercentage)?
|
||||
.to_length_or_percentage()
|
||||
.to_length_or_percentage(clamping_mode)
|
||||
}
|
||||
|
||||
/// Convenience parsing function for `<length>`.
|
||||
pub fn parse_length(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser)
|
||||
input: &mut Parser,
|
||||
clamping_mode: AllowedLengthType)
|
||||
-> Result<CalcLengthOrPercentage, ()>
|
||||
{
|
||||
Self::parse(context, input, CalcUnit::Length)?
|
||||
.to_length_or_percentage()
|
||||
.to_length_or_percentage(clamping_mode)
|
||||
}
|
||||
|
||||
/// Convenience parsing function for `<number>`.
|
||||
|
|
|
@ -539,7 +539,7 @@ pub enum Length {
|
|||
/// A calc expression.
|
||||
///
|
||||
/// https://drafts.csswg.org/css-values/#calc-notation
|
||||
Calc(AllowedLengthType, Box<CalcLengthOrPercentage>),
|
||||
Calc(Box<CalcLengthOrPercentage>),
|
||||
}
|
||||
|
||||
impl From<NoCalcLength> for Length {
|
||||
|
@ -553,7 +553,7 @@ impl HasViewportPercentage for Length {
|
|||
fn has_viewport_percentage(&self) -> bool {
|
||||
match *self {
|
||||
Length::NoCalc(ref inner) => inner.has_viewport_percentage(),
|
||||
Length::Calc(_, ref calc) => calc.has_viewport_percentage(),
|
||||
Length::Calc(ref calc) => calc.has_viewport_percentage(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -562,7 +562,7 @@ impl ToCss for Length {
|
|||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
match *self {
|
||||
Length::NoCalc(ref inner) => inner.to_css(dest),
|
||||
Length::Calc(_, ref calc) => calc.to_css(dest),
|
||||
Length::Calc(ref calc) => calc.to_css(dest),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -637,10 +637,7 @@ impl Length {
|
|||
},
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =>
|
||||
input.parse_nested_block(|input| {
|
||||
CalcNode::parse_length(context, input)
|
||||
.map(|calc| {
|
||||
Length::Calc(num_context, Box::new(calc))
|
||||
})
|
||||
CalcNode::parse_length(context, input, num_context).map(|calc| Length::Calc(Box::new(calc)))
|
||||
}),
|
||||
_ => Err(())
|
||||
}
|
||||
|
@ -770,7 +767,7 @@ impl From<Length> for LengthOrPercentage {
|
|||
fn from(len: Length) -> LengthOrPercentage {
|
||||
match len {
|
||||
Length::NoCalc(l) => LengthOrPercentage::Length(l),
|
||||
Length::Calc(_, l) => LengthOrPercentage::Calc(l),
|
||||
Length::Calc(l) => LengthOrPercentage::Calc(l),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -832,7 +829,7 @@ impl LengthOrPercentage {
|
|||
Ok(LengthOrPercentage::Length(NoCalcLength::from_px(value.value))),
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||
let calc = try!(input.parse_nested_block(|i| {
|
||||
CalcNode::parse_length_or_percentage(context, i)
|
||||
CalcNode::parse_length_or_percentage(context, i, num_context)
|
||||
}));
|
||||
Ok(LengthOrPercentage::Calc(Box::new(calc)))
|
||||
},
|
||||
|
@ -986,7 +983,7 @@ impl LengthOrPercentageOrAuto {
|
|||
Ok(LengthOrPercentageOrAuto::Auto),
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||
let calc = try!(input.parse_nested_block(|i| {
|
||||
CalcNode::parse_length_or_percentage(context, i)
|
||||
CalcNode::parse_length_or_percentage(context, i, num_context)
|
||||
}));
|
||||
Ok(LengthOrPercentageOrAuto::Calc(Box::new(calc)))
|
||||
},
|
||||
|
@ -1092,7 +1089,7 @@ impl LengthOrPercentageOrNone {
|
|||
}
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||
let calc = try!(input.parse_nested_block(|i| {
|
||||
CalcNode::parse_length_or_percentage(context, i)
|
||||
CalcNode::parse_length_or_percentage(context, i, num_context)
|
||||
}));
|
||||
Ok(LengthOrPercentageOrNone::Calc(Box::new(calc)))
|
||||
},
|
||||
|
@ -1169,7 +1166,7 @@ impl LengthOrPercentageOrAutoOrContent {
|
|||
Ok(LengthOrPercentageOrAutoOrContent::Content),
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||
let calc = try!(input.parse_nested_block(|i| {
|
||||
CalcNode::parse_length_or_percentage(context, i)
|
||||
CalcNode::parse_length_or_percentage(context, i, num_context)
|
||||
}));
|
||||
Ok(LengthOrPercentageOrAutoOrContent::Calc(Box::new(calc)))
|
||||
},
|
||||
|
|
|
@ -234,19 +234,14 @@ impl<S: Side> ToComputedValue for PositionComponent<S> {
|
|||
PositionComponent::Side(ref keyword, Some(ref length)) if !keyword.is_start() => {
|
||||
match length.to_computed_value(context) {
|
||||
ComputedLengthOrPercentage::Length(length) => {
|
||||
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
|
||||
length: -length,
|
||||
percentage: Some(1.0),
|
||||
})
|
||||
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage::new(-length, Some(1.0)))
|
||||
},
|
||||
ComputedLengthOrPercentage::Percentage(p) => {
|
||||
ComputedLengthOrPercentage::Percentage(1.0 - p)
|
||||
},
|
||||
ComputedLengthOrPercentage::Calc(calc) => {
|
||||
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
|
||||
length: -calc.length,
|
||||
percentage: Some(1.0 - calc.percentage.unwrap_or(0.)),
|
||||
})
|
||||
let p = 1. - calc.percentage.unwrap_or(0.);
|
||||
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage::new(-calc.length(), Some(p)))
|
||||
},
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue