servo: Merge #17731 - style: Respect calc for percentages (from emilio:percentage-calc); r=nox

Source-Repo: https://github.com/servo/servo
Source-Revision: 2d37700cf819d901552cfb3954e948f1fbadcf78

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 375b4076885e4a0de0333329409bf6662d2d394b
This commit is contained in:
Emilio Cobos Álvarez 2017-07-17 01:29:11 -07:00
parent af81788010
commit b49ad75e0f
28 changed files with 308 additions and 176 deletions

View File

@ -56,7 +56,7 @@ use style::properties::longhands::border_image_repeat::computed_value::RepeatKey
use style::properties::style_structs;
use style::servo::restyle_damage::REPAINT;
use style::values::{Either, RGBA};
use style::values::computed::{Angle, Gradient, GradientItem, LengthOrPercentage};
use style::values::computed::{Angle, Gradient, GradientItem, LengthOrPercentage, Percentage};
use style::values::computed::{LengthOrPercentageOrAuto, NumberOrPercentage, Position};
use style::values::computed::effects::SimpleShadow;
use style::values::computed::image::{EndingShape, LineDirection};
@ -66,7 +66,6 @@ use style::values::generics::image::{Circle, Ellipse, EndingShape as GenericEndi
use style::values::generics::image::{GradientItem as GenericGradientItem, GradientKind};
use style::values::generics::image::{Image, ShapeExtent};
use style::values::generics::image::PaintWorklet;
use style::values::specified::length::Percentage;
use style::values::specified::position::{X, Y};
use style_traits::CSSPixel;
use style_traits::cursor::Cursor;

View File

@ -113,7 +113,7 @@ use style::shared_lock::{SharedRwLock, Locked};
use style::stylearc::Arc;
use style::thread_state;
use style::values::{CSSFloat, Either};
use style::values::specified;
use style::values::{specified, computed};
use stylesheet_loader::StylesheetOwner;
// TODO: Update focus state when the top-level browsing context gains or loses system focus,
@ -576,7 +576,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
LengthOrPercentageOrAuto::Auto => {}
LengthOrPercentageOrAuto::Percentage(percentage) => {
let width_value =
specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(percentage));
specified::LengthOrPercentageOrAuto::Percentage(computed::Percentage(percentage));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Width(width_value)));
@ -605,7 +605,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
LengthOrPercentageOrAuto::Auto => {}
LengthOrPercentageOrAuto::Percentage(percentage) => {
let height_value =
specified::LengthOrPercentageOrAuto::Percentage(specified::Percentage(percentage));
specified::LengthOrPercentageOrAuto::Percentage(computed::Percentage(percentage));
hints.push(from_declaration(
shared_lock,
PropertyDeclaration::Height(height_value)));

View File

@ -18,11 +18,10 @@ use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordData
use std::f32::consts::PI;
use stylesheets::{Origin, RulesMutateError};
use values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image};
use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto, Percentage};
use values::generics::grid::TrackSize;
use values::generics::image::{CompatMode, Image as GenericImage, GradientItem};
use values::generics::rect::Rect;
use values::specified::length::Percentage;
use values::specified::url::SpecifiedUrl;
impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {

View File

@ -18,13 +18,12 @@ use std::cmp::max;
use values::{Auto, Either, ExtremumLength, None_, Normal};
use values::computed::{Angle, LengthOrPercentage, LengthOrPercentageOrAuto};
use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage};
use values::computed::{MaxLength, MozLength};
use values::computed::{MaxLength, MozLength, Percentage};
use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
use values::generics::CounterStyleOrNone;
use values::generics::basic_shape::ShapeRadius;
use values::generics::gecko::ScrollSnapPoint;
use values::generics::grid::{TrackBreadth, TrackKeyword};
use values::specified::Percentage;
/// A trait that defines an interface to convert from and to `nsStyleCoord`s.
pub trait GeckoStyleCoordConvertible : Sized {

View File

@ -14,8 +14,7 @@ use std::marker::PhantomData;
use std::mem;
use std::ops::{Index, IndexMut};
use std::slice;
use values::computed::{Angle, LengthOrPercentage};
use values::specified::length::Percentage;
use values::computed::{Angle, LengthOrPercentage, Percentage};
use values::specified::url::SpecifiedUrl;
impl nsCSSValue {

View File

@ -66,7 +66,7 @@ use std::cmp;
use values::{Auto, CustomIdent, Either, KeyframesName};
use values::computed::ToComputedValue;
use values::computed::effects::{BoxShadow, Filter, SimpleShadow};
use values::specified::length::Percentage;
use values::computed::length::Percentage;
use computed_values::border_style;
pub mod style_structs {

View File

@ -41,12 +41,11 @@ use values::animated::effects::TextShadowList as AnimatedTextShadowList;
use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
use values::computed::{BorderCornerRadius, ClipRect};
use values::computed::{CalcLengthOrPercentage, Color, Context, ComputedValueAsSpecified};
use values::computed::{LengthOrPercentage, MaxLength, MozLength, ToComputedValue};
use values::computed::{LengthOrPercentage, MaxLength, MozLength, Percentage, ToComputedValue};
use values::generics::{SVGPaint, SVGPaintKind};
use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
use values::generics::effects::Filter;
use values::generics::position as generic_position;
use values::specified::length::Percentage;
/// A longhand property whose animation type is not "none".
@ -1686,7 +1685,6 @@ fn add_weighted_transform_lists(from_list: &[TransformOperation],
}
}
} else {
use values::specified::Percentage;
let from_transform_list = TransformList(Some(from_list.to_vec()));
let to_transform_list = TransformList(Some(to_list.to_vec()));
result.push(

View File

@ -278,7 +278,7 @@ ${helpers.predefined_type("border-image-width", "BorderImageWidth",
${helpers.predefined_type("border-image-slice", "BorderImageSlice",
initial_value="computed::NumberOrPercentage::Percentage(computed::Percentage(1.)).into()",
initial_specified_value="specified::NumberOrPercentage::Percentage(specified::Percentage(1.)).into()",
initial_specified_value="specified::NumberOrPercentage::Percentage(specified::Percentage::new(1.)).into()",
spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice",
animation_value_type="discrete",
boxed=True)}

View File

@ -736,7 +736,7 @@ ${helpers.predefined_type(
use values::computed::{LengthOrPercentageOrNumber as ComputedLoPoNumber, LengthOrNumber as ComputedLoN};
use values::computed::{LengthOrPercentage as ComputedLoP, Length as ComputedLength};
use values::generics::transform::Matrix;
use values::specified::{Angle, Integer, Length, LengthOrPercentage, Percentage};
use values::specified::{Angle, Integer, Length, LengthOrPercentage};
use values::specified::{LengthOrNumber, LengthOrPercentageOrNumber as LoPoNumber, Number};
use style_traits::ToCss;
use style_traits::values::Css;
@ -747,7 +747,7 @@ ${helpers.predefined_type(
use app_units::Au;
use values::CSSFloat;
use values::computed;
use values::computed::{Length, LengthOrPercentage, Percentage};
use values::computed::{Length, LengthOrPercentage};
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@ -817,7 +817,7 @@ ${helpers.predefined_type(
// progress: ... } ]
InterpolateMatrix { from_list: T,
to_list: T,
progress: Percentage },
progress: computed::Percentage },
// For accumulate operation of mismatched transform lists.
AccumulateMatrix { from_list: T,
to_list: T,
@ -904,7 +904,7 @@ ${helpers.predefined_type(
/// A intermediate type for interpolation of mismatched transform lists.
InterpolateMatrix { from_list: SpecifiedValue,
to_list: SpecifiedValue,
progress: Percentage },
progress: computed::Percentage },
/// A intermediate type for accumulation of mismatched transform lists.
AccumulateMatrix { from_list: SpecifiedValue,
to_list: SpecifiedValue,

View File

@ -566,8 +566,7 @@ ${helpers.single_keyword_system("font-variant-caps",
use std::fmt;
use style_traits::{HasViewportPercentage, ToCss};
use values::FONT_MEDIUM_PX;
use values::specified::{AllowQuirks, FontRelativeLength, LengthOrPercentage};
use values::specified::{NoCalcLength, Percentage};
use values::specified::{AllowQuirks, FontRelativeLength, LengthOrPercentage, NoCalcLength};
use values::specified::length::FontBaseSize;
impl ToCss for SpecifiedValue {
@ -810,8 +809,8 @@ ${helpers.single_keyword_system("font-variant-caps",
SpecifiedValue::Length(LengthOrPercentage::Length(ref l)) => {
l.to_computed_value(context)
}
SpecifiedValue::Length(LengthOrPercentage::Percentage(Percentage(value))) => {
base_size.resolve(context).scale_by(value)
SpecifiedValue::Length(LengthOrPercentage::Percentage(pc)) => {
base_size.resolve(context).scale_by(pc.0)
}
SpecifiedValue::Length(LengthOrPercentage::Calc(ref calc)) => {
let calc = calc.to_computed_value(context);

View File

@ -12,11 +12,52 @@ 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};
use values::specified::length::{Percentage, ViewportPercentageLength};
use values::specified::length::ViewportPercentageLength;
pub use super::image::Image;
pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
/// A computed `<percentage>` value.
///
/// FIXME(emilio): why is this in length.rs?
#[derive(Clone, Copy, Debug, Default, PartialEq, HasViewportPercentage)]
#[cfg_attr(feature = "servo", derive(Deserialize, HeapSizeOf, Serialize))]
pub struct Percentage(pub CSSFloat);
impl Percentage {
/// 0%
#[inline]
pub fn zero() -> Self {
Percentage(0.)
}
/// 100%
#[inline]
pub fn hundred() -> Self {
Percentage(1.)
}
}
impl ToCss for Percentage {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
write!(dest, "{}%", self.0 * 100.)
}
}
impl ToComputedValue for specified::Percentage {
type ComputedValue = Percentage;
#[inline]
fn to_computed_value(&self, _: &Context) -> Percentage {
Percentage(self.get())
}
#[inline]
fn from_computed_value(computed: &Percentage) -> Self {
specified::Percentage::new(computed.0)
}
}
impl ToComputedValue for specified::NoCalcLength {
type ComputedValue = Au;

View File

@ -38,11 +38,11 @@ pub use self::rect::LengthOrNumberRect;
pub use super::{Auto, Either, None_};
#[cfg(feature = "gecko")]
pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
pub use super::specified::{BorderStyle, Percentage, UrlOrNone};
pub use super::specified::{BorderStyle, UrlOrNone};
pub use super::generics::grid::GridLine;
pub use super::specified::url::SpecifiedUrl;
pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNone, LengthOrNumber, LengthOrPercentage};
pub use self::length::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, MaxLength, MozLength};
pub use self::length::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, MaxLength, MozLength, Percentage};
pub use self::position::Position;
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing};
pub use self::transform::{TimingFunction, TransformOrigin};

View File

@ -9,9 +9,8 @@
use std::fmt;
use style_traits::ToCss;
use values::computed::LengthOrPercentage;
use values::computed::{LengthOrPercentage, Percentage};
use values::generics::position::Position as GenericPosition;
use values::specified::length::Percentage;
/// The computed value of a CSS `<position>`
pub type Position = GenericPosition<HorizontalPosition, VerticalPosition>;

View File

@ -5,10 +5,9 @@
//! Computed types for CSS values that are related to transformations.
use properties::animated_properties::Animatable;
use values::computed::{Length, LengthOrPercentage, Number};
use values::computed::{Length, LengthOrPercentage, Number, Percentage};
use values::generics::transform::TimingFunction as GenericTimingFunction;
use values::generics::transform::TransformOrigin as GenericTransformOrigin;
use values::specified::length::Percentage;
/// The computed value of a CSS `<transform-origin>`
pub type TransformOrigin = GenericTransformOrigin<LengthOrPercentage, LengthOrPercentage, Length>;

View File

@ -4,7 +4,7 @@
//! Generic types for CSS values related to flexbox.
use values::specified::Percentage;
use values::computed::Percentage;
/// A generic value for the `flex-basis` property.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]

View File

@ -12,6 +12,7 @@ use parser::{Parse, ParserContext};
use std::borrow::Cow;
use std::fmt;
use style_traits::{ToCss, ParseError, StyleParseError};
use values::computed::Percentage;
use values::generics::basic_shape::{Circle as GenericCircle};
use values::generics::basic_shape::{ClippingShape as GenericClippingShape, Ellipse as GenericEllipse};
use values::generics::basic_shape::{FillRule, BasicShape as GenericBasicShape};
@ -19,7 +20,7 @@ use values::generics::basic_shape::{FloatAreaShape as GenericFloatAreaShape, Ins
use values::generics::basic_shape::{GeometryBox, ShapeBox, ShapeSource};
use values::generics::basic_shape::{Polygon as GenericPolygon, ShapeRadius as GenericShapeRadius};
use values::generics::rect::Rect;
use values::specified::{LengthOrPercentage, Percentage};
use values::specified::LengthOrPercentage;
use values::specified::border::BorderRadius;
use values::specified::position::{HorizontalPosition, Position, PositionComponent, Side, VerticalPosition};
use values::specified::url::SpecifiedUrl;

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())

View File

@ -4,7 +4,7 @@
//! Specified types for CSS values related to effects.
use cssparser::{BasicParseError, Parser, Token};
use cssparser::Parser;
use parser::{Parse, ParserContext};
use style_traits::{ParseError, StyleParseError};
#[cfg(not(feature = "gecko"))]
@ -15,7 +15,7 @@ use values::computed::effects::SimpleShadow as ComputedSimpleShadow;
use values::generics::effects::BoxShadow as GenericBoxShadow;
use values::generics::effects::Filter as GenericFilter;
use values::generics::effects::SimpleShadow as GenericSimpleShadow;
use values::specified::{Angle, Percentage};
use values::specified::{Angle, NumberOrPercentage};
use values::specified::color::Color;
use values::specified::length::Length;
#[cfg(feature = "gecko")]
@ -33,15 +33,36 @@ pub type Filter = GenericFilter<Angle, Factor, Length, SimpleShadow>;
pub type Filter = GenericFilter<Angle, Factor, Length, Impossible>;
/// A value for the `<factor>` parts in `Filter`.
///
/// FIXME: Should be `NumberOrPercentage`, but Gecko doesn't support that yet.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
pub enum Factor {
/// Literal number.
Number(ComputedNumber),
/// Literal percentage.
Percentage(Percentage),
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Factor(NumberOrPercentage);
impl Parse for Factor {
#[inline]
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<Self, ParseError<'i>> {
NumberOrPercentage::parse_non_negative(context, input).map(Factor)
}
}
impl ToComputedValue for Factor {
type ComputedValue = ComputedNumber;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
use values::computed::NumberOrPercentage;
match self.0.to_computed_value(context) {
NumberOrPercentage::Number(n) => n,
NumberOrPercentage::Percentage(p) => p.0,
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Factor(NumberOrPercentage::Number(ToComputedValue::from_computed_value(computed)))
}
}
/// A specified value for the `drop-shadow()` filter.
@ -156,43 +177,6 @@ impl Parse for Filter {
}
}
impl Parse for Factor {
#[inline]
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<Self, ParseError<'i>> {
match input.next()? {
Token::Number { value, .. } if value.is_sign_positive() => {
Ok(Factor::Number(value))
},
Token::Percentage { unit_value, .. } if unit_value.is_sign_positive() => {
Ok(Factor::Percentage(Percentage(unit_value)))
},
other => Err(BasicParseError::UnexpectedToken(other).into()),
}
}
}
impl ToComputedValue for Factor {
/// This should actually be `ComputedNumberOrPercentage`, but layout uses
/// `computed::effects::Filter` directly in `StackingContext`.
type ComputedValue = ComputedNumber;
#[inline]
fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue {
match *self {
Factor::Number(number) => number,
Factor::Percentage(percentage) => percentage.0,
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Factor::Number(*computed)
}
}
impl Parse for SimpleShadow {
#[inline]
fn parse<'i, 't>(

View File

@ -330,10 +330,10 @@ impl Gradient {
impl<S: Side> From<Component<S>> for NumberOrPercentage {
fn from(component: Component<S>) -> Self {
match component {
Component::Center => NumberOrPercentage::Percentage(Percentage(0.5)),
Component::Center => NumberOrPercentage::Percentage(Percentage::new(0.5)),
Component::Number(number) => number,
Component::Side(side) => {
let p = Percentage(if side.is_start() { 0. } else { 1. });
let p = if side.is_start() { Percentage::zero() } else { Percentage::hundred() };
NumberOrPercentage::Percentage(p)
},
}
@ -363,7 +363,7 @@ impl Gradient {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (NumberOrPercentage::from(*self), NumberOrPercentage::from(*other)) {
(NumberOrPercentage::Percentage(a), NumberOrPercentage::Percentage(b)) => {
a.0.partial_cmp(&b.0)
a.get().partial_cmp(&b.get())
},
(NumberOrPercentage::Number(a), NumberOrPercentage::Number(b)) => {
a.value.partial_cmp(&b.value)
@ -444,14 +444,14 @@ impl Gradient {
let p = match_ignore_ascii_case! { &function,
"color-stop" => {
let p = match NumberOrPercentage::parse(context, i)? {
NumberOrPercentage::Number(number) => number.value,
NumberOrPercentage::Percentage(p) => p.0,
NumberOrPercentage::Number(number) => Percentage::new(number.value),
NumberOrPercentage::Percentage(p) => p,
};
i.expect_comma()?;
p
},
"from" => 0.,
"to" => 1.,
"from" => Percentage::zero(),
"to" => Percentage::hundred(),
_ => return Err(StyleParseError::UnexpectedFunction(function.clone()).into()),
};
let color = Color::parse(context, i)?;
@ -461,11 +461,11 @@ impl Gradient {
Ok((color.into(), p))
})?;
if reverse_stops {
p = 1. - p;
p.reverse();
}
Ok(GenericGradientItem::ColorStop(GenericColorStop {
color: color,
position: Some(LengthOrPercentage::Percentage(Percentage(p))),
position: Some(p.into()),
}))
})
}).unwrap_or(vec![]);
@ -474,11 +474,11 @@ impl Gradient {
items = vec![
GenericGradientItem::ColorStop(GenericColorStop {
color: Color::transparent().into(),
position: Some(Percentage(0.).into()),
position: Some(Percentage::zero().into()),
}),
GenericGradientItem::ColorStop(GenericColorStop {
color: Color::transparent().into(),
position: Some(Percentage(1.).into()),
position: Some(Percentage::hundred().into()),
}),
];
} else if items.len() == 1 {

View File

@ -20,7 +20,7 @@ use stylesheets::CssRuleType;
use super::{AllowQuirks, Number, ToComputedValue};
use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, None_, Normal};
use values::ExtremumLength;
use values::computed::{ComputedValueAsSpecified, Context};
use values::computed::{self, Context};
use values::specified::calc::CalcNode;
pub use values::specified::calc::CalcLengthOrPercentage;
@ -701,39 +701,81 @@ impl<T: Parse> Either<Length, T> {
}
/// A percentage value.
///
/// [0 .. 100%] maps to [0.0 .. 1.0]
///
/// FIXME(emilio): There's no standard property that requires a `<percentage>`
/// without requiring also a `<length>`. If such a property existed, we'd need
/// to add special handling for `calc()` and percentages in here in the same way
/// as for `Angle` and `Time`, but the lack of this this is otherwise
/// undistinguishable (we handle it correctly from `CalcLengthOrPercentage`).
///
/// As of today, only `-moz-image-rect` supports percentages without length.
/// This is not a regression, and that's a non-standard extension anyway, so I'm
/// not implementing it for now.
#[derive(Clone, Copy, Debug, Default, HasViewportPercentage, PartialEq)]
#[cfg_attr(feature = "servo", derive(Deserialize, HeapSizeOf, Serialize))]
pub struct Percentage(pub CSSFloat);
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Percentage {
/// The percentage value as a float.
///
/// [0 .. 100%] maps to [0.0 .. 1.0]
value: CSSFloat,
/// If this percentage came from a calc() expression, this tells how
/// clamping should be done on the value.
calc_clamping_mode: Option<AllowedNumericType>,
}
no_viewport_percentage!(Percentage);
impl ToCss for Percentage {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write,
{
write!(dest, "{}%", self.0 * 100.)
if self.calc_clamping_mode.is_some() {
dest.write_str("calc(")?;
}
write!(dest, "{}%", self.value * 100.)?;
if self.calc_clamping_mode.is_some() {
dest.write_str(")")?;
}
Ok(())
}
}
impl Percentage {
/// Create a percentage from a numeric value.
pub fn new(value: CSSFloat) -> Self {
Self {
value,
calc_clamping_mode: None,
}
}
/// Get the underlying value for this float.
pub fn get(&self) -> CSSFloat {
self.calc_clamping_mode.map_or(self.value, |mode| mode.clamp(self.value))
}
/// Reverse this percentage, preserving calc-ness.
///
/// For example: If it was 20%, convert it into 80%.
pub fn reverse(&mut self) {
let new_value = 1. - self.value;
self.value = new_value;
}
/// Parse a specific kind of percentage.
pub fn parse_with_clamping_mode<'i, 't>(context: &ParserContext,
input: &mut Parser<'i, 't>,
num_context: AllowedNumericType)
-> Result<Self, ParseError<'i>> {
pub fn parse_with_clamping_mode<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
num_context: AllowedNumericType,
) -> Result<Self, ParseError<'i>> {
match input.next()? {
Token::Percentage { unit_value, .. } if num_context.is_ok(context.parsing_mode, unit_value) => {
Ok(Percentage(unit_value))
Ok(Percentage::new(unit_value))
}
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
let result = input.parse_nested_block(|i| {
CalcNode::parse_percentage(context, i)
})?;
// TODO(emilio): -moz-image-rect is the only thing that uses
// the clamping mode... I guess we could disallow it...
Ok(Percentage {
value: result,
calc_clamping_mode: Some(num_context),
})
}
t => Err(BasicParseError::UnexpectedToken(t).into())
}
@ -749,32 +791,39 @@ impl Percentage {
/// 0%
#[inline]
pub fn zero() -> Self {
Percentage(0.)
Percentage {
value: 0.,
calc_clamping_mode: None,
}
}
/// 100%
#[inline]
pub fn hundred() -> Self {
Percentage(1.)
Percentage {
value: 1.,
calc_clamping_mode: None,
}
}
}
impl Parse for Percentage {
#[inline]
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<Self, ParseError<'i>> {
Self::parse_with_clamping_mode(context, input, AllowedNumericType::All)
}
}
impl ComputedValueAsSpecified for Percentage {}
/// A length or a percentage value.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
pub enum LengthOrPercentage {
Length(NoCalcLength),
Percentage(Percentage),
Percentage(computed::Percentage),
Calc(Box<CalcLengthOrPercentage>),
}
@ -797,6 +846,20 @@ impl From<NoCalcLength> for LengthOrPercentage {
impl From<Percentage> for LengthOrPercentage {
#[inline]
fn from(pc: Percentage) -> Self {
if pc.calc_clamping_mode.is_some() {
LengthOrPercentage::Calc(Box::new(CalcLengthOrPercentage {
percentage: Some(computed::Percentage(pc.get())),
.. Default::default()
}))
} else {
LengthOrPercentage::Percentage(computed::Percentage(pc.get()))
}
}
}
impl From<computed::Percentage> for LengthOrPercentage {
#[inline]
fn from(pc: computed::Percentage) -> Self {
LengthOrPercentage::Percentage(pc)
}
}
@ -820,7 +883,7 @@ impl LengthOrPercentage {
NoCalcLength::parse_dimension(context, value, unit).map(LengthOrPercentage::Length)
}
Token::Percentage { unit_value, .. } if num_context.is_ok(context.parsing_mode, unit_value) => {
return Ok(LengthOrPercentage::Percentage(Percentage(unit_value)))
return Ok(LengthOrPercentage::Percentage(computed::Percentage(unit_value)))
}
Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) => {
if value != 0. &&
@ -925,7 +988,7 @@ impl LengthOrPercentage {
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
pub enum LengthOrPercentageOrAuto {
Length(NoCalcLength),
Percentage(Percentage),
Percentage(computed::Percentage),
Auto,
Calc(Box<CalcLengthOrPercentage>),
}
@ -937,9 +1000,9 @@ impl From<NoCalcLength> for LengthOrPercentageOrAuto {
}
}
impl From<Percentage> for LengthOrPercentageOrAuto {
impl From<computed::Percentage> for LengthOrPercentageOrAuto {
#[inline]
fn from(pc: Percentage) -> Self {
fn from(pc: computed::Percentage) -> Self {
LengthOrPercentageOrAuto::Percentage(pc)
}
}
@ -956,7 +1019,7 @@ impl LengthOrPercentageOrAuto {
NoCalcLength::parse_dimension(context, value, unit).map(LengthOrPercentageOrAuto::Length)
}
Token::Percentage { unit_value, .. } if num_context.is_ok(context.parsing_mode, unit_value) => {
Ok(LengthOrPercentageOrAuto::Percentage(Percentage(unit_value)))
Ok(LengthOrPercentageOrAuto::Percentage(computed::Percentage(unit_value)))
}
Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) => {
if value != 0. &&
@ -1009,7 +1072,7 @@ impl LengthOrPercentageOrAuto {
/// Returns a value representing `0%`.
pub fn zero_percent() -> Self {
LengthOrPercentageOrAuto::Percentage(Percentage::zero())
LengthOrPercentageOrAuto::Percentage(computed::Percentage::zero())
}
}
@ -1037,7 +1100,7 @@ impl LengthOrPercentageOrAuto {
#[allow(missing_docs)]
pub enum LengthOrPercentageOrNone {
Length(NoCalcLength),
Percentage(Percentage),
Percentage(computed::Percentage),
Calc(Box<CalcLengthOrPercentage>),
None,
}
@ -1055,7 +1118,7 @@ impl LengthOrPercentageOrNone {
NoCalcLength::parse_dimension(context, value, unit).map(LengthOrPercentageOrNone::Length)
}
Token::Percentage { unit_value, .. } if num_context.is_ok(context.parsing_mode, unit_value) => {
Ok(LengthOrPercentageOrNone::Percentage(Percentage(unit_value)))
Ok(LengthOrPercentageOrNone::Percentage(computed::Percentage(unit_value)))
}
Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) => {
if value != 0. && !context.parsing_mode.allows_unitless_lengths() &&

View File

@ -504,8 +504,11 @@ impl ToCss for Number {
}
}
/// <number-percentage>
/// <number> | <percentage>
///
/// Accepts only non-negative numbers.
///
/// FIXME(emilio): Should probably use Either.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, ToCss)]
@ -517,10 +520,11 @@ pub enum NumberOrPercentage {
no_viewport_percentage!(NumberOrPercentage);
impl NumberOrPercentage {
fn parse_with_clamping_mode<'i, 't>(context: &ParserContext,
input: &mut Parser<'i, 't>,
type_: AllowedNumericType)
-> Result<Self, ParseError<'i>> {
fn parse_with_clamping_mode<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
type_: AllowedNumericType
) -> Result<Self, ParseError<'i>> {
if let Ok(per) = input.try(|i| Percentage::parse_with_clamping_mode(context, i, type_)) {
return Ok(NumberOrPercentage::Percentage(per));
}

View File

@ -12,9 +12,9 @@ use parser::{Parse, ParserContext};
use std::fmt;
use style_traits::{HasViewportPercentage, ToCss, ParseError};
use values::computed::{CalcLengthOrPercentage, LengthOrPercentage as ComputedLengthOrPercentage};
use values::computed::{Context, ToComputedValue};
use values::computed::{Context, Percentage, ToComputedValue};
use values::generics::position::Position as GenericPosition;
use values::specified::{AllowQuirks, LengthOrPercentage, Percentage};
use values::specified::{AllowQuirks, LengthOrPercentage};
use values::specified::transform::OriginComponent;
/// The specified value of a CSS `<position>`
@ -195,7 +195,7 @@ impl<S: Parse> PositionComponent<S> {
impl<S> PositionComponent<S> {
/// `0%`
pub fn zero() -> Self {
PositionComponent::Length(LengthOrPercentage::Percentage(Percentage(0.)))
PositionComponent::Length(LengthOrPercentage::Percentage(Percentage::zero()))
}
}
@ -214,7 +214,8 @@ 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::new(-length, Some(Percentage(1.0))))
ComputedLengthOrPercentage::Calc(
CalcLengthOrPercentage::new(-length, Some(Percentage::hundred())))
},
ComputedLengthOrPercentage::Percentage(p) => {
ComputedLengthOrPercentage::Percentage(Percentage(1.0 - p.0))

View File

@ -9,12 +9,13 @@ use euclid::Point2D;
use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseError;
use style_traits::{ParseError, StyleParseError};
use values::computed::{LengthOrPercentage as ComputedLengthOrPercentage, Context, ToComputedValue};
use values::computed::{Context, LengthOrPercentage as ComputedLengthOrPercentage};
use values::computed::{Percentage as ComputedPercentage, ToComputedValue};
use values::computed::transform::TimingFunction as ComputedTimingFunction;
use values::generics::transform::{StepPosition, TimingFunction as GenericTimingFunction};
use values::generics::transform::{TimingKeyword, TransformOrigin as GenericTransformOrigin};
use values::specified::{Integer, Number};
use values::specified::length::{Length, LengthOrPercentage, Percentage};
use values::specified::length::{Length, LengthOrPercentage};
use values::specified::position::{Side, X, Y};
/// The specified value of a CSS `<transform-origin>`
@ -107,13 +108,13 @@ impl<S> ToComputedValue for OriginComponent<S>
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
OriginComponent::Center => {
ComputedLengthOrPercentage::Percentage(Percentage(0.5))
ComputedLengthOrPercentage::Percentage(ComputedPercentage(0.5))
},
OriginComponent::Length(ref length) => {
length.to_computed_value(context)
},
OriginComponent::Side(ref keyword) => {
let p = Percentage(if keyword.is_start() { 0. } else { 1. });
let p = ComputedPercentage(if keyword.is_start() { 0. } else { 1. });
ComputedLengthOrPercentage::Percentage(p)
},
}
@ -127,7 +128,7 @@ impl<S> ToComputedValue for OriginComponent<S>
impl<S> OriginComponent<S> {
/// `0%`
pub fn zero() -> Self {
OriginComponent::Length(LengthOrPercentage::Percentage(Percentage(0.)))
OriginComponent::Length(LengthOrPercentage::Percentage(ComputedPercentage::zero()))
}
}

View File

@ -2483,8 +2483,9 @@ pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(declarations:
use style::properties::{PropertyDeclaration, LonghandId};
use style::properties::longhands::height::SpecifiedValue as Height;
use style::properties::longhands::width::SpecifiedValue as Width;
use style::values::computed::Percentage;
use style::values::specified::MozLength;
use style::values::specified::length::{LengthOrPercentage, Percentage};
use style::values::specified::length::LengthOrPercentage;
let long = get_longhand_from_id!(property);
let pc = Percentage(value);

View File

@ -8,7 +8,7 @@ use style::properties::animated_properties::{Animatable, IntermediateRGBA};
use style::properties::longhands::transform::computed_value::ComputedOperation as TransformOperation;
use style::properties::longhands::transform::computed_value::T as TransformList;
use style::values::animated::ToAnimatedValue;
use style::values::specified::length::Percentage;
use style::values::computed::length::Percentage;
fn interpolate_rgba(from: RGBA, to: RGBA, progress: f64) -> RGBA {
let from = from.to_animated_value();

View File

@ -5,7 +5,7 @@
use app_units::Au;
use style::attr::{AttrValue, LengthOrPercentageOrAuto, parse_length};
use style::values::computed::CalcLengthOrPercentage;
use style::values::specified::length::Percentage;
use style::values::computed::length::Percentage;
#[test]
fn test_length_calc() {

View File

@ -358,16 +358,16 @@ mod shorthand_serialization {
fn border_radius_should_serialize_correctly() {
let mut properties = Vec::new();
properties.push(PropertyDeclaration::BorderTopLeftRadius(Box::new(BorderCornerRadius::new(
Percentage(0.01).into(), Percentage(0.05).into()
Percentage::new(0.01).into(), Percentage::new(0.05).into()
))));
properties.push(PropertyDeclaration::BorderTopRightRadius(Box::new(BorderCornerRadius::new(
Percentage(0.02).into(), Percentage(0.06).into()
Percentage::new(0.02).into(), Percentage::new(0.06).into()
))));
properties.push(PropertyDeclaration::BorderBottomRightRadius(Box::new(BorderCornerRadius::new(
Percentage(0.03).into(), Percentage(0.07).into()
Percentage::new(0.03).into(), Percentage::new(0.07).into()
))));
properties.push(PropertyDeclaration::BorderBottomLeftRadius(Box::new(BorderCornerRadius::new(
Percentage(0.04).into(), Percentage(0.08).into()
Percentage::new(0.04).into(), Percentage::new(0.08).into()
))));
let serialization = shorthand_properties_to_string(properties);
@ -563,7 +563,7 @@ mod shorthand_serialization {
let grow = Number::new(2f32);
let shrink = Number::new(3f32);
let basis =
FlexBasis::Length(Percentage(0.5f32).into());
FlexBasis::Length(Percentage::new(0.5f32).into());
properties.push(PropertyDeclaration::FlexGrow(grow));
properties.push(PropertyDeclaration::FlexShrink(shrink));

View File

@ -26,7 +26,8 @@ use style::stylesheets::{Origin, Namespaces};
use style::stylesheets::{Stylesheet, StylesheetContents, NamespaceRule, CssRule, CssRules, StyleRule, KeyframesRule};
use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframePercentage};
use style::values::{KeyframesName, CustomIdent};
use style::values::specified::{LengthOrPercentageOrAuto, Percentage, PositionComponent};
use style::values::computed::Percentage;
use style::values::specified::{LengthOrPercentageOrAuto, PositionComponent};
pub fn block_from<I>(iterable: I) -> PropertyDeclarationBlock
where I: IntoIterator<Item=(PropertyDeclaration, Importance)> {