mirror of
https://github.com/servo/servo.git
synced 2025-07-30 10:40:27 +01:00
style: Implement atan2(), and enable calc() trigonometric functions by default on nightly
We now have test coverage, so let's do this. The remaining failures are just about infinity/nan, which is a completely different feature. Differential Revision: https://phabricator.services.mozilla.com/D154831
This commit is contained in:
parent
03e84754cc
commit
dd849de9d9
3 changed files with 180 additions and 117 deletions
|
@ -158,6 +158,14 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the leaf if we can (if simplification has allowed it).
|
||||
pub fn as_leaf(&self) -> Option<&L> {
|
||||
match *self {
|
||||
Self::Leaf(ref l) => Some(l),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to merge one sum to another, that is, perform `x` + `y`.
|
||||
fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> {
|
||||
match (self, other) {
|
||||
|
|
|
@ -43,6 +43,8 @@ pub enum MathFunction {
|
|||
Acos,
|
||||
/// `atan()`: https://drafts.csswg.org/css-values-4/#funcdef-atan
|
||||
Atan,
|
||||
/// `atan2()`: https://drafts.csswg.org/css-values-4/#funcdef-atan2
|
||||
Atan2,
|
||||
}
|
||||
|
||||
/// A leaf node inside a `Calc` expression's AST.
|
||||
|
@ -60,6 +62,15 @@ pub enum Leaf {
|
|||
Number(CSSFloat),
|
||||
}
|
||||
|
||||
impl Leaf {
|
||||
fn as_length(&self) -> Option<&NoCalcLength> {
|
||||
match *self {
|
||||
Self::Length(ref l) => Some(l),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for Leaf {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
|
@ -75,23 +86,22 @@ impl ToCss for Leaf {
|
|||
}
|
||||
}
|
||||
|
||||
/// An expected unit we intend to parse within a `calc()` expression.
|
||||
///
|
||||
/// This is used as a hint for the parser to fast-reject invalid expressions.
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
enum CalcUnit {
|
||||
/// `<number>`
|
||||
Number,
|
||||
/// `<length>`
|
||||
Length,
|
||||
/// `<percentage>`
|
||||
Percentage,
|
||||
/// `<length> | <percentage>`
|
||||
LengthPercentage,
|
||||
/// `<angle>`
|
||||
Angle,
|
||||
/// `<time>`
|
||||
Time,
|
||||
bitflags! {
|
||||
/// Expected units we allow parsing within a `calc()` expression.
|
||||
///
|
||||
/// This is used as a hint for the parser to fast-reject invalid
|
||||
/// expressions. Numbers are always allowed because they multiply other
|
||||
/// units.
|
||||
struct CalcUnits: u8 {
|
||||
const LENGTH = 1 << 0;
|
||||
const PERCENTAGE = 1 << 1;
|
||||
const ANGLE = 1 << 2;
|
||||
const TIME = 1 << 3;
|
||||
|
||||
const LENGTH_PERCENTAGE = Self::LENGTH.bits | Self::PERCENTAGE.bits;
|
||||
// NOTE: When you add to this, make sure to make Atan2 deal with these.
|
||||
const ALL = Self::LENGTH.bits | Self::PERCENTAGE.bits | Self::ANGLE.bits | Self::TIME.bits;
|
||||
}
|
||||
}
|
||||
|
||||
/// A struct to hold a simplified `<length>` or `<percentage>` expression.
|
||||
|
@ -108,6 +118,27 @@ pub struct CalcLengthPercentage {
|
|||
pub node: CalcNode,
|
||||
}
|
||||
|
||||
impl CalcLengthPercentage {
|
||||
fn same_unit_length_as(a: &Self, b: &Self) -> Option<(CSSFloat, CSSFloat)> {
|
||||
use generic::CalcNodeLeaf;
|
||||
|
||||
debug_assert_eq!(a.clamping_mode, b.clamping_mode);
|
||||
debug_assert_eq!(a.clamping_mode, AllowedNumericType::All);
|
||||
|
||||
let a = a.node.as_leaf()?;
|
||||
let b = b.node.as_leaf()?;
|
||||
|
||||
if a.sort_key() != b.sort_key() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let a = a.as_length()?.unitless_value();
|
||||
let b = b.as_length()?.unitless_value();
|
||||
return Some((a, b))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl SpecifiedValueInfo for CalcLengthPercentage {}
|
||||
|
||||
impl PartialOrd for Leaf {
|
||||
|
@ -277,71 +308,47 @@ pub type CalcNode = generic::GenericCalcNode<Leaf>;
|
|||
impl CalcNode {
|
||||
/// Tries to parse a single element in the expression, that is, a
|
||||
/// `<length>`, `<angle>`, `<time>`, `<percentage>`, according to
|
||||
/// `expected_unit`.
|
||||
/// `allowed_units`.
|
||||
///
|
||||
/// May return a "complex" `CalcNode`, in the presence of a parenthesized
|
||||
/// expression, for example.
|
||||
fn parse_one<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
expected_unit: CalcUnit,
|
||||
allowed_units: CalcUnits,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let location = input.current_source_location();
|
||||
match (input.next()?, expected_unit) {
|
||||
(&Token::Number { value, .. }, _) => Ok(CalcNode::Leaf(Leaf::Number(value))),
|
||||
(
|
||||
&Token::Dimension {
|
||||
value, ref unit, ..
|
||||
},
|
||||
CalcUnit::Length,
|
||||
) |
|
||||
(
|
||||
&Token::Dimension {
|
||||
value, ref unit, ..
|
||||
},
|
||||
CalcUnit::LengthPercentage,
|
||||
) => match NoCalcLength::parse_dimension(context, value, unit) {
|
||||
Ok(l) => Ok(CalcNode::Leaf(Leaf::Length(l))),
|
||||
Err(()) => Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
|
||||
},
|
||||
(
|
||||
&Token::Dimension {
|
||||
value, ref unit, ..
|
||||
},
|
||||
CalcUnit::Angle,
|
||||
) => {
|
||||
match Angle::parse_dimension(value, unit, /* from_calc = */ true) {
|
||||
Ok(a) => Ok(CalcNode::Leaf(Leaf::Angle(a))),
|
||||
Err(()) => {
|
||||
Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||
},
|
||||
match input.next()? {
|
||||
&Token::Number { value, .. } => Ok(CalcNode::Leaf(Leaf::Number(value))),
|
||||
&Token::Dimension { value, ref unit, .. } => {
|
||||
if allowed_units.intersects(CalcUnits::LENGTH) {
|
||||
if let Ok(l) = NoCalcLength::parse_dimension(context, value, unit) {
|
||||
return Ok(CalcNode::Leaf(Leaf::Length(l)));
|
||||
}
|
||||
}
|
||||
},
|
||||
(
|
||||
&Token::Dimension {
|
||||
value, ref unit, ..
|
||||
},
|
||||
CalcUnit::Time,
|
||||
) => {
|
||||
match Time::parse_dimension(value, unit, /* from_calc = */ true) {
|
||||
Ok(t) => Ok(CalcNode::Leaf(Leaf::Time(t))),
|
||||
Err(()) => {
|
||||
Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||
},
|
||||
if allowed_units.intersects(CalcUnits::ANGLE) {
|
||||
if let Ok(a) = Angle::parse_dimension(value, unit, /* from_calc = */ true) {
|
||||
return Ok(CalcNode::Leaf(Leaf::Angle(a)));
|
||||
}
|
||||
}
|
||||
if allowed_units.intersects(CalcUnits::TIME) {
|
||||
if let Ok(t) = Time::parse_dimension(value, unit, /* from_calc = */ true) {
|
||||
return Ok(CalcNode::Leaf(Leaf::Time(t)));
|
||||
}
|
||||
}
|
||||
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||
},
|
||||
(&Token::Percentage { unit_value, .. }, CalcUnit::LengthPercentage) |
|
||||
(&Token::Percentage { unit_value, .. }, CalcUnit::Percentage) => {
|
||||
&Token::Percentage { unit_value, .. } if allowed_units.intersects(CalcUnits::PERCENTAGE) => {
|
||||
Ok(CalcNode::Leaf(Leaf::Percentage(unit_value)))
|
||||
},
|
||||
(&Token::ParenthesisBlock, _) => input.parse_nested_block(|input| {
|
||||
CalcNode::parse_argument(context, input, expected_unit)
|
||||
}
|
||||
&Token::ParenthesisBlock => input.parse_nested_block(|input| {
|
||||
CalcNode::parse_argument(context, input, allowed_units)
|
||||
}),
|
||||
(&Token::Function(ref name), _) => {
|
||||
&Token::Function(ref name) => {
|
||||
let function = CalcNode::math_function(name, location)?;
|
||||
CalcNode::parse(context, input, function, expected_unit)
|
||||
CalcNode::parse(context, input, function, allowed_units)
|
||||
},
|
||||
(&Token::Ident(ref ident), _) => {
|
||||
&Token::Ident(ref ident) => {
|
||||
if !trig_enabled() {
|
||||
return Err(location.new_unexpected_token_error(Token::Ident(ident.clone())));
|
||||
}
|
||||
|
@ -352,7 +359,7 @@ impl CalcNode {
|
|||
};
|
||||
Ok(CalcNode::Leaf(Leaf::Number(number)))
|
||||
},
|
||||
(t, _) => Err(location.new_unexpected_token_error(t.clone())),
|
||||
t => Err(location.new_unexpected_token_error(t.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -363,20 +370,20 @@ impl CalcNode {
|
|||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
function: MathFunction,
|
||||
expected_unit: CalcUnit,
|
||||
allowed_units: CalcUnits,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
// TODO: Do something different based on the function name. In
|
||||
// particular, for non-calc function we need to take a list of
|
||||
// comma-separated arguments and such.
|
||||
input.parse_nested_block(|input| {
|
||||
match function {
|
||||
MathFunction::Calc => Self::parse_argument(context, input, expected_unit),
|
||||
MathFunction::Calc => Self::parse_argument(context, input, allowed_units),
|
||||
MathFunction::Clamp => {
|
||||
let min = Self::parse_argument(context, input, expected_unit)?;
|
||||
let min = Self::parse_argument(context, input, allowed_units)?;
|
||||
input.expect_comma()?;
|
||||
let center = Self::parse_argument(context, input, expected_unit)?;
|
||||
let center = Self::parse_argument(context, input, allowed_units)?;
|
||||
input.expect_comma()?;
|
||||
let max = Self::parse_argument(context, input, expected_unit)?;
|
||||
let max = Self::parse_argument(context, input, allowed_units)?;
|
||||
Ok(Self::Clamp {
|
||||
min: Box::new(min),
|
||||
center: Box::new(center),
|
||||
|
@ -390,7 +397,7 @@ impl CalcNode {
|
|||
// Consider adding an API to cssparser to specify the
|
||||
// initial vector capacity?
|
||||
let arguments = input.parse_comma_separated(|input| {
|
||||
Self::parse_argument(context, input, expected_unit)
|
||||
Self::parse_argument(context, input, allowed_units)
|
||||
})?;
|
||||
|
||||
let op = match function {
|
||||
|
@ -402,7 +409,7 @@ impl CalcNode {
|
|||
Ok(Self::MinMax(arguments.into(), op))
|
||||
},
|
||||
MathFunction::Sin | MathFunction::Cos | MathFunction::Tan => {
|
||||
let argument = Self::parse_argument(context, input, CalcUnit::Angle)?;
|
||||
let argument = Self::parse_argument(context, input, CalcUnits::ANGLE)?;
|
||||
let radians = match argument.to_number() {
|
||||
Ok(v) => v,
|
||||
Err(()) => match argument.to_angle() {
|
||||
|
@ -425,7 +432,7 @@ impl CalcNode {
|
|||
Ok(Self::Leaf(Leaf::Number(number)))
|
||||
},
|
||||
MathFunction::Asin | MathFunction::Acos | MathFunction::Atan => {
|
||||
let argument = Self::parse_argument(context, input, CalcUnit::Number)?;
|
||||
let argument = Self::parse_argument(context, input, CalcUnits::empty())?;
|
||||
let number = match argument.to_number() {
|
||||
Ok(v) => v,
|
||||
Err(()) => {
|
||||
|
@ -444,6 +451,46 @@ impl CalcNode {
|
|||
},
|
||||
};
|
||||
|
||||
Ok(Self::Leaf(Leaf::Angle(Angle::from_radians(radians))))
|
||||
},
|
||||
MathFunction::Atan2 => {
|
||||
let a = Self::parse_argument(context, input, CalcUnits::ALL)?;
|
||||
input.expect_comma()?;
|
||||
let b = Self::parse_argument(context, input, CalcUnits::ALL)?;
|
||||
fn resolve_atan2(a: CalcNode, b: CalcNode) -> Result<CSSFloat, ()> {
|
||||
if let Ok(a) = a.to_number() {
|
||||
let b = b.to_number()?;
|
||||
return Ok(a.atan2(b));
|
||||
}
|
||||
|
||||
if let Ok(a) = a.to_percentage() {
|
||||
let b = b.to_percentage()?;
|
||||
return Ok(a.atan2(b));
|
||||
}
|
||||
|
||||
if let Ok(a) = a.to_time() {
|
||||
let b = b.to_time()?;
|
||||
return Ok(a.seconds().atan2(b.seconds()));
|
||||
}
|
||||
|
||||
if let Ok(a) = a.to_angle() {
|
||||
let b = b.to_angle()?;
|
||||
return Ok(a.radians().atan2(b.radians()));
|
||||
}
|
||||
|
||||
let a = a.into_length_or_percentage(AllowedNumericType::All)?;
|
||||
let b = b.into_length_or_percentage(AllowedNumericType::All)?;
|
||||
let (a, b) = CalcLengthPercentage::same_unit_length_as(&a, &b).ok_or(())?;
|
||||
return Ok(a.atan2(b));
|
||||
}
|
||||
|
||||
let radians = match resolve_atan2(a, b) {
|
||||
Ok(v) => v,
|
||||
Err(()) => return Err(
|
||||
input.new_custom_error(StyleParseErrorKind::UnspecifiedError)
|
||||
),
|
||||
};
|
||||
|
||||
Ok(Self::Leaf(Leaf::Angle(Angle::from_radians(radians))))
|
||||
},
|
||||
}
|
||||
|
@ -453,10 +500,10 @@ impl CalcNode {
|
|||
fn parse_argument<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
expected_unit: CalcUnit,
|
||||
allowed_units: CalcUnits,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let mut sum = SmallVec::<[CalcNode; 1]>::new();
|
||||
sum.push(Self::parse_product(context, input, expected_unit)?);
|
||||
sum.push(Self::parse_product(context, input, allowed_units)?);
|
||||
|
||||
loop {
|
||||
let start = input.state();
|
||||
|
@ -467,10 +514,10 @@ impl CalcNode {
|
|||
}
|
||||
match *input.next()? {
|
||||
Token::Delim('+') => {
|
||||
sum.push(Self::parse_product(context, input, expected_unit)?);
|
||||
sum.push(Self::parse_product(context, input, allowed_units)?);
|
||||
},
|
||||
Token::Delim('-') => {
|
||||
let mut rhs = Self::parse_product(context, input, expected_unit)?;
|
||||
let mut rhs = Self::parse_product(context, input, allowed_units)?;
|
||||
rhs.negate();
|
||||
sum.push(rhs);
|
||||
},
|
||||
|
@ -506,15 +553,15 @@ impl CalcNode {
|
|||
fn parse_product<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
expected_unit: CalcUnit,
|
||||
allowed_units: CalcUnits,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let mut node = Self::parse_one(context, input, expected_unit)?;
|
||||
let mut node = Self::parse_one(context, input, allowed_units)?;
|
||||
|
||||
loop {
|
||||
let start = input.state();
|
||||
match input.next() {
|
||||
Ok(&Token::Delim('*')) => {
|
||||
let rhs = Self::parse_one(context, input, expected_unit)?;
|
||||
let rhs = Self::parse_one(context, input, allowed_units)?;
|
||||
if let Ok(rhs) = rhs.to_number() {
|
||||
node.mul_by(rhs);
|
||||
} else if let Ok(number) = node.to_number() {
|
||||
|
@ -527,7 +574,7 @@ impl CalcNode {
|
|||
}
|
||||
},
|
||||
Ok(&Token::Delim('/')) => {
|
||||
let rhs = Self::parse_one(context, input, expected_unit)?;
|
||||
let rhs = Self::parse_one(context, input, allowed_units)?;
|
||||
// Dividing by units is not ok.
|
||||
//
|
||||
// TODO(emilio): Eventually it should be.
|
||||
|
@ -627,7 +674,7 @@ impl CalcNode {
|
|||
},
|
||||
};
|
||||
|
||||
if matches!(function, Sin | Cos | Tan | Asin | Acos | Atan) && !trig_enabled() {
|
||||
if matches!(function, Sin | Cos | Tan | Asin | Acos | Atan | Atan2) && !trig_enabled() {
|
||||
return Err(location.new_unexpected_token_error(Token::Function(name.clone())));
|
||||
}
|
||||
|
||||
|
@ -650,7 +697,7 @@ impl CalcNode {
|
|||
clamping_mode: AllowedNumericType,
|
||||
function: MathFunction,
|
||||
) -> Result<CalcLengthPercentage, ParseError<'i>> {
|
||||
Self::parse(context, input, function, CalcUnit::LengthPercentage)?
|
||||
Self::parse(context, input, function, CalcUnits::LENGTH_PERCENTAGE)?
|
||||
.into_length_or_percentage(clamping_mode)
|
||||
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||
}
|
||||
|
@ -661,7 +708,7 @@ impl CalcNode {
|
|||
input: &mut Parser<'i, 't>,
|
||||
function: MathFunction,
|
||||
) -> Result<CSSFloat, ParseError<'i>> {
|
||||
Self::parse(context, input, function, CalcUnit::Percentage)?
|
||||
Self::parse(context, input, function, CalcUnits::PERCENTAGE)?
|
||||
.to_percentage()
|
||||
.map(crate::values::normalize)
|
||||
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||
|
@ -674,7 +721,7 @@ impl CalcNode {
|
|||
clamping_mode: AllowedNumericType,
|
||||
function: MathFunction,
|
||||
) -> Result<CalcLengthPercentage, ParseError<'i>> {
|
||||
Self::parse(context, input, function, CalcUnit::Length)?
|
||||
Self::parse(context, input, function, CalcUnits::LENGTH)?
|
||||
.into_length_or_percentage(clamping_mode)
|
||||
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||
}
|
||||
|
@ -685,7 +732,7 @@ impl CalcNode {
|
|||
input: &mut Parser<'i, 't>,
|
||||
function: MathFunction,
|
||||
) -> Result<CSSFloat, ParseError<'i>> {
|
||||
Self::parse(context, input, function, CalcUnit::Number)?
|
||||
Self::parse(context, input, function, CalcUnits::empty())?
|
||||
.to_number()
|
||||
.map(crate::values::normalize)
|
||||
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||
|
@ -697,7 +744,7 @@ impl CalcNode {
|
|||
input: &mut Parser<'i, 't>,
|
||||
function: MathFunction,
|
||||
) -> Result<Angle, ParseError<'i>> {
|
||||
Self::parse(context, input, function, CalcUnit::Angle)?
|
||||
Self::parse(context, input, function, CalcUnits::ANGLE)?
|
||||
.to_angle()
|
||||
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||
}
|
||||
|
@ -708,7 +755,7 @@ impl CalcNode {
|
|||
input: &mut Parser<'i, 't>,
|
||||
function: MathFunction,
|
||||
) -> Result<Time, ParseError<'i>> {
|
||||
Self::parse(context, input, function, CalcUnit::Time)?
|
||||
Self::parse(context, input, function, CalcUnits::TIME)?
|
||||
.to_time()
|
||||
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||
}
|
||||
|
@ -719,7 +766,7 @@ impl CalcNode {
|
|||
input: &mut Parser<'i, 't>,
|
||||
function: MathFunction,
|
||||
) -> Result<NumberOrPercentage, ParseError<'i>> {
|
||||
let node = Self::parse(context, input, function, CalcUnit::Percentage)?;
|
||||
let node = Self::parse(context, input, function, CalcUnits::PERCENTAGE)?;
|
||||
|
||||
if let Ok(value) = node.to_number() {
|
||||
return Ok(NumberOrPercentage::Number { value });
|
||||
|
@ -737,7 +784,7 @@ impl CalcNode {
|
|||
input: &mut Parser<'i, 't>,
|
||||
function: MathFunction,
|
||||
) -> Result<AngleOrNumber, ParseError<'i>> {
|
||||
let node = Self::parse(context, input, function, CalcUnit::Angle)?;
|
||||
let node = Self::parse(context, input, function, CalcUnits::ANGLE)?;
|
||||
|
||||
if let Ok(angle) = node.to_angle() {
|
||||
let degrees = angle.degrees();
|
||||
|
|
|
@ -90,25 +90,23 @@ impl FontBaseSize {
|
|||
impl FontRelativeLength {
|
||||
/// Return true if this is a zero value.
|
||||
fn is_zero(&self) -> bool {
|
||||
self.unitless_value() == 0.
|
||||
}
|
||||
|
||||
/// Return the unitless, raw value.
|
||||
fn unitless_value(&self) -> CSSFloat {
|
||||
match *self {
|
||||
FontRelativeLength::Em(v) |
|
||||
FontRelativeLength::Ex(v) |
|
||||
FontRelativeLength::Ch(v) |
|
||||
FontRelativeLength::Cap(v) |
|
||||
FontRelativeLength::Ic(v) |
|
||||
FontRelativeLength::Rem(v) => v == 0.,
|
||||
FontRelativeLength::Rem(v) => v,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_negative(&self) -> bool {
|
||||
match *self {
|
||||
FontRelativeLength::Em(v) |
|
||||
FontRelativeLength::Ex(v) |
|
||||
FontRelativeLength::Ch(v) |
|
||||
FontRelativeLength::Cap(v) |
|
||||
FontRelativeLength::Ic(v) |
|
||||
FontRelativeLength::Rem(v) => v < 0.,
|
||||
}
|
||||
self.unitless_value() < 0.
|
||||
}
|
||||
|
||||
fn try_sum(&self, other: &Self) -> Result<Self, ()> {
|
||||
|
@ -388,13 +386,16 @@ pub enum ViewportPercentageLength {
|
|||
impl ViewportPercentageLength {
|
||||
/// Return true if this is a zero value.
|
||||
fn is_zero(&self) -> bool {
|
||||
let (_, _, v) = self.unpack();
|
||||
v == 0.
|
||||
self.unitless_value() == 0.
|
||||
}
|
||||
|
||||
fn is_negative(&self) -> bool {
|
||||
let (_, _, v) = self.unpack();
|
||||
v < 0.
|
||||
self.unitless_value() < 0.
|
||||
}
|
||||
|
||||
/// Return the unitless, raw value.
|
||||
fn unitless_value(&self) -> CSSFloat {
|
||||
self.unpack().2
|
||||
}
|
||||
|
||||
fn unpack(&self) -> (ViewportVariant, ViewportUnit, CSSFloat) {
|
||||
|
@ -642,7 +643,8 @@ pub enum AbsoluteLength {
|
|||
}
|
||||
|
||||
impl AbsoluteLength {
|
||||
fn is_zero(&self) -> bool {
|
||||
/// Return the unitless, raw value.
|
||||
fn unitless_value(&self) -> CSSFloat {
|
||||
match *self {
|
||||
AbsoluteLength::Px(v) |
|
||||
AbsoluteLength::In(v) |
|
||||
|
@ -650,20 +652,16 @@ impl AbsoluteLength {
|
|||
AbsoluteLength::Mm(v) |
|
||||
AbsoluteLength::Q(v) |
|
||||
AbsoluteLength::Pt(v) |
|
||||
AbsoluteLength::Pc(v) => v == 0.,
|
||||
AbsoluteLength::Pc(v) => v,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.unitless_value() == 0.
|
||||
}
|
||||
|
||||
fn is_negative(&self) -> bool {
|
||||
match *self {
|
||||
AbsoluteLength::Px(v) |
|
||||
AbsoluteLength::In(v) |
|
||||
AbsoluteLength::Cm(v) |
|
||||
AbsoluteLength::Mm(v) |
|
||||
AbsoluteLength::Q(v) |
|
||||
AbsoluteLength::Pt(v) |
|
||||
AbsoluteLength::Pc(v) => v < 0.,
|
||||
}
|
||||
self.unitless_value() < 0.
|
||||
}
|
||||
|
||||
/// Convert this into a pixel value.
|
||||
|
@ -780,6 +778,16 @@ impl Mul<CSSFloat> for NoCalcLength {
|
|||
}
|
||||
|
||||
impl NoCalcLength {
|
||||
/// Return the unitless, raw value.
|
||||
pub fn unitless_value(&self) -> CSSFloat {
|
||||
match *self {
|
||||
NoCalcLength::Absolute(v) => v.unitless_value(),
|
||||
NoCalcLength::FontRelative(v) => v.unitless_value(),
|
||||
NoCalcLength::ViewportPercentage(v) => v.unitless_value(),
|
||||
NoCalcLength::ServoCharacterWidth(c) => c.0 as f32,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the value of this length without unit is less than zero.
|
||||
pub fn is_negative(&self) -> bool {
|
||||
match *self {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue