diff --git a/components/layout/block.rs b/components/layout/block.rs index 4da24dfebd0..adeb04730a3 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -46,7 +46,6 @@ use gfx_traits::print_tree::PrintTree; use incremental::RelayoutMode; use layout_debug; use model::{AdjoiningMargins, CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo, MaybeAuto}; -use model::{specified, specified_or_none}; use sequential; use serde::{Serialize, Serializer}; use servo_geometry::max_rect; @@ -326,7 +325,7 @@ impl CandidateBSizeIterator { MaybeAuto::Specified(block_container_block_size.scale_by(percent)) } (LengthOrPercentageOrAuto::Calc(calc), _) => { - MaybeAuto::from_option(calc.to_computed(block_container_block_size)) + MaybeAuto::from_option(calc.to_used_value(block_container_block_size)) } (LengthOrPercentageOrAuto::Percentage(_), None) | (LengthOrPercentageOrAuto::Auto, _) => MaybeAuto::Auto, @@ -337,7 +336,7 @@ impl CandidateBSizeIterator { Some(block_container_block_size.scale_by(percent)) } (LengthOrPercentageOrNone::Calc(calc), _) => { - calc.to_computed(block_container_block_size) + calc.to_used_value(block_container_block_size) } (LengthOrPercentageOrNone::Percentage(_), None) | (LengthOrPercentageOrNone::None, _) => None, @@ -348,7 +347,7 @@ impl CandidateBSizeIterator { block_container_block_size.scale_by(percent) } (LengthOrPercentage::Calc(calc), _) => { - calc.to_computed(block_container_block_size).unwrap_or(Au(0)) + calc.to_used_value(block_container_block_size).unwrap_or(Au(0)) } (LengthOrPercentage::Percentage(_), None) => Au(0), (LengthOrPercentage::Length(length), _) => length, @@ -1167,7 +1166,7 @@ impl BlockFlow { match (content_block_size, containing_block_size) { (LengthOrPercentageOrAuto::Calc(calc), _) => { - calc.to_computed(containing_block_size) + calc.to_used_value(containing_block_size) } (LengthOrPercentageOrAuto::Length(length), _) => Some(length), (LengthOrPercentageOrAuto::Percentage(percent), Some(container_size)) => { @@ -1417,8 +1416,8 @@ impl BlockFlow { // we know. if kid.is_inline_flow() { kid.as_mut_inline().first_line_indentation = - specified(self.fragment.style().get_inheritedtext().text_indent, - containing_block_size); + self.fragment.style().get_inheritedtext().text_indent + .to_used_value(containing_block_size); } } } @@ -1512,14 +1511,12 @@ impl BlockFlow { } else { content_box.size.inline } - self.fragment.margin.inline_start_end(); - let max_inline_size = specified_or_none( - self.fragment.style().max_inline_size(), - self.base.block_container_inline_size - ).unwrap_or(MAX_AU); - let min_inline_size = specified( - self.fragment.style().min_inline_size(), - self.base.block_container_inline_size - ); + let max_inline_size = + self.fragment.style().max_inline_size() + .to_used_value(self.base.block_container_inline_size) + .unwrap_or(MAX_AU); + let min_inline_size = + self.fragment.style().min_inline_size().to_used_value(self.base.block_container_inline_size); let specified_inline_size = self.fragment.style().content_inline_size(); let container_size = self.base.block_container_inline_size; let inline_size = @@ -2413,8 +2410,7 @@ pub trait ISizeAndMarginsComputer { // If the tentative used inline-size is greater than 'max-inline-size', inline-size should // be recalculated, but this time using the computed value of 'max-inline-size' as the // computed value for 'inline-size'. - match specified_or_none(block.fragment().style().max_inline_size(), - containing_block_inline_size) { + match block.fragment().style().max_inline_size().to_used_value(containing_block_inline_size) { Some(max_inline_size) if max_inline_size < solution.inline_size => { input.computed_inline_size = MaybeAuto::Specified(max_inline_size); solution = self.solve_inline_size_constraints(block, &input); @@ -2425,8 +2421,8 @@ pub trait ISizeAndMarginsComputer { // If the resulting inline-size is smaller than 'min-inline-size', inline-size should be // recalculated, but this time using the value of 'min-inline-size' as the computed value // for 'inline-size'. - let computed_min_inline_size = specified(block.fragment().style().min_inline_size(), - containing_block_inline_size); + let computed_min_inline_size = + block.fragment().style().min_inline_size().to_used_value(containing_block_inline_size); if computed_min_inline_size > solution.inline_size { input.computed_inline_size = MaybeAuto::Specified(computed_min_inline_size); solution = self.solve_inline_size_constraints(block, &input); diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 9d81ea6ff87..36336b94b44 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -33,7 +33,7 @@ use gfx_traits::{combine_id_with_fragment_type, FragmentType, StackingContextId} use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT}; use ipc_channel::ipc; use list_item::ListItemFlow; -use model::{self, MaybeAuto, specified}; +use model::{self, MaybeAuto}; use msg::constellation_msg::BrowsingContextId; use net_traits::image::base::PixelFormat; use net_traits::image_cache::UsePlaceholder; @@ -1026,10 +1026,8 @@ impl FragmentDisplayListBuilding for Fragment { let horiz_position = *get_cyclic(&background.background_position_x.0, index); let vert_position = *get_cyclic(&background.background_position_y.0, index); // Use `background-position` to get the offset. - let horizontal_position = model::specified(horiz_position, - bounds.size.width - image_size.width); - let vertical_position = model::specified(vert_position, - bounds.size.height - image_size.height); + let horizontal_position = horiz_position.to_used_value(bounds.size.width - image_size.width); + let vertical_position = vert_position.to_used_value(bounds.size.height - image_size.height); // The anchor position for this background, based on both the background-attachment // and background-position properties. @@ -1185,8 +1183,8 @@ impl FragmentDisplayListBuilding for Fragment { repeating: bool, style: &ServoComputedValues) -> display_list::RadialGradient { - let center = Point2D::new(specified(center.horizontal, bounds.size.width), - specified(center.vertical, bounds.size.height)); + let center = Point2D::new(center.horizontal.to_used_value(bounds.size.width), + center.vertical.to_used_value(bounds.size.height)); let radius = match *shape { GenericEndingShape::Circle(Circle::Radius(length)) => { Size2D::new(length, length) @@ -1195,7 +1193,7 @@ impl FragmentDisplayListBuilding for Fragment { convert_circle_size_keyword(extent, &bounds.size, ¢er) }, GenericEndingShape::Ellipse(Ellipse::Radii(x, y)) => { - Size2D::new(specified(x, bounds.size.width), specified(y, bounds.size.height)) + Size2D::new(x.to_used_value(bounds.size.width), y.to_used_value(bounds.size.height)) }, GenericEndingShape::Ellipse(Ellipse::Extent(extent)) => { convert_ellipse_size_keyword(extent, &bounds.size, ¢er) diff --git a/components/layout/flex.rs b/components/layout/flex.rs index dd990c61510..0abd32b6dc0 100644 --- a/components/layout/flex.rs +++ b/components/layout/flex.rs @@ -18,7 +18,6 @@ use flow::{INLINE_POSITION_IS_STATIC, IS_ABSOLUTELY_POSITIONED}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use layout_debug; use model::{IntrinsicISizes, MaybeAuto, SizeConstraint}; -use model::{specified, specified_or_none}; use std::cmp::{max, min}; use std::ops::Range; use style::computed_values::{align_content, align_self, flex_direction, flex_wrap, justify_content}; @@ -52,7 +51,7 @@ impl AxisSize { } } LengthOrPercentageOrAuto::Calc(calc) => { - match calc.to_computed(content_size) { + match calc.to_used_value(content_size) { Some(length) => AxisSize::Definite(length), None => AxisSize::Infinite, } @@ -79,7 +78,7 @@ fn from_flex_basis(flex_basis: LengthOrPercentageOrAutoOrContent, (LengthOrPercentageOrAutoOrContent::Percentage(_), None) => MaybeAuto::Auto, (LengthOrPercentageOrAutoOrContent::Calc(calc), _) => - MaybeAuto::from_option(calc.to_computed(containing_length)), + MaybeAuto::from_option(calc.to_used_value(containing_length)), (LengthOrPercentageOrAutoOrContent::Content, _) => MaybeAuto::Auto, (LengthOrPercentageOrAutoOrContent::Auto, Some(size)) => @@ -169,10 +168,11 @@ impl FlexItem { - margin + block.fragment.box_sizing_boundary(direction); self.base_size = basis.specified_or_default(content_size); - self.max_size = specified_or_none(block.fragment.style.max_inline_size(), - containing_length).unwrap_or(MAX_AU); - self.min_size = specified(block.fragment.style.min_inline_size(), - containing_length); + self.max_size = + block.fragment.style.max_inline_size() + .to_used_value(containing_length) + .unwrap_or(MAX_AU); + self.min_size = block.fragment.style.min_inline_size().to_used_value(containing_length); } Direction::Block => { let basis = from_flex_basis(block.fragment.style.get_position().flex_basis, @@ -182,10 +182,11 @@ impl FlexItem { - block.fragment.border_padding.block_start_end() + block.fragment.box_sizing_boundary(direction); self.base_size = basis.specified_or_default(content_size); - self.max_size = specified_or_none(block.fragment.style.max_block_size(), - containing_length).unwrap_or(MAX_AU); - self.min_size = specified(block.fragment.style.min_block_size(), - containing_length); + self.max_size = + block.fragment.style.max_block_size() + .to_used_value(containing_length) + .unwrap_or(MAX_AU); + self.min_size = block.fragment.style.min_block_size().to_used_value(containing_length); } } } diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 39233ecc4a2..11b82bceb61 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -907,8 +907,8 @@ impl Fragment { // cascading. let padding = if flags.contains(INTRINSIC_INLINE_SIZE_INCLUDES_PADDING) { let padding = style.logical_padding(); - (model::specified(padding.inline_start, Au(0)) + - model::specified(padding.inline_end, Au(0))) + (padding.inline_start.to_used_value(Au(0)) + + padding.inline_end.to_used_value(Au(0))) } else { Au(0) }; @@ -935,8 +935,8 @@ impl Fragment { if flags.contains(INTRINSIC_INLINE_SIZE_INCLUDES_SPECIFIED) { specified = MaybeAuto::from_style(style.content_inline_size(), Au(0)).specified_or_zero(); - specified = max(model::specified(style.min_inline_size(), Au(0)), specified); - if let Some(max) = model::specified_or_none(style.max_inline_size(), Au(0)) { + specified = max(style.min_inline_size().to_used_value(Au(0)), specified); + if let Some(max) = style.max_inline_size().to_used_value(Au(0)) { specified = min(specified, max) } @@ -1159,10 +1159,10 @@ impl Fragment { let border_width = self.border_width(); SpeculatedInlineContentEdgeOffsets { start: MaybeAuto::from_style(logical_margin.inline_start, Au(0)).specified_or_zero() + - model::specified(logical_padding.inline_start, Au(0)) + + logical_padding.inline_start.to_used_value(Au(0)) + border_width.inline_start, end: MaybeAuto::from_style(logical_margin.inline_end, Au(0)).specified_or_zero() + - model::specified(logical_padding.inline_end, Au(0)) + + logical_padding.inline_end.to_used_value(Au(0)) + border_width.inline_end, } } @@ -1491,10 +1491,10 @@ impl Fragment { // the size constraints work properly. // TODO(stshine): Find a cleaner way to do this. let padding = self.style.logical_padding(); - self.border_padding.inline_start = model::specified(padding.inline_start, Au(0)); - self.border_padding.inline_end = model::specified(padding.inline_end, Au(0)); - self.border_padding.block_start = model::specified(padding.block_start, Au(0)); - self.border_padding.block_end = model::specified(padding.block_end, Au(0)); + self.border_padding.inline_start = padding.inline_start.to_used_value(Au(0)); + self.border_padding.inline_end = padding.inline_end.to_used_value(Au(0)); + self.border_padding.block_start = padding.block_start.to_used_value(Au(0)); + self.border_padding.block_end = padding.block_end.to_used_value(Au(0)); let border = self.border_width(); self.border_padding.inline_start += border.inline_start; self.border_padding.inline_end += border.inline_end; @@ -2847,12 +2847,14 @@ impl Fragment { let mut transform = Matrix4D::identity(); let transform_origin = &self.style.get_box().transform_origin; - let transform_origin_x = model::specified(transform_origin.horizontal, - stacking_relative_border_box.size - .width).to_f32_px(); - let transform_origin_y = model::specified(transform_origin.vertical, - stacking_relative_border_box.size - .height).to_f32_px(); + let transform_origin_x = + transform_origin.horizontal + .to_used_value(stacking_relative_border_box.size.width) + .to_f32_px(); + let transform_origin_y = + transform_origin.vertical + .to_used_value(stacking_relative_border_box.size.height) + .to_f32_px(); let transform_origin_z = transform_origin.depth.to_f32_px(); let pre_transform = Matrix4D::create_translation(transform_origin_x, @@ -2875,10 +2877,8 @@ impl Fragment { Matrix4D::create_scale(sx, sy, sz) } transform::ComputedOperation::Translate(tx, ty, tz) => { - let tx = - model::specified(tx, stacking_relative_border_box.size.width).to_f32_px(); - let ty = - model::specified(ty, stacking_relative_border_box.size.height).to_f32_px(); + let tx = tx.to_used_value(stacking_relative_border_box.size.width).to_f32_px(); + let ty = ty.to_used_value(stacking_relative_border_box.size.height).to_f32_px(); let tz = tz.to_f32_px(); Matrix4D::create_translation(tx, ty, tz) } @@ -2907,10 +2907,13 @@ impl Fragment { Either::First(length) => { let perspective_origin = self.style().get_box().perspective_origin; let perspective_origin = - Point2D::new(model::specified(perspective_origin.horizontal, - stacking_relative_border_box.size.width).to_f32_px(), - model::specified(perspective_origin.vertical, - stacking_relative_border_box.size.height).to_f32_px()); + Point2D::new( + perspective_origin.horizontal + .to_used_value(stacking_relative_border_box.size.width) + .to_f32_px(), + perspective_origin.vertical + .to_used_value(stacking_relative_border_box.size.height) + .to_f32_px()); let pre_transform = Matrix4D::create_translation(perspective_origin.x, perspective_origin.y, diff --git a/components/layout/model.rs b/components/layout/model.rs index aba7c3f3927..a762c1d59c8 100644 --- a/components/layout/model.rs +++ b/components/layout/model.rs @@ -412,7 +412,7 @@ impl MaybeAuto { MaybeAuto::Specified(containing_length.scale_by(percent)) } LengthOrPercentageOrAuto::Calc(calc) => { - MaybeAuto::from_option(calc.to_computed(Some(containing_length))) + MaybeAuto::from_option(calc.to_used_value(Some(containing_length))) } LengthOrPercentageOrAuto::Length(length) => MaybeAuto::Specified(length) } @@ -463,24 +463,6 @@ pub fn style_length(style_length: LengthOrPercentageOrAuto, } } -pub fn specified_or_none(length: LengthOrPercentageOrNone, containing_length: Au) -> Option { - match length { - LengthOrPercentageOrNone::None => None, - LengthOrPercentageOrNone::Percentage(percent) => Some(containing_length.scale_by(percent)), - LengthOrPercentageOrNone::Calc(calc) => calc.to_computed(Some(containing_length)), - LengthOrPercentageOrNone::Length(length) => Some(length), - } -} - -pub fn specified(length: LengthOrPercentage, containing_length: Au) -> Au { - match length { - LengthOrPercentage::Length(length) => length, - LengthOrPercentage::Percentage(p) => containing_length.scale_by(p), - LengthOrPercentage::Calc(calc) => - containing_length.scale_by(calc.percentage()) + calc.length(), - } -} - /// Computes a border radius size against the containing size. /// /// Note that percentages in `border-radius` are resolved against the relevant @@ -495,8 +477,8 @@ pub fn specified_border_radius( -> Size2D { let generics::BorderRadiusSize(size) = radius; - let w = specified(size.width, containing_size.width); - let h = specified(size.height, containing_size.height); + let w = size.width.to_used_value(containing_size.width); + let h = size.height.to_used_value(containing_size.height); Size2D::new(w, h) } @@ -507,10 +489,10 @@ pub fn padding_from_style(style: &ServoComputedValues, -> LogicalMargin { let padding_style = style.get_padding(); LogicalMargin::from_physical(writing_mode, SideOffsets2D::new( - specified(padding_style.padding_top, containing_block_inline_size), - specified(padding_style.padding_right, containing_block_inline_size), - specified(padding_style.padding_bottom, containing_block_inline_size), - specified(padding_style.padding_left, containing_block_inline_size))) + padding_style.padding_top.to_used_value(containing_block_inline_size), + padding_style.padding_right.to_used_value(containing_block_inline_size), + padding_style.padding_bottom.to_used_value(containing_block_inline_size), + padding_style.padding_left.to_used_value(containing_block_inline_size))) } /// Returns the explicitly-specified margin lengths from the given style. Percentage and auto @@ -559,7 +541,7 @@ impl SizeConstraint { max_size: LengthOrPercentageOrNone, border: Option) -> SizeConstraint { let mut min_size = match container_size { - Some(container_size) => specified(min_size, container_size), + Some(container_size) => min_size.to_used_value(container_size), None => if let LengthOrPercentage::Length(length) = min_size { length } else { @@ -568,7 +550,7 @@ impl SizeConstraint { }; let mut max_size = match container_size { - Some(container_size) => specified_or_none(max_size, container_size), + Some(container_size) => max_size.to_used_value(container_size), None => if let LengthOrPercentageOrNone::Length(length) = max_size { Some(length) } else { diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 980ef36b280..4271f5885aa 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -24,7 +24,7 @@ impl From 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 for CalcLengthOrPercentage { } else { None }; - CalcLengthOrPercentage { - length: Au(other.mLength), - percentage: percentage, - } + Self::new(Au(other.mLength), percentage) } } diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index e23b4877e56..0fffb440d01 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -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] diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 1bab68160be..f361f1c4cb8 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -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, } impl CalcLengthOrPercentage { + /// Returns a new `CalcLengthOrPercentage`. + #[inline] + pub fn new(length: Au, percentage: Option) -> 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, + 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) -> Option { + pub fn to_used_value(&self, container_len: Option) -> Option { 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 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 for Option { fn from(len: LengthOrPercentageOrAuto) -> Option { 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 { + 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 { diff --git a/components/style/values/specified/calc.rs b/components/style/values/specified/calc.rs index 4f49df256e7..4db36e998c2 100644 --- a/components/style/values/specified/calc.rs +++ b/components/style/values/specified/calc.rs @@ -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, pub vw: Option, pub vh: Option, @@ -271,8 +273,12 @@ impl CalcNode { /// Tries to simplify this expression into a `` or ` /// value. - fn to_length_or_percentage(&self) -> Result { - let mut ret = CalcLengthOrPercentage::default(); + fn to_length_or_percentage(&self, clamping_mode: AllowedLengthType) + -> Result { + 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 ` | `. pub fn parse_length_or_percentage( context: &ParserContext, - input: &mut Parser) + input: &mut Parser, + clamping_mode: AllowedLengthType) -> Result { Self::parse(context, input, CalcUnit::LengthOrPercentage)? - .to_length_or_percentage() + .to_length_or_percentage(clamping_mode) } /// Convenience parsing function for ``. pub fn parse_length( context: &ParserContext, - input: &mut Parser) + input: &mut Parser, + clamping_mode: AllowedLengthType) -> Result { Self::parse(context, input, CalcUnit::Length)? - .to_length_or_percentage() + .to_length_or_percentage(clamping_mode) } /// Convenience parsing function for ``. diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index 7a6f6259732..d117593738c 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -539,7 +539,7 @@ pub enum Length { /// A calc expression. /// /// https://drafts.csswg.org/css-values/#calc-notation - Calc(AllowedLengthType, Box), + Calc(Box), } impl From 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(&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 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))) }, diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs index 678d2a8777d..abeef00fe21 100644 --- a/components/style/values/specified/position.rs +++ b/components/style/values/specified/position.rs @@ -234,19 +234,14 @@ impl ToComputedValue for PositionComponent { 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))) }, } }, diff --git a/components/style_traits/values.rs b/components/style_traits/values.rs index 663a39fb6ac..847177c2aaa 100644 --- a/components/style_traits/values.rs +++ b/components/style_traits/values.rs @@ -189,6 +189,13 @@ pub mod specified { NonNegative } + impl Default for AllowedLengthType { + #[inline] + fn default() -> Self { + AllowedLengthType::All + } + } + impl AllowedLengthType { /// Whether value is valid for this allowed length type. #[inline] diff --git a/tests/unit/style/attr.rs b/tests/unit/style/attr.rs index 10f1bd5e585..25fe085a637 100644 --- a/tests/unit/style/attr.rs +++ b/tests/unit/style/attr.rs @@ -5,17 +5,18 @@ use app_units::Au; use style::attr::{AttrValue, LengthOrPercentageOrAuto, parse_length}; use style::values::computed::CalcLengthOrPercentage; +use style_traits::values::specified::AllowedLengthType; #[test] fn test_length_calc() { - let calc = CalcLengthOrPercentage { length: Au(10), percentage: Some(0.2) }; - assert_eq!(calc.to_computed(Some(Au(10))), Some(Au(12))); - assert_eq!(calc.to_computed(Some(Au(0))), Some(Au(10))); - assert_eq!(calc.to_computed(None), None); + let calc = CalcLengthOrPercentage::new(Au(10), Some(0.2)); + assert_eq!(calc.to_used_value(Some(Au(10))), Some(Au(12))); + assert_eq!(calc.to_used_value(Some(Au(0))), Some(Au(10))); + assert_eq!(calc.to_used_value(None), None); - let calc = CalcLengthOrPercentage { length: Au(10), percentage: None }; - assert_eq!(calc.to_computed(Some(Au(0))), Some(Au(10))); - assert_eq!(calc.to_computed(None), Some(Au(10))); + let calc = CalcLengthOrPercentage::new(Au(10), None); + assert_eq!(calc.to_used_value(Some(Au(0))), Some(Au(10))); + assert_eq!(calc.to_used_value(None), Some(Au(10))); } #[test]