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